ViteHub

Cloudflare R2

Configure @vitehub/blob to store objects through Cloudflare R2 bindings.

Use the Cloudflare provider when Blob storage should resolve through a Cloudflare R2 bucket.

Cloudflare needs two pieces: an R2 bucket bound to the runtime and Blob config that uses the same binding name.

Create and Bind an R2 Bucket

Create an R2 bucket in Cloudflare, then bind it to the Worker or Pages project that runs your app.

ViteHub looks for a binding named BLOB by default.

Configure Blob

Register the Vite plugin and set blob.driver to cloudflare-r2:

vite.config.ts
import { defineConfig } from 'vite'
import { hubBlob } from '@vitehub/blob/vite'

export default defineConfig({
  plugins: [hubBlob()],
  blob: {
    driver: 'cloudflare-r2',
    binding: 'BLOB',
    bucketName: 'assets',
  },
})

Use a Different Binding Name

Set binding when your R2 binding does not use the default BLOB name.

blob: {
  driver: 'cloudflare-r2',
  binding: 'FILES',
  bucketName: 'assets',
}

At runtime, the Cloudflare driver reads that binding from the active request environment. If the binding is missing, Blob throws:

R2 binding "FILES" not found

Generate Cloudflare Output

When bucketName is set, ViteHub can emit the R2 bucket binding into generated Cloudflare output.

Vite builds write a generated wrangler.json for the Cloudflare output. The R2 binding is included when Blob resolves a Cloudflare R2 store with bucketName.

You can also provide the bucket name with an environment variable during config resolution:

BLOB_BUCKET_NAME=assets

CLOUDFLARE_R2_BUCKET_NAME is also supported.

Use Hosting Inference

On Cloudflare hosting, Blob resolves cloudflare-r2 automatically when no explicit driver is configured.

blob: {
  binding: 'BLOB',
  bucketName: 'assets',
}

Cloudflare hosting takes precedence over Vercel Blob environment inference.

Verify the Provider

Call a route that writes a known object:

curl -X PUT http://localhost:3000/api/blob \
  -H 'content-type: application/json' \
  -d '{"pathname":"notes/cloudflare.txt","value":"stored in r2"}'

A successful response includes the R2 object pathname:

{
  "pathname": "notes/cloudflare.txt",
  "contentType": "text/plain; charset=utf-8",
  "size": 12
}

Common Failures

SymptomCauseFix
R2 binding "BLOB" not foundThe runtime request environment does not include the configured R2 binding.Add the binding in Cloudflare or set blob.binding to the existing binding name.
Generated output has no R2 bucket bindingBlob resolved Cloudflare R2 without bucketName.Set blob.bucketName, BLOB_BUCKET_NAME, or CLOUDFLARE_R2_BUCKET_NAME.
Local development writes to .data/blob instead of R2Hosting inference did not detect Cloudflare.Set blob.driver to cloudflare-r2 explicitly.
Copyright © 2026