Prev Next

Database / Supabase Intermediate to Advanced Interview Questions

How can you optimize zero-downtime schema migrations for a table already receiving production traffic?

The general strategy is expand-and-contract: make additive, backward-compatible changes first, deploy application code that can handle both the old and new shape simultaneously, then remove the old shape only once nothing depends on it anymore — rather than changing the schema and application code in one atomic, simultaneous step.

Concretely, adding a new column should be done as nullable (or with a fast, non-blocking default) rather than NOT NULL immediately, since a NOT NULL constraint with a non-null default historically forced a full table rewrite; adding a column and backfilling it in small batches afterward avoids a long-held lock on a large table. Renaming a column is safer done as add-new-column, dual-write from the application, backfill, then drop-old-column, rather than a single ALTER TABLE ... RENAME that breaks any code still referencing the old name mid-deploy.

-- Step 1: additive, non-blocking
alter table orders add column status_v2 text;

-- Step 2: app dual-writes both columns, backfill in batches
update orders set status_v2 = status where status_v2 is null limit 1000;

-- Step 3: once fully migrated and app only reads status_v2
alter table orders drop column status;

Indexes deserve the same care: creating one with CREATE INDEX CONCURRENTLY avoids holding an exclusive lock for the index build's duration, at the cost of it taking longer and needing a retry if it's interrupted. The unifying principle is minimizing the time any single migration statement holds a lock that blocks concurrent reads or writes on a live table.

What is the core strategy behind zero-downtime schema migrations?
Why use CREATE INDEX CONCURRENTLY instead of a plain CREATE INDEX on a live table?

More Related questions...

How does Supabase expose custom Postgres functions as callable RPC endpoints? What is the difference between a SECURITY DEFINER and a SECURITY INVOKER Postgres function? How does pg_cron enable scheduled jobs directly inside a Supabase Postgres database? What is the difference between a read replica and the primary database in a Supabase project? When should you use a read replica versus scaling the primary database's resources? What is the difference between daily backups and Point-in-Time Recovery in Supabase? How does Supabase's database branching feature isolate schema changes per git branch? When would you choose a preview branch over testing migrations directly in staging? What is the difference between a custom access token hook and a raw JWT claim? Why should you avoid embedding sensitive business data directly inside JWT claims? How does Supabase support anonymous sign-ins, and how do you convert one to a permanent account? What is the difference between linking an OAuth identity and creating a brand-new user account? How is Storage object access controlled compared to table-level Row Level Security? What is the difference between resumable (TUS) uploads and standard uploads in Supabase Storage? How does Supabase's image transformation feature resize images without a separate CDN service? What is the difference between LISTEN/NOTIFY and Supabase Realtime's Postgres Changes channel? What is the difference between schema-per-tenant and RLS-based multi-tenancy? Why is EXPLAIN ANALYZE useful before optimizing a slow Supabase query? What is the difference between JSONB and a fully normalized relational schema in Postgres? When should you use a JSONB column instead of creating additional relational tables? How does wrapping auth.uid() in a subquery improve Row Level Security performance? Why do we use SECURITY DEFINER functions when RLS would otherwise block a needed operation? How does pg_net let Postgres make asynchronous HTTP calls without blocking a transaction? Explain the lifecycle of a Point-in-Time Recovery (PITR) backup in Supabase? How does a custom access token Auth Hook let you enrich a user's JWT with custom claims? How does Supabase enforce multi-factor authentication (MFA) at the session level? Why doesn't disabling RLS on a table make it invisible in the auto-generated API docs? Explain the internal working of Supabase Vault for storing encrypted secrets in Postgres? Why should you store third-party API keys in Vault instead of a plain table column? When should you choose LISTEN/NOTIFY over Supabase Realtime for internal service communication? How can you optimize a multi-tenant schema design using Row Level Security instead of schema-per-tenant? How do you troubleshoot a Postgres query that performs well in the SQL editor but slowly through the REST API? Explain the execution flow of a private Realtime broadcast channel authorized by Row Level Security? Why do private Realtime channels need their own RLS-style authorization check? How does Supabase's connection string differ between the direct connection, session pooler, and transaction pooler? Why doesn't the transaction pooler support prepared statements the way a direct connection does? How can you optimize zero-downtime schema migrations for a table already receiving production traffic? What happens when a long-running migration locks a table that's still receiving live writes? How does Supabase Studio's SQL editor differ from running migrations through the CLI in a CI pipeline? Which is better for production schema changes, editing directly in Studio or CLI-managed migrations, and why?
Show more question and Answers...


Comments & Discussions