
netlify-blobs
Store and retrieve unstructured objects, files, and cache-like state on Netlify with the @netlify/blobs module. Use when persisting user file uploads (images/documents), caching computed output from functions or Background Functions, serving downloadable assets, storing JSON blobs keyed by ID, or seeding deploy-specific data. Reach for this for key/value or object storage from Functions, Edge Functions, or Build Plugins — not for per-user, transactional, or relational data (use Netlify DB for that). Triggers include "save an uploaded file", "cache API results", "store generated site map", "key/value store for a function", or "file uploads without a database".
- Installs
- 3.1K
- Last 24h
- +20
- Trending rank
- #5921
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/netlify/context-and-tools --skill netlify-blobs- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads netlify-blobs automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Netlify Blobs
Modern syntax: import from @netlify/blobs, open a store, then call methods on the handle.
import { getStore, getDeployStore, listStores } from "@netlify/blobs";
import type { Context } from "@netlify/functions"; // or "@netlify/edge-functions"
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
const uploads = getStore("file-uploads");
// set: value is ArrayBuffer | Blob | string
await uploads.set(key, file, { metadata: { country: "Spain" } });
// setJSON: any JSON-serializable value
await uploads.setJSON(key, { hello: "world" });
// get: returns value or null. type: text (default) | json | arrayBuffer | blob | stream
const entry = await uploads.get(key); // string
const obj = await uploads.get(key, { type: "json" });
if (entry === null) { /* 404 */ }
set/setJSON overwrite an existing key. Both return { modified, etag }. etag is omitted when no new entry was generated.
Persisting a user upload (Function)
import { getStore } from "@netlify/blobs";
import type { Context } from "@netlify/functions";
import { v4 as uuid } from "uuid";
export default async (req: Request, context: Context) => {
const form = await req.formData();
const file = form.get("file") as File;
const key = uuid();
const uploads = getStore("file-uploads");
await uploads.set(key, file, { metadata: { country: context.geo.country.name } });
return new Response("Submission saved");
};
Edge functions are identical except import type { Context } from "@netlify/edge-functions";.
Reading (Function)
export default async (req: Request, context: Context) => {
const { key } = context.params;
const uploads = getStore("file-uploads");
const entry = await uploads.get(key);
if (entry === null) return new Response(`Not found: ${key}`, { status: 404 });
return new Response(entry);
};
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.
// getWithMetadata: data + metadata + etag
const entry = await uploads.getWithMetadata(key);
if (entry === null) return new Response(`Not found: ${key}`, { status: 404 });
const { data, metadata } = entry;
return new Response(data, { headers: { "X-Country": metadata.country } });
// getMetadata: metadata + etag only, without downloading the blob
const meta = await uploads.getMetadata(key); // { etag, metadata } or null
if (meta === null) { /* missing */ }
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.
const entry = await uploads.getWithMetadata("my-key", { etag: cachedETag });
if (entry !== null && entry.etag === cachedETag) {
// entry.data is null: cached copy still fresh
}
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 }:
// Create only if key does not exist
const { modified } = await emails.set("jane@netlify.com", "Jane Doe", { onlyIfNew: true });
if (!modified) return new Response("Email already exists", { status: 400 });
// Update only if the ETag still matches
const { modified } = await emails.set("jane@netlify.com", "New Jane", { onlyIfMatch: etag });
if (!modified) return new Response("Cached data is stale", { status: 400 });
Listing
const { blobs } = await uploads.list(); // blobs: [{ etag, key }]
list({ directories, paginate, prefix }). Group keys hierarchically with /:
const { blobs, directories } = await animals.list({ directories: true });
// directories: ["cats", "dogs"]; blobs: top-level keys only
// Drill in. Trailing slash REQUIRED (without it "catsuit" also matches)
const res = await animals.list({ directories: true, prefix: "cats/" });
Pagination: list returns all pages by default, in pages of up to 1,000 entries. Set paginate: true to get an AsyncIterator:
for await (const page of store.list({ paginate: true })) {
console.log(page.blobs);
}
listStores({ paginate }) returns { stores: string[] } in pages of up to 1,000. It does not include deploy-specific stores.
Deleting
await uploads.delete(key); // resolves undefined
const { deletedBlobs } = await uploads.deleteAll(); // deletes every object = deletes the store
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:
await uploads.set(key, body, { metadata: { expiration: new Date("2025-01-01").getTime() } });
const entry = await uploads.getWithMetadata(key);
if (entry === null) return new Response("Blob does not exist");
const { expiration } = entry.metadata;
if (expiration && expiration < Date.now()) await uploads.delete(key);
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:
const store = getStore({ name: "animals", consistency: "strong" }); // whole store
await store.get("dog", { consistency: "strong" }); // single 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-2and 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.
const uploads = getDeployStore({ name: "file-uploads", region: "ap-southeast-2" });
const profiles = getStore({ name: "user-profiles", region: "eu-central-1" });
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.
.netlify/blobs/deploy/
├─ dogs/good-boy.jpg
├─ dogs/$good-boy.jpg.json # metadata for good-boy.jpg
├─ cat.jpg
└─ mouse.jpg
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. 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+:
netlify recipes blobs-migrate YOUR_STORE_NAME
Reference
Full API and background: Netlify Blobs docs and the data & 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.
- Blobs is not a database. For dynamic, per-user, or transactional data, use Netlify DB — Blobs is for objects, files, and cache-like state.
- When a store operation fails, surface the error and read the function logs — do not invent REST endpoints or side-channel APIs to retry.
netlify blobs:list/get/set/deleteexist for inspection; the CLI reference is their source of truth — link, don't restate.- 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.
- 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. - Don't build counters, balances, or read-modify-write logic on a blob key —
even with
onlyIfMatchretries. That's transactional data; use Netlify DB. - Build plugins: state BOTH halves — they can read from any of the site's
stores, but write only to deploy-specific stores (
getDeployStore).
FAQ
What does the netlify-blobs skill do?
Store and retrieve unstructured objects, files, and cache-like state on Netlify with the @netlify/blobs module. Use when persisting user file uploads (images/documents), caching computed output from functions or Background Functions, serving downloadable assets, storing JSON blobs keyed by ID, or seeding deploy-specific data. Reach for this for key/value or object storage from Functions, Edge Functions, or Build Plugins — not for per-user, transactional, or relational data (use Netlify DB for that). Triggers include "save an uploaded file", "cache API results", "store generated site map", "key/value store for a function", or "file uploads without a database".
How do I install netlify-blobs?
Run npx skills add https://github.com/netlify/context-and-tools --skill netlify-blobs in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/netlify-blobs/ (personal) or .claude/skills/netlify-blobs/ (project).
Which AI agents can use netlify-blobs?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is netlify-blobs safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains netlify-blobs?
It is published by netlify in netlify/context-and-tools. It has 3,082 recorded installs.
More from netlify/context-and-tools
netlify-deploy
netlify/context-and-tools
Create, configure, and manage Netlify deploys from code — reach for this when setting up Git continuous deployment, running netlify deploy or netlify deploy --prod from the CLI, writing netlify.toml deploy contexts, adding a Deploy to Netlify button, wiring build hooks, configuring Deploy Previews or branch deploys, locking or skipping deploys, fixing a failed or secrets-scanning deploy, or when someone asks to "deploy my site", "set up preview deploys", "add per-branch build config", "keep staging out of Google", or "add a deploy button to my README".
netlify-config
netlify/context-and-tools
Configure Netlify builds and routing via netlify.toml, redirects, and headers. Use when setting a build command or publish directory, adding redirects or rewrites or proxies, adding an SPA fallback rewrite, setting custom response headers or basic auth, managing environment variables and secrets, scoping vars per deploy context, marking a var as secret, disabling secret scanning, configuring functions bundling, ignoring builds, or wiring up a monorepo or JavaScript SPA on Netlify.
netlify-functions
netlify/context-and-tools
Write, configure, and deploy Netlify serverless functions in TypeScript, JavaScript, or Go. Use this when adding an API endpoint or backend route, adding a contact form handler, wiring auth or Identity signup/login hooks, identifying which Netlify user is calling a private or team-login-protected app, building streaming or AI-proxy responses, scheduling cron jobs, running long background jobs (batch processing/scraping), reacting to deploy or form events, setting up rate limiting or region/memory config, or reading environment variables and secrets inside a function. Covers file locations, the Request/Context/Response handler shape, path routing, config options, and local testing with netlify dev.
netlify-frameworks
netlify/context-and-tools
Deploy and configure web frameworks on Netlify — build settings and SSR/edge adapters plus local platform emulation and env vars. Use when setting up or fixing a framework deploy (Next.js / Astro / Nuxt / SvelteKit / Remix / React Router / TanStack Start / SolidStart / Gatsby / Angular / Vite / Express / Hydrogen / Hugo / Eleventy / Vue / React), adding SSR or edge functions or middleware wired to Netlify context, fixing SPA redirect and catch-all rules, setting a build command or publish directory, or debugging "why isn't my env var updating" and framework build failures.
netlify-edge-functions
netlify/context-and-tools
Write, route, cache, and debug Netlify Edge Functions, the Deno-based TypeScript or JavaScript handlers in netlify/edge-functions that run at the network edge in front of static files and serverless functions. Activate this skill whenever someone wants to add auth middleware or a login gate, redirect or rewrite visitors by country or cookie, localize or personalize a page with geolocation, run A/B testing, transform or inject HTML into a response, stream server-side rendering at the edge, or cache an edge response. Also use it when an edge function silently does nothing, runs in the wrong order, ignores its Cache-Control headers, or cannot read an environment variable.
netlify-forms
netlify/context-and-tools
Serverless form handling on Netlify-hosted sites — detects HTML forms at deploy time, stores submissions, filters spam, and sends notifications. Use when adding a contact form, lead-capture form, file-upload form, or newsletter signup to a Netlify site; wiring AJAX form submission; setting up a custom thank-you page; adding a honeypot or reCAPTCHA to a form; getting forms working in Next.js, Nuxt, SvelteKit, Astro, or Gatsby; reading form submissions via the Netlify API; setting up submission notifications or ChatGPT automations on form submission events; or debugging missing submissions and forms that silently fail to register.
Popular devops & cloud skills
microsoft-foundry
microsoft/azure-skills
Build, deploy, evaluate, optimize, fine-tune, and manage Microsoft Foundry agents, models, and resources end to end. USE FOR: foundry, azd ai agent, azd provision/deploy, hosted agent scaffold/develop/run/deploy/troubleshoot, prompt agent create, managed harness agent create, GitHub Copilot harness agent, create agent, update agent, add tool to agent, invoke agent, agent insights, evaluate agent, batch eval, continuous eval, continuous monitoring, agent CI/CD, optimize prompt, improve prompt, optimize agent instructions, Agent Optimizer scaffold, dataset curation from traces, deploy model, model fine-tuning (SFT/DPO/RFT), Foundry project, RBAC, role assignment, permissions, quota, capacity, region, deployment failure, AI Services, create Foundry resource, knowledge index, customize deployment, onboard, availability, training-data, grader, distillation, large file upload. DO NOT USE FOR: Azure Functions, App Service, general Azure deploy (use azure-deploy), general Azure prep (use azure
azure-diagnostics
microsoft/azure-skills
Debug Azure production issues on Azure using AppLens, Azure Monitor, resource health, and safe triage. WHEN: debug production issues, troubleshoot app service, app service high CPU, app service deployment failure, troubleshoot container apps, container app 503 or target port mismatch, troubleshoot functions, function telemetry missing or stopped after a config/connection-string change, troubleshoot AKS, VM RDP, Linux SSH, VM black screen, can't connect to VM, reset VM password, NSG or firewall blocking, kubectl cannot connect, kube-system/CoreDNS failures, pod pending, crashloop, node not ready, upgrade failures, analyze logs, KQL, insights, image pull failures, cold start issues, health probe failures, resource health, root cause of errors, troubleshoot event hubs, troubleshoot service bus, messaging SDK error, AMQP connection failure, message lock lost, lock renewal during long-running processing, service bus dead letter.
azure-prepare
microsoft/azure-skills
Prepare azd-based Azure projects for deployment: generates azure.yaml, infrastructure (Bicep/Terraform), and Dockerfiles for the Azure Developer CLI (azd) workflow. USE ONLY when the user explicitly wants to use azd as the deployment tool, or the project already has an azure.yaml file. DO NOT USE FOR: non-azd deployments, Python App Service code-only deploys (use python-appservice-deploy), or cross-cloud migration (use azure-cloud-migrate). WHEN: prepare app for azd, create azure.yaml, set up azd infrastructure, modernize app for Azure with azd, deploy with azd, function app, timer trigger, service bus trigger, event-driven function, managed identity, generate Bicep, generate Terraform, create and deploy to Azure.
azure-ai
microsoft/azure-skills
Use for Azure AI: Search, Speech, OpenAI, Document Intelligence. Helps with search, vector/hybrid search, speech-to-text, text-to-speech, transcription, OCR. WHEN: AI Search, query search, vector search, hybrid search, semantic search, speech-to-text, text-to-speech, transcribe, OCR, convert text to speech.
azure-deploy
microsoft/azure-skills
Execute Azure deployments for ALREADY-PREPARED applications that have existing .azure/deployment-plan.md and infrastructure files. DO NOT use this skill when the user asks to CREATE a new application — use azure-prepare instead. This skill runs azd up, azd deploy, terraform apply, and az deployment commands with built-in error recovery. Requires .azure/deployment-plan.md from azure-prepare and validated status from azure-validate. WHEN: "run azd up", "run azd deploy", "execute deployment", "push to production", "push to cloud", "go live", "ship it", "bicep deploy", "terraform apply", "publish to Azure", "launch on Azure". DO NOT USE WHEN: "create and deploy", "build and deploy", "create a new app", "set up infrastructure", "create and deploy to Azure using Terraform" — use azure-prepare for these.
azure-validate
microsoft/azure-skills
Pre-deployment validation for Azure readiness. Run deep checks on configuration, infrastructure (Bicep or Terraform), RBAC role assignments, managed identity permissions, and prerequisites before deploying. WHEN: validate my app, check deployment readiness, run preflight checks, verify configuration, check if ready to deploy, validate azure.yaml, validate Bicep, test before deploying, troubleshoot deployment errors, validate Azure Functions, validate function app, validate serverless deployment, verify RBAC roles, check role assignments, review managed identity permissions, what-if analysis, validate Container Apps deployment.