Releases: vercel/storage
@vercel/blob@2.4.1
Patch Changes
- b7027de: Read the Vercel OIDC token via the
@vercel/oidcpackage (getVercelOidcTokenSync) instead of an inlined copy. This makes the dependency explicit and discoverable, and matches how other Vercel packages consume OIDC. Behavior is unchanged except for one edge case: a blankx-vercel-oidc-tokenrequest-context header now resolves to no token rather than falling back toVERCEL_OIDC_TOKEN.
@vercel/blob@2.4.0
Minor Changes
- 20eeaff: Add Vercel OIDC auth and presigned URLs
@vercel/blob@2.3.3
Patch Changes
- d2ea7cf: Enforce
maximumSizeInBytesclient-side for multipart uploads. Bodies with a known size (Blob, File, Buffer) are now checked before the upload starts, avoiding wasted API calls. - 949e994: Fix multipart upload hanging forever on empty streams, and fix
createChunkTransformStreambypassing backpressure by removing incorrectqueueMicrotaskwrapping.
@vercel/blob@2.3.2
Patch Changes
- c9d9a1a: Apply
ifMatch/allowOverwritevalidation tohandleUploadandgenerateClientTokenFromReadWriteToken. WhenifMatchis set viaonBeforeGenerateTokenor direct token generation,allowOverwriteis now implicitly enabled. Explicitly passingallowOverwrite: falsewithifMatchthrows a clear error. - 6dcecb8: Make
ifMatchimplyallowOverwrite: trueonput(). Previously, usingifMatchwithout explicitly settingallowOverwrite: truewould cause the server to send conflicting conditional headers to S3, resulting in 500 errors. Now the SDK implicitly enablesallowOverwritewhenifMatchis set, and throws a clear error ifallowOverwrite: falseis explicitly combined withifMatch.
@vercel/blob@2.3.1
Patch Changes
- a9a733a: fix: validate URL domain in
get()to prevent sending the token to arbitrary hosts
@vercel/blob@2.3.0
Minor Changes
-
04ca1f0: Add private storage support (beta), a new
get()method, and conditional getsPrivate storage (beta)
You can now upload and read private blobs by setting
access: 'private'onput()andget(). Private blobs require authentication to access — they are not publicly accessible via their URL.New
get()methodFetch blob content by URL or pathname. Returns a
ReadableStreamalong with blob metadata (url, pathname, contentType, size, etag, etc.).Conditional gets with
ifNoneMatchPass an
ifNoneMatchoption toget()with a previously received ETag. When the blob hasn't changed, the response returnsstatusCode: 304withstream: null, avoiding unnecessary re-downloads.Example
import { put, get } from "@vercel/blob"; // Upload a private blob const blob = await put("user123/avatar.png", file, { access: "private" }); // Read it back const response = await get(blob.pathname, { access: "private" }); // response.stream — ReadableStream of the blob content // response.blob — metadata (url, pathname, contentType, size, etag, ...) // Conditional get — skip download if unchanged const cached = await get(blob.pathname, { access: "private", ifNoneMatch: response.blob.etag, }); if (cached.statusCode === 304) { // Blob hasn't changed, reuse previous data }
Learn more: https://vercel.com/docs/vercel-blob/private-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.