Sketio

Cloudflare Workers and D1: SQL Database API

Updated

Cloudflare D1 is a managed, serverless SQL database that uses SQLite's SQL semantics. A Worker reaches it through a binding: a name you give in the Wrangler configuration, which then appears in your code as env.DB. There is no connection string to manage and no driver to set up, so a Worker with D1 is a short path to an API with relational data.

This template shows that API together with the three things a real project adds soon after the first query: migration files that version the schema, the binding in the Wrangler configuration, and read replicas for read-heavy traffic.

HTTPSmigrations applyClientWorkerWrangler configD1 primaryD1 read replicaMigration filesbindingwritesreadsreplicates

Scroll sideways to see the whole diagram

Cloudflare Workers and D1: SQL Database API. Open it in Sketio to change it.

Start from this diagram and edit it on your own board.

By continuing, you agree to the Terms of Service and Privacy Policy, including sending images of your strokes, diagram labels and similar data to providers in the United States (Cloudflare, Inc. and TypeSafe AI, Inc.) for AI conversion.

What each part does

Client
A browser, an app or another service that calls the API over HTTPS. If read replication is on, it also carries a bookmark from one request to the next, so that it can read what it just wrote.
Worker
Your API code. It builds each query with env.DB.prepare(sql).bind(values), where ? placeholders keep values out of the SQL text, and runs it with methods such as run(), all() and first(). env.DB.batch() sends several statements together; they run in order, and if one fails the whole sequence is rolled back.
Wrangler config
Declares the binding in a d1_databases entry with a binding name, a database_name and a database_id. It can also set the folder of the migration files (migrations_dir) and, for a separate preview database, a preview_database_id.
D1 primary
The database instance that accepts writes. Every write query is forwarded to it, whether or not replicas exist. It is also where a session can be told to start (first-primary) when the freshest data matters.
D1 read replica
A read-only copy that Cloudflare creates for you in supported regions once read replication is switched on for the database. It serves reads closer to the user. A session that carries a bookmark is only served by a replica that has caught up to it.
Migration files
Numbered .sql files in the migrations folder. wrangler d1 migrations create adds one, migrations list shows the ones not yet applied, and migrations apply runs them. D1 keeps a record of what ran in a d1_migrations table.

How a request flows

  1. The client sends an HTTPS request to the Worker.
  2. The Worker prepares a statement on its D1 binding and binds the request's values to it. A write goes to the primary, and related writes can be sent together with batch().
  3. For reads, the Worker opens a session with env.DB.withSession(bookmark). The first query of a session can be served by the primary or any replica, and later queries in the session never see an older version of the database than the one before.
  4. When the session carries a bookmark, a replica answers only once it is at least as up to date as that bookmark, so the read reflects the version the bookmark points to or a newer one.
  5. The Worker returns its JSON response and includes the session's latest bookmark (session.getBookmark()), for example in a response header. The client sends it back on its next request.
  6. Separately from requests, a schema change is a new migration file. wrangler d1 migrations apply runs the files that have not run yet against the database.

When to use it

Common variations

Turn on read replication

Switch it on per database in the dashboard (D1, your database, Settings, Enable Read Replication) and use withSession() in the Worker. Replicas are created automatically and add no storage or compute charge; billing still counts rows read and written. Pass first-primary to withSession() when a request must start from the latest data.

Use an ORM with nested migration folders

Some ORMs, such as Drizzle, write each migration into its own folder. Set migrations_pattern next to migrations_dir in the binding (for example migrations/*/migration.sql) so that wrangler d1 migrations apply finds them.

Keep a preview database apart from production

Give the binding a preview_database_id for local and preview runs. When you run migrations, use the database name rather than the binding name: the binding name can change, the database name cannot.

Recover from a bad change

D1 Time Travel can restore a database to any minute within the last 30 days, which helps when a migration or a query has damaged data.

Make it yours

Rename the binding and the database after your project, then replace the example tables in the first migration file with your own.

Opens this diagram as a board you can edit.

By continuing, you agree to the Terms of Service and Privacy Policy, including sending images of your strokes, diagram labels and similar data to providers in the United States (Cloudflare, Inc. and TypeSafe AI, Inc.) for AI conversion.

All templates