Skip to main content

evnx

CI Release crates.io PyPI npm License: MIT GitHub Marketplace

A CLI tool for managing .env files — validation, secret scanning, format conversion, and migration to cloud secret managers.

Website | Getting Started | Changelog


Why evnx?

Accidentally committing secrets to version control is one of the most common and costly developer mistakes. evnx is a local-first tool that catches misconfigurations, detects credential leaks, and converts environment files to the format each deployment target expects — before anything reaches CI or production.


Testing & playground

→ urwithajit9/evnx-test — try evnx in your browser via GitHub Actions, no installation required.


Installation

Linux / macOS

curl -sSL https://raw.githubusercontent.com/urwithajit9/evnx/main/scripts/install.sh | bash

Homebrew (macOS and Linux)

brew install urwithajit9/evnx/evnx

npm

npm install -g @evnx/cli
pipx install evnx

pipx installs CLI tools into isolated environments and wires them to your system PATH automatically. It is the correct tool for installing Python- distributed CLI binaries like evnx.

Don't have pipx?

macOS

brew install pipx
pipx ensurepath

Ubuntu / Debian (Python 3.11+)

sudo apt install pipx
pipx ensurepath

On older Ubuntu (20.04 and below) where pipx is not in apt:

pip install --user pipx
python -m pipx ensurepath

Note: pip install evnx will fail on Ubuntu 22.04+ with an "externally managed environment" error (PEP 668). This is intentional — Ubuntu protects the system Python. Use pipx instead.

Windows

python -m pip install --user pipx
python -m pipx ensurepath

After running ensurepath, close and reopen your terminal (a full logout/login may be required for PATH changes to take effect), then:

pipx install evnx

After installing pipx on any platform, restart your terminal and run:

pipx install evnx
evnx --version

Cargo

cargo install evnx
# with all optional features
cargo install evnx --all-features

Windows

Scoop (user-local, no admin required)

scoop bucket add evnx https://github.com/urwithajit9/scoop-evnx
scoop install evnx

Winget (system-wide)

winget install urwithajit9.evnx

Cargo (Windows)

Install Rust first, then:

cargo install evnx
evnx --version

Verify

evnx --version
evnx --help

Commands

evnx init

Interactive project setup. Creates .env and .env.example files for your project through a guided TUI.

evnx init

Running evnx init launches an interactive menu with three modes:

How do you want to start?
  Blank      — create empty .env files
  Blueprint  — use a pre-configured stack (Python, Node.js, Rust, Go, PHP, and more)
  Architect  — build a custom stack by selecting services interactively

There are no flags required. The interactive flow handles stack and service selection inside the TUI.


evnx add

Add variables to an existing .env file interactively. Supports custom input, service blueprints, and variable templates.

evnx add

evnx validate

Validates your .env file for common misconfigurations before deployment.

evnx validate                            # pretty output
evnx validate --strict                   # exit non-zero on warnings
evnx validate --format json              # machine-readable output
evnx validate --format github-actions    # inline GitHub annotations

Detects: missing required variables, placeholder values (YOUR_KEY_HERE, CHANGE_ME), the boolean string trap (DEBUG="False" is truthy in most runtimes), weak secret keys, localhost in production, and suspicious port numbers.


evnx scan

Scans files for accidentally committed credentials using pattern matching and entropy analysis.

evnx scan                         # scan current directory
evnx scan --path src/             # specific path
evnx scan --format sarif          # SARIF output for GitHub Security tab
evnx scan --exit-zero             # warn but do not fail CI

Detects: AWS Access Keys, Stripe keys (live and test), GitHub tokens, OpenAI and Anthropic API keys, RSA/EC/OpenSSH private keys, high-entropy strings, and generic API key patterns.


evnx diff

Compares .env and .env.example and shows what is missing, extra, or mismatched.

evnx diff                     # compare .env vs .env.example
evnx diff --show-values       # include actual values
evnx diff --reverse           # swap comparison direction
evnx diff --format json       # JSON output

evnx convert

Converts your .env file to 14+ output formats for various deployment targets.

evnx convert --to json
evnx convert --to yaml
evnx convert --to shell
evnx convert --to docker-compose
evnx convert --to kubernetes
evnx convert --to terraform
evnx convert --to github-actions
evnx convert --to aws-secrets
evnx convert --to gcp-secrets
evnx convert --to azure-keyvault
evnx convert --to heroku
evnx convert --to vercel
evnx convert --to railway
evnx convert --to doppler

Advanced filtering and transformation:

evnx convert --to json \
  --output secrets.json \
  --include "AWS_*" \
  --exclude "*_LOCAL" \
  --prefix "APP_" \
  --transform uppercase \
  --base64

Pipe directly to AWS Secrets Manager:

evnx convert --to aws-secrets | \
  aws secretsmanager create-secret \
    --name prod/myapp/config \
    --secret-string file:///dev/stdin

evnx sync

Keeps .env and .env.example aligned, in either direction.

# Forward: .env → .env.example (document what you have)
evnx sync --direction forward --placeholder

# Reverse: .env.example → .env (generate env from template)
evnx sync --direction reverse

evnx migrate (requires --features migrate)

Migrates secrets directly to cloud secret managers.

# GitHub Actions secrets
evnx migrate --from env-file --to github-actions \
  --repo owner/repo --github-token $GITHUB_TOKEN

# AWS Secrets Manager
evnx migrate --to aws-secrets-manager --secret-name prod/myapp/config

# Doppler (with dry run)
evnx migrate --to doppler --dry-run

evnx doctor

Runs a health check on your environment configuration setup.

evnx doctor                          # check current directory
evnx doctor --path /path/to/project

Checks: .env exists and has secure permissions, .env is in .gitignore, .env.example is tracked by Git, and project structure detection.


evnx template

Generates configuration files from templates using .env variable substitution.

evnx template \
  --input config.template.yml \
  --output config.yml \
  --env .env

Supported inline filters:

database:
  host: {{DB_HOST}}
  port: {{DB_PORT|int}}
  ssl:  {{DB_SSL|bool}}
  name: {{DB_NAME|upper}}

evnx backup / evnx restore (requires --features backup)

Creates and restores AES-256-GCM encrypted backups using Argon2 key derivation.

evnx backup .env --output .env.backup
evnx restore .env.backup --output .env

Cloud sync (requires --features cloud)

Push your .env to the cloud and pull it on any machine or in any pipeline — with the server mathematically unable to read it.

Encryption and decryption happen on your machine. The server stores ciphertext and holds no key that can open it: not with full database access, not with a court order, not after a breach.

evnx auth register                       # create an account
evnx auth login                          # sign in on this machine
evnx vault create app --env production   # a vault holds one .env, versioned
evnx cloud link app/production           # bind this directory to it
evnx cloud push                          # encrypt locally, upload ciphertext
evnx cloud pull                          # download, decrypt, write .env

Installing with cloud support

Cloud is off by default and not included in the prebuilt binaries, so cargo install evnx and the npm / PyPI / Homebrew / Scoop packages are unchanged. To get it you must build from source:

cargo install evnx --features cloud

⚠️ If you already installed evnx another way, check which binary you are running. A package-manager install often sits earlier in PATH than ~/.cargo/bin, so cargo install appears to succeed while the old binary still answers — and evnx vault list reports "unrecognized subcommand".

which -a evnx     # if ~/.cargo/bin/evnx is not first, that is why

What the server can and cannot see

Sent to the server Never sent
Ciphertext — AES-256-GCM, encrypted before upload Your .env values
Your key names (DATABASE_URL, STRIPE_KEY) so a listing can show what a vault holds Your master password
An SRP-6a verifier, which proves knowledge of the password without revealing it Your master key, or any vault key in usable form

Key names travelling in the clear is a deliberate trade for a usable listing. If a name is itself sensitive, do not make it a name.

There is no password reset. The server holds only ciphertext, so nobody — including us — can recover an account whose master password is lost. Enable a second factor and keep your recovery codes:

evnx auth totp enable

Versioning and rollback

Every push is a new version. Nothing is overwritten.

evnx cloud history                  # what changed, when, and who pushed it
evnx cloud pull --version 3         # restore an earlier version

If someone else pushed since you last pulled, your push is refused with a conflict rather than silently overwriting them. Pull, re-apply, push again — the version number is authenticated into the ciphertext, so the same bytes cannot simply be re-sent.

CI/CD

Mint a token scoped to one vault, read-only:

evnx auth token create ci --scope read --vault app/production --expires-in-days 90

Then in the pipeline:

export EVNX_TOKEN=evnx_tok_...
echo "$EVNX_PASSWORD" | evnx cloud pull --vault <VAULT_ID> --password-stdin

Two things to understand:

  • The token authenticates; it does not decrypt. The master password is still required, and it is the more sensitive of the two. What the token buys is blast radius: scoped to one vault and read, it reaches that vault and nothing else.
  • Use the vault id, not name/environment. A vault-scoped token is refused permission to list vaults — by design — so it cannot resolve a name. Get the id from evnx vault list --verbose.

Pipe the password rather than exporting it where you can: an environment variable is visible in process listings and tends to end up in logs.

Self-hosting

evnx cloud talks to https://api.evnx.dev by default. Point it anywhere:

evnx cloud status --server https://evnx.internal.example

or set EVNX_SERVER, or server = "..." in ~/.config/evnx/config.toml. The server is open source and ships a Docker stack. Plain http:// is refused for anything but a loopback address, because tokens travel in request headers.


CI/CD Integration

GitHub Actions

name: Validate environment

on: [push, pull_request]

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install evnx
        run: |
          curl -sSL https://raw.githubusercontent.com/urwithajit9/evnx/main/scripts/install.sh | bash

      - name: Validate configuration
        run: evnx validate --strict --format github-actions

      - name: Scan for secrets
        run: evnx scan --format sarif > scan-results.sarif

      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        if: always()
        with:
          sarif_file: scan-results.sarif

GitLab CI

validate-env:
  stage: validate
  image: alpine:latest
  before_script:
    - apk add --no-cache curl bash
    - curl -sSL https://raw.githubusercontent.com/urwithajit9/evnx/main/scripts/install.sh | bash
  script:
    - evnx validate --strict --format json
    - evnx scan --format sarif > scan.sarif
  artifacts:
    reports:
      sast: scan.sarif

pre-commit / prek Integration

Use evnx as automatic git hooks via pre-commit or prek — no manual evnx install needed. The binary is compiled and cached automatically on first run.

Add to .pre-commit-config.yaml:

default_install_hook_types: [pre-commit, pre-push]

repos:
  - repo: https://github.com/urwithajit9/evnx
    rev: v0.3.6
    hooks:
      - id: evnx-scan        # blocks commit if secrets found
      - id: evnx-validate    # blocks commit if .env misconfigured
      - id: evnx-diff        # warns on .env/.env.example drift
      - id: evnx-scan-push   # strict scan on push

Then install:

pre-commit install   # or: prek install

That's it. On your next commit, hooks will auto-compile and run.


Configuration

Store defaults in .evnx.toml at the project root:

[defaults]
env_file = ".env"
example_file = ".env.example"
verbose = false

[validate]
strict = true
auto_fix = false
format = "pretty"

[scan]
ignore_placeholders = true
exclude_patterns = ["*.example", "*.sample", "*.template"]
format = "pretty"

[convert]
default_format = "json"
base64 = false

[aliases]
gh = "github-actions"
k8s = "kubernetes"
tf = "terraform"

Known Limitations

Array and multiline values — evnx follows the strict .env spec where values are simple strings. The following will not parse correctly:

# Not supported
CORS_ALLOWED=["https://example.com", "https://admin.example.com"]
CONFIG={"key": "value"}
DATABASE_HOSTS="""
host1.example.com
host2.example.com
"""

Use comma-separated strings and parse them in application code. A --lenient flag for extended syntax is under consideration — see open issues.

One .env file at a time — evnx works with .env and .env.example. Variants like .env.prod, .env.production, .env.local and .env.staging are not discovered by evnx scan when scanning a directory; it reports "no secrets detected" without opening them. evnx validate and evnx diff are unaffected — pass the file explicitly with --env. Multi-file support is planned for a future release.

Windows — file permissions checking is limited (no Unix permission model). Terminal color support requires PowerShell or Windows Terminal on older systems.


Development

git clone https://github.com/urwithajit9/evnx.git
cd evnx

cargo build                          # core features only
cargo build --all-features
cargo test
cargo clippy --all-features -- -D warnings
cargo fmt

Feature flags:

[features]
default = []
migrate = ["reqwest", "base64", "indicatif"]
backup  = ["aes-gcm", "argon2", "rand"]
full    = ["migrate", "backup"]

Contributing

See CONTRIBUTING.md. Contributions are welcome in: additional format converters, secret pattern improvements, Windows enhancements, extended .env format support, and integration examples.


License

MIT — see LICENSE.


Credits

Built by Ajit Kumar.

Related projects: python-dotenv, dotenvy, direnv, git-secrets.


Website | Issues | Discussions | Email

Release files for evnx 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for evnx 0.4.0
File Size Uploaded
evnx-0.4.0.tar.gz 286.1 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for evnx 0.4.0
File
evnx-0.4.0-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
evnx-0.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64 Details
evnx-0.4.0-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
evnx-0.4.0-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 13.5 MB

Release files / evnx-0.4.0.tar.gz

Download URL evnx-0.4.0.tar.gz
Size 286.1 kB
Tags Source
SHA-256 checksum
How to use checksums
c2da2b1aba573a76e20e4f183a069b90131e111a64df24f92c5aca622b3cfb42
BLAKE2b-256 checksum
How to use checksums
76fc6df8fc74b341e3febf69ebcabf9af32029f4594b4b72a1c2ae68a6896d8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / evnx-0.4.0-py3-none-win_amd64.whl

Download URL evnx-0.4.0-py3-none-win_amd64.whl
Size 3.5 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
25fcb2788ef9dd4b31e948101ce7262e8eab91ca50419797b05fdca6f6da84a3
BLAKE2b-256 checksum
How to use checksums
2c914c213f288e95e8cbe02190632d555dd25bacc9cffd49518f954dd7b96efb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / evnx-0.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL evnx-0.4.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 3.4 MB
Tags Linux glibc 2.17+ x86-64 Python 3
SHA-256 checksum
How to use checksums
8bea27604f6a501d03b2ab88af88fa3eaf13374ebcecf0942c25a433c5265e38
BLAKE2b-256 checksum
How to use checksums
f661c7e244187c26f8f73d5e9bef48c08f7adf7e59c43d6ea3d19498dbe2baec
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / evnx-0.4.0-py3-none-macosx_11_0_arm64.whl

Download URL evnx-0.4.0-py3-none-macosx_11_0_arm64.whl
Size 3.1 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
d8a56fd1c22c68ea4628bfe9b52b5d3035de5e96c1bef6b4c507b4420d66975b
BLAKE2b-256 checksum
How to use checksums
936ad012868cffe25a5fb3f2ce66e5a226c20b04ee10dab9ba0e9ccea19544be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / evnx-0.4.0-py3-none-macosx_10_12_x86_64.whl

Download URL evnx-0.4.0-py3-none-macosx_10_12_x86_64.whl
Size 3.3 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
d86eccd4e380add7234a1203fc9ca52059b408693dfa39f11fbd5bab79871f0f
BLAKE2b-256 checksum
How to use checksums
e536f62c36efad347fb26f12450b976ade2585a60ab6795c0c0951569d46a016
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.5.2

5 release files

0.5.1

5 release files

0.5.0

5 release files

This release

0.4.0 This release

5 release files

0.3.8

5 release files

0.3.7

5 release files

0.3.6

5 release files

0.3.5

5 release files

0.3.1

7 release files

0.3.0

7 release files

0.2.1

7 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page