Beignet API reference
    Preparing search index...

    Module @beignet/provider-storage-vercel-blob

    @beignet/provider-storage-vercel-blob

    Runtime: Beignet requires Node.js 22.12 or newer. Bun is optional.

    Vercel Blob object storage provider for Beignet

    Caution

    Beignet is experimental alpha software. The 0.0.x package line is for early evaluation, and APIs may change between releases while the framework settles.

    This package adapts Vercel Blob to Beignet's StoragePort, so apps deployed on Vercel get durable object storage without hand-writing an adapter.

    createVercelBlobStorageProvider(...) returns the stable VercelBlobStorageProvider type. VercelBlobConfig describes its validated config; the Zod schema remains internal.

    bun add @beignet/provider-storage-vercel-blob @vercel/blob@^2.8.0
    

    @vercel/blob 2.8.0 or newer within the v2 line is required.

    Or scaffold everything — dependencies, provider wiring, ports, env example, and setup notes — with the CLI preset:

    bun beignet provider add storage-vercel-blob
    
    // server/providers.ts
    import { createVercelBlobStorageProvider } from "@beignet/provider-storage-vercel-blob";

    export const providers = [
    // ...
    createVercelBlobStorageProvider(),
    ] as const;

    The provider contributes ports.storage (the standard Beignet StoragePort) and ports.vercelBlob (an escape hatch, see below). Configuration comes from BLOB_* env vars and, for OIDC authentication, VERCEL_OIDC_TOKEN:

    Env var Meaning
    BLOB_READ_WRITE_TOKEN Read-write token. Set automatically on Vercel deployments with a connected Blob store; set it manually elsewhere.
    BLOB_ACCESS Store-wide access level: private (default) or public.
    BLOB_KEY_PREFIX Optional prefix applied to every object key.
    BLOB_STORE_ID Optional store id when authenticating with a Vercel OIDC token.
    VERCEL_OIDC_TOKEN Vercel-provided OIDC token used with BLOB_STORE_ID instead of a read-write token.

    Local storage keeps working with zero setup by switching on the available credentials, the same way environment-swapped rate-limit providers work:

    import { createLocalStorageProvider } from "@beignet/provider-storage-local";
    import { createVercelBlobStorageProvider } from "@beignet/provider-storage-vercel-blob";

    const hasVercelBlobCredentials =
    Boolean(process.env.BLOB_READ_WRITE_TOKEN) ||
    Boolean(process.env.BLOB_STORE_ID && process.env.VERCEL_OIDC_TOKEN);

    export const providers = [
    // Vercel Blob in deployed environments (local disk does not survive
    // serverless); the local provider keeps dev working with zero setup.
    hasVercelBlobCredentials
    ? createVercelBlobStorageProvider()
    : createLocalStorageProvider(),
    ] as const;

    Vercel Blob stores per-object access at write time but does not report it back from head(...), so this adapter keeps the whole store uniform: every object shares the configured access level, and a put(...) that requests a different visibility is rejected with an error instead of silently misreporting visibility on later reads. Run two providers over two Blob stores when an app needs both levels.

    publicUrl(...) returns the blob URL for public stores and null for private stores. Private objects should be served through app routes that enforce the app's own authorization, then stream the body from ctx.ports.storage.get(...).

    Vercel Blob has no arbitrary per-object metadata, so StorageObject.metadata is always reported empty. Cache lifetimes map from the Cache-Control max-age directive to Vercel Blob's cacheControlMaxAge seconds; other directives do not survive the mapping.

    Use the direct factory when you own provider wiring or need a second store:

    import { createVercelBlobStorage } from "@beignet/provider-storage-vercel-blob";

    const storage = createVercelBlobStorage({
    access: "public",
    keyPrefix: "avatars",
    storeId: process.env.AVATARS_BLOB_STORE_ID,
    token: process.env.AVATARS_BLOB_TOKEN,
    });

    Omit token to let @vercel/blob read BLOB_READ_WRITE_TOKEN from the environment. storeId is forwarded explicitly to every SDK operation for OIDC-authenticated stores; the SDK reads VERCEL_OIDC_TOKEN, and the env-backed provider maps BLOB_STORE_ID to the same option. The client option accepts a fake SDK surface for tests.

    beignet doctor --strict and beignet preflight accept either the read-write token or the complete BLOB_STORE_ID plus VERCEL_OIDC_TOKEN pair.

    Some StoragePort promises need an extra Blob API round-trip:

    • put(...) issues a post-write head(...) because the port returns the authoritative stored object, not an echo of inputs.
    • delete(...) issues a pre-delete head(...) because Vercel Blob's del(...) does not report whether the object existed.

    ports.vercelBlob exposes the raw pieces for integrations the port does not cover:

    const { client, access, keyPrefix, storeId, objectKey, checkHealth } =
    ctx.ports.vercelBlob;

    await client.list({ prefix: objectKey("exports"), limit: 100 });
    const health = await checkHealth();

    checkHealth() issues a one-item list(...) and reports { ok, message?, metadata } for readiness endpoints.

    Object keys and keyPrefix use the shared validation and prefix helpers from @beignet/core/ports, keeping Blob behavior aligned with memory, local, and S3 storage.

    get(...) returns a one-shot response body. Consume one body method, or call await object.cancel() when only inspecting metadata so the unread response releases its resources. Prefer stat(...) for metadata-only reads.

    When @beignet/devtools is installed before this provider, storage operations appear under the dashboard's Storage watcher. The provider records storage.put, storage.get, storage.stat, storage.delete, storage.exists, and storage.publicUrl events with key, size, and duration; failures are recorded with .failed event names and the original error is rethrown.

    Missing objects resolve to null (get, stat, publicUrl) or false (delete, exists) — BlobNotFoundError never escapes the port. All other SDK errors are rethrown unchanged after an instrumentation event, including missing-token errors, so misconfiguration fails loudly rather than pretending storage is empty.

    This package covers server-mediated storage through StoragePort. Vercel Blob's browser-direct uploads use its own client-token protocol (@vercel/blob/client), which does not fit Beignet's plain presigned-PUT UploadSignerPort; use createS3UploadSigner from @beignet/provider-storage-s3 when direct uploads are a requirement, or Vercel's client SDK directly.

    Keep dev and tests on @beignet/provider-storage-local or createMemoryStorage() from @beignet/core/ports; both implement the same port. Inject a fake VercelBlobClient through the client/createClient options to test app code against this adapter without network access.

    Connect a Blob store to the Vercel project and configure one credential path: use BLOB_READ_WRITE_TOKEN, or use Vercel OIDC with VERCEL_OIDC_TOKEN plus BLOB_STORE_ID. Doctor, provider audit, and preflight validate those alternatives without treating the read-write token as the only valid path; run beignet preflight --connect to prove the configured store is reachable. Prefer private stores unless objects are genuinely world-readable: public blob URLs are unauthenticated and long-cached.

    StorageObject
    StorageObjectBody
    StoragePort
    VercelBlobConfig
    VercelBlobStorageHealth
    VercelBlobStorageOptions
    VercelBlobStorageProviderOptions
    VercelBlobStorageProviderPorts
    StorageBody
    StorageMetadata
    StorageVisibility
    VercelBlobClient
    VercelBlobStorageProvider
    createVercelBlobStorage
    createVercelBlobStorageProvider