---
title: "Why your deploy preview can delete Netlify Blobs data | Netlify Knowledge Base"
description: "Guides and articles to help you get the most out of the Netlify platform."
source: "https://www.netlify.com/knowledge-base/why-your-deploy-preview-can-delete-netlify-blobs-data/"
last_updated: "2026-09-23T19:51:14.000Z"
---
## Key takeaways

`getStore(name)` is site-scoped, which means it’s shared across **every** deploy context. Code running on a Deploy Preview reads, overwrites, and deletes the exact same data your production site serves. The fix is `getDeployStore(name)`, which scopes the store to a single deploy, or a store name that includes the deploy context. If you’ve been seeding test data or running destructive tests from a preview, that data went to production.

-   **One store name, one store.** There’s no per-context namespace on a site-scoped store.
-   **`getDeployStore()` is isolated** from production and cleaned up when the deploy is deleted — not immediately when a newer deploy publishes over it, but when the deploy record itself is deleted.
-   **`deleteAll()` from a preview wipes the production store.** No confirmation, no context check.
-   **A test that writes to a fixed key overwrites the live value at that key.** This is the quiet version, and the one that’s hardest to notice.
-   **Netlify Dev won’t reproduce this.** Local development uses a sandboxed store and can’t reach production data, so the problem only appears once your branch is deployed.

## The bug you don’t find in review

You added a feature that stores uploads in Blobs. You wrote a test that seeds a few records and clears them afterward. It passes locally. You open a pull request, the Deploy Preview builds, the test suite runs against the preview, everything’s green.

Meanwhile the records your production site was serving are gone.

Nothing in that sequence looks wrong. The mistake is one call, and it’s the call almost everyone writes first because it’s the shorter one. Here’s what’s actually happening and what to write instead.

## When this applies to you

This is your situation if any of these are true:

-   You call `getStore(...)` anywhere in code that runs on a Deploy Preview or branch deploy
-   You seed, fixture, or clean up blob data from tests that run against a deployed preview
-   You call `deleteAll()` outside of production code paths
-   You use a fixed, predictable key (`"latest"`, `"cache"`, `"config"`) rather than a per-record ID

This is **not** your situation if you only ever call `getDeployStore(...)`, or if all your blob writes happen in production code paths against per-record keys and you never run destructive operations from a preview. It’s also not your situation locally: Netlify Dev’s sandboxed store can’t touch production, which is precisely why this survives local testing.

If you’re choosing a storage primitive rather than debugging one, start at How to store files and objects with Netlify Blobs instead.

## What’s actually happening

Blobs gives you two ways to open a store, and they differ in scope rather than in API:

```
import { getStore, getDeployStore } from "@netlify/blobs";
const siteStore   = getStore("file-uploads");        // site-scoped: ALL contexts share thisconst deployStore = getDeployStore("file-uploads");  // this deploy only
```

`getStore("file-uploads")` resolves to one store for the whole site. Production resolves it to that store. Your Deploy Preview resolves it to that same store. So does every branch deploy and every agent preview. The store persists across deploys, which is what you want for production data and exactly what makes preview writes dangerous.

`getDeployStore("file-uploads")` resolves to a store scoped to the deploy that’s running. Production’s copy and your preview’s copy are different stores that happen to share a name.

### The blast radius

Ordered roughly by how bad it is versus how likely you are to notice:

What preview code does

What happens to production

`store.deleteAll()`

The entire production store is deleted. `deletedBlobs` reports the count.

`store.delete(key)`

That production record is gone

`store.set(key, testValue)` on a fixed key

The production value at that key is replaced. **Quietest and most common.**

`store.set(newKey, testValue)`

Test data accumulates in the production store

`store.get(key)`

Reads real user data into your preview environment

The third row is the one worth staring at. A test that writes `store.set("config", {...})` doesn’t error, doesn’t warn, and doesn’t leave an obvious trace. It just replaces whatever production had at `"config"` with your fixture. If nothing reads that key for a while, you find out later.

Note also that `onlyIfNew` and `onlyIfMatch` don’t save you here. They’re concurrency guards, not context guards. `onlyIfNew` will happily refuse to overwrite, but that means your test now behaves differently against a populated production store than it did against an empty local one.

## The fix

For anything throwaway, per-deploy, or test-related, use the deploy store:

```
import { getDeployStore } from "@netlify/blobs";
const uploads = getDeployStore("file-uploads");await uploads.set(key, file);   // isolated from production
```

Deploy-scoped stores are cleaned up when the deploy is deleted, so preview data doesn’t pile up.

If you need the data to outlive a single deploy but stay out of production, put the context in the store name:

```
import { getStore } from "@netlify/blobs";import type { Context } from "@netlify/functions";
export default async (req: Request, context: Context) => {  const store = getStore(`uploads-${context.deploy.context}`);  // production      -> "uploads-production"  // deploy preview  -> "uploads-deploy-preview"  // branch deploy   -> "uploads-branch-deploy"  ...};
```

`context.deploy.context` gives you the current deploy context, so each context gets its own store while persisting across deploys within that context. Watch the 64-byte store-name limit if you’re composing longer names.

If you want a hard stop rather than a separate store, gate the destructive path on context:

```
if (context.deploy.context !== "production") {  return new Response("Refusing to run destructive operation outside production", { status: 403 });}
```

## Common failure modes

**You fixed the code but production data is already gone.** Blobs has no built-in versioning or point-in-time restore. Deleted is deleted. Check whether the data exists anywhere else (a database, the original uploads, a downstream system) and rebuild from there. Worth knowing before you need it: **downloading a deploy does not include its blobs**, so a deploy download isn’t a backup.

**You assumed locking the deploy protected the store.** It doesn’t. Locking a published deploy prevents new deploys from publishing; it does not prevent writes to that deploy’s deploy-specific stores.

**You checked with the CLI and the data looked fine.** The CLI always uses strong consistency, while your function reads eventually-consistent by default. Deletes and updates propagate within 60 seconds, so the CLI and your function can disagree for up to a minute. Neither one is lying to you.

**You switched to `getDeployStore()` and your existing data disappeared.** Expected. It’s a different store. Data written through `getStore()` is still in the site-scoped store; you’ll need to copy across what you want to keep.

**You tried to enumerate deploy stores to audit the damage.** `listStores()` **excludes deploy-specific stores**, so it won’t show them.

**You audited your own code and found nothing.** Check your build plugins too. Plugins can read from any of the site’s stores. They can only write to deploy-specific stores, so they can’t cause the destructive version of this, but a plugin reading production data into a preview build is still worth knowing about.

## Reference

### Store scope

Call

Scope

Persists across deploys

Cleaned up on deploy deletion

`getStore(name)`

Entire site, all contexts

Yes

No

`getDeployStore(name)`

Single deploy

No

Yes

``getStore(`${name}-${context.deploy.context}`)``

One deploy context

Yes

No

### Deploy context values

`context.deploy.context` returns the current context: `production`, `deploy-preview`, `branch-deploy`, `preview-server`, or `dev`.

### What doesn’t isolate a store

Not a safeguard

Why

`onlyIfNew` / `onlyIfMatch`

Concurrency guards, not context guards

Locking a published deploy

Doesn’t prevent writes to deploy-specific stores

Netlify Dev’s sandbox

Only applies locally; a deployed preview reaches the real store

`listStores()`

Excludes deploy-specific stores, so it can’t audit them

Downloading a deploy

Does not include blobs

### Related limits

-   Store names: no `/`, no `:`, max 64 bytes
-   Default consistency: eventual. Updates and deletes propagate within 60 seconds.
-   `deleteAll()` returns `{ deletedBlobs }`, or `0` if the store didn’t exist

## FAQs

**Can a Netlify deploy preview write to production Blobs data?** Yes, if the code calls `getStore(name)`. Site-scoped stores are shared across every deploy context, so preview code reads, overwrites, and deletes production data. Use `getDeployStore(name)` to isolate a deploy.

**What’s the difference between `getStore` and `getDeployStore`?** `getStore` opens one store shared by the whole site across all contexts. `getDeployStore` opens a store scoped to the running deploy, isolated from production and cleaned up when the deploy is deleted.

**How do I give each deploy context its own Blobs store?** Either use `getDeployStore()`, or include the context in the store name so each context resolves to its own store (see the example above). Keep the name under 64 bytes.

**Can I recover Blobs data deleted from a deploy preview?** No. Blobs has no versioning or point-in-time restore, and a deploy download doesn’t include blobs. Rebuild from another source if you have one.

**Why didn’t this show up in local testing?** Netlify Dev uses a sandboxed local store that can’t read or write production data. The shared-store behavior only appears once the code runs on a real deploy.

**Does locking a deploy protect its Blobs data?** No. Locking stops new deploys from publishing. It doesn’t prevent writes to deploy-specific stores.

**Is `onlyIfMatch` enough to make preview writes safe?** No. It’s a concurrency guard against competing writers, not a check on which deploy context you’re in. Scope the store instead.

## Related

-   [Netlify CLI blobs commands](https://cli.netlify.com/commands/blobs/)

This article is generated from Netlify’s open-source agent guidance at [netlify/context-and-tools](https://github.com/netlify/context-and-tools), the same reference our AI coding agents use. The store-scoping warning above is flagged “READ THIS FIRST” in the source.

* * *

Building something that needs storage? Start at [netlify.new](https://netlify.new).