Environments
An environment is a named set of aliases pointing at connections. A flow asks for an alias; the environment decides which real connection that resolves to today.
Anatomy of an environment
Section titled “Anatomy of an environment”Environments live under config/environments/{name}/definition.yaml:
kind: productiondescription: "Production environment for the nightly archive pipeline."
connections: sftp: archive-sftp http: zenvara-defaultThree fields:
kind:— restriction level used for cross-validation (see Cross-environment validation).extends:— optional list of parent environments composed in order; the child can override individual aliases. Single-level only — no transitive chains.connections:— the alias map. Each entry binds a short alias (the name a flow uses) to a connection name (a file underconfig/connections/).
How a flow uses an alias
Section titled “How a flow uses an alias”A flow references the alias, never the connection name directly:
- $deploy: create: sftp.file on: sftp # the alias from the environment with: Path: "/htdocs/index.html" Input: "${build.dist-path}/index.html"Same flow, different environments — dev maps sftp to a sandbox SFTP, prod maps it to the live one. (on: replaced the older connection: keyword.)
One flow, many targets
Section titled “One flow, many targets”A single product-sync flow runs against dev, staging, and prod without YAML edits. Three environment files, one flow, three behaviours:
kind: developmentconnections: { db: warehouse-dev, sftp: drop-zone-dev }
# config/environments/staging/definition.yamlkind: stagingconnections: { db: warehouse-staging, sftp: drop-zone-staging }
# config/environments/prod/definition.yamlkind: productionconnections: { db: warehouse-prod, sftp: drop-zone-prod }zen invoke-flow product-sync --env devzen invoke-flow product-sync --env stagingzen invoke-flow product-sync --env prodThe flow is the same file in storage; the environment chosen at invocation routes it to a different set of services.
Cross-environment validation
Section titled “Cross-environment validation”Validation is level-based, not symmetric: a higher-kind environment may use lower-kind connections (a production env can read from a staging connection — useful for read-only audit scrapes), but a lower-kind env cannot pull from a higher-kind one (a staging env asking for a production connection fails validation). Default levels:
| Kind | Level |
|---|---|
production | 4 |
staging | 3 |
development | 2 |
sandbox | 1 |
This is a guard against the classic “ran dev flow against prod DB” mistake. Two opt-outs: omit kind: from the connection (validation only triggers when both sides declare a kind), or set EnvironmentKinds.RequireKind: false (the default) so untyped connections aren’t forced into a tier.
Bare connection bypass
Section titled “Bare connection bypass”Sometimes a flow needs a specific connection by name regardless of environment — an audit pipeline that always goes to the same audit DB is the canonical case:
using: connections: audit: audit-postgres-prod # always this connection, regardless of envInside the flow, on: audit resolves to audit-postgres-prod no matter which environment runs it. Use this sparingly — it deliberately breaks portability. The using: block accepts both shapes together: the operator list (using: [zenvara/http]) and this connection-bypass map are independent.