shipanysaas
Documentation
Back
  • Getting started
    • Install and run
    • Project structure
    • Configuration
    • Commands
  • Coding agents
    • Agent skills
  • Authentication
    • Email sign-in
    • OAuth providers
    • Two-step sign-in and passkeys
  • Database
    • Migrations
    • Row-level security
    • Database tests
    • Reading and writing data
  • Features
    • Teams and invitations
    • Email
    • File uploads
    • Blog, docs and changelog
  • Billing
    • Stripe and Lemon Squeezy
    • Pricing plans
    • Webhooks
  • Live demo
  • Schema changes and migrations

    Change the schema in apps/web/supabase/schemas, turn the change into a migration, regenerate types, and deploy it.

    The schema files in apps/web/supabase/schemas/ describe what the database should look like. Migrations in apps/web/supabase/migrations/ are what actually runs against a database. Change both together. The steps below come from apps/web/supabase/AGENTS.md, which your coding agent also follows.

    Add a new table

    # 1. Write the table, its grants and its policies in a new schema file
    touch apps/web/supabase/schemas/20-projects.sql
    
    # 2. Create an empty migration and copy the same SQL into it
    pnpm --filter web supabase migrations new projects
    
    # 3. Apply it locally and regenerate the types
    pnpm --filter web supabase migrations up
    pnpm supabase:web:typegen
    

    Change an existing table

    # 1. Edit the schema file, then let the CLI write the migration from the diff
    pnpm --filter web supabase:db:diff -f update_projects
    
    # 2. Apply and regenerate
    pnpm --filter web supabase migrations up
    pnpm supabase:web:typegen
    

    The diff tool does not write column-level grant update (...) statements. Add those to the migration by hand (see the next section).

    Rules every new table follows

    From apps/web/supabase/AGENTS.md:

    • Turn row-level security on.
    • revoke all from anon, authenticated and service_role first. Supabase's defaults grant TRUNCATE and other privileges to all three, and TRUNCATE ignores row-level security.
    • Never grant table-wide UPDATE to authenticated. Grant it on the columns users may edit, and leave out id and account_id, so a user cannot move a row into another account.
    • Prefer generated always as identity over serial, so there is no sequence privilege to get wrong.
    • Write policies with the existing helper functions (has_role_on_account, has_permission and others; see Row-level security).

    apps/web/supabase/AGENTS.md has a full table template with these lines in place.

    Check the change

    pnpm supabase:web:reset   # rebuild the local database from all migrations
    pnpm supabase:web:test    # run the pgTAP tests
    

    schema-conditions.test.sql fails if any table in public has row-level security off, so a forgotten enable row level security shows up here. Add your own test for the new table too: see Database tests. If your agent made the change, the root AGENTS.md also requires the /rls-review skill.

    Deploy

    SUPABASE_PROJECT_REF=<your-project-ref> pnpm --filter web supabase:deploy
    

    This links the hosted project and runs supabase db push, which applies the migrations that are not there yet. It does not push seed.sql. Do not add --include-seed: the seed contains a published super-admin login.

    The development seed also creates the database webhook that calls /api/db/webhook when a subscription row is deleted. In production, create that webhook yourself in the Supabase dashboard (see Webhooks).