Releases: vercel/storage
@vercel/blob@2.2.0
Minor Changes
- 2b1cbbc: Add
ifMatchoption todel()for conditional deletes (optimistic concurrency control). Only works for single-URL deletes.
@vercel/blob@2.1.0
Minor Changes
-
6c68442: Add ETag support for conditional writes (optimistic concurrency control)
- Return
etagin all blob responses (put, copy, head, list, multipart) - Accept
ifMatchoption in put/copy/createMultipartUpload for conditional writes - Add
BlobPreconditionFailedErrorfor ETag mismatch (HTTP 412)
Usage Example: Preventing Lost Updates
When multiple users or processes might update the same blob concurrently, use
ifMatchto ensure you don't overwrite someone else's changes:import { put, head, BlobPreconditionFailedError } from "@vercel/blob"; // User 1: Read the current blob and get its ETag const metadata = await head("config.json"); console.log(metadata.etag); // e.g., '"abc123"' // User 2: Also reads the same blob (same ETag) const metadata2 = await head("config.json"); // User 1: Updates the blob with ifMatch // This succeeds because the ETag matches const result1 = await put( "config.json", JSON.stringify({ setting: "user1" }), { access: "public", allowOverwrite: true, // Required when updating existing blobs ifMatch: metadata.etag, // Only write if ETag still matches } ); console.log(result1.etag); // New ETag: '"def456"' // User 2: Tries to update with their (now stale) ETag // This fails because User 1 already changed the blob try { await put("config.json", JSON.stringify({ setting: "user2" }), { access: "public", allowOverwrite: true, ifMatch: metadata2.etag, // Stale ETag - blob was modified! }); } catch (error) { if (error instanceof BlobPreconditionFailedError) { // The blob was modified since we last read it // Re-fetch, merge changes, and retry const freshMetadata = await head("config.json"); await put("config.json", JSON.stringify({ setting: "user2" }), { access: "public", allowOverwrite: true, ifMatch: freshMetadata.etag, // Use fresh ETag }); } }
Key Points
allowOverwrite: true: Required when updating an existing blob at the same pathifMatch: Only performs the write if the blob's current ETag matches this value- Combined: "Overwrite, but only if the blob hasn't changed since I last read it"
- ETags follow RFC 7232 format with surrounding quotes (e.g.,
"abc123")
- Return
@vercel/blob@2.0.1
Patch Changes
- e2de71a: Upgrade undici to fix security issue warning
@vercel/edge-config@1.4.3
Patch Changes
-
1dee5ab: Support Next.js v16 Cache Components even within
proxy.ts(fkamiddleware.ts) - see #890The
@vercel/edge-configv1.4.1 release added support for Next.js v16cacheComponents, but did not support using@vercel/edge-configin Next.js'sproxy.ts(fkamiddleware.ts) when thecacheComponentsflag was enabled innext.config.ts. This releases fixes this issue so@vercel/edge-configcan be used in any server side context in Next.js again.
@vercel/edge-config@1.4.2
Patch Changes
- 309509c: Adjust README
@vercel/blob@2.0.0
Major Changes
-
0b8ead9: BREAKING CHANGE:
To continue receiving
onUploadCompletedcallback once a file is uploaded with Client Uploads when not hosted on Vercel, you need to provide thecallbackUrlat theonBeforeGenerateTokenstep when usinghandleUpload.When hosted on Vercel:
No code changes required. ThecallbackUrlis inferred from Vercel system environment variables:- In preview environment:
VERCEL_BRANCH_URLwhen available, otherwiseVERCEL_URL - In production environment:
VERCEL_PROJECT_PRODUCTION_URL
If you're not hosted on Vercel or you're not using Vercel system environment variables, your will need to provide the
callbackUrl:Before:
await handleUpload({ body, request, onBeforeGenerateToken: async (pathname) => { /* options */ }, onUploadCompleted: async ({ blob, tokenPayload }) => { /* code */ }, });
After:
await handleUpload({ body, request, onBeforeGenerateToken: async (pathname) => { return { callbackUrl: 'https://example.com' }; // the path to call will be automatically computed }, onUploadCompleted: async ({ blob, tokenPayload }) => { /* code */ }, });
For local development:
Set theVERCEL_BLOB_CALLBACK_URLenvironment variable to your tunnel URL:VERCEL_BLOB_CALLBACK_URL=https://abc123.ngrok-free.app
See the updated documentation at https://vercel.com/docs/vercel-blob/client-upload to know more.
Details:
Before this commit, during Client Uploads, we would infer the
callbackUrlat the client side level (browser) based onlocation.href(for convenience).
This is wrong and allows browsers to redirect the onUploadCompleted callback to a different website.While not a security risk, because the blob urls are already public and the browser knows them, it still pose a risk of database drift if you're relying on onUploadCompleted callback to update any system on your side.
- In preview environment:
@vercel/blob@1.1.1
Patch Changes
- f65d3c9: copy, head and del can receive a blob url or pathname, until now it was not very clear.
@vercel/blob@1.1.0
Minor Changes
-
2b4acc3: feat(blob): Add support for custom headers in client upload method
This change adds the ability to pass custom headers to the
uploadmethod in the client, which will be forwarded to the server endpoint specified byhandleUploadUrl. This is particularly useful for sending authorization headers and solves issues like #796 and #420.
@vercel/blob@1.0.2
Patch Changes
- d3627fa: Update Vercel Blob API endpoint to a more efficient one
@vercel/blob@1.0.1
Patch Changes
- af5f54b: Add correct documentation to all exported methods