Use overlays to change only what differs between local, preview, and production
Keep one base config, layer environment-specific overrides with , and let Devflare resolve preview or production details only in the commands that actually need them.
Devflare environments are an overlay system, not a second copy of the whole config file. The base config should hold the stable project story, and should only override the parts that genuinely differ by environment.
- Best for
- Projects that need different bindings or runtime behavior in preview and production
- Merge model
- Base config first, then , then preview materialization when relevant
- Main habit
- Repeat only the keys that actually differ by environment
Keep one base config and let the overlay change only the deltas
The main config should describe the stable project: the worker name, the usual file surfaces, and the bindings or defaults that exist regardless of environment. is where you change only the parts that diverge for preview, production, or another named lane.
The overlay model feels more predictable than copying whole config files around. The shared story stays in one place, while the environment-specific differences stay small enough to review accurately.
A smaller overlay is usually a better overlay
If an environment block starts to repeat most of the base config, that is usually a sign the base config should be refactored instead of duplicated.
Use `config.env` for targeted overrides instead of a second full config
Know what environment overlays are actually allowed to change
This is why is more than a raw Wrangler mirror. It can change the Devflare-owned parts of the project too, as long as those differences are still part of the same package story.
| Override lane | Typical reason to change it |
|---|---|
| , compatibility settings | The environment truly needs a different runtime identity or compatibility posture. |
| , , | Preview or production uses different surfaces, resources, or schedules. |
| , | Runtime strings or secret-binding declarations differ by environment. |
| , , , | Deployment routing, static assets, CPU limits, or observability should differ by lane. |
| , , | The build host or the passthrough escape hatch needs environment-specific behavior. |
Environment overrides: arrays replace, objects deep-merge, primitives replace
Overlays compose onto the base config with three rules: object-shaped values are deep-merged key by key, primitive values (strings, numbers, booleans) are replaced wholesale, and array-shaped values are replaced wholesale (they do not append). Reading an environment block as an override of the base — not as an addition to it — keeps these rules predictable.
The replace-arrays rule is the one most likely to surprise someone arriving from a config system that appended arrays. If a base config sets and the overlay sets , the overlay’s array becomes the resolved value; the base array is not concatenated. The same applies to and to nested arrays like .
| Field shape | Merge rule | Example |
|---|---|---|
| (array) | Replace | Base + overlay resolves to **only** the preview entry. |
| (array) | Replace | Base + overlay resolves to **only** the v2 entry. To preserve history, restate the prior migrations in the overlay. |
| (array under nested object) | Replace at the array level (the parent object is still deep-merged) | Base + overlay resolves to . Other keys on deep-merge as usual. |
| (object) | Deep-merge | Adding in an overlay extends the base map; existing namespaces survive unless the overlay names the same key. |
| , (primitive) | Replace | The overlay value wins when present; otherwise the base value stays. |
Arrays replace, they do not append
If you only want to add one extra route, one extra cron, or one extra migration to the base, the overlay must restate the base entries alongside the new one. An overlay that lists only the new entry will silently drop the base entries from the resolved config.
Choose the environment where it matters, and let explicit deploy targets do the rest
- 1
Use commands like or when you want to inspect or compile one named environment intentionally.
- 2
Let explicit preview deploys target the preview environment instead of also layering on an unrelated decision.
- 3
Let explicit production deploys stay pinned to production so the deployment target is never ambiguous.
- 4
Keep preview-only resource naming and preview lifecycle behavior inside the preview lane instead of leaking it into the base config.
Environment choice and deploy target are related, but not identical
chooses a config overlay for commands that resolve config environments. Explicit preview and production deploy flags choose the deployment destination itself.
Keep , , and in separate jobs
- Use and for config-time inputs. Devflare reads those files itself from the config directory upward, with closer files winning and overriding in the same directory.
- Use for values that should compile into Worker-facing output, including nested typed values produced by descriptors.
- Use to declare runtime secret binding names, not to store those secret values in config. Today that is mostly schema and type metadata: the schema accepts , but generated env typing still treats declared secrets as present and Devflare does not currently turn that flag into a separate deploy-time guarantee.
- Use to document config-time inputs for the team instead of leaving those values to memory or chat scrollback.
Do not let every string become an environment variable by reflex
Stable infrastructure names and intentional runtime strings usually belong in authored config. Save secrets for the values that are actually secret.
Previous
Generated types
turns config, discovered Durable Objects, named entrypoints, and cross-worker references into one generated TypeScript contract instead of a pile of hand-maintained env guesswork.
Next
Typed env vars
Use descriptors inside , parse or default them in config, and read the resulting typed values at runtime with .