Skip to main content
Your database is where user accounts, blog posts, form submissions, and everything else your app remembers get stored. Here’s how to design tables in Hiveku.
You need a provisioned database first. If you haven’t done that yet, see Set Up the Database.

Easiest

Describe it to the AI

Visual

Use the Create Table modal

For developers

Write SQL directly
All three paths live at:
Project > Database > Tables tab

Option 1: Ask the AI (Easiest)

1

Open the AI chat

Click the AI tab in your project.
2

Describe the table

Be concrete about column names, types, and relationships:
Create a posts table with:
- title (text, required)
- body (text)
- author_id (uuid, foreign key to auth.users)
- created_at (timestamptz, default now())
3

Review the plan

The AI shows the SQL it will run and the RLS policy it suggests. Approve or ask for changes — “Make title unique” or “Add a slug column”.
4

Apply

The AI runs the migration. Your table is live in seconds.

Option 2: Create Table Modal (Visual)

1

Open Tables

Go to Database > Tables and click + Create Table.
2

Name the table

Use lowercase snake_case — blog_posts, not BlogPosts or blog posts.
3

Add columns

For each column pick a type:
TypeUse for
uuidIDs, foreign keys to auth.users
textAny length of string — prefer over varchar
varchar(n)Fixed-length strings (rare)
integerWhole numbers up to ~2B
bigintWhole numbers beyond 2B
numericMoney, precise decimals
booleanTrue/false flags
timestamptzAny date/time (always include timezone)
dateCalendar dates with no time
jsonbFlexible/nested data, settings, metadata
4

Set constraints

For each column, toggle:
  • Primary key (exactly one per table)
  • Nullable (can the value be empty?)
  • Unique (no duplicates)
  • Default value (e.g., now() for timestamps, gen_random_uuid() for UUIDs)
5

Create

Click Create. Hiveku runs the DDL and the table appears in your list.
Hiveku auto-adds three columns to every new table so you don’t have to: id uuid PRIMARY KEY DEFAULT gen_random_uuid(), created_at timestamptz DEFAULT now(), and updated_at timestamptz DEFAULT now(). You can remove them in the modal if you don’t want them.

Option 3: SQL Editor (Developers)

For complex schemas, constraints, indexes, or extensions, use raw SQL.
1

Open the SQL editor

From the Database panel, click the SQL tab.
2

Write DDL

create table public.posts (
  id uuid primary key default gen_random_uuid(),
  title text not null,
  body text,
  author_id uuid references auth.users(id) on delete cascade,
  published boolean default false,
  metadata jsonb default '{}'::jsonb,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

create index posts_author_idx on public.posts(author_id);
3

Run

Click Run (or press Cmd/Ctrl+Enter). Errors show inline with line numbers.

Naming and Schema Conventions

  • Table names: lowercase snake_case, plural — blog_posts, orders, invoices
  • Column names: lowercase snake_case, singular — first_name, is_active, total_cents
  • Foreign keys: reference column name ends in _iduser_id, post_id
  • Always use timestamptz (never bare timestamp) to avoid timezone bugs
  • Store money as integer or bigint cents, or numeric(12, 2) — never float

Common Column Patterns

-- Foreign key to the authenticated user
user_id uuid references auth.users(id) on delete cascade

-- Flexible settings or metadata
settings jsonb default '{}'::jsonb

-- Soft delete
deleted_at timestamptz

-- Slug for URLs
slug text unique not null

-- Enum-like field (pick one of a set)
status text check (status in ('draft', 'published', 'archived'))

Editing an Existing Table

Click any table row in the list to open its schema editor. You can:
  • Add new columns (safe for existing data)
  • Rename columns (safe, updates dependent queries if you use Hiveku’s codegen)
  • Change column types (risky — existing values must cast cleanly)
  • Drop columns (irreversible — data is gone)
Dropping a column is permanent. Export the table first if you might need the data back.

Verifying Your Table

Run a quick sanity check from the SQL editor:
select * from your_table_name limit 5;
Or insert a test row:
insert into your_table_name (title) values ('Hello world')
returning *;

Troubleshooting

Postgres reserves words like user, order, group. Either rename (app_users, orders is fine, user_groups) or quote the name — but renaming is almost always cleaner.
Create the parent table first. If referencing Supabase auth users, the exact reference is auth.users(id) — note the auth. schema prefix.
Row-level security is on but no policy allows the action. Either add an RLS policy (the Owner access template works for most user-owned tables — see Set Up User Authentication) or use the service role key in backend code.
You tried to add a NOT NULL column without a default, and existing rows have nothing to fill it with. Either add a default value, or make the column nullable and backfill before adding the constraint.
Another table has an FK pointing at this one. Either drop that table first, drop the FK constraint on the child, or add cascade to the drop: drop table your_table cascade; (careful — cascades delete dependent rows).

What’s Next?

Set Up User Authentication

Add RLS policies so users can only access their own data

Set Up the Database

Provision or connect the database itself