A tool to manage multiple .env files by combining reusable fragments into artifacts.
# System-wide (user install, recommended)
pip install --user .
# or
uv pip install --user .This installs the managenv command to ~/.local/bin/. Make sure ~/.local/bin is on your PATH.
Alternatively, install system-wide (requires root) or run directly with python managenv.py.
1. Create fragments in fragments/:
# fragments/backend.env
API_HOST=localhost
API_PORT=8000
# fragments/frontend.env
VITE_API_URL=http://localhost:80002. Configure managenv.json:
{
"fragments": {
"backend": {"uri": "file://fragments/backend.env"},
"frontend": {"uri": "file://fragments/frontend.env"}
},
"artifacts": {
"dev.env": ["backend", "frontend"]
}
}3. Generate:
managenv
# Generated: artifacts/dev.envmanagenvGenerates all artifacts defined in the config.
managenv -a dev.envGenerates only the specified artifact.
Multiple artifacts (repeatable flag or comma-separated):
managenv -a dev.env -a prod.env
managenv dev.env,prod.envmanagenv --dry-runShows what would be generated without writing files.
managenv --listDisplays all fragments and artifacts defined in the config.
managenv --validateChecks for missing files and undefined fragment references.
managenv --diff dev.envShows what would change compared to existing artifact files.
Multiple artifacts:
managenv --diff dev.env --diff prod.env
managenv --diff dev.env,prod.envmanagenv --add dev.env backend,frontendAdds a new artifact definition to the config. Optionally specify a custom deployment path:
managenv --add prod.env backend.prod --uri file:///var/www/app/.envUse --deploy to generate the artifact immediately after adding:
managenv --add dev.env backend,frontend --deploymanagenv --delete dev.envRemoves an artifact definition from the config.
managenv --import existing.env --prefix backendImports an existing .env file as a new fragment. Auto-creates config if needed.
managenv --initCreates a new managenv-config.json with default structure.
Auto-install to rc file:
# Install to ~/.bashrc
managenv --scripts bash --apply
# Install to ~/.zshrc
managenv --scripts zsh --applyRunning --apply again is safe — it detects if completions are already installed.
Save to file (manual):
# Generate bash completion
managenv --scripts bash > ~/.managenv-completion.bash
echo 'source ~/.managenv-completion.bash' >> ~/.bashrc
# Generate zsh completion
managenv --scripts zsh > ~/.managenv-completion.zsh
echo 'source ~/.managenv-completion.zsh' >> ~/.zshrcLoad directly in current shell:
# Bash
source <(./managenv.py --scripts bash)
# Zsh
source <(./managenv.py --scripts zsh)Provides intelligent completion for artifact names, fragment names, and flags.
managenv -c /path/to/config.jsonUses a custom config file. The base directory (used to resolve relative paths) is always the directory containing the config file.
Default config location (searched in order):
- Path specified with
-c/--configflag managenv.jsonin script directory (if exists)managenv.jsonin current working directory
Fragments are small .env snippets that can be combined. Each fragment is defined with a URI.
Config:
{
"fragments": {
"database": {"uri": "file://fragments/database.env"},
"cache": {"uri": "file://fragments/cache.env"}
}
}Fragment file (fragments/database.env):
DB_HOST=localhost
DB_PORT=5432
DB_NAME=myappArtifacts are the generated output files. They combine one or more fragments.
Brief format (array of fragment aliases):
{
"artifacts": {
"dev.env": ["database", "cache"]
}
}This saves to artifacts/dev.env by default.
Full format (with custom deployment path):
{
"artifacts": {
"dev.env": {
"fragments": ["database", "cache"],
"deployment": "file:///home/user/project/.env"
}
}
}This saves to the specified absolute path.
Use dot notation to create inheritance chains. When you reference database.prod, it automatically includes database first, then applies database.prod overrides.
Config:
{
"fragments": {
"database": {"uri": "file://fragments/database.env"},
"database.prod": {"uri": "file://fragments/database.prod.env"}
},
"artifacts": {
"production.env": ["database.prod"]
}
}Fragments:
# fragments/database.env
DB_HOST=localhost
DB_PORT=5432
# fragments/database.prod.env
DB_HOST=prod.rds.amazonaws.comResult (artifacts/production.env):
DB_HOST=prod.rds.amazonaws.com
DB_PORT=5432The database.prod reference automatically includes database first, then overrides DB_HOST.
Fragments can be loaded from various sources.
Relative path (both formats work):
{"uri": "fragments/backend.env"}
{"uri": "file://fragments/backend.env"}Absolute path:
{"uri": "/etc/shared/common.env"}
{"uri": "file:///etc/shared/common.env"}URL (read-only):
{"uri": "https://config.example.com/base.env"}URL content is cached during each run.
Control where artifacts are saved using the deployment property.
Default (saves to artifacts/ folder):
{
"artifacts": {
"dev.env": ["backend", "frontend"]
}
}Saves to: artifacts/dev.env
Relative path:
{
"artifacts": {
"dev.env": {
"fragments": ["backend"],
"deployment": "file://output/dev.env"
}
}
}Saves to: output/dev.env (relative to config)
Absolute path:
{
"artifacts": {
"production.env": {
"fragments": ["backend.prod"],
"deployment": "file:///var/www/app/.env"
}
}
}Saves to: /var/www/app/.env
Deploy artifacts to remote servers using ssh:// or rsync:// URIs. The tool uses your existing SSH and rsync configuration (.ssh/config, keys, etc.).
SSH deployment:
{
"artifacts": {
"production.env": {
"fragments": ["backend.prod"],
"deployment": "ssh://prod-server/var/www/app/.env"
}
}
}Uses scp to copy the file to the remote server.
Rsync deployment:
{
"artifacts": {
"staging.env": {
"fragments": ["backend.staging"],
"deployment": "rsync://staging/home/deploy/.env"
}
}
}Uses rsync -az to sync the file to the remote server.
URI format:
| URI | Host | Remote Path |
|---|---|---|
ssh://myserver/var/www/.env |
myserver | /var/www/.env |
ssh://user@host/path/.env |
user@host | /path/.env |
rsync://backup/data/.env |
backup | /data/.env |
Error handling:
By default, remote deployment failures cause the tool to exit immediately. Set exit_on_fail to false to continue with other artifacts:
{
"artifacts": {
"staging.env": {
"fragments": ["backend.staging"],
"deployment": "rsync://staging/home/deploy/.env",
"exit_on_fail": false
}
}
}Note: The artifact is always saved locally to artifacts/<name> first, then deployed to the remote location.
Convert existing .env files into fragments.
managenv --import /path/to/existing.env --prefix backendThis:
- Reads the existing file
- Removes variables already defined in parent fragments (if any)
- Saves unique variables to
fragments/backend.env - Adds the fragment to your config
With inheritance:
# First import the base
managenv --import base.env --prefix database
# Then import prod (removes inherited vars automatically)
managenv --import prod.env --prefix database.prodAll relative paths in the config are resolved from the config file's directory (the base directory).
project/
├── managenv.json # Configuration (base directory = project/)
├── fragments/ # Your .env fragments (relative to config)
│ ├── backend.env
│ ├── backend.prod.env
│ └── frontend.env
├── artifacts/ # Generated .env files (default location)
│ ├── dev.env
│ └── production.env
└── history/ # Automatic backups before overwrite
Example with custom config location:
/home/user/configs/app.json # Config file (base directory = /home/user/configs/)
/home/user/configs/fragments/ # Fragments resolved from config directory
/home/user/configs/artifacts/ # Artifacts resolved from config directory
Config (managenv-config.json):
{
"fragments": {
"backend": {"uri": "file://fragments/backend.env"},
"backend.prod": {"uri": "file://fragments/backend.prod.env"},
"frontend": {"uri": "file://fragments/frontend.env"},
"frontend.prod": {"uri": "file://fragments/frontend.prod.env"}
},
"artifacts": {
"dev.env": ["backend", "frontend"],
"production.env": {
"fragments": ["backend.prod", "frontend.prod"],
"deployment": "file:///var/www/app/.env"
}
}
}Generate:
managenv
# Generated: artifacts/dev.env
# Generated: /var/www/app/.env