# `wrangler dev --remote` silently writes to your production KV namespace — here's the fix

> Source: <https://dev.to/riversea/wrangler-dev-remote-silently-writes-to-your-production-kv-namespace-heres-the-fix-2c6p>
> Published: 2026-07-01 01:08:50+00:00

I lost production data on a Tuesday afternoon because `wrangler.toml`

had one missing field. Not a code bug. Not a logic error. A missing `preview_id`

.

By default, `wrangler dev`

uses a local SQLite simulation — safe, isolated, zero real traffic. The moment you add `--remote`

, every KV read and write goes to the actual Cloudflare namespace over the API. If your `wrangler.toml`

only has the `id`

field pointing at your production namespace, those writes land in prod. No warning. No confirmation prompt. Just silent data mutation on the namespace your live users depend on.

The fix is a single extra field:

```
[[kv_namespaces]]
binding = "MY_STORE"
id = "PROD_NAMESPACE_ID_HERE"
preview_id = "DEV_NAMESPACE_ID_HERE"
```

Wrangler automatically routes `--remote`

traffic through `preview_id`

instead of `id`

. Create a separate dev namespace with `wrangler kv namespace create "MY_STORE_dev"`

, drop its ID into `preview_id`

, and your production namespace is untouched. This should probably be in the quickstart docs. It isn't, at least not prominently.

The second thing worth knowing: `--remote`

exposes a behavioral gap that local simulation hides entirely. Local KV is synchronous and in-process — a `put()`

followed by a `get()`

on the same key always returns the fresh value. Remote KV is eventually consistent. I had a rate-limiting worker that looked completely broken under `--remote`

: I'd write a counter, immediately read it back, and get the old value. The worker was correct. The local simulation had been lying to me about how production actually behaves. Switching to `--remote`

(against a dev namespace, not prod) surfaced the real race condition. That's uncomfortable, but it's accurate.

There's also a write-rate ceiling worth knowing before you run any kind of seed script: hit roughly 1,000 writes/minute and you'll start seeing `429 Too Many Requests`

with error code `10013`

. A 70ms sleep between writes keeps you under the limit without dramatically slowing a seed operation down.

I wrote up the full breakdown — including the `wrangler tail`

JSON truncation trap that cost me two hours, a shell script for seeding a dev namespace with representative data, and the exact `cacheTtl: 0`

pattern for honest read behavior — over on dailymanuallab.com.
