CLI Commands¶
For library integration, see the separate Python API reference.
CLI Commands¶
load¶
Load and export variables for shell integration (primary usage).
Options:
-f, --file PATH- File to load (default: auto-detect by load order)-o, --format FORMAT- Output format: bash, zsh, fish, powershell, json (default: bash)--load-order ORDER- Promote comma-separated inputs (fuse,fuse-local,env); omitted inputs retain their default relative order--override- Override existing environment variables (default)--no-override- Preserve existing environment variables--var, -V KEY=VALUE- Compilation variable (e.g.,--var ENV=prod)--restrict-imports- Confine imports to the source file's parent directory--age-identity PATH- Age identity file; repeatable and replacesDOTENV_FUSION_AGE_IDENTITY--walk- Search parent directories if not found locally (default: 1 level, configure withDOTENV_FUSION_WALK_DEPTH)--walk-up N- Search up to N parent directories (implies--walk)-v, --verbose- Verbose mode:-v(logic and names),-vv(values with secrets masked)-d, --debug- Show resolved values with secrets and derived values masked-t, --typed- Show values with types, with secrets and derived values masked
Examples:
# Basic usage
eval "$(dotenv-fusion load)"
# Production environment
eval "$(dotenv-fusion load -f .env.production)"
# Fish shell
eval (dotenv-fusion load -o fish)
# PowerShell
dotenv-fusion load -o powershell | Invoke-Expression
# JSON output
dotenv-fusion load -o json
# Preserve existing environment variables
eval "$(dotenv-fusion load --no-override)"
# Prefer .env, then keep the remaining default fallbacks
eval "$(dotenv-fusion load --load-order=env)"
# With compilation variables
eval "$(dotenv-fusion load --var ENV=prod --var REGION=eu)"
# Search parent directories
eval "$(dotenv-fusion load --walk)"
eval "$(dotenv-fusion load --walk-up 3)"
# Debug mode (secret values remain masked)
dotenv-fusion load --debug
# Verbose mode
dotenv-fusion load -v
dotenv-fusion load -vv
The default load order is fuse,fuse-local,env. --load-order and DOTENV_FUSION_LOAD_ORDER may provide a partial order: listed inputs are promoted, while omitted inputs retain their default relative order. Thus --load-order=env expands to env,fuse,fuse-local. Duplicate and unknown items are errors. An explicit -f/--file bypasses automatic ordering.
DOTENV_FUSION_EXISTING_ENV accepts override or no-override for load, exec, and fuse --load. Explicit --override and --no-override take precedence; without either setting, file values override existing variables.
check¶
Validate a .env or .env-fuse file without exporting variables and without writing compiled output.
Options:
-f, --file PATH- File to check (default: auto-detect .env or .env-fuse)--var, -V KEY=VALUE- Compilation variable (e.g.,--var ENV=prod)--restrict-imports- Confine imports to the source file's parent directory--age-identity PATH- Age identity file; repeatable and replacesDOTENV_FUSION_AGE_IDENTITY--no-resolve-sources- Validate source declarations without contacting secret backends--walk- Search parent directories if not found locally (default: 1 level, configure withDOTENV_FUSION_WALK_DEPTH)--walk-up N- Search up to N parent directories (implies--walk)-v, --verbose- Verbose mode:-v(logic and names),-vv(values with secrets masked)
Checks:
- Imports resolve correctly.
- Conditional blocks are balanced.
- Required variables are present or available in the environment.
- Type conversion succeeds.
- Validation regexes pass.
- Variable names are valid for shell export.
- Secret sources resolve and their selected values pass type and regex validation.
- Unknown directives, malformed active lines, circular imports, and lexical ordering fallbacks are reported as warnings. Under
#@mode strict=true, they are errors.
Examples:
dotenv-fusion check
dotenv-fusion check -f .env-fuse --var ENV=prod --var REGION=eu
dotenv-fusion check -f .env-fuse --no-resolve-sources
dotenv-fusion check --walk-up 3
With --no-resolve-sources, check validates source URI syntax, supported backends, option combinations, dependencies, and cycles without checking store access, selectors, or source-dependent values.
Successful output includes the number of collected warnings. Warning details are written to stderr; the library itself only stores them in loader.warnings.
exec¶
Resolve the configuration and secret sources, then run a command directly without generating shell exports.
Options:
-f, --file PATH- File to load (default: auto-detect .env or .env-fuse)--override- Replace variables already present in the parent environment (default)--no-override- Preserve variables already present in the parent environment--var, -V KEY=VALUE- Compilation variable for imports and conditions--restrict-imports- Confine imports to the source file's parent directory--age-identity PATH- Age identity file; repeatable and replacesDOTENV_FUSION_AGE_IDENTITY--walk,--walk-up N- Search parent directories-v, --verbose- Show loading logic and masked variable information
dotenv-fusion exec -- application --serve
dotenv-fusion exec -f .env-fuse --age-identity ~/.config/age/keys.txt -- application
Arguments are passed as an argv without shell interpretation. The child exit code is preserved. File values replace existing environment variables by default. With --no-override, a parent value wins and also prevents its backend from being contacted.
exec returns 127 when the command is not found, 126 when it cannot be executed, and otherwise preserves the child process exit code.
See Get Started with age for the age://store/...#selector contract.
migrate¶
Run an explicit migration family. A subcommand is required; the former flat dotenv-fusion migrate --secret ... form is not accepted.
migrate secret¶
Move selected variables from a basic .env into an age-encrypted bundle while generating the matching .env-fuse definitions.
Options:
--from PATH- Basic dotenv source (default:.env)--to PATH- Generated dotenv-fusion file--secret NAME_OR_GLOB- Case-sensitive name or glob; required and repeatable--public NAME_OR_GLOB- Exclude matching names; repeatable--age-output PATH- Ciphertext bundle to create--age-store DIR- Runtime store root used to build the source URI--age-recipient RECIPIENT- Public age recipient; repeatable--age-recipients-file PATH- Age recipients file; repeatable--dry-run- Print names and paths without encryption or writes--force- Atomically replace the exact existing outputs
dotenv-fusion migrate secret \
--secret '*_TOKEN' \
--secret '*_PWD' \
--public 'PUBLIC_*' \
--age-output secrets/application.env.age \
--age-recipient 'age1...'
The source .env is retained. Values are never printed and plaintext is passed to age through stdin. See Encrypt Secrets from an Existing .env for the complete contract.
migrate schema¶
Extract admissible inline #@def declarations into a new schema and replace them with one explicit #@schema reference.
Options:
-f, --file PATH- Source composition file (default:.env-fuse)-o, --output PATH- New schema file; required and never overwritten--dry-run- Validate and list definitions without writing files
The command refuses conditional or imported definitions, an existing schema, lossy re-emission, existing output, and source or destination symlinks. See Define a Shared Schema for publication and recovery guarantees.
list¶
List all variable names.
list auto-detects .env or .env-fuse and accepts the shared -f, --var, --walk, --walk-up, -v, and --restrict-imports input options. It includes sourced variable names without contacting their backends.
Example:
docs¶
Show variable documentation from #@def directives.
docs accepts the same shared input options as list, including --var for dynamic imports. Defaults belonging to secret or secret-derived variables are displayed as ***REDACTED***. Source-backed definitions are shown with their public source URI and no value; their backends are not contacted.
Example:
Output:
PORT (int) (default: 3000): HTTP listening port
DEBUG (bool) (default: false): Enable debug mode
API_KEY (str) [required]: API authentication key
template¶
Generate template .env file from #@def directives.
template accepts the same shared input options as list and docs. Secret values and values derived from them are emitted as empty placeholders; public values and defaults are preserved. Source-backed placeholders include a comment with the public source URI and never contact the backend.
Example:
dotenv-fusion template > .env.example
dotenv-fusion template -f .env.production > .env.prod.template
fuse¶
Compile .env-fuse to standard .env format (flatten all directives).
Options:
-f, --file PATH- Source file to compile (default: .env-fuse)-o, --output PATH- Target file (default: source without -fuse suffix)--var, -V KEY=VALUE- Compilation variable (e.g.,--var ENV=prod)--restrict-imports- Confine imports to the source file's parent directory--load- Print shell exports after compiling; use withevalto load them--stdout- Print to stdout instead of file--dry-run- Preview compilation without writing the output file--diff- Show a redacted diff against the target file without writing--age-identity PATH- Age identity file used during explicit materialization; repeatable--strip-comments- Remove header comments from output--dialect {dotenv,docker}- Serialization contract (default:dotenv; usedockerfordocker run --env-file)--override- Override existing environment variables in emitted exports (default)--no-override- Preserve existing environment variables in emitted exports--walk- Search parent directories if not found locally (default: 1 level, configure withDOTENV_FUSION_WALK_DEPTH)--walk-up N- Search up to N parent directories (implies--walk)-v, --verbose- Verbose mode:-v(logic and names),-vv(values with secrets masked)
Examples:
# Basic compilation
dotenv-fusion fuse # .env-fuse → .env
# With compilation variables
dotenv-fusion fuse --var ENV=prod # Single variable
dotenv-fusion fuse --var ENV=prod --var REGION=eu # Multiple
dotenv-fusion fuse -V ENV=prod -V REGION=eu # Short form
# Custom source/target
dotenv-fusion fuse -f .env-fuse.prod -o .env.production
# Raw values for docker run --env-file
dotenv-fusion fuse --dialect docker -o .env.docker
# Compile and emit shell exports
eval "$(dotenv-fusion fuse --load --var ENV=dev)"
# Output to stdout
dotenv-fusion fuse --stdout --strip-comments
# Review generated output without writing
dotenv-fusion fuse --dry-run --var ENV=prod
dotenv-fusion fuse --diff --var ENV=prod # exits 1 when drift is detected
# Explicit durable plaintext artifact for a sourced configuration
dotenv-fusion fuse -o .env.production
dotenv-fusion fuse -o .env.production --diff
Exit codes:
fuse --dry-run:0when compilation succeeds.fuse --diff:0when the target is up to date,1when drift is detected.- CLI usage errors return
2; parse/validation errors return1.
fuse --diff compares generated and existing content deterministically. No mandatory freshness warning is inferred from file modification times. All existing assignment values are masked, even after the last source= is removed or replaced by a public assignment. New public values remain visible when the current configuration has no sources; new secret values are masked.
When a source= declaration is present, fuse resolves and validates it before writing. --stdout and --load also emit the resolved plaintext values. --dry-run resolves and validates without writing; for sourced configurations, --diff masks every assignment value because the previous artifact's secret provenance may no longer be available. New POSIX output files use mode 0600, while existing permissions are preserved.
Option meanings by subcommand¶
Existing option names remain unchanged. Their meanings depend on the subcommand as follows:
| Subcommand | -o | --override |
|---|---|---|
load | Output format | Replace existing variables by default; --no-override preserves them |
check | Not available | Not available |
exec | Not available | Replace existing variables by default; --no-override preserves them |
migrate secret | Not available (--to selects the generated file) | Not available (--force controls replacement of files) |
migrate schema | New schema destination | Not available |
list | Not available | Not available |
docs | Not available | Not available |
template | Not available | Not available |
fuse | Compiled output file | With --load, include existing variables by default |
The Python API reference now has a dedicated Python API page.
Standalone Script¶
The core dotenvfusion.py can be used as a standalone script for regular dotenv features:
python src/dotenv_fusion/dotenvfusion.py --help
python src/dotenv_fusion/dotenvfusion.py load -f .env --debug
Package installs include official backend modules. A copied standalone core loads optional backends from <prefix>/lib/dotenv-fusion/backends/ when it is installed in <prefix>/bin/. Set DOTENV_FUSION_BACKEND_PATH to an absolute directory to override that location. The core accepts only backend names in its integrated allowlist and validates each sidecar's API version before use.
Security¶
Shell Escaping¶
All values are properly escaped using Python's shlex.quote() to prevent command injection:
Security mechanisms:
shlex.quote(): Standard Python function for safe shell escaping- Variable name validation: Only
[A-Za-z_][A-Za-z0-9_]*names are exported - Command injection prevention: Malicious values are safely escaped
Example:
# .env file with dangerous value
MALICIOUS=$(rm -rf /)
NORMAL=safe_value
# Load with dotenv-fusion
eval "$(dotenv-fusion load)"
# The command is NOT executed - it's escaped as a literal string
echo $MALICIOUS # Output: $(rm -rf /)
Security best practices:
-
Inspect before loading: Use
--debugto see resolved non-secret values; secrets and values derived from them remain masked -
Review untrusted files: Always review
.envfiles from untrusted sources -
Use proper syntax: Always use
eval "$(dotenv-fusion load)"pattern -
JSON for scripts: Use JSON format for safer scripting