Storage Overview
S3-compatible file storage, bucket management, and upload presigning.
The storage workspace exposes two adapter methods: getSignedUploadUrl(path, options) and getSignedUrl(path, options). Each returns a URL string. There are no public uploadFile, deleteFile or getSignedDownloadUrl helpers.
import { getSignedUploadUrl, getSignedUrl } from "storage";
const uploadUrl = await getSignedUploadUrl("avatars/example.png", {
bucket: "vibekit",
contentType: "image/png",
});
const downloadUrl = await getSignedUrl("avatars/example.png", {
bucket: "vibekit",
expiresIn: 300,
});Run these helpers on the server after checking the caller's permission to access the path and bucket. The S3 adapter creates upload URLs valid for 60 seconds; download expiry is supplied by the caller.
Choose storage
The s3 adapter supports S3-compatible endpoints, including S3, R2 and MinIO. Set S3_ENDPOINT, S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY, or use the existing S3 setup form. The current S3 client uses region auto and path-style addressing. The app's avatar bucket is NEXT_PUBLIC_AVATARS_BUCKET_NAME; S3_BUCKET and S3_REGION do not configure this adapter.
MOCK_SERVICES=true forces mock storage. Without an endpoint, non-production falls back to mock; production fails instead. STORAGE_PROVIDER=mock alone is not allowed in production. Outside production, signed /api/storage/mock-upload and /api/storage/mock-file URLs support local uploads and reads. Files are stored privately in a temporary directory, expire after one hour and are capped at 100 entries. MOCK_SERVICES=true can select and sign mock URLs in production mode, but the mock HTTP routes reject production requests; use S3 for working production uploads.
Supabase Storage and Vercel Blob
Select STORAGE_PROVIDER=supabase or STORAGE_PROVIDER=vercelblob, or save the provider in /app/admin/setup. Environment selection and credentials take precedence over saved values. Both adapters preserve the existing signed-URL and browser PUT flow.
For Supabase, create a private Storage bucket, then generate S3 access credentials under Storage settings. Set SUPABASE_S3_ENDPOINT to the project's S3 endpoint, SUPABASE_S3_REGION to its region, and SUPABASE_S3_ACCESS_KEY_ID / SUPABASE_S3_SECRET_ACCESS_KEY to the generated values. These server credentials bypass RLS, so ownership checks remain in the application's signing procedures. Do not use an anon key or expose S3 credentials to the browser. Configure bucket CORS for your site's origin and PUT/GET requests.
For Vercel Blob, create a private Blob store and set its static BLOB_READ_WRITE_TOKEN. This adapter requires that token; OIDC-only authentication is not supported. The bucket argument becomes an object prefix within the store. Signed application routes proxy uploads and reads while keeping the token private. Uploads expire after 60 seconds and are limited to 4 MiB, including streamed bodies; reads honor the requested expiry. Existing avatar paths can be overwritten. The proxy uses the application origin, so no cross-origin Blob upload configuration is needed. Rotating the Blob token invalidates outstanding signed URLs.
Add an adapter
Implement StorageAdapter from storage in packages/storage/provider/. Add the provider ID to the storage tuple in packages/config/providers.ts and a lazy resolver in packages/storage/provider/index.ts. Keep credentials and vendor SDK code in the adapter. Adding an S3-compatible service normally only needs configuration, not a new adapter.
Verify signing, content type, expiry, authorization at callers and failure handling before switching a deployed app. See Local MinIO Setup and Handling Uploads.
When adding a provider ID, also add its credential-guidance entry in packages/config/providers.ts. This supports product validation and setup guidance; a product manifest does not automatically select a runtime adapter.