The Vercel Blob bill has more lines than "GB stored". Here is what each one
counts, using Vercel's published Pro example rates for iad1. Prices are
regional; check your store's region.
| Line | Counts | Example rate |
|---|---|---|
| Storage | Monthly average store size, sampled every 15 minutes | $0.023 per GB-month |
| Simple operations | head(), and URL reads that miss the cache | $0.40 per million |
| Advanced operations | put(), upload(), copy(), list() | $5.00 per million |
| Blob data transfer | Bytes downloaded from the store | $0.05 per GB |
Plus standard CDN lines: an Edge Request per URL access, and Fast Origin
Transfer on cache misses. del() is free.
Hobby includes 1 GB of storage, 10,000 simple operations, 2,000 advanced operations and 10 GB of transfer a month, then stops. Blob stays off until the 30-day window passes. It does not bill you, it just stops working.
Advanced operations grow fastest
- Every upload is one. A multipart upload is one to start, one per part, one to finish.
- Every
list()call is one. A page that lists a user's files on every view burns them per view. Store keys in your database and query that. - The Vercel dashboard counts. Refreshing the Blob browser runs
list(). A teammate clicking through folders shows up on your bill.
Egress: public vs private
Uploads are free when they are client uploads. Downloads are not.
- Public blob: the browser fetches from the store. You pay Blob data transfer (about 3x cheaper than Fast Data Transfer on average).
- Private blob streamed through a function: you pay Blob data transfer into the function, then Fast Data Transfer out to the browser. Two lines for the same bytes, plus function time.
- Private blob via a presigned URL: the browser fetches from the store with a signed, expiring URL. No function in the path.
Vercel's own guidance: avoid serving files over 100 MB through private stores unless traffic is low, and put large public media in a public store.
Cache hits are the cheap path
A cache hit is not a simple operation and has no Fast Origin Transfer.
Immutable pathnames and a long cacheControlMaxAge (one month is the
default) keep most reads as hits. Two ways to lose that:
- Overwriting at the same pathname, which forces misses and stale reads.
- Blobs over 512 MB, which are never cached. Every read is a miss.
Habits that keep it flat
- Client uploads for user files. No transfer charge in, no function time.
- New pathname per version. Never overwrite a hot file.
- Delete orphans. Storage is averaged over the month, so a cleanup shows up gradually, not instantly.
- No
list()on request paths. - Resize images before storing them if they are shown small.
- On Pro, set a Spend Management amount so a runaway loop pages you instead of surprising you.