ADR-0006 — Durable Object SQLite over D1 for the Cloudflare catalog
- Status: Accepted
- Date: 2026-05-11
- Related specs: 06-deployment.md
Context
Section titled “Context”The Cloudflare topology needs a catalog backend that holds cursors, run history, schema versions, and schema-evolution decisions per project. The hard invariant is single-writer per pipeline — concurrent advances of the same cursor are unsafe for non-monotonic cursor-kind connectors (ADR-0005).
Cloudflare offers two SQLite-shaped backends:
- Durable Object SQLite: SQLite embedded inside a Durable Object, with the DO’s actor model guaranteeing single-writer per object.
- D1: a managed multi-writer SQLite-compatible service with eventual reconciliation.
Decision
Section titled “Decision”The Cloudflare catalog is a Durable Object with embedded SQLite, one DO per project.
D1 is reserved for the M3 hosted control plane where multi-tenancy and multi-writer reconciliation are the goals.
Consequences
Section titled “Consequences”| Durable Object SQLite | D1 | |
|---|---|---|
| Concurrency | Single-writer per object | Multi-writer (eventual reconciliation) |
| Same-region latency | Sub-ms | Few ms |
| Storage limit | 10 GB per DO | 10 GB per DB |
| Hakiri fit (v0) | Per-project catalog (one DO per project) | — |
| Hakiri fit (M3) | — | Multi-tenant control plane |
Positive
- DO’s single-writer guarantee maps exactly onto the “one process owns the cursor” invariant from ADR-0005. No application-level leasing inside one project.
- Sub-millisecond same-region reads keep the reconciler’s plan-and-dispatch loop cheap.
- Storage limit comfortably fits a per-project catalog at expected scale.
Negative
- One DO per project means cross-project queries require fan-out at the application level. Acceptable — the catalog is project-scoped by design.
- 10 GB per DO is a hard ceiling; very large catalogs would need partitioning. Not a v0 concern.
- DO SQLite is Cloudflare-only. The same role is played by RDS Postgres on AWS (ADR-0007) — both implement the
trait Catalogport fromhakiri-core.
Neutral
- The catalog port is one of several backends, swappable per deployment.
Alternatives considered
Section titled “Alternatives considered”D1. Multi-writer with eventual reconciliation is exactly wrong for the single-writer-per-pipeline invariant. We’d have to add application-level leasing on top, which is what the DO model gives us for free. D1’s role is the future multi-tenant control plane, not the per-project catalog.
KV. Eventual consistency, no transactions. Non-starter for catalog semantics.
External Postgres (Neon, Supabase, etc.) from a Worker. Latency penalty per call, plus an additional credential and operational surface in the Cloudflare topology. Acceptable on AWS where RDS is in-VPC; not on CF where DO SQLite is right there.