Vercel Blob
Vercel Blob as the planned MainSDK files driver for apps on Vercel, with setup, main.yaml, a direct upload example and how privacy is kept.
Vercel Blob is object storage on Vercel. The vercel-blob driver for files keeps your uploads next to your app and adds owner scope, scanning and short-lived URLs on top. You would pick it when your app already runs on Vercel and you want no separate bucket to manage.
Interfaces it serves
Pick Vercel Blob in main.yaml for any of these. Your calls stay the same, and you can swap later.
filesBuilding for 0.3Driver vercel-blob Vercel BlobFrom the files-share spec
files:
driver: vercel-blobSwap to another provider
Before you start
- Create a Blob store in your Vercel project.
- Keep its read-write token as
BLOB_READ_WRITE_TOKENin your secrets manager or Vercel environment, never in code. - Deploy to Vercel with the guide in Deploy on Vercel.
Configure
files:
driver: vercel-blob
key: secret:BLOB_READ_WRITE_TOKEN
scan: true
max-size: 25MBUse it
Issue an upload on the server. The browser sends the file straight to the store, which also covers files larger than a serverless request body allows.
import { auth, files } from "mainsdk";
export async function POST(req: Request) {
const session = await auth.require(req);
const upload = await files.uploadUrl({
owner: session.user,
maxSize: "25MB",
types: ["application/pdf", "image/png", "image/jpeg"],
});
return Response.json(upload);
}import { auth, files } from "mainsdk";
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
const session = await auth.require(req);
const { id } = await params; // upload.ref.id
const ref = await files.complete(id, { owner: session.user }); // only the uploader can finish it
const url = await files.url(ref, { for: session.user, expiresIn: "1h" });
return Response.json({ url });
}The browser sends the file to upload.url with upload.method. The browser function, the Hono version and the offline test are in Upload files with S3, Uploadthing or Vercel Blob.
A public blob URL is never returned for a private file. If the store can only serve a file on a public URL, the driver declares that gap in its capability profile and mainsdk check names it. Whether the driver can keep a blob private is not defined yet.
Local development and testing
Use the local driver in development and createTestApp() from @mainsdk/testing in tests. Neither needs a Blob store.
What MainSDK adds on top
- Owner-scoped reads and short-lived URLs on every file.
- A scan before a file is readable, and idempotent uploads.
mainsdk checkfails if route code imports@vercel/blobdirectly;files.raw()gives you its client and is listed as outside the guarantees.
Verify
Run npx mainsdk check --env prod. A pass exits 0 and names no MAIN-FILES or MAIN-CONFIG finding.
If it fails
| Code | Cause | Fix |
|---|---|---|
MAIN-FILES-0002 | files.url() was called for a reader access denies (403). | Read as the owner, or add an access rule for the reader. |
MAIN-FILES-0005 | The scan in files.complete() found an infected file. The upload fails and the file is quarantined. | Ask the user for a clean file. Nothing to fix in code. |
MAIN-FILES-0010 | mainsdk check found @vercel/blob imported in route code. | Use files.uploadUrl() and files.complete(), and keep the store as the files driver. |
MAIN-CONFIG-0004 | key is a literal value, not a secret: reference. | Move the value to your secrets manager and write secret:BLOB_READ_WRITE_TOKEN. |
For agents
Goal: use vercel-blob as the files driver and add owner-scoped uploads to this app.
Read: docs/specs/files-share.md, this page, main.yaml.
Touch only: main.yaml, main.env.dev.yaml, app/api/uploads/**, one test file.
Do: set files.driver to vercel-blob with key: secret:BLOB_READ_WRITE_TOKEN;
issue uploads with files.uploadUrl({ owner, maxSize, types });
send the file to upload.url with upload.method; call files.complete(upload.ref.id, { owner }) as the same user, then files.url(ref, { for, expiresIn }).
Verify: npx mainsdk check --json --agent
Never weaken, skip or loosen a check to make it pass.
Never import @vercel/blob in route code.Swap it
Change driver to s3, uploadthing or getqr. Your calls stay the same. See Swap a driver.
Open questions
Was this page helpful?