bowline
Concepts

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.

FileProfile
.envBase environment for the project.
.env.localLocal overrides for the current checkout.
.env.developmentDevelopment profile.
.env.productionProduction 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_URL on your laptop and DB_HOST on a remote host advances both without a conflict.
  • The same key in two files is separate state. API_URL in .env and API_URL in .env.local are 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 export prefixes.
  • 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 .zshrc or .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 status and bowline explain.

On this page