---
title: Vercel Blob
description: Vercel Blob. Prefers auto-rotating Vercel OIDC (VERCEL_OIDC_TOKEN + BLOB_STORE_ID), falls back to BLOB_READ_WRITE_TOKEN, or pass credentials manually.
peerDeps:
  - "@vercel/blob"
---

## Installation

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

```package-install
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.

```ts lineNumbers
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:

```ts lineNumbers
// 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

<AutoTypeTable
  path="../../packages/files-sdk/src/vercel-blob/index.ts"
  name="VercelBlobAdapterOptions"
/>

## 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.                                                                                          |
