Get Started with age¶
dotenv-fusion can resolve selected values from an age-encrypted dotenv bundle immediately before starting an application. The project configuration keeps public references and validation rules; the encrypted bundle keeps the values.
1. Install age support¶
Package installations made with pip, uv, or uvx include the official age backend. Install the age executable through the operating system.
The standalone dotenv-fusion script needs the matching backend sidecar described on the Installation page.
Backends are never selected from arbitrary Python module paths declared in .env-fuse. The core maps supported URI schemes to reviewed package modules and sidecar filenames, then rejects incompatible backend API versions.
2. Configure an identity¶
Recipient-encrypted files need the private age identity that can decrypt the bundle. In the usual case, configure one identity and then start the application:
export DOTENV_FUSION_AGE_IDENTITY=/home/user/.config/age/keys.txt
dotenv-fusion exec -- python app.py
The path belongs to the machine or execution environment, not .env-fuse. For a one-off command, pass the same identity explicitly:
Everything before -- configures dotenv-fusion. Everything after -- is the application command. Repeat --age-identity only when the configuration uses bundles encrypted for different identities.
With no configured identity, age uses its normal interactive flow, including passphrase-protected files.
3. Create a bundle¶
Add ordinary dotenv assignments in the editor:
See Create & Edit Secrets for recipients, editor selection, backups, and recovery behavior.
4. Declare selectors¶
Reference only the keys the application needs:
#@def DATABASE_USERNAME source="age://store/application.env.age#DATABASE_USERNAME"
#@def DATABASE_PASSWORD required=true source="age://store/application.env.age#DATABASE_PASSWORD"
DATABASE_URL=postgresql://${DATABASE_USERNAME}:${DATABASE_PASSWORD}@database/app
The bundle is decrypted and parsed once per invocation, even when several definitions select from it. Omitting #SELECTOR selects the final variable name. Values derived from a secret are also treated as secret.
5. Validate and run¶
# Inspect the public contract without secret access
dotenv-fusion check --no-resolve-sources -f .env-fuse
# Resolve the bundle and validate selected values
dotenv-fusion check -f .env-fuse
# Resolve and start the application without an intermediate file
dotenv-fusion exec -f .env-fuse -- application --serve
Static commands such as list, docs, and template inspect source declarations without contacting age. Full check, load, exec, and fuse resolve the values when their behavior requires them.
check --no-resolve-sources validates source URI syntax, supported backends, option combinations, dependencies, and source-derived cycles. It cannot verify store access, selectors, or type and regex rules that depend on resolved values. Use a full check inside an authorized boundary for those checks.
load emits real resolved values because the shell or JSON consumer needs them. Prefer exec when starting one application, and review the distinction in Security & Limitations.
Store location¶
By default, age://store/... reads ciphertexts from secrets beside the main .env-fuse. Select another root in the file when the layout belongs to the project:
The parent environment can override it:
Relative paths from either source are resolved from the main .env-fuse, not the process working directory. Absolute paths and store roots outside the project are supported. References remain confined beneath the canonical store root.
Execution boundaries¶
Give each boundary only the identities it needs:
| Boundary | Recommended usage |
|---|---|
| Developer workstation | Configure the developer's local identity |
| Pull request or static CI | Provide no identity and run check --no-resolve-sources |
| Authorized CI job | Inject an identity file and pass its path with --age-identity |
| Production application | Provide the production identity and start with exec |