veR2
Pre-alpha · 0.x

Object versioning for Cloudflare R2

Add version history to an existing R2 bucket without changing how anything reads from it. Every put, delete and restore keeps an immutable version.

npm i @ver2/sdk

How it works

How veR2 stores versions in an R2 bucketYour app writes through the veR2 SDK, which stores a manifest, immutable version objects and the live object in the R2 bucket. Readers such as CDNs, public URLs and presigned GETs read the live object directly.Your appveR2 SDKwritesR2 bucket.ver2/m/uploads/a.pngManifest: history + write journal.ver2/o/…/<versionId>Immutable version bytesuploads/a.pngLive object: same key as alwaysReadersCDNs · public URLs · presigned GETsreads, unchanged
Writes go through veR2. Reads go straight to R2, exactly as before.
Reads don't change
Live objects stay at their keys. CDNs, public URLs and presigned GETs keep working, and veR2 is never in the read path.
Every write keeps a version
Each put, delete and restore keeps an immutable version under a reserved namespace, verified by SHA-256 on download.
Crash-safe by design
Every write is journaled. An interrupted operation is finished or undone from storage evidence, or flagged instead of guessed.

Use it from code or the terminal

import { createVer2 } from "@ver2/sdk";
import { S3ObjectStore } from "@ver2/sdk/s3";

const ver2 = createVer2({ store: new S3ObjectStore({ bucket, accountId, credentials }) });

const { versionId } = await ver2.put("docs/report.pdf", bytes);
await ver2.versions.list("docs/report.pdf");
await ver2.versions.restore("docs/report.pdf", versionId);

Honest guarantees

veR2 guarantees what R2 lets it guarantee and documents the rest. Read the details.

✅Concurrent veR2 writers to one keySerialized; losers get ConcurrencyConflict
✅A direct write racing a veR2 writeDetected; never silently clobbered
✅Crash mid-operationRolled forward/back from evidence, or flagged OperationIncomplete
✅Version integritySHA-256 verified on download
⚠️Direct deletes (outside veR2)Cannot be prevented or undone: R2 ignores delete conditions
⚠️Hot keysR2 allows about 1 write/s per key; expect 429s on rapid rewrites
⚠️Large objectsBodies are buffered in memory for now; streaming comes later

Start keeping history

Install the SDK, point it at your bucket, and every write is versioned.