Detachment contract
A standalone backend is a repository Dee Wan generates from a site’s models and published content. This page says what you can rely on once you have one, and what happens if you stop using Dee Wan.
Status: every line below is covered by automated tests on a development machine. None has yet been proven on a real Cloudflare deployment, and no performance figures exist.
For the ordered operator procedure, credential split and acceptance commands, use the detachment runbook. It combines verify:deployment and verify:media without treating a local check as real-cloud acceptance.
What you get
Section titled “What you get”| Guarantee | What it means for you |
|---|---|
| You own the repository | The project is written into the directory and GitHub repository you name. |
| You own the database | The D1 database is created in your Cloudflare account. Generation writes only to that database. |
| You own the deployment and its credentials | The project has its own Wrangler configuration and deployment script. Its API accepts the writer bearer API_BEARER_TOKEN, the read tokens listed in ACCESS_CONFIG and, when standalone authentication is on, sessions from its own Better Auth. |
| Real tables | Each content model becomes a table with typed columns, with indexes for sort fields, publication state and relations. |
| Reviewable, append-only migrations | A schema change adds a new migration after the ones already applied. An applied migration is never rewritten. |
| Familiar routes | Routes are generated with prisma-generator-express and follow Prisma model and query semantics. |
| The API does not call Dee Wan | The API Worker reads only its own D1 database. It never calls Dee Wan and does not depend on its accounts, uptime or infrastructure. Some website routes do call Dee Wan: see What still depends on Dee Wan. |
| Your code survives regeneration | Files under src/owned/ are written once and never touched again. |
| Your data survives regeneration | Rows you write into your own tables are kept across a schema change. |
| You can leave | deploy-from-repository.yml deploys a commit without Dee Wan. Regenerating needs a definitions.json you kept. See Stopping. |
Files in a standalone backend fall into three ownership zones: generated (rewritten on every
regeneration), owned (src/owned/, never overwritten) and shared (written once, then yours).
The full rule is in Extending your backend.
What still depends on Dee Wan
Section titled “What still depends on Dee Wan”The API and the website are different surfaces. Statically built pages come from the committed
pages.json and need nothing from Dee Wan. These website routes reach Dee Wan on every request:
| Route or feature | What it reads or sends | Answered by |
|---|---|---|
| Blog routes and the Blog RSS feed | Published posts from /v1 on the site’s own host |
Dee Wan public Worker |
| Blog chunks of the sitemap | /v1/_sitemap |
Dee Wan public Worker |
| Search pages, and pages with a Latest entries or Site search section | /v1 and /v1/_search |
Dee Wan public Worker |
| Pages of a model that takes visitor comments | Comments from /v1/_comments. New comments and reactions go to /v1/interactions/*. |
Dee Wan public and intake Workers |
| Form sections | Submissions go to /v1/interactions/form.submit |
Dee Wan intake Worker. The admin Worker delivers them. |
/preview |
Drafts from previewApiOrigin |
Dee Wan public API, only while it is set |
| An exported managed renderer, if you deploy it | /v1 on every request |
Dee Wan public Worker |
On these routes, rich text that holds an embed or a plugin block also reads /v1/_embeds or
/v1/_rich-blocks. Latest entries in a shared section shown in a region are pinned at generation
and read nothing.
A publish or unpublish in the CMS reaches these routes at once. It does not change the standalone API or statically built pages until you regenerate and deploy.
Retiring the Dee Wan installation stops every route in the table. Check the list before you retire the CMS.
Two things to know
Section titled “Two things to know”A changed snapshot replaces the generated content tables. Every deployment runs data:load.
When the committed snapshot differs from the one last loaded into that database, the load deletes
every row of each table the snapshot owns and writes the snapshot’s rows. A row the snapshot does not
contain is gone, regardless of who wrote it. There is no refusal. This happens after a regeneration and after a
rollback to a commit with different content. Loading the same snapshot again changes nothing. Tables the
generator did not create are not in the snapshot and are never touched. Keep your own data in your
own tables, with your own migrations.
Making an existing field required needs a backfill first. Rebuilding the table fails on rows that contain NULL, and the run refuses rather than lose data. Fill the empty values, then make the field required.
How updates reach it
Section titled “How updates reach it”Two separate things are involved:
- The build webhook, set in Dee Wan under Settings → Source & delivery → Advanced — build webhook and deployment, is the URL Dee Wan calls to start your repository’s CI.
- The Deploy button, on the Standalone backend card in the same place, calls that webhook. Your CI then regenerates the generated files, applies migrations and deploys.
Nothing regenerates or deploys on its own. A later publish in the CMS reaches the standalone API and statically built pages only through a new regeneration and deployment. It is a release, not a live feed. The CMS public API and the routes in What still depends on Dee Wan are different: a publish reaches them immediately.
Stopping
Section titled “Stopping”Detaching is a supported outcome, not an emergency exit. To detach, remove the build webhook in Dee Wan, stop pressing Deploy, and keep the repository.
What keeps working:
- the deployed Worker and its database.
- every route already generated.
- the migrations already applied.
- your code under
src/owned/and your own tables. deploy-from-repository.ymland your CI. Deployment appliesmigrations/withwrangler d1 migrations apply, then runswrangler deploy. Locally,npm run db:initapplies the same migrations.- the routes in What still depends on Dee Wan, only while the Dee Wan installation still serves them.
What stops:
- new model definitions from the CMS.
- newly published CMS content in the standalone API and statically built pages.
- revocation of CMS-issued read tokens. Their digests stay in
access/read-tokens.jsonuntil you remove them. See Stop the CMS connection.
From then on, change the schema with your own SQL migration: add a file after the last one in
migrations/. A migration file does not change prisma/schema.prisma or the generated client.
Change the schema yourself and run npm run prisma:generate. Once nobody regenerates, you can edit
files in the generated zone freely. The zone rule only matters while Dee Wan still writes into
that tree.
Unreleased / pre-MVP; no stable version
Source revision: fe23db481c422b40e317b92fc98116b4c0c26a87 (modified checkout)
Build date (UTC): 2026-10-18T09:22:34.630Z
Upgrade target: unavailable: modified checkout. Release notes