Vercel Blob

Use Vercel Blob as a Files SDK backend with OIDC or read-write token authentication.

Create the adapter

package main

import (
	"context"

	files "github.com/cersho/gofiles-sdk"
	"github.com/cersho/gofiles-sdk/providers/vercelblob"
)

func newClient(ctx context.Context) (*files.Client, error) {
	// On Vercel, OIDC is used when VERCEL_OIDC_TOKEN and BLOB_STORE_ID
	// are available. Off Vercel, BLOB_READ_WRITE_TOKEN is used.
	adapter, err := vercelblob.New(vercelblob.Options{})
	if err != nil {
		return nil, err
	}

	return files.New(files.Options{Adapter: adapter})
}

For OIDC-only configuration, pass OIDCToken and StoreID or let the adapter read VERCEL_OIDC_TOKEN and BLOB_STORE_ID from the environment.

adapter, err := vercelblob.New(vercelblob.Options{
	OIDCToken: os.Getenv("VERCEL_OIDC_TOKEN"),
	StoreID:   os.Getenv("BLOB_STORE_ID"),
})

Environment variables

When options are empty, the adapter reads:

VariablePurpose
VERCEL_OIDC_TOKENVercel OIDC token for store-scoped operations.
BLOB_STORE_IDBlob store ID used with OIDC and public URL derivation.
BLOB_READ_WRITE_TOKENLong-lived read-write token fallback.

An explicit Token option wins over OIDC. Otherwise, OIDC is used when both token and store ID are present. If neither credential mode is complete, construction returns a provider error.

Public and private blobs

Public access is the default. It uploads blobs with access: public, supports byte ranges through the public CDN URL, and URL returns the permanent public URL. ExpiresIn is ignored because Vercel Blob has no signing primitive, and ResponseContentDisposition returns a provider error.

Private access uploads blobs with access: private. Reads use authenticated blob fetches, range reads are not advertised, and URL returns a provider error because private blobs have no permanent public URL.

adapter, err := vercelblob.New(vercelblob.Options{
	Access: vercelblob.AccessPrivate,
})

Resumable uploads

Vercel Blob supports resumable multipart uploads through files.UploadControl. The adapter uses Vercel's manual multipart API and stores the provider upload key in the resumable session.

control := files.NewUploadControl()

_, err := client.Upload(ctx, "videos/intro.mp4", files.FileBody("intro.mp4"), files.UploadOptions{
	ContentType: "video/mp4",
	Control:     control,
})

Vercel Blob does not expose an abort-multipart primitive, so Abort stops the local upload flow but does not send a provider-side cleanup request.

Compatibility

MethodStatusNotes
uploadYesCache-Control maps to Vercel's max-age option. User metadata is not supported.
downloadYesPublic blobs support ranges. Private blobs read with credentials and do not support ranges.
deleteYesBulk delete uses Vercel's multi-delete endpoint.
listYesDirectory-style listing supports the / delimiter only.
searchYesUses SDK list/search behavior.
headYesReturns metadata and exposes a lazy body.
existsYesReturns false only for provider NotFound responses.
copyYesUses Vercel's server-side copy endpoint.
urlPartialPublic blobs return permanent CDN URLs; private blobs are unsupported.
signedUploadUrlNoVercel Blob has no presigned upload primitive for this API. Use Vercel client uploads instead.

On this page