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 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 engine’s own allow-list fixes these closed, live types: kv, r2, secrets, d1, cf-config, workers, stream and images.
The TypeScript union that describes a record declares two further members. Both are absent from the allow-list, so no configuration can select either. durable_object is a not-wired stub: it has no adapter, so its crawl throws rather than producing an empty backup.
artifacts has a working adapter, and its restore is reprovision-only (the restore gives re-push guidance and has no write sink). A deliberate beta gate holds it back. Cloudflare’s Artifact Registry is a closed beta that almost no account can reach, so its backup has no end-to-end test. Opening the artifacts gate also needs the discover route and the console to turn on their own gates.
| 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, a version inventory and their cron triggers |
| 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 reads these values without a Cloudflare API token. It can only read the values of the secrets it was explicitly granted, never the whole store.
From engine 0.3.6, a Secrets downpipe also uses the discovery token, when one is set, to record each secret’s scopes, comment and Worker wiring. That read lists the metadata of every secret in the store and the settings of each Worker script. It never reads a secret value.
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 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 carries no descriptor. 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. The flag 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 and the engine binding, and from engine 0.3.6 the scopes, the comment and every Worker that binds it. The plaintext is never written to a descriptor field, never logged and never persisted as metadata |
| Workers | Four records per script: the code (the module or bundle bytes), the settings as canonical JSON, a small versions inventory and the cron triggers. 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. 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. An expiry that has already passed, which is any backup older than the namespace’s time-to-live, is dropped rather than written: the key restores and does not expire until you set a new one. The dry-run plan counts them before you apply, alongside a second count of the expiries that pass before an apply of that plan could finish, and the receipt counts what was dropped after |
| 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 (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 with guidance that names that cause and tells you to recover the value with the offline reader and your break-glass key, then re-create the secret through the Cloudflare API or wrangler |
| 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 by default; 228 are backup-and-preview only, and 25 have a write path that is off by default because its natural-key matching is not yet confirmed; a request has to name one |
| 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. A Secrets Store binding cannot write a secret value back, 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. When an Owner turns on restore approval, it needs a second approver, as any other restore does. 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; 228 are backup-and-preview only, captured and verified recoverable but re-applied out of band with no diff preview, because they hold no write path at all. The 25 in between have a write path that is off by default, because its matching of existing items by Cloudflare’s natural keys is not yet confirmed: a restore that names no scope leaves them alone, and a request that names one gets its diff and its write. 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.
A config re-apply writes to the account you name
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. Run in-band cf-config restore under supervision rather than as a hands-off operation, 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 .