Skip to content
Files SDK
Esc
navigateopen⌘Jpreview
On this page

Vercel Blob

Vercel Blob. Prefers auto-rotating Vercel OIDC (VERCEL_OIDC_TOKEN + BLOB_STORE_ID), falls back to BLOB_READ_WRITE_TOKEN, or pass credentials manually.

Installation

@vercel/blob is an optional peer dependency of files-sdk - install alongside the SDK so the adapter’s imports resolve at runtime.

npm install files-sdk @vercel/blob
pnpm add files-sdk @vercel/blob
yarn add files-sdk @vercel/blob
bun add files-sdk @vercel/blob

Usage

On Vercel, the adapter prefers Vercel’s OIDC authentication when VERCEL_OIDC_TOKEN and BLOB_STORE_ID are present (both are auto-injected when the Blob store is connected to the project). OIDC tokens rotate automatically, so they remove the risk that a long-lived secret leaks from the codebase or environment. Off Vercel - or if OIDC isn’t configured - the adapter falls back to BLOB_READ_WRITE_TOKEN. An explicit token option always wins.

import { Files } from "files-sdk";
import { vercelBlob } from "files-sdk/vercel-blob";

// On Vercel: VERCEL_OIDC_TOKEN + BLOB_STORE_ID are auto-injected when the
// Blob store is connected to the project (OIDC, recommended). Off Vercel,
// or as a fallback, BLOB_READ_WRITE_TOKEN is used.
const files = new Files({ adapter: vercelBlob() });

Pass oidcToken and storeId directly for runtimes that don’t expose process.env (Vite, etc.), or to bypass env detection entirely:

// Frameworks that don't load .env.local into process.env (Vite, etc.)
// need OIDC credentials passed explicitly.
const files = new Files({
  adapter: vercelBlob({
    oidcToken: loadOidcToken(),
    storeId: loadStoreId(),
  }),
});

downloadTimeoutMs bounds the public-URL fetches issued by download() and the lazy bodies returned from head()/list(). Defaults to 5 minutes; pass 0 to disable. A hung CDN response would otherwise leak a fetch that never resolves.

access selects public or private blobs and is fixed at construction. Default "public" matches the existing behavior. With access: "private", uploads use Vercel’s private mode and reads route through blob.get() with whichever credentials the adapter resolved (OIDC or read-write token) instead of a public URL fetch - there is no permanent public URL for private blobs, so url() throws. Need both? Use two adapters.

Options

PropType
token?string

Long-lived read-write token. Defaults to `process.env.BLOB_READ_WRITE_TOKEN`. Takes priority over OIDC even when both are present (mirrors the upstream `@vercel/blob` resolution order). For code running on Vercel, prefer leaving this unset and using OIDC instead.

Typestring
oidcToken?string

Vercel OIDC token. Defaults to `process.env.VERCEL_OIDC_TOKEN`, which Vercel populates automatically on every deployment when a Blob store is connected to the project. OIDC tokens are short-lived and auto-rotated, so they remove the risk that a long-lived `BLOB_READ_WRITE_TOKEN` leaks from your codebase or environment. To activate OIDC, **both** `oidcToken` and `storeId` must be available (option or env) and `token` must be unset — that matches the upstream SDK's resolution order. Pass `oidcToken` explicitly when your framework doesn't load `.env.local` into `process.env` automatically (Vite, etc.) — the adapter would otherwise silently fall back to the read-write token.

Typestring
storeId?string

Blob store id, used with OIDC. Defaults to `process.env.BLOB_STORE_ID`. Accepted in either `store_<id>` or `<id>` form (mirrors the SDK). Independently powers the `url()` fast path: when a `storeId` is known (from option, env, or derived from a `vercel_blob_rw_<storeId>_…` token), public URLs are synthesized without a round trip if `addRandomSuffix: false`.

Typestring
access?"public" | "private"

Whether blobs uploaded by this adapter are public or private. - `"public"` (default): blobs are uploaded with `access: "public"` and reachable via their CDN URL without authentication. `url()` returns a permanent public URL. - `"private"`: blobs are uploaded with `access: "private"`. They cannot be fetched by URL — `download()` and the lazy bodies returned from `head()` / `list()` instead route through `blob.get(key, { access: "private" })`, which uses whichever credentials the adapter resolved (read-write token or OIDC). `url()` throws because there is no permanent public URL for private blobs. The setting is fixed at construction so a single `Files` instance is unambiguously one or the other. If you need both, instantiate two adapters.

Type"public" | "private"
addRandomSuffix?boolean

Add a random suffix to uploaded keys (Vercel default). When `false`, the resulting pathname matches the key 1:1, which keeps the API consistent with S3/R2 where callers expect to control the key. Defaults to `false`.

Typeboolean
allowOverwrite?boolean

Allow overwriting existing keys on upload. Defaults to `true` so that the "predictable keys" behavior (`addRandomSuffix: false`) actually works — Vercel rejects same-pathname uploads otherwise. **Trade-off:** with the defaults, an `upload(key, ...)` call silently clobbers any existing object at `key`. If keys are derived from untrusted input or your callers expect "create-only" semantics, set `allowOverwrite: false` and handle the resulting Conflict.

Typeboolean
downloadTimeoutMs?number

Timeout in milliseconds for public-URL fetches issued by `download()`, and by lazy bodies returned from `head()`/`list()`. A hung CDN response would otherwise leak a fetch that never resolves. Defaults to 300_000 (5 minutes). Pass `0` to disable the timeout (not recommended in server contexts — a stuck request will pin a connection until the runtime tears it down).

Typenumber

Limitations

User metadata isn’t supported by the underlying API, so passing a non-empty metadata throws rather than silently dropping it. cacheControl is supported (it maps to the blob’s cacheControlMaxAge).

Compatibility

Public access

Method Status Notes
upload
download
delete
list
search
head
exists
copy
url ⚠️ Returns the permanent CDN URL. expiresIn is silently ignored (no signing primitive); responseContentDisposition throws (no Content-Disposition override available). Use a different provider for buckets with untrusted user-uploaded content.
signedUploadUrl No presigned upload primitive. Use handleUpload() from @vercel/blob/client for browser uploads.

Private access

Method Status Notes
upload
download
delete
list
head
exists
copy
url No URL primitive for private blobs - the underlying SDK requires an authenticated blob.get() call with the token. Use download() instead, or instantiate a second public-access adapter.
signedUploadUrl No presigned upload primitive. Use handleUpload() from @vercel/blob/client for browser uploads.

Was this page helpful?