# TL;DR
Local dev and production bind different resources by default: local mode emulates KV, D1, R2, and Durable Objects against local storage (or empty state), while the deployed worker hits your real remote resources. Reproduce the gap deliberately: run wrangler dev --remote to test against the real production bindings, and compare IDs, binding names, and persisted data between the two modes before blaming the code.

```text
workerd: local vs deployed parity broken, binding behaves differently
```

1. Confirm the binding names match between your wrangler.toml and the deployed config:

```
wrangler deploy --dry-run
```

Expected: the dry run prints the same binding names you see in the wrangler dev startup banner. A mismatch (typo, env override) explains most parity breaks.

2. Compare local vs remote directly by switching one variable at a time. First, run local mode and note the behavior:

```
wrangler dev
```

Expected: baseline behavior with emulated local bindings.

3. Then run the same worker against real remote resources:

```
wrangler dev --remote
```

Expected: behavior now matches the deployed worker. If the bug appears only in --remote mode, the difference is the resource contents or permissions, not your code. If it appears in neither, the difference may be env (production vs preview) or routes.

4. Check the remote resources themselves. For KV, list keys; for D1, run the same query you run in code against the remote database; for R2, list the bucket. Compare against what the local emulator seeded.

Expected: the remote resource has the rows, keys, or objects your code expects. Missing data locally is expected (emulator starts empty unless seeded); missing data remotely is a migration or seed gap.

5. If the binding exists locally but is missing remotely, verify it was actually attached at deploy time: check the Cloudflare dashboard worker bindings page or redeploy and read the deploy output for binding lines.

Expected: every binding in the toml appears in the deployed worker. Bindings added to the toml after the last deploy are the classic cause.

## Use this when
- Code works with wrangler dev but fails after wrangler deploy, with the failure pointing at env.SOME_BINDING.
- Deployed worker works but local dev throws on a binding.
- A Durable Object, D1 table, or KV key exists in one environment and not the other.

## Not for this skill when
- The behavior differs for reasons unrelated to bindings (different request paths, missing routes, cron triggers). That is a config/route issue.
- Both environments fail identically. Then it is a code bug, not parity.
- Local dev fails to start at all. Fix the startup error first.

## Variant phrasings
- wrangler dev binding works locally but not in production
- KV works in dev but not after deploy
- durable object different behavior local vs deployed
- workerd local emulation vs production binding mismatch

## Why it happens
wrangler dev local mode deliberately does not touch your production data URIs it spins up local emulations of KV, D1, R2, queues, and Durable Objects backed by a local directory. That protects production but means local state is a separate, usually empty, world. The deployed worker uses the real resource IDs from your account. Parity breaks when the two worlds diverge: unseeded local emulators, a table migrated remotely but not locally, a binding attached in one env block but not another, or code that assumes data the emulator never had.

## Edge cases
- Preview environments (wrangler dev --remote with a preview, or *.workers.dev) can bind preview-specific resource IDs. A route pointing at production while you test preview reads the wrong dataset.
- Durable Object IDs are not portable: an ID created in local emulation will not resolve remotely. Do not persist local DO IDs into production data.
- Secrets are never synced to local dev automatically; set them with wrangler secret put and expect local dev to need its own copy via .dev.vars for local testing.
- --persist-to changes where local emulator data lives. Two developers (or an agent and a human) with different persist dirs each see different local state and both call it "local dev behavior".

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_MEbiW98Fu5PvOWTCpkg6Ww
