D1 foundations
Understand where D1 fits
Use relational structure and SQLite semantics without treating D1 as KV, object storage, or a process-local file.
8 minute lesson
D1 is Cloudflare’s managed relational database built on SQLite. You get tables, indexes, joins, constraints, and transactions — real SQL, without provisioning a server, opening a network port, or managing a connection pool.
If you know SQLite, the query language is already familiar. What changes is the access model. A Worker talks to D1 through a binding rather than opening a local file:
const user = await env.DB.prepare(
'select * from users where email = ?'
).bind(email).first()
There is no connection string and nothing to keep alive. env.DB is injected by the platform, configured once in wrangler.jsonc.
That distinction matters more than it looks. D1 is not a .sqlite file your process owns. It is a managed service with its own limits, its own transaction behavior, and a migration workflow. Habits from embedded SQLite — long-lived open handles, filesystem tricks, “just copy the file to back it up” — do not transfer.
Choose it for relational data
Choose D1 when rows, relationships, constraints, transactions, and SQL queries match the data. Users, notes, orders, settings: entities that reference each other and need queries like “the ten most recent notes by this user, with their tags.”
select notes.title, group_concat(tags.name) as tags
from notes
join note_tags on note_tags.note_id = notes.id
join tags on tags.id = note_tags.tag_id
where notes.user_id = ?
group by notes.id
order by notes.created_at desc
limit 10;
That query is the argument for relational storage. Doing the same with key-value lookups means fetching everything and joining by hand in JavaScript.
Know what it is not
Each neighbor product keeps its own job. Choose R2 for file bodies — storing images as blobs in database rows wastes both products. Choose KV for read-heavy, eventually consistent values with no query needs, like feature flags. Choose Durable Objects when one entity needs serialized coordination, like a counter that must be exact under concurrency.
My rule of thumb: a key and a value, KV. Entities and relationships, D1. Files, R2. One hot coordinated thing, Durable Objects.
Now model a notes application with users, notes, and tags. Identify the primary keys, the relationships between the three tables, and one query that makes relational storage useful.
Lesson completed