Skip to content
Chapter 40Lesson 4

Quiz - Migrations and seeding

Quiz progress

0 / 0

When you run drizzle-kit generate, what does it actually compare your db/schema.ts against to decide what SQL to emit?

The saved snapshot in meta/ — the recorded schema state on disk. It never inspects the live database, which is why the meta/ files must be committed alongside the .sql.

The live database it connects to at DATABASE_URL_UNPOOLED, reading the current columns and diffing against your schema.

The most recent .sql migration file, replaying its statements in memory to reconstruct the current shape.

You’re configuring dbCredentials.url in drizzle.config.ts. Why does the course insist on the unpooled DATABASE_URL_UNPOOLED here rather than the pooled URL your app uses?

Migration DDL holds long transactions that don’t survive transaction-mode pooling — the pooler can cut off a long ALTER TABLE mid-transaction.

The pooled URL is read-only by design, so it can run SELECT queries but rejects any CREATE or ALTER statement.

Drizzle Studio needs the unpooled URL, and since one config drives all commands, migrate inherits it as a side effect.

A solo prototype on an ephemeral Neon branch versus a staging database your team shares — when is drizzle-kit push the right tool?

Only the ephemeral prototype branch. push resolves an ambiguous rename-vs-drop diff by silently dropping the column, and there’s no .sql file to review — so it belongs only where you’d happily wipe the data.

Both — push is fine anywhere that isn’t production, since staging data is just test data and can be regenerated.

Neither — push is never acceptable in this stack because it skips the migration file entirely.

Drizzle Kit emitted CREATE INDEX "idx_invoices_status" ON "invoices" ("status") bundled in a migration alongside an ALTER TABLE. invoices is a live, write-heavy table. What’s the production-safe rework?

Move it to its own migration file as CREATE INDEX CONCURRENTLY — concurrent index builds can’t run inside a transaction, and Drizzle wraps each file in one, so it has to sit alone.

Add CONCURRENTLY in place and wrap it with --> statement-breakpoint markers so the runner commits the surrounding statements first.

Leave it as-is but schedule the deploy for off-peak hours, since the write lock only matters during high traffic.

A merged migration turns out to be wrong — it added a column with a bad type. What does the 2026 senior do?

Write a new, corrective migration that fixes it going forward. Merged migrations are immutable; editing an applied file drifts the snapshot from the database and makes the next generate emit nonsense.

Edit the offending migration file to correct the type, then re-run migrate so the database matches the fixed file.

Generate a down migration to reverse it, then a fresh up migration with the correct type.

Your seed config has organizations: { count: 2 } and invoices: { count: 200, with: { lineItems: 5 } }. How many line items does this produce?

1,000 — count is the total for a table (200 invoices), but with is per parent (5 line items × each of the 200 invoices).

5 — with: { lineItems: 5 } sets the total number of line items across the whole table.

400 — 2 organizations × 200 invoices, with with capped at one line item per invoice.

Why does the shipped seed script call reset(dbUnpooled, schema) before seed(...), instead of just seed on its own?

To make the script idempotent — reset clears all rows in FK-safe order so every run starts from empty and lands the same state, instead of doubling rows or hitting a unique/FK violation on the second run.

Because seed only inserts into empty tables and skips any table that already contains rows, so reset is what unlocks re-seeding.

Because reset drops and recreates the tables from the schema, guaranteeing the structure matches before data is inserted.

Your id columns are UUIDv7, filled by a $defaultFn so rows sort by creation time. How should the seed config’s columns map handle id?

Leave id out of columns entirely and let the column’s own default fill it — f.uuid() emits random v4, which would destroy the v7 time-ordering.

Set id: f.uuid() so the seeder generates valid UUIDs that satisfy the column type.

Set id: f.default() so the seeder explicitly invokes the v7 $defaultFn for each row.

Quiz complete

Score by topic