netlify-blobs
Store and retrieve unstructured objects, file uploads, and cache-like state on Netlify using the @netlify/blobs key/value API from Functions, Edge Functions, and Build Plugins. Use when a task involves saving user file or image uploads, persisting form or contact-form submissions, storing generated
By netlify · 2,244 installs
npx skills add netlify/context-and-tools --skill netlify-blobs
Source repository · Upstream listing
Netlify Blobs
Modern syntax: import from @netlify/blobs , open a store, then call methods on the handle.
In Functions, Edge Functions, and Build Plugins, siteID , deployID , token (and region for getDeployStore ) are injected automatically. Install with npm install @netlify/blobs .
Not a database. For dynamic, per user, transactional, or relational data, use Netlify DB. Blobs is for objects, files, and cache like state. It is optimized for frequent reads and infrequent writes.
Store scope is a footgun. Read this first. getStore opens a site wide store shared across ALL deploy contexts . Code on a deploy preview reads, overwrites, and deletes production data. Never run destructive tests or seed throwaway data from a preview against a site wide store. Use getDeployStore() or a context specific store name for isolation.
Choosing a store type
getStore(name) : site wide and shared across all deploys. Data persists across deploys, and previews see production data.
getDeployStore(name) : deploy specific and scoped to one deploy. It stays in sync on rollback and is cleaned up on deploy deletion. Use it for isolation and for anything a failed deploy must not corrupt.
Build plugins can READ from any of the site's stores, but WRITE only to deploy specific stores ( getDeployStore ). File based uploads also write only to deploy specific stores.
Core writes and reads
set / setJSON overwrite an existing key. Both return { modified, etag } . etag is omitted when no new entry was generated.
Persisting a user upload (Function)
Edge functions are identical except import type { Context } from "@netlify/edge functions"; .
Reading (Function)
Metadata and conditional reads
Null check before destructuring. getWithMetadata and getMetadata resolve to null when the key is absent. Destructuring the return value directly ( const { data } = await store.getWithMetadata(key) ) throws on a missing key. Assign the result to a variable, check for null , then read its fields.
Both accept { consistency, etag, type } .
Conditional read: pass a cached etag . If it still matches server side, data is null , which means your copy is fresh. Compare the whole ETag value, including surrounding quotes and any weakness prefix.
Concurrency: atomic conditional writes
Last write wins. There is no concurrency control. Do NOT build counters, balances, or read modify write logic on a blob key, even with onlyIfMatch retries. That is transactional data; use Netlify DB.
set / setJSON accept { onlyIfNew, onlyIfMatch } :
Listing
list({ directories, paginate, prefix }) . Group keys hierarchically with / :
Pagination: list returns all pages by default, in pages of up to 1,000 entries. Set paginate: true to get an AsyncIterator :
listStores({ paginate }) returns { stores: string[] } in pages of up to 1,000. It does not include deploy specific stores .
Deleting
Expiration (no server side TTL)
Blobs never expire on their own. Store an expiration timestamp in metadata, check it on read, and delete the blob once it has passed:
Consistency
The default is eventual consistency. New writes are globally available immediately, but updates and deletions take up to 60 seconds to reach all edge locations. Opt into strong consistency per store or per read:
Netlify CLI always uses strong consistency.
Regions
region takes an AWS region code , not the airport code used for the functions region. Supported values are ap southeast 1 , ap southeast 2 , eu central 1 , us east 1 , and us east 2 . Any other value throws InvalidBlobsRegionError before the request is made.
Deploy specific stores default to your functions region (auto injected).
Site wide stores default to us east 2 and do NOT follow your functions region.
Footgun: the site wide region is per call. To keep a site wide store in a specific region, pass region on every getStore call for that store (reads, writes, deletes). A call that omits it uses us east 2 and silently sees no data. There is no error or warning.
Footgun: changing a region does not move data. The store appears empty in the new region while its data stays in the old one. To migrate, copy each entry to a store opened in the new region, then delete it from the old one.
File based uploads (no build plugin)
Place files under .netlify/blobs/deploy in the base directory. Netlify uploads them to deploy specific stores , preserving directory structure. To attach metadata, add a sibling JSON file named $<filename .json . It must be valid JSON or the deploy fails.
Caution: Netlify empties .netlify/blobs/deploy before each build. Files committed to your repo are NOT uploaded. Create blob files during the build, with your build command or a build plugin.
Access control (default to private)
Blobs have no built in access control : the serving function is the gate. Blobs are only reachable through your own site's code and are encrypted at rest and in transit. When in doubt, default to private and gate reads behind an authenticated function rather than exposing blobs publicly.
For sensitive data, do not serve arbitrary user supplied keys. Scope keys with something callers cannot tamper with. Blobs is not part of Netlify's HIPAA compliant offering.
Constraints
Store names: no / or : , max 64 bytes.
Keys: non empty, cannot start with / , max 600 bytes. Any Unicode is allowed, but some characters take more than 1 byte.
Object size max 5 GB; metadata max 2 KB.
Functions written in Go cannot access Netlify Blobs .
The Fetch API is required (Node.js 18+). Otherwise pass a custom fetch : getStore({ fetch, name: "file uploads" }) .
Local dev (Netlify Dev) uses a sandboxed local store. It does not support file based uploads and cannot read production data.
File based uploads require continuous deployment or CLI deploys.
When an operation fails
Surface the error and read the function logs. Do not invent REST endpoints or side channel APIs to retry.
CLI and UI
netlify blobs:list/get/set/delete exist for inspection. See the [CLI command reference](https://cli.netlify.com/commands/blobs/). To browse and download blobs in the UI, go to Data & Storage Blobs .
Module version migration
Site wide stores written with @netlify/blobs 6.5.0 or earlier become inaccessible after upgrading, because of a namespacing change. Migrate them with the latest CLI, then use module 7.0.0+:
Reference
Full API and background: [Netlify Blobs docs](https://docs.netlify.com/build/data and storage/netlify blobs/) and the [data & storage overview](https://docs.netlify.com/build/data and storage/overview/).
<! system: agent context/blobs/system.md — human owned, merged by ctx gen; edit system.md, not this section
Netlify house rules (blobs)
These are org conventions, not docs facts — merged into the rendered skill by
ctx gen and never generated. Owned by the skills maintainer.
1. Blobs is not a database. For dynamic, per user, or transactional data,
use Netlify DB — Blobs is for objects, files, and cache like state.
2. When a store operation fails, surface the error and read the function
logs — do not invent REST endpoints or side channel APIs to retry.
3. netlify blobs:list/get/set/delete exist for inspection; the CLI
reference is their source of truth — link, don't restate.
4. Blobs have no built in access control — the serving function is the gate.
When in doubt, default to private: gate reads behind an authenticated
function rather than exposing blobs publicly.
5. Site scoped stores are shared across ALL deploy contexts — code on a
deploy preview reads, overwrites, and deletes production data. Never run
destructive tests or seed throwaway data from previews; use
getDeployStore() or a context specific store name for isolation.
6. Don't build counters, balances, or read modify write logic on a blob key —
even with onlyIfMatch retries. That's transactional data; use Netlify DB.
7. Build plugins: state BOTH halves — they can read from any of the site's
stores, but write only to deploy specific stores ( getDeployStore ).