drizzle-kit check vs push vs pull vs migrate: what each command actually checks
A practical Drizzle Kit guide to check, push --explain, pull, generate, and migrate: which commands inspect the live database, which inspect migration history, and where schema drift can still hide.
Drizzle Kit has several commands that all sound like they should tell you whether your database is “correct.” They do not inspect the same state.
The useful distinction is what each command compares.
| Command | Reads your Drizzle schema? | Reads live DB? | Reads migration history? | Main purpose |
|---|---|---|---|---|
drizzle-kit push | Yes | Yes | No migration files required | Compute code-vs-live-DB changes and normally apply them |
drizzle-kit push --explain | Yes | Yes | No migration files required | Dry-run the SQL push plans to apply |
drizzle-kit pull | No schema required as source | Yes | No | Introspect DB → generate Drizzle schema |
drizzle-kit generate | Yes | No | Yes | Compare current code schema to the latest migration snapshot and write migration SQL |
drizzle-kit migrate | No code-vs-DB diff | DB migration log | Yes | Apply migration files that have not yet been recorded as applied |
drizzle-kit check | No live schema comparison | No | Yes | Check migration-history consistency / branch collisions |
This matters because “Drizzle has drift detection” and “Drizzle has no drift detection” are both too vague to be useful.
push absolutely does introspect the live database and compute a diff. check absolutely does not check the live database. generate + migrate is a migration-history workflow, not the same thing as a live schema.ts vs production database comparison.
drizzle-kit push: code vs the live database
This is the command most people should understand first when talking about Drizzle schema drift.
npx drizzle-kit pushDrizzle's current documentation describes four steps:
- Read your Drizzle schema and create a schema snapshot.
- Introspect the connected database.
- Compute the differences.
- Generate and apply SQL changes to the database.
So push is a live code-vs-database diff workflow.
schema.ts ─────┐
├── diff ──> SQL changes ──> database
live database ─┘That corrects a common oversimplification: it is not accurate to say Drizzle Kit has no way to see whether the live database differs from schema.ts.
The more precise question is whether you want discovering a difference and changing the database to be part of the same command flow.
drizzle-kit push --explain: the important dry run
Recent Drizzle Kit documentation exposes an --explain option for push:
npx drizzle-kit push --explainAccording to the official command reference, --explain prints the planned SQL changes without applying them.
That makes it the closest built-in Drizzle command to a read-before-write schema comparison.
If your question is:
“What would Drizzle change right now if I pushed this schema?”
push --explain is the relevant command.
You can also add --verbose when you want more SQL detail:
npx drizzle-kit push --explain --verboseDo not confuse that with --force. Drizzle documents --force as auto-accepting data-loss statements. That is the opposite of a cautious inspection workflow.
drizzle-kit check: migration consistency, not live database drift
This is where the command name can mislead people.
npx drizzle-kit checkcheck does not connect your schema.ts to production and tell you whether the live database matches it.
Drizzle's documentation says check validates the consistency of generated SQL migration history. The v1 migration documentation goes further: the command checks for non-commutative migration changes across branches, such as two branches modifying the same object in incompatible ways.
Think of it like this:
migration branch A ─┐
├── drizzle-kit check ──> history conflict?
migration branch B ─┘
live database ──────X not the comparison targetThat is valuable in a team. It solves a different problem.
What check is good at
- Multiple developers create migrations on different branches.
- You want to know whether their DDL operations can be composed safely.
- You want migration-history consistency before merging.
- You want to catch branch collisions before deployment.
What check does not answer
- Did someone manually run
ALTER TABLEin production? - Is the production index set different from
schema.ts? - Did staging receive a schema change outside the Drizzle migration history?
- Does the database you are connected to right now match the application schema?
For those questions, migration-history consistency is not enough.
drizzle-kit pull: database → code
pull is Drizzle's database-first introspection command:
npx drizzle-kit pullIt reads the existing database DDL and generates a Drizzle schema.ts representation.
live database
│
▼
schema.tsUse it when the database is the source of truth: adopting Drizzle on an existing database, reconstructing schema definitions from an external system, or intentionally bringing database-first changes into code.
That makes pull directionally different from push:
pull: DB → codepush: code → DB after computing a live diff
Neither command is a replacement for migration history when your team needs a reviewable, replayable sequence of changes.
drizzle-kit generate: code vs previous migration snapshot
generate does not need to inspect the live database to create a migration.
npx drizzle-kit generate --name add_order_statusThe current Drizzle docs describe this process:
- Read the current Drizzle schema.
- Read previous migration snapshots.
- Compare the current schema snapshot with the previous one.
- Write the resulting SQL migration and new snapshot.
The comparison is therefore roughly:
current schema.ts
│
├── diff ──> migration.sql
│
previous migration snapshotNotice what is missing from that diagram: the current production database.
That is not a flaw. It is the point of a migration-history workflow. You generate the next change from code/history, review it, commit it, and later apply it to environments.
But it means generate cannot by itself prove that the live database still matches the history you think it has.
drizzle-kit migrate: apply pending migration files
migrate is the execution half of the generated-migration workflow:
npx drizzle-kit migrateThe official docs say it:
- Reads SQL files from the migration folder.
- Reads the applied-migrations log in the database.
- Determines which migrations have not yet been applied.
- Runs those migrations and records them as applied.
The key point is that migrate is asking:
“Which migration files are pending?”
It is not asking:
“Does every table, column, index, and foreign key in this database currently match
schema.ts?”
Those are different questions.
Imagine a production hotfix:
ALTER TABLE orders ADD COLUMN emergency_flag boolean DEFAULT false;If that change was made manually and never represented in your code or migration history, migrate can still correctly know which Drizzle migrations are pending while your database is simultaneously in a state your application schema does not describe.
That is schema drift.
So does Drizzle have a drift detector?
The answer depends on what you mean by “drift detector.”
If you mean “can Drizzle compare schema.ts with a live database?”
Yes. drizzle-kit push introspects the live database and computes a diff. push --explain can show the planned SQL without applying it.
If you mean “does drizzle-kit check compare the live database with schema.ts?”
No. It checks generated migration-history consistency and branch conflicts.
If you mean “does drizzle-kit migrate perform a full live-schema preflight before applying pending migrations?”
That is not how the official migrate workflow is documented. It reads migration files and the database migration log to decide what is pending.
If you mean “is there a dedicated always-visible read-only drift view in Drizzle Kit?”
That is a different product workflow from the CLI commands above.
This distinction is the reason QueryDeck Drift Mode is positioned as a database-client feature rather than another migration command. QueryDeck parses the ORM schema and the connected database and keeps the mismatch visible while you browse the database. It does not replace Drizzle Kit's migration tooling.
Which command should I use?
“I changed schema.ts and want to see what would happen to my DB”
Use:
npx drizzle-kit push --explainIf you are happy with the planned SQL and your workflow uses direct push:
npx drizzle-kit push“I want versioned migration SQL in Git”
Generate it:
npx drizzle-kit generate --name describe_the_changeReview and commit the result, then apply pending migrations with:
npx drizzle-kit migrate“Two branches both generated migrations and I want to catch collisions”
Use:
npx drizzle-kit checkThis is exactly the migration-history problem check is designed for.
“The database changed outside Drizzle and I want code to reflect it”
Use:
npx drizzle-kit pullThen review what was generated before integrating it into your application and migration strategy.
“I want to know whether the database I am looking at matches my ORM right now”
You can inspect what push would change with push --explain. If you want that comparison as a persistent read-only view while working in the database client, that is the use case for QueryDeck Drift Mode.
Why this matters in production
Teams often talk about “the schema” as if there were only one copy. In practice there are several:
schema.ts
migration snapshots
migration SQL files
applied migration log
staging database
production databaseEach Drizzle Kit command deliberately works with a subset of that state.
generatecares about code and migration snapshots.migratecares about migration files and the applied-migration log.checkcares about migration-history compatibility.pullcares about the live database as source of truth.pushcares about current code vs the live database.
Once you think in those terms, the tooling becomes much easier to reason about.
It also becomes obvious where drift can hide: between two pieces of state that the command you are running does not compare.
For a deeper walkthrough of real drift scenarios, see Drizzle and Prisma schema drift. For the broader ORM trade-off, see Drizzle vs Prisma in 2026.
Sources
- Drizzle Kit overview — official command map for generate, migrate, push, pull, and check.
- Drizzle Kit `push` — official code-vs-live-DB introspection flow and
--explaindry run. - Drizzle Kit `check` — official migration-history consistency behavior.
- Drizzle v0 → v1 changes — current commutativity / branch-collision semantics for
check. - Drizzle Kit `pull` — official database-first introspection workflow.
- Drizzle Kit `generate` — how current schema snapshots are compared with migration snapshots.
- Drizzle Kit `migrate` — how migration files and the applied-migration log determine what runs.