Environments vs Branches
Two questions come up the moment a flow leaves your laptop:
- Where should it run — against the sandbox API or the live one?
- Which version of the definition should run — the one in production, or the edit I am still reviewing?
Zenvara answers these with two independent mechanisms that are easy to confuse and important to keep apart. Environments answer where. Branches answer which version. They never overlap, and reaching for the wrong one is the single most common source of dev→prod confusion.
The three nouns
Section titled “The three nouns”| Noun | Axis | Answers | Priced? |
|---|---|---|---|
| Connection | the atom | which single external service — one host, one credential | Yes — the only counted unit |
| Environment | WHERE | which set of services a run talks to | No |
| Branch | WHEN / version | which version of the definitions runs | No |
A connection is the atomic unit: one database, one SFTP, one API, with its own credential. It is also the only axis Zenvara meters — environments and branches are free structure you layer on top. That framing matters: you never create a second connection just to get a second environment, and you never split a flow across branches to reach two systems.
Environment = WHERE
Section titled “Environment = WHERE”An environment maps a flow’s logical aliases (db, sftp, pim) onto concrete connections. The same product-sync flow runs against dev and prod with no YAML edits — the environment chosen at run time decides which real services db and sftp resolve to.
An environment carries a kind: — production, staging, development, or sandbox. kind is a guard tier, not a copy of your infrastructure. It drives real behaviour: it gates ephemeral inline runs, feeds kind-aware authorization, and powers cross-environment validation (a development environment cannot pull from a production connection). It does not imply “make a second copy of everything” — a starter setup is one environment mapping a handful of aliases, extended later by adding aliases, not by cloning.
Branch = WHEN (which version)
Section titled “Branch = WHEN (which version)”A branch is a staging area for definition changes. With git-backed versioning on, you stage an edit on a branch, review the diff, and promote it into production storage. Production flows are untouched until you promote. The URL carries the branch as a path segment: /api/v1/main/flows/... runs the production version; /api/v1/edi-rework/flows/... runs the version staged on the edi-rework branch.
A branch answers which version of the definitions runs. It says nothing about which systems those definitions talk to — that is still the environment’s job.
Why the two axes never collide
Section titled “Why the two axes never collide”The axes are orthogonal by construction:
graph TD
subgraph WHEN["Branch — which version"]
main["main (production)"]
edi["edi-rework (staged edit)"]
end
subgraph WHERE["Environment — which systems"]
dev["dev → sandbox services"]
prod["prod → live services"]
end
main -. run against .-> dev
main -. run against .-> prod
edi -. run against .-> dev
edi -. run against .-> prod
Any branch can run against any environment. You can run the production main branch against your dev environment (a safe rehearsal of the live definition against sandbox systems), or the staged edi-rework branch against prod (a final check of the new definition against live systems, before promotion). Four combinations, two knobs — because version and target are genuinely independent decisions.
They intersect in exactly one place: storage. A branch is a git overlay over the same connection and environment definitions, so an edit staged on a branch can change an environment’s alias map for that branch only, until promoted. That is the whole overlap — a versioning overlay over the config, not a second routing dimension.
When do I create a second environment?
Section titled “When do I create a second environment?”When you have a second deployment target — a distinct set of real systems you want the same flows to run against. Sandbox vs live. A per-customer production estate. A read-only audit region.
Never to get a second connection. If the only difference is one more database or one more API, that is a new connection added to an existing environment’s alias map — not a new environment. The wizard scaffolds one shared starter environment for exactly this reason: most setups need one environment per deployment target, not one per connection.
Why does on= take an environment, not a connection?
Section titled “Why does on= take an environment, not a connection?”When you run a flow you select the environment — on=prod, --env prod, or the branch/env combination — never a connection directly. That is deliberate (ZEN-1446):
- Aliases keep flows portable. A flow names
db, notwarehouse-prod. Binding to a connection at run time would hard-wire the flow to one host and defeat the whole point of the alias. - The guard tier stays in the loop. Routing through the environment is what lets
kindcross-validation catch a dev run pointed at a production connection. A direct connection binding would bypass that guard. - You can still pin one connection when you must.
on=<env>/<alias>selects a specific alias inside a declared environment — precise without re-coupling. If an environment binds two connections of the same connector type and you don’t qualify, you get a structuredambiguousBindingerror listing the aliases.
So on= is environment-scoped on purpose: it keeps the flow portable and keeps the guard tier enforceable.
Don’t confuse the two loops
Section titled “Don’t confuse the two loops”Task → mechanism
Section titled “Task → mechanism”| I want to… | Reach for | Not |
|---|---|---|
| Run the same flow against sandbox, then live | An environment per target; on=<env> at run time | A branch per target |
| Add one more database to a running setup | A new connection in the existing environment’s alias map | A new environment |
| Edit a flow and review before it goes live | A branch: stage → diff → promote | Editing production directly |
| Rehearse the live definition against sandbox | Production branch × dev environment | A copy of the flow |
| Keep a permanent test system | An environment (kind: development/sandbox) | A long-lived branch |
| Pin one step to a specific connection | on=<env>/<alias> | Binding a connection by name |
Where to go next
Section titled “Where to go next”- The mechanics of both loops end-to-end, with a worked example: From dev to prod.
- The environment reference: Environments.
- Enabling branch staging: Git-backed Versioning.