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 import — reach for this: Install: npm install @netlify/blobs . Fetch API is required (built into Node 18+); otherwise pass a custom fetch . Two ways to open a store — use the options object form when you need consistency or a custom fetch (the string form cannot pass them): siteID , token , deployID , and region are set automatically inside Functions, Edge Functions, and Build Plugins — do not pass them manually there. Choosing the store type — READ THIS FIRST getStore(name) — site scoped. Persists across deploys and is shared across ALL deploy contexts . Code on a Deploy Preview reads, overwrites, and deletes production data. Never seed throwaway data or run destructive tests from a preview. getDeployStore(name) — scoped to one deploy; isolated from production. Use this for throwaway/per deploy data, or use a context specific store name for isolation. Blobs have no built in access control — the serving function is the gate. Default to private: gate reads behind an authenticated function rather than exposing blobs publicly. Never accept an arbitrary caller supplied key against a store holding sensitive data. Common tasks Persist a user upload with metadata ( set ) Edge Function form is identical but imports Context from @netlify/edge functions . Persist JSON ( setJSON ) Read a blob ( get ) — always null check Pass type for other formats: get(key, { type: "json" "arrayBuffer" "blob" "stream" "text" }) . Atomic conditional write Write only if the key is new: Write only if the entry matches a known ETag (compare and swap): 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. List blobs Manual pagination (returns an AsyncIterator ): Hierarchical listing — group keys with / , set directories: true to list one level, and use a trailing slash on prefix to drill in (without it, cats would also match catsuit ): List stores Delete Build plugin — write to a deploy specific store Build plugins can READ from any of the site's stores, but can WRITE only to deploy specific stores ( getDeployStore ). Client side expiration (no server side TTL) Blobs have no TTL. Store a timestamp in metadata, check it on read, and delete when expired: Conditional read with ETag ( getWithMetadata ) getWithMetadata returns { data, etag, metadata } , or null if the key is absent. getMetadata(key) returns { metadata, etag } (no blob body) — use it to check existence cheaply. API surface Store instance methods: set(key, value, { metadata, onlyIfMatch, onlyIfNew }) → { modified, etag } . value is ArrayBuffer Blob string . setJSON(key, value, { metadata, onlyIfMatch, onlyIfNew }) → { modified, etag } . get(key, { consistency, type }) → blob in requested format, or null . getWithMetadata(key, { consistency, etag, type }) → { data, etag, metadata } or null . getMetadata(key, { consistency, etag }) → { metadata, etag } or null . list({ directories, paginate, prefix }) → { blobs, directories } (auto paginates unless paginate: true ). delete(key) → undefined . deleteAll() → { deletedBlobs } . Module functions: listStores({ paginate }) → { stores } . Excludes deploy specific stores. Configuration Consistency Default is eventual : writes are globally readable immediately; updates and deletes propagate within 60 seconds . Opt into strong consistency per store or per read: The CLI always uses strong consistency. Regions (deploy specific stores) Deploy specific stores default to the function's region. Override with region : Available regions: https://docs.netlify.com/build/functions/configuration region File based uploads (no build plugin) Place blob files under .netlify/blobs/deploy/ in the site's base directory; Netlify uploads them to deploy specific stores (preserving directory structure) after build, before deploy. Attach metadata with a sibling JSON file prefixed with $ : $mouse.jpg.json for mouse.jpg , dogs/$good boy.jpg.json for dogs/good boy.jpg . Metadata files must be valid JSON or the deploy fails . .netlify/blobs/deploy is wiped before each build — files must be created DURING the build (build command or plugin). Files committed to the repo beforehand are NOT uploaded. Requires continuous deployment or CLI deploys. Constraints & gotchas Store names: no / , no : , max 64 bytes. Keys: non empty, cannot start with / , max 600 bytes, any Unicode. (UTF 8: most chars 1 byte, some more, e.g. à = 2 bytes.) Sizes: object ≤ 5 GB; metadata ≤ 2 KB. Pagination pages: list and listStores cap pages at 1,000 entries/stores. Last write wins — no concurrency control beyond onlyIfMatch / onlyIfNew . Go Functions cannot access Blobs. Local dev (Netlify Dev) uses a sandboxed local store: no file based uploads, and you cannot read production data. Not supported under Netlify's HIPAA compliant hosting. Deploy deletion cleans up deploy specific stores only; other stores need manual deletion or your own expiration logic. Downloading a deploy does NOT include deploy specific blobs; locking a published deploy does NOT prevent writes to its deploy specific stores. Encrypted at rest and in transit; blobs are reachable only through your own site. When something fails Surface the error and read the function logs. Do not invent REST endpoints or side channel APIs to retry a failed store operation. CLI & migration Inspect blobs with netlify blobs:list / :get / :set / :delete — reference: https://cli.netlify.com/commands/blobs/ If you wrote to site wide stores with @netlify/blobs ≤ 6.5.0, data becomes inaccessible after upgrading (namespacing change). Migrate with the latest CLI, which makes the store accessible on 7.0.0+: <! 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 ).