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

# Quickstart: Drizzle ORM

Last updated 29 October 2026

From sign-in to a first [Drizzle ORM](https://orm.drizzle.team) query on a Tonbo database.

Run it from your laptop or any machine with Node.js 22.19 or later and internet access, with nothing to allowlist, on Linux (x64 or arm64) or macOS on Apple silicon; on any other platform, such as an Intel Mac, build the package’s SQLite extension from source first (see [Requirements](https://tonbo.dev/docs/databases/connect.md#requirements)).

## Sign in

Sign in at [tonbo.dev](https://tonbo.dev/login) with GitHub or Google. A new account asks you to choose a username: it names your personal account, which holds your databases, streams and keys, and appears in the console’s addresses. You can change it once every 90 days.

## Create a database

Create a database named `notes`. It goes to the default region, `us-east-1`, unless you choose another (see [Regions and URLs](https://tonbo.dev/docs/databases/manage.md#regions)): pick the one nearest where your program runs. With the CLI, name it with `--region`, as in `tonbo database create notes --region ap-southeast-1`.

**Console**

1. Open [Databases](https://tonbo.dev/) in the console.
2. Choose **Create database** and name it `notes`.

**CLI**

```shell
npm i -g @tonbo/cli
tonbo login
tonbo database create notes
```

`tonbo login` signs you in through a browser on the same machine. On a machine without one, such as a remote server, set `TONBO_API_KEY` to a key that acts as you and is not narrowed, created in the console under **API keys**, and the CLI uses it instead.

**API**

With a key that acts as you and is not narrowed, in `TONBO_API_KEY`: create one in the console under **API keys** without narrowing it. The next step’s key is narrowed, and a narrowed key never creates databases.

```shell
curl -sS https://api.tonbo.dev/v1/databases \
  -H "Authorization: Bearer $TONBO_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name":"notes"}'
```

It answers `201` once the database is active, or `202` while it is still being created.

The database is creating for a moment, then active. Node.js code opens it by name, and Python code by its URL, which `tonbo database show notes` and the console show (see [Regions and URLs](https://tonbo.dev/docs/databases/manage.md#regions)).

## Create an API key

Give the program its own key, narrowed to `notes`: it reads and writes only that database, and may name one that does not exist yet. A key that acts as you and is not narrowed reaches every database and stream you can in its account (see [What a key can reach](https://tonbo.dev/docs/platform/api-keys.md#key-scope)).

**Console**

1. In the [console](https://tonbo.dev/), choose **API keys** in the sidebar.
2. Choose **New API key** and narrow it to the database `notes`.
3. Copy the key. It starts with `tbo_` and is shown once.

**CLI**

```shell
tonbo api-key create notes-app --database notes
```

It prints the key once, as `TONBO_API_KEY=...`, ready for the program’s environment. Put it before the command that runs the program, as the next step does, rather than exporting it in your shell: the CLI reads `TONBO_API_KEY` too, and would then act with the narrowed key.

On this machine, after `tonbo login`, a Node.js program can also open its databases with no key at all: `open()` falls back to your login (see [Connect](https://tonbo.dev/docs/databases/connect.md)). Python does not, and the narrowed key is what any program uses anywhere else.

## Install the packages

```shell
npm install --save-exact @tonbo/sqlite-ursula@0.11.2 drizzle-orm@1.0.0-rc.5
npm install --save-dev drizzle-kit@1.0.0-rc.5
```

Check that npm added the prebuilt extension for your platform:

```shell
npm ls --all | grep @tonbo/sqlite-ursula-
```

It prints the extension’s package, such as `@tonbo/sqlite-ursula-darwin-arm64` on a Mac with Apple silicon. If it prints nothing, npm skipped that optional package: install again without `--omit=optional`, or, on a platform with no prebuilt extension, build it from source (see [Requirements](https://tonbo.dev/docs/databases/connect.md#requirements)).

## Define the schema

**schema.mjs**

```js
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const todos = sqliteTable("todos", {
  id: integer().primaryKey(),
  title: text().notNull(),
  done: integer({ mode: "boolean" }).notNull(),
});
```

**drizzle.config.ts**

```js
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "sqlite",
  schema: "./schema.mjs",
  out: "./drizzle",
});
```

Generate the migration from it:

```shell
npx drizzle-kit generate
```

## Open, migrate and query

Save this as `app.mjs`:

**app.mjs**

```js
import { open } from "@tonbo/sqlite-ursula/tonbo";
import { eq } from "drizzle-orm";
import { drizzle } from "drizzle-orm/node-sqlite";
import { migrate } from "drizzle-orm/node-sqlite/migrator";
import { todos } from "./schema.mjs";

const client = await open("notes");
const db = drizzle({ client });

migrate(db, { migrationsFolder: "./drizzle" });

await db.insert(todos).values({ title: "write the docs", done: false });
const pending = await db.select().from(todos).where(eq(todos.done, false));

await client.synced();
console.log(pending);
```

Run it with the key from the API key step:

```shell
TONBO_API_KEY=tbo_... node app.mjs
```

It prints the pending todos. Run it again, on this machine or another: the migration is already applied, and the rows are there.

## Add it to a project

In a project of your own, with the program’s API key in `TONBO_API_KEY` where the project keeps its secrets, never in its code:

1. Create the database with `tonbo database create notes`, signed in with `tonbo login`, or in the console. `tonbo database show notes` prints `State:` `active` once it is ready.
2. Install, keeping the exact versions:

   ```shell
   npm install --save-exact @tonbo/sqlite-ursula@0.11.2 drizzle-orm@1.0.0-rc.5
   npm install --save-dev drizzle-kit@1.0.0-rc.5
   ```

   `npm ls --all | grep @tonbo/sqlite-ursula-` then prints the prebuilt extension for your platform.
3. Hand Drizzle the database opened by name, with `open` from `@tonbo/sqlite-ursula/tonbo` and `drizzle` from `drizzle-orm/node-sqlite`: `const client = await open("notes"); const db = drizzle({ client });` Run the migrations from the program with `migrate` (see [Drizzle ORM](https://tonbo.dev/docs/databases/drizzle.md)).
4. Await `client.synced()` before anything outside the process acts on a commit: until then the commit is only on this machine.

One process writes a database at a time: the last one to open it (see [When two instances run](https://tonbo.dev/docs/databases/how-it-works.md#takeover)).

## Next steps

- [Use with Drizzle](https://tonbo.dev/docs/databases/drizzle.md): Why migrations run in the app, synced(), transactions and what does not work.
- [Connect from Node.js](https://tonbo.dev/docs/databases/connect.md): The options of open, the key and its errors, and what the host needs.
- [Guarantees](https://tonbo.dev/docs/databases/how-it-works.md): What happens to the database when the process stops, moves or runs twice.
