Summary
Many modern tools—including Bun and dotenvx—have popularized the use of .env.* files (e.g., .env.production, .env.development) to override values in .env. However, dotenv-vault fully replaces the target environment when pushing a file, causing any variables not in the pushed file to be lost.
A partial override workflow would bring dotenv-vault more in line with the common “base + environment-specific override” pattern.
The Problem
Proposed Solution: Partial Override
- Only override the keys present in
.env.[environment].
- If a key exists in
.env.production, overwrite (or add) it.
- If a key does not exist in
.env.production, preserve its existing value in the vault.
How It Could Work
CLI-Level Merge
On dotenv-vault push production .env.production, the CLI would:
- Pull existing variables from
production.
- Merge them with the local
.env.production (where any duplicates in .env.production override existing values).
- Push the merged result back to
production.
This ensures any variables not declared in .env.production remain unchanged in the vault.
Flags and Options
- A
--merge flag (or similar) to explicitly enable partial overrides.
- A
--all or --base option to push .env across all environments, providing a common starting point for overrides.
Limitations
-
Not Actually Syncing Layered Files
- Pulling from the vault retrieves only the final compiled
.env for a given environment (e.g., production, development). You don’t get separate .env and .env.production files back—just the merged result.
-
Potential for Environments Getting Out of Sync
- Since dotenv-vault doesn’t natively support true layered environments, environments can drift apart over time.
- Example scenario:
- You push
.env (shared base variables).
- You push
.env.production (overriding production-specific values).
- Later, you push
.env again—this fully replaces the environment, wiping out values previously overridden by .env.production.
- This means pushing
.env later does not preserve per-environment overrides, requiring manual tracking of all expected values.
-
dotenv-vault design and use case needs
- In a true layered system, you push
.env once and then independently push per-environment overrides without losing values.
- However, dotenv-vault only stores the final resolved environment, not the separate
.env.* files.
- Unlike Bun and dotenvx, where
.env and .env.production are dynamically merged at runtime, dotenv-vault environments are static snapshots—meaning each push must fully account for all values, not just overrides.
Why This Proposal is Still a Good Compromise
- Implementing true layered environments would likely require major changes to how dotenv-vault stores and manages variables.
- This proposal minimizes destructive behavior by allowing partial overrides, while keeping the existing vault structure intact.
- It still requires some manual tracking when updating environments, but it’s significantly less risky than the current full-replacement behavior.
Potential Impact
-
Infrastructure/Security
- Minimal, as the logic change is entirely CLI-side. The vault would still store only the final merged result.
-
Backward Compatibility
- Could be opt-in (e.g., via a
--merge flag), allowing current full-replacement behavior to remain the default if desired.
Summary
Many modern tools—including Bun and dotenvx—have popularized the use of
.env.*files (e.g.,.env.production,.env.development) to override values in.env. However, dotenv-vault fully replaces the target environment when pushing a file, causing any variables not in the pushed file to be lost.A partial override workflow would bring dotenv-vault more in line with the common “base + environment-specific override” pattern.
The Problem
Loss of Existing Variables
.env.productiondoesn’t contain all necessary variables, pushing it toproductionremoves any keys not listed.Misalignment with
.env.*Patterns.env.productionto override values from.env, not replace them entirely. Dotenv-vault's current behavior breaks this expectation.Proposed Solution: Partial Override
.env.[environment]..env.production, overwrite (or add) it..env.production, preserve its existing value in the vault.How It Could Work
CLI-Level Merge
On
dotenv-vault push production .env.production, the CLI would:production..env.production(where any duplicates in.env.productionoverride existing values).production.This ensures any variables not declared in
.env.productionremain unchanged in the vault.Flags and Options
--mergeflag (or similar) to explicitly enable partial overrides.--allor--baseoption to push.envacross all environments, providing a common starting point for overrides.Limitations
Not Actually Syncing Layered Files
.envfor a given environment (e.g.,production,development). You don’t get separate.envand.env.productionfiles back—just the merged result.Potential for Environments Getting Out of Sync
.env(shared base variables)..env.production(overriding production-specific values)..envagain—this fully replaces the environment, wiping out values previously overridden by.env.production..envlater does not preserve per-environment overrides, requiring manual tracking of all expected values.dotenv-vault design and use case needs
.envonce and then independently push per-environment overrides without losing values..env.*files..envand.env.productionare dynamically merged at runtime, dotenv-vault environments are static snapshots—meaning each push must fully account for all values, not just overrides.Why This Proposal is Still a Good Compromise
Potential Impact
Infrastructure/Security
Backward Compatibility
--mergeflag), allowing current full-replacement behavior to remain the default if desired.