Skip to content

ADR-0006 — Durable Object SQLite over D1 for the Cloudflare catalog

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.

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.

Durable Object SQLiteD1
ConcurrencySingle-writer per objectMulti-writer (eventual reconciliation)
Same-region latencySub-msFew ms
Storage limit10 GB per DO10 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 Catalog port from hakiri-core.

Neutral

  • The catalog port is one of several backends, swappable per deployment.

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.