What downpipes backs up: the eight Cloudflare source types and their capture and restore semantics
downpipes backs up exactly eight kinds of thing in your Cloudflare account. This page is the scope answer an evaluator needs first: it names all eight source types, says what each one captures beyond the raw value bytes, and sets out how each one comes back on a restore. It is written for someone deciding whether downpipes covers what they need to protect.
A source is read inside your own account and reduced to an ordered stream of records that the seal pipeline turns into a signed, encrypted archive. The vendor holds none of it, and the engine that reads your data lives in your account, not ours. Two facts shape everything below: there is no single point-in-time snapshot of the whole account (each source is captured on its own terms), and a successful backup is a separate thing from a proven restore.
The eight source types
The closed set of live source types is fixed in the engine’s own type definition: kv, r2, secrets, d1, cf-config, workers, stream and images. The TypeScript union also declares a durable_object member, but it is a not-wired stub: it is absent from the engine’s allow-list and has no adapter, so no configuration can select it.
| Source type | What it is |
|---|---|
| KV | A Workers KV namespace |
| R2 | An R2 bucket |
| D1 | A D1 SQL database |
| Secrets | Named secrets in the Secrets Store (or a per-Worker secret) |
| cf-config | Your Cloudflare account and zone configuration |
| Workers | Your deployed Worker scripts, their settings and a version inventory |
| Stream | Your Cloudflare Stream videos |
| Images | Your Cloudflare Images library and its variants |
How a source is read: bindings versus the discovery token
The eight split cleanly into two reading methods, and the split matters for what a token can and cannot reach.
KV, R2, D1 and Secrets are read through a Workers binding. The engine is wired to the resource the same way any Worker is, and at runtime it reads only what is bound to it. It never holds a Cloudflare API token to reach these, and it can only see the secrets it was explicitly granted, never the whole store.
cf-config, Workers, Stream and Images are read through the read-only Cloudflare REST API, using your discovery token (the same token labelled “Read all resources” in the dashboard). These four are account-scoped rather than binding-scoped, so they need no binding at all. The Workers source exists precisely because a customer’s Worker code and wiring are otherwise unrecoverable, including the downpipes engine and console Workers themselves.
| Read method | Source types | Reaches |
|---|---|---|
| Workers binding | KV, R2, D1, Secrets | Only the resource bound to the engine; no API token held |
| Read-only REST API + discovery token | cf-config, Workers, Stream, Images | Account-scoped; lists configuration, code and a media inventory. It never reaches KV, R2, D1 or secret values; it only reaches media file bytes when you opt in with includeContent |
What each type captures
Most sources capture the value bytes, and most also capture a per-record restore descriptor: the configuration a restore needs beyond the bytes (a KV key’s metadata and expiry, an R2 object’s content type, a D1 dump’s body format). The descriptor is emitted only when there is something to describe, so a plain record stays as small as it ever was. cf-config and Workers records carry no descriptor; their value already is their full configuration JSON. Stream and Images capture a metadata inventory by default and the value bytes only when you opt in with includeContent, which is off by default and valid only for these two.
| Source type | Captured |
|---|---|
| KV | The value, plus the per-key metadata returned by getWithMetadata and the absolute expiration (a Unix epoch second; absent means the key does not expire) |
| R2 | The object bytes, plus its HTTP metadata (content type, cache control and the rest) and its custom metadata string map |
| D1 | A resumable, bounded sequence per database, all read within one consistent D1 Sessions snapshot: one header record (every table’s DDL and columns), many per-table keyset row-page records, and one schema record (indexes, triggers and views) applied last |
| Secrets | The value, sealed encrypted into the archive so the secret is recoverable, plus its wiring (the store, the scope, an optional comment, and for a per-Worker secret the Worker and the binding variable). The plaintext is never written to a descriptor field, never logged and never persisted as metadata |
| Workers | Three records per script: the code (the module or bundle bytes), the settings as canonical JSON, and a small versions inventory. Secret bindings in the settings come back from the API redacted, so they are recorded as a name-and-type reprovision checklist with no value |
| cf-config | One record per configuration surface, the value being that surface’s configuration as canonical JSON |
| Stream | Account video inventory, one record per video uid (fully paged). With includeContent: the video bytes and caption tracks |
| Images | Account image inventory plus a variants record (paged). With includeContent: each image’s original bytes |
Worker secret values are never backed up
A Worker’s secret_text, secret_key and Secrets Store references are write-only at the Cloudflare API: there is no value to read back, and none is fabricated. The settings record keeps only each secret binding’s name and type as a checklist for you to re-provision after a restore. It never carries a value, and it never even carries a store id that could turn the record into an oracle.
How each type restores
Restore is the write-back dual of the seal. It is dry-run by default (it writes nothing and returns a plan of what an apply would do), and only an explicit confirm writes. Before any byte is written back, every in-scope record’s plaintext hash is re-verified, so a tampered archive aborts the whole apply rather than half-overwriting a live resource. The restore safety class differs by source type.
| Source type | Restore class |
|---|---|
| KV | Writes back in-account at full fidelity through the binding, metadata and expiry reconstructed from the descriptor |
| R2 | Writes back in-account at full fidelity, HTTP and custom metadata reconstructed; a large object is streamed back rather than buffered |
| D1 | Replays the dump into a fresh database: the schema is re-created and rows are re-inserted in batches. It is not a whole-database atomic swap, so a write fault can leave a partially loaded target, which the failure reason says plainly (drop it and retry into a fresh database) |
| Secrets | Out of band only. Secrets Store bindings are read-only at runtime, so there is no in-account write path; the record is surfaced as “restore out of band” for you to re-create through the Cloudflare API |
| Workers | Reprovision only. The engine never blind-redeploys a Worker from a backup (that could brick a live service). The snapshot is verified recoverable and surfaced with re-deploy guidance; you re-deploy deliberately. There is no destructive Workers restore path |
| cf-config | Mostly out of band. Only 60 surfaces re-apply in-console; the other 253 are backup-and-preview only |
| Stream | Reprovision by default: the inventory is verified recoverable and surfaced for a deliberate re-upload. When captured with includeContent, an opt-in additive re-upload, driven from the console’s restore flow or the engine API, can re-create each video (a restored video takes a new uid, mapped for you) |
| Images | Reprovision by default: the inventory is verified recoverable and surfaced for a deliberate re-upload. When captured with includeContent, an opt-in additive re-upload, driven from the console’s restore flow or the engine API, can re-create each image, keeping its id |
A reserved target binding (one of the engine’s own bindings, such as its signer key or destination credentials) is refused before any write, the same guard the read side applies, so a restore can never overwrite the engine’s own configuration.
Secrets and Workers are deliberately not auto-restored
These two share a restraint that is worth stating plainly. A secret value lives only in Cloudflare and is referenced by id and name, so downpipes never re-injects it for you. A Worker is live infrastructure, so downpipes proves the code and the binding inventory are recoverable and then hands you a deliberate re-deploy rather than overwriting a running service. In both cases the archive is the proof, and the act of restoring is yours.
The same restraint extends to the media sources. Stream and Images media re-upload is opt-in and additive, driven from the console’s restore flow (a media edit token and account id, previewed in the dry-run plan) or the engine API, and needs the same dual-control approval as any other restore, so re-creating a video or image is a deliberate act you trigger, not a hands-off one.
The cf-config split
cf-config is one registry of 313 Cloudflare config surfaces. Of those, 60 auto-restore in-band, previewing a live diff and re-applying straight back into your live account through the console; the remaining 253 are backup-and-preview only, captured and verified recoverable but re-applied out of band with no diff preview. The full registry, the credential model and the per-surface behaviour are covered on the dedicated Cloudflare configuration backup and restore page in the operations section.
cf-config restore is supervised-first
The in-console cf-config re-apply path is built and wired on the main branch, but it is not yet enabled on the live demo. The account scope is guarded: an apply into an account that is not provably the archive’s recorded origin is refused unless you type the target account id back. Treat in-band cf-config restore as a near-term capability under supervision rather than a hands-off one, and supply the edit token and account deliberately.
A backup is not a proof of recoverability
This is the most important framing on the page. A run that sealed successfully tells you the bytes were written and the archive read back clean at seal time. It does not, on its own, prove the archive decrypts and restores end to end. downpipes treats “protected” as needing both a successful run and a proven restore, which is why there are assurance tiers from a keyless signature attestation up to a full blind restore test that decrypts every record. See prove recoverability for what each tier actually checks and how often it runs.
Where this fits
- Snapshot consistency explains why there is no whole-account point-in-time view, and what a KV or R2 crawl actually represents.
- Stream and Images goes deeper on the two account-scoped media sources, their opt-in binary capture and how each restores.
- Connect a source is the task page for getting a source protected from the console with no terminal.
- What restore can and cannot write back goes deeper on the per-type restore classes summarised here.
- The no-custody trust model explains why the engine reads your data but the vendor holds nothing.
- Anatomy of a backup run walks the seal pipeline that turns these records into a signed archive.
Last updated .