> Fetch the index of every Tonbo docs page as Markdown at https://tonbo.dev/llms.txt

# Use with Drizzle

Last updated 29 October 2026

Use [Drizzle ORM](https://orm.drizzle.team) on a Tonbo database once the [Drizzle quickstart](https://tonbo.dev/docs/getting-started/quickstarts/drizzle.md) runs: the driver, migrations in the app, `synced()`, transactions, and what does not work.

## The driver

`open()` returns a [`DatabaseSync`](https://nodejs.org/docs/latest-v22.x/api/sqlite.html#class-databasesync), which Drizzle’s [node:sqlite driver](https://orm.drizzle.team/docs/connect-node-sqlite) takes as its client. The driver ships only in Drizzle’s 1.0 release candidate, so pin it exactly; Tonbo’s Streams acceptance test runs drizzle-orm 1.0.0-rc.5.

## Migrations run in the app

[`drizzle-kit generate`](https://orm.drizzle.team/docs/migrations) reads only the schema, so it runs anywhere. The migrator then runs in the app, on the connection `open()` returned: it applies the migrations it has not applied, in one transaction, and records each in `__drizzle_migrations`. The migration replicates like any commit, so every later open, on any host, finds it applied.

## Why not drizzle-kit migrate

`drizzle-kit migrate`, `push`, `pull` and `studio` open the database file with their own driver. The files in the cache root are not SQLite files outside the extension, so they fail with `SQLITE_NOTADB` and change nothing. Even a file they could open would be a local copy whose changes never reach Tonbo.

## synced()

Drizzle knows nothing of `synced()`. A Drizzle write returns once it is committed on this host. Call `await client.synced()` on the connection before anything outside the process acts on what you wrote, such as a response. See [When a commit is durable](https://tonbo.dev/docs/databases/how-it-works.md#commit).

## Transactions

The node:sqlite driver’s [transactions](https://orm.drizzle.team/docs/transactions) are synchronous. Pass a function that is not `async`, and run each query in it with `.run()`, `.all()` or `.get()` instead of `await`:

```js
db.transaction((tx) => {
  tx.insert(todos).values({ title: "first", done: false }).run();
  tx.update(todos).set({ done: true }).where(eq(todos.id, 1)).run();
  return tx.select().from(todos).all();
});
```

The transaction commits when the function returns, and rolls back when it throws. An `await` inside it would let the transaction commit before the awaited query runs; Drizzle’s types reject an `async` function here. To roll back on purpose, call `tx.rollback()`, which throws `TransactionRollbackError`:

```js
import { TransactionRollbackError } from "drizzle-orm";

try {
  db.transaction((tx) => {
    tx.insert(todos).values({ title: "draft", done: false }).run();
    tx.rollback();
  });
} catch (error) {
  if (!(error instanceof TransactionRollbackError)) throw error;
}
```

## What does not work

- `drizzle-kit migrate`, `push`, `pull` and `studio` against the cache root, as above.
- Drizzle’s stable releases (0.x) have no node:sqlite driver. Use the release candidate.
- `async` transaction functions, and the `concurrent` transaction behavior, which the driver refuses.
