Environment Compositionο
Compose environments from multiple files to separate shared baseline settings from environment-specific overrides β without repeating yourself.
Why compose?ο
A single environment file works fine for one environment. Once you have several, common settings (shared variables, security config, audit policy) get duplicated across each file. If a shared value changes, every file must be updated in sync.
Composition solves this:
environments/
βββ base.yaml β variables, secrets, audit, and security policy every env shares
βββ eu-region.yaml β region-specific settings (shared across EU deployments)
βββ prd.yaml β production-specific overrides (counts, images, feature flags)
# deploy-prd.yaml
spec:
environments:
- environments/base.yaml
- environments/eu-region.yaml
- environments/prd.yaml # last file wins on any key conflict
strata merges all listed files β left to right β into a single effective environment before applying overrides to the workspace.
Merge semanticsο
Each spec section follows a documented merge strategy. There are no surprises.
Section |
Strategy |
Notes |
|---|---|---|
|
Last-wins by |
|
|
Last-wins by |
Same pattern as variables |
|
Last-wins by |
Each flag merged independently β |
|
Shallow |
Keys not present in later files are preserved from earlier files |
|
Shallow |
Same as |
|
Last-wins (wholesale) |
The last file that declares |
|
Last-wins (wholesale) |
Same as |
|
Last-wins by |
|
|
Last-wins by |
Matches the override uniqueness constraint |
|
Last-wins by |
β |
|
Last-wins by |
Pin different branches per env |
|
Shallow |
β |
|
Append (dedup by |
Includes are additive |
|
Append (dedup by output |
Output files are additive |
Single-file deployments are unaffected. The merge runs but produces an identical result.
Example: base + prdο
environments/base.yamlο
apiVersion: strata.huybrechts.xyz/v1
kind: environment
meta:
name: base
labels:
version: "1.0.0"
spec:
variables:
- key: APP_PORT
store: constant
value: "8080"
- key: LOG_LEVEL
store: constant
value: info
secrets:
- key: TERRAFORM_API_TOKEN
store: bitwarden
value: <shared-tf-token-id>
features:
- key: enable_metrics
store: constant
value: true
- key: enable_debug
store: constant
value: false
audit:
policy:
events:
deploy_audit: true
policy_violation: true
environments/prd.yamlο
apiVersion: strata.huybrechts.xyz/v1
kind: environment
meta:
name: production
labels:
version: "1.0.0"
spec:
variables:
- key: LOG_LEVEL # overrides base
store: constant
value: warning
- key: REPLICA_COUNT # prd-only
store: constant
value: "5"
secrets:
- key: DB_PASSWORD # prd-only
store: bitwarden
value: <prd-db-id>
features:
- key: enable_debug # overrides base: keeps enable_metrics=true
store: constant
value: false
overrides:
resources:
- resource: manager
count: 3
properties:
ha_enabled: true
Effective resultο
Key |
Value |
From |
|---|---|---|
|
|
base.yaml |
|
|
prd.yaml |
|
|
prd.yaml |
|
(bitwarden) |
base.yaml |
|
(bitwarden) |
prd.yaml |
|
|
base.yaml |
|
|
prd.yaml |
|
|
prd.yaml |
|
|
prd.yaml |
Tracing value origins with --traceο
When debugging a deployment, use --trace to see which file contributed each value:
strata values list -f deploy/deploy-prd.yaml --trace
Console output:
VARIABLES
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
KEY STORE VALUE / STATUS SOURCE
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
APP_PORT constant 8080 environments/base.yaml
LOG_LEVEL constant warning environments/prd.yaml
REPLICA_COUNT constant 5 environments/prd.yaml
SECRETS
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
KEY STORE VALUE / STATUS SOURCE
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
TERRAFORM_API_TOKEN bitwarden abc***** environments/base.yaml
DB_PASSWORD bitwarden xyz***** environments/prd.yaml
Merge order: environments/base.yaml β environments/prd.yaml
Combine with --show-store for full store reference details:
strata values list -f deploy/deploy-prd.yaml --trace --show-store
JSON output with --traceο
strata values list -f deploy/deploy-prd.yaml --trace --output json
Each row gains source (the winning file) and the top-level response includes merge_order:
{
"file": "deploy/deploy-prd.yaml",
"merge_order": ["environments/base.yaml", "environments/prd.yaml"],
"variables": [
{
"key": "LOG_LEVEL",
"store": "constant",
"store_ref": "warning",
"display": "warning",
"ok": true,
"note": "",
"source": "environments/prd.yaml"
}
]
}
Common patternsο
Base + region + environmentο
# deploy-us-prd.yaml
spec:
environments:
- environments/base.yaml
- environments/us-east.yaml # region-specific networking, KMS keys
- environments/prd.yaml # production sizing and feature flags
Tenant overlaysο
# deploy-acme-prd.yaml
spec:
environments:
- environments/base.yaml
- environments/prd.yaml
- tenants/acme/env-overrides.yaml # tenant-specific custom metadata and secrets
Merge validationο
strata validates each file individually before merging. If any file fails schema validation, the merge is aborted and the error points to the specific file.
After merging, the resulting model is re-validated. Duplicate keys within a single file are still rejected (enforced by model validators) β the last-wins rule only applies across files.
See alsoο
Environment configuration reference β full schema and field reference
Deployment configuration reference β how to declare environment lists
Cookbook: Add a New Environment β step-by-step for adding a second env
strata values listβ resolve and inspect values