Skip to content
VibORM
Esc
↑↓navigate↵open⌘Jpreview
On this page

R2 Storage

Keep migration histories in an R2 bucket

Quick Start

import { createMigrationClient } from "viborm/migrations";
import { createR2StorageWriter } from "viborm/migrations/storage/r2";

const migrations = createMigrationClient(client, {
  storage: createR2StorageWriter(env.HISTORY, { prefix: `tenants/${id}/` }),
});
// wrangler.jsonc
{
  "r2_buckets": [{ "binding": "HISTORY", "bucket_name": "migration-history" }]
}

Use R2 when histories must be shared or inspected outside one object. Every read is a request to R2, so a command costs more than with Durable Object storage. The entry loads without nodejs_compat.

Configuration

const storage = createR2StorageWriter(bucket, { prefix });
Parameter Type Description
bucket R2Bucket The bucket binding
prefix string Optional key prefix for this estate, such as tenants/42/. Defaults to "".

Each estate needs its own prefix. Under one prefix, two estates are one history: a different target is refused, and a second tenant with the same target shares the first tenant’s states.

How Publication Stays Atomic

A publish is a put conditioned on etagDoesNotMatch: "*" (If-None-Match: *). R2 checks the condition and stores the object in one step; when the key already exists it stores nothing and returns null. Under contention for one key, hosted R2 may instead reject the losing put with error 10058 (“Reduce your concurrent request rate for the same object”), having stored nothing; once the winner’s object is there, VibORM treats that put as lost the same way. VibORM then reads the stored bytes: identical bytes are an idempotent publish, different bytes are refused as corruption.

R2 writes and listings are strongly consistent, so a state is listed as soon as its publish returns. Listing follows R2’s cursor until R2 reports the listing complete: a page may hold fewer keys than its limit while more remain (hosted R2 returned 1,001 keys as pages of 485, 485 and 31).

Layout

<prefix>estate.json
<prefix>snapshots/<snapshot-hash>.json
<prefix>sql/<sql-hash>.sql
<prefix>states/<state-id>.json

Do not write, overwrite or delete these keys yourself, and do not apply lifecycle rules that expire them.

Next Steps

Was this page helpful?