Knowledge base · KB Article

Why delivery has no database

90Ø120 pitchØ60 pitchAB
Fig. 01 Spur wheel and pinionThirty teeth to fifteen: the wheel turns once for every two turns of its pinion.
Kind
KB Article
Published
10 Jul 2026
Reading
8 min

Applies to: every Coho project, for sites and apps that read published content

You will learn: why the service that serves your published content has no database behind it, what it reads instead, and what that means for speed, reliability, and security


The short version

When your site asks Coho for a page, the answer does not come from a database. It comes from a release that was built in advance, stored as files, and opened by the delivery service before anyone asked for it.

Coho has a database. It sits behind authoring, where your team writes, branches, merges, and releases. Delivery, the read-only service your sites call, never connects to it. Between the two is a single, deliberate step: cutting a release turns your content into a finished, read-optimized snapshot, and promoting the release points an environment at it.

That one decision is behind most of what delivery does well. It is fast because it reads finished data. It keeps serving while authoring is busy, being upgraded, or unavailable. And it cannot change your content, because there is nothing behind it to write to.


Why the database is usually there

In most content platforms, published content lives in the same database the editors write to, or in a copy kept in sync with it. Reading a page means a query: find the entry, join its references, pick the locale, shape the response. Caches sit in front to absorb the load, but every cache miss ends at that database.

That design is easy to build, and it carries a few costs:

  • Every read competes with every write. A bulk import, a large merge, or a busy editing afternoon draws on the same database that answers your visitors.
  • The read path is only as available as the database. Maintenance, a failover, a slow migration, or a connection limit on the authoring side becomes a problem for your public site.
  • "Published" is a query, not a thing. What your site shows is whatever the database returns at that moment, so the question "what exactly is live?" is answered by looking, not by naming a release.
  • The internet-facing service holds database credentials. Whatever reaches delivery is one step from the data behind it.

What delivery reads instead

Coho splits the work in two, and puts a release between the halves.

  authoring                       release                         delivery
  ─────────                       ───────                         ────────
  branches, merges,   ── tag ──▶  snapshot built once,  ◀── reads ── sites and
  the database                    stored as files                   apps

A release is built once. When you cut a tag, Coho builds a snapshot of it in the background: every entry at that point, indexed for the reads delivery serves (by id, by slug, by type, in sorted lists) and written to object storage. A tag never changes, so its snapshot never needs rebuilding. Ten environments pointing at the same tag share one snapshot.

An environment is a small pointer file. When you promote prod to v1.4.0, Coho records the move in authoring and then publishes a tiny document per project, saying which tag each environment points at. Delivery re-reads it every few seconds. That file is the only thing about your content that changes over time, and it is how a promotion or a rollback reaches your site within seconds.

Keys are files too. Delivery checks your delivery key against a published list of key hashes, never the keys themselves. A revoked key stops working within a few seconds.

That is everything delivery reads: finished snapshots, pointer files, and key lists, all from object storage. There is nothing from authoring on the request path.

Releases are opened before they are needed. Each delivery instance copies the snapshots its environments point at onto local disk and keeps them open. When an environment moves, the new release is opened before traffic arrives. And Coho will not promote a release whose snapshot is still building: the promotion waits with SNAPSHOT_NOT_READY (the CLI simply waits for it). So the moment prod moves, the release behind it is ready to serve.


What this buys you

Speed

A read from a snapshot environment is a lookup into data that was finished before it went live, held on local disk by the instance answering. There is no query to plan, no join to assemble at request time, and no connection to wait for. Our design target for snapshot reads is under 80 milliseconds at the 99th percentile. It is a target, not yet a published measurement.

Caching gets simpler too, because the data underneath never changes:

  • A read by tag name can be cached indefinitely. v1.4.0 will hold the same content forever, so its responses carry a tag that can never go stale.
  • A read through an environment is cached briefly, so a promotion or rollback shows within seconds.
  • Asking "has this changed?" is cheap. Every response carries an ETag, and a client that already holds the content gets a 304 Not Modified back. The delivery SDKs do this for you.

Steadiness

Because delivery does not depend on authoring, nothing that happens in authoring reaches your visitors until you release it:

  • Heavy authoring work never slows reads. A 100,000-entry import, a large merge, or a hundred editors saving at once all happen in a database delivery never touches.
  • Authoring can be upgraded, migrated, or briefly unavailable, and your site keeps serving the release it was serving.
  • Delivery scales on its own terms. Adding delivery capacity means opening the same files on more instances. There is no database connection pool to exhaust and no replica to keep in step.

Safety

  • Delivery cannot change your content. The delivery API has no write operations, and the service has nowhere to write to. Content changes only by authoring it, releasing it, and promoting the release.
  • No database credentials face the internet. The service your sites call holds none, and never connects to the authoring database. A problem in delivery is contained in delivery.
  • What is live is a name. prod points at v1.4.0, and v1.4.0 is exactly what was reviewed and released. Every move is recorded in the environment's history, with who made it and why.

The same answer everywhere

Previews of unreleased work (dev, or a feature branch) are served from authoring, because that content has no release yet. But they speak the same delivery contract, and a test holds the two implementations to returning byte-identical responses for the same content. Code you write against a preview is the code you run in production.


What it costs

No design is free, and this one makes a few trade-offs on purpose:

  • Content reaches your site only through a release. A save does not appear in production until someone tags and promotes it. For most teams that is the point. For a page that must change the moment an editor types, it is a step you have to take.
  • The first promotion of a new tag waits for its snapshot. A larger project takes longer to build. It happens once per tag, in the background, and never while your site is waiting on a request.
  • Delivery answers the reads it was built for. By id, by slug, by type, with sorting, references, and locales: the reads a site makes. It is not a general query engine over your content, and does not try to be.

Common questions

Does my site need to know any of this? No. Your site calls the delivery API, or a generated library, with a delivery key and an environment name, and gets content back. The design is what makes those reads fast and steady.

How quickly does my site see a promotion or a rollback? Within seconds. Delivery re-reads where each environment points every few seconds, and the release behind it is already open.

What does dev read, if not a snapshot? dev and other live environments follow a branch, so they read your latest saved work through authoring. They are private, need a signed-in person or a project token, and are never served from the public read path.

Is my content stored twice? Your history is stored once, in authoring. Each release adds a snapshot, built for reading, which environments on the same release share. You can export any tag, exactly as it was released.