Database and migrations

Version schema changes

Create, review, reset, test, and push migration files rather than relying on undocumented dashboard state.

9 minute lesson

~~~

Dashboard edits feel fast until the day you need a second environment and cannot say what production’s schema actually is. Migration files fix that: every schema change is a SQL file, committed to Git, applied in order.

Create one with the Supabase CLI:

supabase migration new add_notes_pinned
# Created new migration at supabase/migrations/20260803141530_add_notes_pinned.sql

Write the change in that file:

alter table notes
  add column pinned boolean not null default false;

Then prove the whole history still builds from zero:

supabase db reset
# Resetting local database...
# Applying migration 20260803141530_add_notes_pinned.sql...
# Seeding data from supabase/seed.sql...

supabase db reset rebuilds the local database from nothing but your migration files and seed data. If it fails, your history is broken and you found out locally, which is the point. Run it after every migration you write.

If you did make a change through the local Studio UI, capture it instead of losing it: supabase db diff -f change_name writes the difference between your migration history and the live local schema into a new migration file.

Treat generated diffs as drafts. Review permissions, extensions, destructive statements, and data migrations before pushing — the diff tool records what changed, not whether the change was wise. A generated drop column deserves particular suspicion.

Shipping to the remote project

Link once, then push:

supabase link --project-ref abcdefghijkl
supabase db push --dry-run
# Would push these migrations: 20260803141530_add_notes_pinned.sql
supabase db push

The dry run previews exactly which migrations would apply. Read it before the real push.

The classic disaster in this workflow is drift: someone edits production through the dashboard, local history no longer matches remote state, and the next db push fails or half-applies. When that happens, capture the remote change with supabase db diff --linked and fold it into a proper migration file.

And never reset a production database. db reset is a local rebuilding tool; on anything shared it is data loss with a progress bar.

Finish the loop the way the exercise describes: add one column through a migration, rebuild locally, apply it to a disposable remote project, then run one old application path against it to prove the change was additive.

Lesson completed

Take this course offline

Get every free book and course as PDF and EPUB files.

Get the download library →