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
Option 1: Ask the AI (Easiest)
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”.
Option 2: Create Table Modal (Visual)
Add columns
For each column pick a type:
| Type | Use for |
|---|---|
uuid | IDs, foreign keys to auth.users |
text | Any length of string — prefer over varchar |
varchar(n) | Fixed-length strings (rare) |
integer | Whole numbers up to ~2B |
bigint | Whole numbers beyond 2B |
numeric | Money, precise decimals |
boolean | True/false flags |
timestamptz | Any date/time (always include timezone) |
date | Calendar dates with no time |
jsonb | Flexible/nested data, settings, metadata |
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)
Option 3: SQL Editor (Developers)
For complex schemas, constraints, indexes, or extensions, use raw SQL.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
_id—user_id,post_id - Always use
timestamptz(never baretimestamp) to avoid timezone bugs - Store money as
integerorbigintcents, ornumeric(12, 2)— neverfloat
Common Column Patterns
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)
Verifying Your Table
Run a quick sanity check from the SQL editor:Troubleshooting
Table name rejected with "reserved word" or "invalid identifier"
Table name rejected with "reserved word" or "invalid identifier"
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.Foreign key error: referenced table or column doesn't exist
Foreign key error: referenced table or column doesn't exist
Create the parent table first. If referencing Supabase auth users, the exact reference is
auth.users(id) — note the auth. schema prefix.Client code gets permission denied errors
Client code gets permission denied errors
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.
Migration fails: column 'x' contains null values
Migration fails: column 'x' contains null values
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.Can't delete a table — referenced by foreign key
Can't delete a table — referenced by foreign key
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