Samuel Arendt

Automatic PITR changes Cloudflare D1 operational cost

Cloudflare D1 Time Travel can restore a database to any minute within its retention window by replaying the write-ahead log. The feature is enabled by default, so recovery history exists even when nobody remembered to create a snapshot before a risky migration.

The free plan retains seven days and paid plans retain 30. Cloudflare does not add a separate restore or history-retention fee; D1 billing remains based on reads, writes, and storage. Restoring to one point also does not erase older bookmarks, so a team can run another restore if the first cut was too recent.

This removes setup friction, not incident decisions. Someone still needs to identify the last known-good moment, preserve evidence, choose whether to restore into a new database, validate the result, and redirect traffic. The useful feature is that the underlying history is already there when the incident begins.

Someone still chooses the cutover minute

Time Travel records the WAL and can return to any minute in the window. The product does not pick the minute. In an incident the question stays human: what was the last state known to be good? Was it the DELETE without WHERE at 14:12, the migration at 18:03, or the job that ran at 18:40 on top of the damage?

Without that slice, restoring "a little earlier" can replay the error or throw away legitimate writes. Bookmarks are lexicographically sortable and derivable from a Unix timestamp; that helps you be precise. It does not replace the deploy trail, the migration log, and a channel where someone says "stop writing".

Preserve evidence before the restore. A dump, an export, or at least the current bookmark that wrangler d1 time-travel info returns. If the restore goes wrong, you will want the point from now and the earlier one. The operation returns a bookmark you can undo with. Write it down. Incidents where nobody copied the ID become guesswork.

The automatic gain is that history exists even when the team forgot Friday's snapshot. The cost that remains is decision, communication, and validation. Cheap PITR without a runbook is just another dangerous button on the CLI.

An in-place restore cancels what is live

The docs are blunt: restoring to a point in time overwrites the database in place. In-flight queries are cancelled. There is no fork to a new copy, at least in this design. "Restore into another database and redirect traffic" is the habit of people who came from RDS. On current D1, the habit has to change: the restore is destructive on the identifier the application already uses.

That is why rehearsal matters. Run the command on a staging database, watch the duration, watch what the application does when queries return errors, watch how the Worker behaves with a refused connection mid-request. In production, the same gesture hits the user immediately.

There is a cap of 10 restores every 10 minutes per database. Anxious retries in the middle of an incident hit the limit. Undo uses the previous bookmark returned by the restore itself. If you restored too far back, you can still go to a point between the two, because older bookmarks do not vanish. What vanishes is the state that was live, unless someone exported it.

Export to R2 via Workflows exists for anyone who needs retention beyond the window. That is a file backup, not PITR. Distinguishing the two in the runbook avoids the meeting where someone asks for "the database from 45 days ago" and learns the window was 30.

Seven- or thirty-day retention changes the runbook

Workers Free keeps 7 days. Paid, 30. The feature is always on; the window is not. A silent bug that only shows on day 12, on a free account, is already outside history. Teams that use D1 in preview on the free plan need to know that a restore rehearsal of last week's migration may be impossible.

The runbook therefore cites the window per environment. Paid production: 30 days, still finite. Free staging: 7. Data that audit wants for a year does not fit in Time Travel. It fits in an export, in another database, or in not using D1 as an eternal system of record.

Billing does not add a line for restore or for history retention. It stays rows read, rows written, and storage. The restore itself is not the invoice item that should scare you. Database storage is, if the WAL and data grow. The operational point is different: because restore is in-place, the risk is loss of recent writes, not the bill.

Mark on the incident calendar the day the window closes for the event. If the bad migration was on day 1 and today is day 28 on a paid plan, slack is small. "Always on" PITR numbs the team until the window shuts.

Rehearse the restore outside the incident

The RDS comparison in the opening is about ritual, not product parity. In a crisis nobody wants to discover the Wrangler flag, the storage version (production versus legacy alpha, which still uses snapshots), and the fact that the command asks for y/N while Slack explodes.

Once a quarter, on staging: note a bookmark, make a known write, restore to the bookmark, confirm the write vanished, undo to the later bookmark, confirm it returned. Time it. Save the output. Put the command in the runbook with the real database name, not YOUR_DATABASE.

Confirm the database is on the production subsystem (wrangler d1 info, version field). Legacy alpha does not have Time Travel. Learning that during an incident is the kind of detail that turns theoretical PITR into "we did not have it".

Wrangler 3.4.0 or later is a documented requirement. The CI image and the on-call laptop need that version. Without a pin, the command disappears from PATH at the wrong time.

The SQLite-at-the-edge ceiling still applies

PITR does not raise the maximum database size, does not turn D1 into Postgres with multi-region replicas, and does not change the fact that each database is single-threaded. 10 GB on paid, 500 MB on free, queries up to 30 s, restores with a rate limit. Time Travel covers one class of error (you wrote the wrong thing, you want to go back). It does not cover a data model that already blew the ceiling, a hot shard, or an analytical report.

If the application is already at the size limit, historical WAL is not the main problem. If the application needs a clone for blue/green, the product still does not offer fork. The workaround is export/import, with the cost and window that implies. Planning the risky migration for a time when an in-place restore is acceptable remains operations work.

For a team already on Workers, the account looks like this: minute-level history with no extra fee, a destructive restore, a short window, mandatory rehearsal. That is cheap in money and expensive in discipline. The team that only celebrates "it is free and always on" will use the command for the first time against the wrong database.

If your company is weighing something similar, reach me on LinkedIn or WhatsApp.

References

#Architecture, #Operations, #Radar, #Software Quality