D1
env.<BINDING> of a d1_databases entry: prepared statements, exec and sessions (withSession). CellB
runs Miniflare’s D1 simulator with workerd’s D1 client, both vendored; the database is a cell, with
the application’s tables directly in its SQLite, as on celld.
{
"name": "d1",
"main": "index.js",
"compatibility_date": "2026-01-01",
"d1_databases": [
{
"binding": "DB",
"database_name": "guestbook",
"database_id": "00000000-0000-0000-0000-000000000000"
}
]
}
const SCHEMA = `
CREATE TABLE IF NOT EXISTS entries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
message TEXT NOT NULL,
at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS entries_at ON entries (at DESC);
`;
export default {
async fetch(request, env) {
await env.DB.exec(SCHEMA);
const url = new URL(request.url);
if (request.method === "POST") {
const { name, message } = await request.json();
const written = await env.DB
.prepare("INSERT INTO entries (name, message, at) VALUES (?, ?, ?)")
.bind(name, message, Date.now())
.run();
return Response.json({
id: written.meta.last_row_id,
changes: written.meta.changes,
}, { status: 201 });
}
const count = await env.DB
.prepare("SELECT count(*) AS n FROM entries")
.first("n");
if (url.pathname === "/count") return Response.json({ count });
const { results } = await env.DB
.prepare(
"SELECT id, name, message, at FROM entries ORDER BY at DESC LIMIT ?",
)
.bind(20)
.all();
return Response.json({ count, entries: results });
},
};
This is celld’s d1 example (conformance/celld-examples/d1), copied unchanged
and run by the conformance suite on Node and in Chromium.
A database is a cell named after its id
A database lives in a cell __D1Database:<id>, whose key does not depend on the script, so
projects naming the same database id share it, as on celld. Sessions return the bookmark
celld:primary: there is one copy, the cell’s.
Migrations are a function, not a CLI
applyNodeD1Migrations(dir, runtime, database) (@statewalker/cellb/node) does what
celld d1 migrations apply does: it reads migrations_dir (default migrations/) of the
d1_databases entry, applies the NNNN_description.sql files not applied yet in the order of
their numbers, and records each in migrations_table (default d1_migrations, the table
wrangler d1 migrations uses).
How it is checked
celld’s d1 example, D1 migrations, and CellB’s d1-details project, on Node and in Chromium.
What breaks
ATTACH, TEMP objects and VACUUM are refused, as celld refuses them.