Skip to main content

Environment Overlays

Source file: examples/environment_overrides.hen

What It Demonstrates

  • collection-level scalar defaults
  • named env blocks in the preamble
  • extending those env blocks with per-environment dotenv layers
  • selecting an environment at run time with --env
  • one request body reused across environment-specific IDs and headers

Key Pattern

$ API_ORIGIN = https://lorem-api.com/api
$ CLIENT_ID = hen-cli
$ AUDIENCE = public
$ USER_ID = abc1234

env local
$ API_ORIGIN = https://lorem-api.com/api
$ CLIENT_ID = hen-local
$ AUDIENCE = local
$ USER_ID = local-demo-user

env staging
$ API_ORIGIN = https://lorem-api.com/api
$ AUDIENCE = staging
$ USER_ID = staging-demo-user

This keeps one request body while swapping environment-specific scalar values at execution time.

The same overlay model can also preload dotenv files before those scalar bindings resolve:

dotenv .env

$ API_ORIGIN = env("API_ORIGIN")

env local
dotenv .env.local

env staging
dotenv .env.staging

That pattern keeps one request body while letting each selected environment add its own dotenv layer on top of any shared top-level defaults. Use env(...) for ordinary values like origins, and secret.env(...) only when the loaded value should be masked.

Run It

hen verify ./examples/environment_overrides.hen
hen run ./examples/environment_overrides.hen 0 --env local --non-interactive
hen run ./examples/environment_overrides.hen 0 --env staging --non-interactive

What To Notice

  • CLIENT_ID changes in local without editing the request.
  • USER_ID changes with the selected environment while the request shape stays the same.
  • The default collection values still run with --non-interactive when no environment is selected.
  • The same env ... blocks can now add dotenv directives when the changing inputs live in local files instead of authored scalar overrides.

Related reference: Variables and environments