Skip to content
downpipes docs

Why back up Cloudflare: durability is not backup, and what downpipes does and does not cover

Cloudflare keeps your data highly durable. It does not keep you a backup. Those are different guarantees. Conflating them is how a team discovers, on a bad afternoon, that the redundancy it relied on never protected against what actually went wrong.

This page makes the coverage case explicit before you reach the trust model. It states why durability is not a backup, what downpipes captures, and what it does not capture. It is for an evaluator who needs the boundary stated explicitly.

The short version is that a backup is an independent, recoverable copy that you control, taken on a schedule and provable to restore. Platform durability is not that. The two protect against different failures, and you want both.

Durability is not backup

Cloudflare’s own redundancy keeps your data alive across hardware faults, disk failures and data-centre loss. That is real and valuable, and it is exactly what durability is for. What it does not do is undo a change you did not want.

Consider the failures that actually cause data loss in practice. A key deleted by mistake is still deleted on every durable replica. A bad deploy that overwrites a record is faithfully replicated in its corrupted form. A compromised account can erase or alter resources with full credentials, and the platform will dutifully keep the damage durable. Operator error, a fat-fingered bulk delete or a wrong-environment apply, lands the same way. None of these are hardware faults, so durability does nothing about any of them.

A backup is the independent copy that survives all of these, because it is held apart from the live account, taken before the damaging change, and recoverable on your terms. That independence is the whole point, and it is why downpipes runs the copy and its keys on your side rather than the vendor’s: a vendor outage or a vendor compromise can never cost you recoverability when the recoverable copy and the only key that universally unwraps it are yours. The custody argument behind that claim is set out in full in the no-custody trust model.

What downpipes covers

downpipes backs up the Cloudflare data and configuration layer and Workers code. It does not back up all of the compute layer; the next section sets out that line. The following is covered.

CoveredWhat it isHow it restores
Workers KVNamespaces, keys and values, with each record’s metadata and expiration preservedIn-account restore, by the newest good run
R2Buckets and objects, with HTTP and custom metadata preservedIn-account restore, by the newest good run
D1A SQL-level export of the whole database: one header record carrying every table’s CREATE TABLE text and columns, many keyset-ordered row pages, then one schema record for indexes, triggers and viewsRestore the export into a fresh, empty database
Secrets StoreThe value, sealed encrypted, 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 loggedThe value is re-applied out of band, since the binding is read-only at runtime: downpipes recovers it and you put it back through the API
WorkersCaptured for referenceReprovision with guidance, not a one-click redeploy (see the boundary below)
StreamPer-video metadata inventory, with the video file and caption tracks captured when content capture is enabledReprovision; with content capture, additive re-upload via the engine API (video gets a new uid)
ImagesPer-image metadata inventory and the delivery variants, with the original bytes captured when content capture is enabledReprovision; with content capture, additive re-upload via the engine API, keeping the original id
Cloudflare configuration313 Cloudflare config surfaces across the zone and the accountMixed, by surface (see the config backup and restore page)

The configuration coverage is broad: those 313 surfaces span DNS records, the WAF and rulesets, page and firewall rules, Access and Zero-Trust apps and groups, load balancers, Email Routing, Logpush jobs, Turnstile widgets, and account members and roles, among others. The full per-surface list is in the Cloudflare config surface reference.

Two limits apply to this list. D1 is exported as a resumable sequence of bounded records with a checkpoint between each one, so peak memory is a single row page plus the current sealed chunk rather than the whole database. Each page is sized from the measured row width toward 8 MiB, never exceeds two thousand rows, and is refused above a 96 MiB in-memory guard. The total is bounded by the run’s segment and subrequest budget rather than a fixed database-size cap. The export reads through a single first-primary D1 session bookmark, which captures a torn-free, sequentially-consistent snapshot even under concurrent write load; the restore target is still a fresh, empty database, because the SQL-level dump is replayed into a clean one.

Of the 313 configuration surfaces, only 60 carry an automatic in-band restore. 228 are backup-and-preview only: downpipes captures them in full and verifies they are recoverable, then an operator re-applies them out of band, following tier-specific guidance (dependency order, or a re-provision checklist) rather than the engine blind-writing them to production. The other 25 have a write path that is off by default because its natural-key matching is not yet confirmed, so a restore reaches one only when the request names it and an approver signs a plan that includes it. A live diff against your account comes with the 60 by default, and with one of the 25 when it is named. The deeper detail below states that split on both axes it can be read on.

A config restore 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. Scope the Cloudflare edit token to the configuration you are restoring and nothing wider, and delete it once the restore is done.

What downpipes does not cover

Read this part slowly. None of the stored state below is captured. Do not plan around any of it.

Read every row below as being about the resource’s own stored state, not its account configuration. Queues, Vectorize, Hyperdrive and Pages projects each have a configuration surface inside the 313 captured above, so their wiring is backed up; what is not captured is the data they hold.

Not coveredStatus
Workers script code, versions and bindings as a restorable redeployCaptured for reference, but reprovision-with-guidance only, not a redeploy
Durable Object SQLite stateNot captured at all. The source type is declared in the engine’s own type union, but its adapter is an unwired stub and the type is absent from the allow-list, so no downpipe can select it
Queue messagesThe queue’s configuration is captured under cf-config; the messages in it are not
Vectorize index contentsThe index configuration is captured under cf-config; the vectors are not
Hyperdrive-fronted database contentsThe Hyperdrive configuration is captured under cf-config; the origin database behind it is not a Cloudflare-held resource and is out of scope
Pages project builds and deployed assetsThe project configuration is captured under cf-config, value-free because it carries secrets; the built output is not
The downpipes Workers themselves, as a restorable redeployThe engine and console scripts are captured by the Workers source like any other script in the account, so you hold the record; like every Worker they come back as a reprovision checklist rather than a redeploy

Two points deserve emphasis. First, the compute layer is the headline gap: your Workers code and their bindings do not restore through downpipes as a redeploy, and Durable Object SQLite state is not captured. Workers are captured, so you have the record, but a restore emits a reprovision checklist with guidance rather than redeploying the code. Second, the downpipes engine and console are Workers too, so they sit on the same side of that line: their code and settings are captured, and putting them back is a deliberate re-deploy rather than an automatic one. That is consistent with the design, because recovery never depends on downpipes’ own infrastructure being intact: the offline reader and the open archive format recover your data regardless of whether the engine is running.

Why no-custody and self-hosted matter to the backup case

The reason downpipes is built no-custody and self-hosted is not a feature preference. It is what makes the backup do its job in the worst case.

A backup exists to survive failures of the systems around it, so a backup that depends on a vendor’s continued goodwill and uptime is weaker than one that does not. With downpipes the recoverable copy lives in a destination bucket you own. The single key that universally unwraps an archive, the offline break-glass private key, is generated on your side and never transmitted anywhere. The vendor holds no customer data, no keys and no Cloudflare token, and there is no inbound path from the vendor into your account. A vendor outage therefore cannot make your data unreadable, and a vendor compromise cannot reach into your account or read your archives. The strongest thing a hostile vendor could do is withdraw the assurance layer, and that fails open: backups and recovery continue.

In the two-recipient posture the engine also holds a decryption-capable operational private key, in your account, to support an in-account read-back path. That key is what lets a full compromise of your own Cloudflare account decrypt past archives through the operational path. The vendor still holds nothing, and break-glass recovery is unaffected because its private key is offline. If you want to remove the operational path entirely, the break-glass-only high-assurance posture omits the operational recipient, at the cost of in-account read-back. The full posture choice is set out in recovery postures, and the worst-case account-compromise analysis is in the threat model.

Deeper detail: the config restore split, and how a surface knows its own restore tier

The 313 surfaces, on two axes. The headline figure is exactly 313 Cloudflare config surfaces. On the coverage axis, 60 of them carry an automatic in-band restore (the engine reads the live config, diffs it against the snapshot, and applies only the differing items, additively, never a blind wholesale overwrite), 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, so a request must name one before it runs. The whole registry: 60 plus 228 plus 25 is 313, and a default restore writes back the 60 and none of the other 253.

On a separate classification axis, each surface declares a restore tier that explains why: 176 surfaces are idempotent (a setting PATCH, a ruleset PUT or a list create replays cleanly), 76 are ordered (they need dependency-ordered creation and id remapping, such as Access apps depending on groups and identity providers, or load balancers depending on pools), and 61 are reprovision (they carry write-only values such as certificate private keys, service-token secrets, identity-provider client secrets or tunnel secrets, so a restore can only emit a re-provision checklist). The 176-idempotent figure is the tier axis and is not the same number as the 60 that carry an automatic in-band write. Idempotent describes how cleanly a surface replays when it is applied; it does not mean downpipes applies it for you.

Why the in-band writes are safe. The surfaces that do auto-restore in-band follow a strict contract. They never PUT a whole collection: each item is created or updated on its own, so one item the API rejects skips itself and never fails the rest. They are additive by default, so a live item the snapshot does not mention is left alone rather than pruned, because deleting live records the backup happens not to contain is destructive and is deliberately not the default. They also match items by a natural key rather than only the server id, so a re-run against a fresh zone converges instead of duplicating.

Secrets carry their value, encrypted, plus their wiring. A Secrets Store record’s restore descriptor carries the store and the engine binding. From engine 0.3.6 it also carries the secret’s scopes, its comment and every Worker that binds it. If the engine cannot read that whole Worker list, the record marks the list as unknown and carries none of it. The value itself is sealed encrypted into the archive as the record’s value. A secrets restore is out of band not because the value is missing but because Secrets Store bindings are read-only at runtime: there is no in-account write path, so downpipes recovers the value and leaves you to re-apply it.

The same descriptor mechanism is what preserves KV metadata and expiration, and R2 HTTP and custom metadata, so a restored record comes back with its metadata intact rather than value-only. A KV expiration is preserved as the absolute instant it was, so an expiration that has passed by the time you restore is dropped and counted rather than written, and the key comes back without a time-to-live; see what restore can and cannot write back.

Where this fits

This page draws the coverage boundary. The proof of the custody claim it rests on is the no-custody trust model. That page covers what is held where and why the engine seals to an offline break-glass key it can never unwrap. The adversary-by-adversary analysis, including the default-posture account-compromise residual named above, is the threat model. For the limit on each security property, read security properties and their limits.

Next steps

For the full list of source types and the capture and restore semantics of each, read what downpipes backs up. For the detail on the two sources with the most caveats, read D1 in depth and secrets and Workers. To see the whole product framed in a paragraph, return to the documentation home.

Last updated .