Configure the binding
To add a database, declare it in thewrangler.json file:
wrangler.json
d1_databases entry:
You don’t provision the database. celld creates it on first use.
Each database has one writer. If one database receives too many writes, split the data across more databases.
Write migrations
Put each schema change in a SQL file in themigrations/ directory:
- Use flat files named
NNNN_description.sql, directly in the migrations directory. Files run in name order, so the zero-padded number sets the order. - Each file runs in its own transaction. Don’t write
BEGINorCOMMITstatements in a migration. ACREATE TRIGGER ... BEGIN ... ENDstatement is permitted. - Don’t change a migration after a deploy or after the dev server applied it. A file that the dev server applied doesn’t apply again when you change it. To change the schema again, add another file.
How Judt applies migrations at deploy
Judt applies pending migrations for each database when you deploy. The timing depends on whether the live version of the App already uses the database:- A database that the live version uses: migrations run before the deployed code goes live. If a migration fails, then the deploy stops with the
migration_failederror (HTTP422). Nothing is published, and the live version keeps serving. - A database that the live version doesn’t use: migrations run after the deployed code goes live. For a few seconds, the deployed code can see an empty database. If a migration fails, then the deployed version stays live and the deployment reports
migration_failed.
Keep migrations additive
For a short time during a deploy, the old code runs on the migrated schema. Make each migration additive, for example by adding tables, columns, or indexes. To remove or rename a column, use two deploys:- Deploy code that no longer reads the column.
- Deploy a migration that removes the column.
Test migrations on the dev server
The dev server applies migrations the same way to the dev database. Each time a build starts to serve, it applies the files that the dev database doesn’t have yet. App code usesenv.DB and never applies migrations.
If a migration fails on the dev server, then the preview request fails with preview_failed and the SQL error. The failed file rolls back. Correct the file, and the next rebuild applies it.
For more information, see Test on the dev server.
Query the database
The following examples show each way to run a prepared statement:- Always bind values with
?or?NNNplaceholders. Don’t put user input into the SQL text. - The
preparemethod accepts one statement only. To run more than one statement, use thebatchorexecmethod. RETURNINGclauses work with thefirstandallmethods.- To page through large results, use keyset pagination, for example
WHERE id > ? ORDER BY id LIMIT ?. - Store times as integers (
Date.now()) and booleans as0or1. JSON functions work on TEXT columns. - Foreign keys apply only after
PRAGMA foreign_keys = ON.
Bind types
The following table shows how JavaScript values bind to SQL:
For an optional value, bind
value ?? null.
Run statements in a transaction
Application SQL can’t useBEGIN, COMMIT, ROLLBACK, or SAVEPOINT. Instead, use the batch method. It runs all of its statements in one transaction and one round trip:
WHERE, ON CONFLICT DO NOTHING, CHECK, or UNIQUE. For read-then-write logic, use a Durable Object.
Each run call is one round trip. To reduce round trips, put related statements in one batch.
Search with full-text search
D1 supports FTS5. Create the virtual table and a trigger that keeps it in sync in a migration:migrations/0003_posts_fts.sql
MATCH:
Limits
The following table lists the limits for D1 on celld:
Keep large data in R2.
Differences from Cloudflare
celld differs from Cloudflare D1 in the following ways:- Judt applies migrations at deploy, before or after the code goes live. The dev server also applies them, to the dev database.
- celld refuses
ATTACH,DETACH,VACUUM,load_extension(), andTEMPobjects. FTS5 works, and the D1 PRAGMA list applies. - The
dumpmethod throws. - There is no Time Travel and no REST API.
- There are no read replicas. The
withSessionmethod always uses the primary, and each read sees all committed writes. - A write is durable before the call returns.