orm-guidesby September 8, 20269 min read1,752 words

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 check vs pushdrizzle kit push explaindrizzle kit pulldrizzle schema driftdrizzle kit migrate
ShareXLinkedInHN

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.

CommandReads your Drizzle schema?Reads live DB?Reads migration history?Main purpose
drizzle-kit pushYesYesNo migration files requiredCompute code-vs-live-DB changes and normally apply them
drizzle-kit push --explainYesYesNo migration files requiredDry-run the SQL push plans to apply
drizzle-kit pullNo schema required as sourceYesNoIntrospect DB → generate Drizzle schema
drizzle-kit generateYesNoYesCompare current code schema to the latest migration snapshot and write migration SQL
drizzle-kit migrateNo code-vs-DB diffDB migration logYesApply migration files that have not yet been recorded as applied
drizzle-kit checkNo live schema comparisonNoYesCheck 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 push

Drizzle's current documentation describes four steps:

  1. Read your Drizzle schema and create a schema snapshot.
  2. Introspect the connected database.
  3. Compute the differences.
  4. 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 --explain

According 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 --verbose

Do 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 check

check 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 target

That 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 TABLE in 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 pull

It reads the existing database DDL and generates a Drizzle schema.ts representation.

live database
     │
     ▼
schema.ts

Use 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 → code
  • push: 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_status

The current Drizzle docs describe this process:

  1. Read the current Drizzle schema.
  2. Read previous migration snapshots.
  3. Compare the current schema snapshot with the previous one.
  4. Write the resulting SQL migration and new snapshot.

The comparison is therefore roughly:

current schema.ts
      │
      ├── diff ──> migration.sql
      │
previous migration snapshot

Notice 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 migrate

The official docs say it:

  1. Reads SQL files from the migration folder.
  2. Reads the applied-migrations log in the database.
  3. Determines which migrations have not yet been applied.
  4. 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 --explain

If 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_change

Review 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 check

This 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 pull

Then 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 database

Each Drizzle Kit command deliberately works with a subset of that state.

  • generate cares about code and migration snapshots.
  • migrate cares about migration files and the applied-migration log.
  • check cares about migration-history compatibility.
  • pull cares about the live database as source of truth.
  • push cares 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

ShareXLinkedInHN
Related articles

Try QueryDeck free for 14 days.

Launch offer: Lifetime at $79 for the first 10 customers, then $149. Try it free for 14 days, no card required.

Launch offerLifetime at $79 for the first 10 customers, then $149.Try free for 14 days