Fix: drizzle-kit push — statement does not return data
PostgreSQL

Fix: drizzle-kit push — statement does not return data

drizzle-kit push failing with a driver-level TypeError on SQLite/libSQL/Turso setups. Why .run() and .get() aren't interchangeable, and the two safe ways around it.

Mahdi Ben RhoumaMahdi Ben Rhouma
Updated
7 min read
Fix: drizzle-kit push — statement does not return data

TL;DR#

TypeError: This statement does not return data. Use run() instead from npx drizzle-kit push is a driver-level mismatch, not a schema error: the SQLite family of drivers splits query execution into methods for statements that return rows (.get(), .all()) and methods for statements that don't (.run()), and drizzle-kit push's internal introspection calls the wrong one for a step in your migration. Skip straight to the fix if you just need the error gone.

The error, and where it comes from#

The clearest report of this is drizzle-team/drizzle-orm#2766, a 20-reaction GitHub issue: running npx drizzle-kit push and confirming the prompt to apply schema changes throws immediately, with no SQL syntax error and no indication of which table or column is at fault.

text
TypeError: This statement does not return data. Use run() instead

The message is coming from the SQLite driver itself, not from your schema — Drizzle is a thin layer over drivers like better-sqlite3, @libsql/client (used for Turso), and bun:sqlite, and those drivers distinguish between two families of prepared-statement methods:

  • .get() / .all() — for statements expected to return rows, like SELECT.
  • .run() — for statements that only report how many rows were affected, like INSERT, UPDATE, CREATE TABLE, or PRAGMA.

Calling .get() against a statement the driver knows returns no rows is exactly what raises this TypeError, and it happens inside drizzle-kit's own introspection/diffing logic — the step that reads your current database schema to compute what SQL to run — not inside your application code.

Why push is more fragile than generate#

drizzle-kit push works by connecting live to your database, introspecting the current schema, diffing it against your Drizzle schema definitions, and executing the resulting statements directly — all in one step, with no intermediate file. That live introspection path has to call the right driver method for every kind of statement it might encounter, across every supported SQLite driver, and a mismatch in any one combination surfaces as this exact error. If the database was built with push and you now switch to generate and migrate, the first migrate replays your initial migration against tables that already exist, so baseline the migration log first.

drizzle-kit generate, by contrast, only reads your TypeScript schema and writes plain .sql migration files to disk — it does not need to introspect a live connection, so this specific class of driver-method bug has nothing to trigger on. You then apply those files explicitly:

ts
// migrate.ts
import { drizzle } from 'drizzle-orm/libsql';
import { migrate } from 'drizzle-orm/libsql/migrator';
import { createClient } from '@libsql/client';
 
const client = createClient({ url: process.env.DATABASE_URL! });
const db = drizzle(client);
 
await migrate(db, { migrationsFolder: './drizzle' });
bash
npx drizzle-kit generate
node migrate.ts

This two-step flow is also what Drizzle's own documentation recommends for production and CI/CD — push is positioned as the fast, iterative option for local prototyping specifically because it skips the review step a generated SQL file gives you.

The fix: two ways around it#

1. Update drizzle-kit first#

This class of bug — a driver method mismatch surfaced by push's introspection — is exactly the kind of thing the Drizzle team patches per SQLite driver as reports come in. Before changing your workflow, rule out that you're simply on a version predating the fix for your specific driver:

bash
npm install drizzle-kit@latest drizzle-orm@latest
npx drizzle-kit push

If your driver package itself (@libsql/client, better-sqlite3, or the Bun runtime's built-in bun:sqlite) is old, update that too — the method contract between Drizzle and the driver has to match on both sides.

2. Fall back to generate + migrate()#

If push still throws after updating, switch that one schema change to the file-based flow above. This isn't a downgrade — it's the same command real deployments already use, since push's live-diff convenience is a local-dev feature that most teams disable for anything shared:

bash
npx drizzle-kit generate --name add_new_column

Inspect the generated .sql file in ./drizzle/ before running it — this also catches any unintended drop or rewrite the diff engine inferred, which push would have executed without showing you first.

If you're specifically on Turso / libSQL#

Turso's hosted libSQL and the local @libsql/client file mode have historically diverged slightly in which statements support .get() versus requiring .run(), since libSQL's remote HTTP protocol and its embedded/local mode aren't identical implementations of SQLite's C API. If the error only reproduces against a remote Turso database and not against a local .db file, that divergence — not your schema — is the more likely trigger, and the generate + migrate() path sidesteps it entirely because it never depends on live introspection over the network.

Verifying the fix#

  1. npx drizzle-kit generate and read the resulting .sql file — confirm it contains only the change you intended, nothing extra picked up by a stale diff.
  2. Run node migrate.ts (or your project's equivalent) against a disposable copy of the database first, not production.
  3. Confirm the table/column exists afterward with a direct query, rather than trusting a silent exit code — migrate() throws on failure, but a partially-applied multi-statement migration is worth checking by hand once.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

Push also stops to ask questions it can't answer alone#

Separate from the driver-method TypeError, drizzle-kit push has another source of surprise failures worth ruling out first if the error only shows up in CI or a scripted deploy step: when its schema diff can't tell whether a column was renamed or dropped and re-added under a new name, it pauses and asks interactively which one you meant. In a terminal that works fine — you pick an option and it continues. In a non-interactive shell (a CI runner, a Docker build step, a cron job) there's no terminal to answer the prompt, so the process either hangs until the job times out or exits with an unhelpful error that has nothing to do with the driver-method mismatch this page otherwise covers.

The practical takeaway is the same one this page already recommends for the TypeError case, for an unrelated reason: push's live, interactive diff is built for a human at a keyboard during local development, not for unattended pipelines. If a deploy step needs to apply schema changes without a person present, generate the SQL ahead of time with drizzle-kit generate and commit the resulting file, then run migrate() against it in CI — that step has nothing to introspect or disambiguate, so it has no prompt to hang on. Schema introspection speed is a separate but related pain point once a project's schema grows large enough that even generate and IDE type-checking start lagging, covered in Fix Extremely Slow Drizzle IntelliSense on Large Schemas.

Further reading: Fix npx prisma db push Hanging on Supabase (Port 6543), Prisma Can't Connect to PostgreSQL: Fix invalid port. Also see Drizzle D1: migrations do not match any local migration.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote