examples/live-notes Public
---id: 0003-snapshots-in-r2type: decisionowner: justinreviewed: 2026-10-16status: accepted---# 0003 Snapshots of every note in R2, every 100 versions## ContextA room keeps one row with the current text and a log of the last 200 ops, which is all thesequencer needs ([[0001-single-sequencer-per-note]]). Anything older is gone. When someonedeletes half a note by accident and notices an hour later, there is nothing to go back to.Keeping more in the Durable Object would work, but every note's history would then live insideits object: reading it means waking the room, and deleting the object deletes its history.## DecisionEvery 100 versions, the room writes the note's text to an R2 bucket, `live-notes-snapshots`,under `snapshots/<object id>/<version>.txt`. The write happens after the replies, and a failedwrite is retried on the next edit. The Worker reads the bucket directly for`GET /notes/:id/snapshots`. See [[snapshots]].## Consequences- A note's history is readable without waking its room, and it is ordinary R2 objects that can be listed, copied or given a lifecycle rule.- History has 100 version steps. What happened between two snapshots is not kept once it leaves the op log. A version is roughly a word of typing, so a step is a sentence or two.- One R2 write per 100 edits per note. A note is at most 100,000 characters, so a thousand edits cost at most about a megabyte of storage, and a typical note far less.- Nothing deletes snapshots yet. When that matters, an R2 lifecycle rule on the `snapshots/` prefix is the place to do it, not the room.- Restoring from a snapshot is by hand for now: read the text, paste it into the editor. The paste is an ordinary edit, so everyone sees it and it is in the next snapshot.