Env sync
How Bowline imports, encrypts, merges by key, and rematerializes your project .env files so the same environment follows your code to every machine and agent.
Env sync is part of Bowline's default workspace contract. Your project .env
files travel with the code. Bowline imports, encrypts, merges them per key, and
rewrites them where your tools expect, so cd ~/Code/acme && pnpm dev runs the
same on every authorized machine and agent without you copying secrets by hand.
Bowline tracks this as a project's Project Env State: the per-key environment values it has imported, encrypted, synced, and rematerialized. Env sync follows the rest of the workspace model; it is not a separate product you configure.
What env sync covers
Env sync imports your Workspace-Owned Env Files: the .env* files inside the
accepted workspace root, normally ~/Code. Bowline detects them through the
same scanner and path policy that classify the
rest of your tree, so any .env* file that is source-like project state is in
scope.
The accepted workspace root is the boundary, not the repo or package root. A
.env.local deep inside a monorepo package syncs the same way as one at a
project root.
| File | Profile |
|---|---|
.env | Base environment for the project. |
.env.local | Local overrides for the current checkout. |
.env.development | Development profile. |
.env.production | Production profile. |
.env.* | Any other profile suffix, for example .env.test. |
Bowline excludes .env* files under generated, dependency, cache, and
explicitly local-only paths. A .env inside node_modules is never imported.
How env state syncs
Bowline does not sync a .env file as one opaque blob. It parses each file into
encrypted per-key records, which is what makes env changes merge safely.
- Each key is stored as its own encrypted record. Values never reach the control plane and never appear in logs, events, status, or command output.
- Changes merge by key. Editing
API_URLon your laptop andDB_HOSTon a remote host advances both without a conflict. - The same key in two files is separate state.
API_URLin.envandAPI_URLin.env.localare distinct records that sync independently.
When two machines change the same key in the same file two different ways, Bowline raises a per-key conflict and preserves both values outside the live file rather than overwriting one. See Conflicts.
Rematerialization
On every authorized machine and agent, Bowline rewrites your env back to the
files your tools read, preserving the source filename and profile identity. A
.env.local stays .env.local; it is never flattened into one file or renamed.
Bowline writes rematerialized env files with owner-only permissions and makes a best-effort attempt to preserve the original layout:
- Comments, blank lines, and key order.
- Quoting style and
exportprefixes. - Lines it cannot parse stay opaque and round-trip unchanged, so nothing meaningful is silently dropped.
Run bowline explain .env.local to see a file's Project Env State and
source-file profile identity, or bowline status for a project overview.
Inheritance and restrictions
By default, every authorized machine, workspace, and agent inherits a project's env. That default is what makes a freshly synced project runnable without granting secrets again.
Restricting a record is an explicit opt-in policy decision, not the default. Until you restrict it, an agent lease working in a project receives the same env your machine would, through a scoped provider rather than by writing secrets into prompt text.
What env sync does not import
Env sync covers env that belongs to the workspace, not env that belongs to your machine. Env outside the accepted workspace root is not imported unless you explicitly import it. That includes:
- Shell configuration such as
.zshrcor.bashrc. - Home-directory environment and profile files.
- Machine-global secrets stored outside
~/Code.
Important
Project Env State reports sync, access, profile, and materialization state. It
does not check whether your project runtime has every variable it needs. If
pnpm dev fails because STRIPE_SECRET was never in a .env file, that is a
variable the project must add, not a sync failure Bowline reports.
Env sync clears one bar: cd ~/Code/foo && pnpm dev works everywhere your
workspace does, because the env that lived next to the code came with it.
Next steps
- Setup recipes: prepare a freshly synced project
to run with
.bowlinesetup. - Path policy: control which files sync with
.bowlineignore. - Conflicts: how Bowline preserves both sides when a key diverges.
- CLI commands: inspect env with
bowline statusandbowline explain.