Worker environments have had a complicated past. Service environments are deprecated, and wrangler environments just create separate workers rather than different configs on the same worker.
I wanted preview deployments with separate bindings (staging KV, staging D1, etc). This is the workaround I landed on.
Your root config is production. Add a staging environment below it:
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2025-10-01"
[vars]
ENVIRONMENT = "production"
[env.staging]
name = "my-worker-staging"
[env.staging.vars]
ENVIRONMENT = "staging"
env.staging creates a separate worker called my-worker-staging. Deploy both manually first:
npx wrangler deploy # production
npx wrangler deploy -e staging # staging
Now go to your production worker in the dashboard (my-worker, not staging). Open Settings, enable Workers Builds, connect your repo.
For the production branch, leave the default. It runs npx wrangler deploy.
For non-production branches, set the build command to:
npx wrangler versions upload -e staging
Don’t configure anything on the staging worker. All the build config lives on the production worker.
Push to main, production deploys. Push to any other branch, staging gets a new version with a preview URL.