Skip to content

Cloudflare D1 App

Status: Authored

Cloudflare Workers or Pages Functions using D1 with versioned SQL migrations and environment-specific bindings.

Full rubric

Cloudflare D1 App v1

Reference implementation

Score evidence Value
Repository vibecodeqa/ref-cloudflare-d1-app (published)
VCQA report 92/100
Verification self-reported
Assessed commit 167e6e4
Assessed on 2026-07-25
CI run success (2026-07-25)
Independent assessment None published yet. The score above is the reference repo's own claim, not third-party proof.
Catalog entry last verified 2026-08-08

Reference template map

Evidence Where to look What it proves
Per-environment bindings wrangler.toml Local, preview, and production D1 databases are declared separately and selected on purpose.
Versioned migrations migrations/ Schema history is ordered SQL files, not ad hoc console statements.
Drift guard migrations/manifest.json, scripts/check-migration-manifest.mjs An applied migration cannot be edited without the checksum check failing.
Clean local apply gate scripts/check-migrations.mjs Every migration is proved to apply to an empty database before remote promotion.
Query safety src/db.ts, scripts/check-query-safety.mjs Request values reach SQL through prepared-statement binding, and the rule is enforced by a script rather than by review habit.
HTTP boundary tests src/http.test.ts, src/db.test.ts Query helpers and the request boundary are covered, not just the happy path.
Deploy ordering .github/workflows/deploy.yml, scripts/check-deploy-shape.mjs CI gates run, then production migrations apply, then code deploys - in that order.
Operations docs/runbook.md Migration failure and rollback have a written procedure.
Score evidence docs/vcqa-report.md The template carries a tracked VCQA score and visible gaps.

What this teaches

Choose this stack when a Cloudflare runtime owns a SQL database and the schema has to change over time without losing data. The interesting part is not writing D1 queries - Cloudflare documents that - it is that a database is the one part of a deploy you cannot roll back by redeploying the previous artifact. Code is replaceable; applied schema is not.

Everything this standard judges follows from that asymmetry. Migrations are append-only once a shared environment has applied them, because editing an applied file makes source history and database history disagree with no way to detect it later - hence a checksum manifest or equivalent drift guard. Migrations must be proved to apply to a clean database in CI, because the only environment where an untested migration is cheap is a disposable one. Environments must be distinct databases, because a single shared database turns a preview experiment into a production incident. Tenant isolation must be a declared model rather than an assumption, because "we always pass the tenant id" is not a control. And deploy ordering must be explicit, because a release whose code expects a column that has not landed fails in the least recoverable place.

Do not choose this stack for generic SQL style guidance, for non-Cloudflare databases, or for a repo that merely reads a D1 binding it does not own the schema of.

Decision matrix

Need Better fit
A Cloudflare runtime that owns D1 schema and migrations Cloudflare D1 App.
A Pages app with an API but no database of its own Cloudflare Pages Fullstack alone.
A Pages app with an API and D1 Both standards; this one owns schema, migrations, and query safety.
Key-value or object storage only (KV, R2) Not this standard; binding scope is judged by the hosting stack standard.
A database outside Cloudflare (Postgres, Turso, PlanetScale) Not this standard. The migration doctrine transfers; the rules and detection signals do not.
Per-tenant databases, provisioning, and promotion gates Tenant-Deployed Cloudflare SaaS plus this standard.
Reading a D1 binding whose schema another repo owns The consuming stack's standard; schema rules belong to the owner.

Upstream references

Cloudflare owns D1 and Wrangler doctrine; VCQA owns the migration, drift, isolation, and deploy-ordering glue that no single upstream page covers.

Scope

Cloudflare Workers or Pages Functions using D1 with versioned SQL migrations and environment-specific bindings.

Not in scope

  • generic SQL style
  • non-Cloudflare database deployments
  • frontend state management

Composes

VCQA-owned rule surface

  • append-only/versioned migrations.
  • migration checksum or drift guard.
  • local apply test.
  • staging/prod/tenant database isolation.
  • parameterized query enforcement.

Detection signals

  • [[d1_databases]] in Wrangler config
  • migrations/*.sql
  • D1 binding usage in app code

Combination-born guidelines

  • Migrations are append-only after deployment; editing applied migrations is a defect.
  • CI applies migrations to a clean local database before production deployment.
  • Tenant, staging, preview, and production databases need distinct binding boundaries.

Rule highlights

  • R-SHAPE-1: The runtime boundary is Cloudflare-owned. D1 access belongs in Workers, Pages Functions, or server code compiled to those runtimes, never in browser code.
  • R-BIND-1: Binding names are stable and typed at the boundary. D1 bindings should be represented in generated Cloudflare types or explicit Env/Bindings interfaces.
  • R-MIG-1: Migrations are append-only after shared apply. A migration that may have reached preview, staging, production, or a tenant database is changed only by a later migration.
  • R-MIG-3: Clean local migration apply is a required gate. CI applies all migrations to a clean local D1 database before remote promotion.
  • R-DRIFT-1: Applied migration identity is drift-checked. A checksum manifest, protected migration history, or equivalent guard proves source history still matches applied database history.
  • R-ENV-1: Local, preview/staging, and production use distinct databases. Wrangler and Pages bindings must make the target database explicit.
  • R-TENANT-1: Tenant isolation model is declared and enforced. Multi-tenant apps choose per-tenant database, per-tenant binding/service boundary, or shared database with mandatory row/table scoping.
  • R-SQL-1: Untrusted values use prepared statement binding. Request data, auth claims, route params, and tenant IDs enter SQL through .bind(...), not interpolation.
  • R-CI-2: Production migrations run before production code deploy. Deploy ordering must match the schema expectations of the release, with documented exceptions for staged rollouts.
  • R-DEPLOY-1: Preview deploys do not run production migrations. Pull request and preview workflows use preview/staging databases only.

Limitations

  • Append-only is judged from repository history. VCQA can see that a migration file changed after it was added; it cannot see which databases had already applied it. A repo that rewrites history, or squashes, can hide a real violation.
  • Drift is checked against a manifest, not against the live database. The guard proves source history is internally consistent. Only a query against the deployed database proves the database agrees, and a repository scan does not connect to one.
  • Environment isolation is judged from declared config. Databases created and bound through the Cloudflare dashboard rather than in Wrangler config cannot be seen, so the check falls back to evidence-only.
  • Tenant isolation is judged as a declared model plus its enforcement points. A shared database with row scoping can satisfy the rule and still leak if one query forgets the predicate; the rubric asks for enforcement you can point at, not a proof of correctness.
  • Query safety detection is pattern-based. Prepared-statement binding is detectable; SQL assembled through several helpers before reaching D1 may need human review.
  • Backup and restore posture is out of scope for v1. Time Travel and export are cited as upstream references, not judged as rules.

Anti-patterns

  • Editing a migration after it has been applied to staging or production.
  • Reusing one D1 database for preview, staging, and production.
  • Building SQL strings with request data.
  • Running production migrations from a local laptop with no CI gate.
  • Leaving tenant isolation as an implementation assumption instead of a documented model.

Benefits

  • Cloudflare SaaS example D1 usage.

Maintenance

Maintenance Value
Latest edition Cloudflare D1 App v1
Pin reports and scans to /standards/cloudflare-d1-app/v1/
Last reviewed 2026-07
Next review due 2027-07
Edition targets cloudflareD1 latest, wrangler 4, typescript 6
Lifecycle active
Errata none
Composes cloudflare-d1, cloudflare-pages-functions, cloudflare-workers, typescript, web-security, github-actions

Editions are cut on material change, not on a calendar. A review that finds the edition still correct moves Last reviewed forward without a new edition. Metadata lives in standards/registry.json.

Independent Assessment