Environment file encryption and management tool for secure development workflows.
- Overview
- Features
- Prerequisites
- Installation
- Quick Start
- Commands
- Configuration
- Workflow Examples
- Security Best Practices
- Integration with Direnv
- Troubleshooting
- API Reference
- Testing
- Development
- Changelog
- License
- Support
EnvX is a command-line tool that helps you securely manage environment files across different stages (development, staging, production) using GPG encryption. It provides a simple workflow for encrypting sensitive environment variables while maintaining ease of use for development teams.
- GPG-based encryption for maximum security
- Stage-based management (development, staging, production, etc.)
- Interactive setup with guided configuration
- Batch operations on multiple files and directories
- Secret management with
.envrcintegration - Project configuration via
.envxrcfor per-project ignore patterns and environment tracking - Environment filtering to auto-ignore non-secret files (example, sample, template)
- Dry run mode to preview operations without making changes
- Config management CLI for managing project settings without editing JSON
- Beautiful CLI with colored output and progress indicators
- Best practices enforcement and security recommendations
Before using EnvX, ensure you have:
- Node.js >= 14.0.0
- GPG (GNU Privacy Guard) installed and configured
brew install gnupgsudo apt-get install gnupgDownload from https://gnupg.org/download/
gpg --versionnpm install -g envx-clinpm install envx-cli
npx envx --help- Initialize EnvX in your project:
envx init- Create environment files:
envx create -e development
envx create -e production- Set up secrets for encryption:
envx interactive- Encrypt your environment files:
envx encrypt -e production- Commit encrypted files to git:
git add *.gpg
git commit -m "Add encrypted environment files"- Copy environment to .env for use:
envx copy -e production- Decrypt when needed:
envx decrypt -e productionInitialize EnvX in a new project with guided setup.
envx initThe init wizard will:
- Verify GPG is available
- Discover existing environment files, auto-ignoring non-secret files (example, sample, template)
- Let you select which environments to manage via checkbox prompt
- Offer to add non-selected environments to the ignore list in
.envxrc - Save your selected environments to
.envxrc - Update
.gitignorewith recommended patterns - Optionally start interactive secret setup
- Optionally encrypt your environment files immediately after setup
Options:
-c, --cwd <path>- Working directory
Create new environment files.
# Create a single environment file
envx create -e development
# Interactive mode for multiple environments
envx create -i
# Use a template file
envx create -e production -t .env.example
# Overwrite existing files
envx create -e staging --overwriteOptions:
-e, --environment <env>- Environment name-t, --template <path>- Template file path-i, --interactive- Interactive mode--overwrite- Overwrite existing files-c, --cwd <path>- Working directory
Encrypt environment files using GPG.
# Encrypt specific environment
envx encrypt -e production
# Encrypt all environments at once
envx encrypt --all
# Preview what would be encrypted (no changes made)
envx encrypt -e production --dry-run
# Use custom secret from .envrc
envx encrypt -e production -s CUSTOM_SECRET
# Interactive file selection (for single environment)
envx encrypt -e staging -i
# Encrypt all with specific passphrase
envx encrypt --all -p "your-passphrase"
# Overwrite existing encrypted files
envx encrypt -e production --overwriteOptions:
-e, --environment <env>- Environment name (required unless using --all)-a, --all- Process all available environments-p, --passphrase <pass>- Encryption passphrase-s, --secret <secret>- Secret variable name from .envrc-i, --interactive- Interactive file selection (disabled with --all)--overwrite- Overwrite existing encrypted files--dry-run- Show what would happen without making changes-c, --cwd <path>- Working directory
Decrypt environment files.
# Decrypt specific environment
envx decrypt -e production
# Decrypt all environments at once
envx decrypt --all
# Preview what would be decrypted (no changes made)
envx decrypt -e production --dry-run
# Overwrite existing files without confirmation
envx decrypt -e development --overwrite
# Decrypt all with overwrite flag
envx decrypt --all --overwrite
# Interactive file selection (for single environment)
envx decrypt -e staging -iOptions:
-e, --environment <env>- Environment name (required unless using --all)-a, --all- Process all available environments-p, --passphrase <pass>- Decryption passphrase-s, --secret <secret>- Secret variable name from .envrc-i, --interactive- Interactive file selection (disabled with --all)--overwrite- Overwrite existing files without confirmation--dry-run- Show what would happen without making changes-c, --cwd <path>- Working directory
Interactive setup for .envrc file with secrets.
# Start interactive setup
envx interactive
# Overwrite existing .envrc
envx interactive --overwrite
# Generate random secrets for all environments
envx interactive --generateOptions:
--overwrite- Overwrite existing .envrc file--generate- Generate random secrets-c, --cwd <path>- Working directory
List all environment files and their status. Automatically filters out non-secret environments (example, sample, template) based on your ignore patterns.
# List all environment files
envx list
# Short alias
envx lsOptions:
-c, --cwd <path>- Working directory
Copy environment file from a specific stage to .env. This command is perfect for deployment scenarios where you need to activate a specific environment configuration.
# Copy production environment to .env (single directory)
envx copy -e production
# Copy to ALL directories with environment files (multi-service)
envx copy -e production --all
# Copy development environment to .env
envx copy -e development
# Copy with overwrite (no confirmation)
envx copy -e staging --overwrite
# Copy from encrypted file (auto-decrypts)
envx copy -e production -p "your-passphrase"
# Use secret from .envrc for encrypted files
envx copy -e production -s PRODUCTION_SECRET
# Copy production to all services from project root
envx copy -e production --all --overwriteOptions:
-e, --environment <env>- Environment name (required)-a, --all- Process all directories with environment files-p, --passphrase <pass>- Passphrase for decryption (if source is encrypted)-s, --secret <secret>- Secret variable name from .envrc--overwrite- Overwrite existing .env file without confirmation-c, --cwd <path>- Working directory
How it works:
- Single directory mode: Copies
.env.<environment>to.envin current directory - Multi-directory mode (
--all): Finds all directories with environment files and copies to each - If
.env.<environment>exists (unencrypted), it copies directly to.env - If
.env.<environment>.gpgexists (encrypted), it decrypts and copies to.env - Prefers unencrypted files over encrypted ones if both exist
- Creates backup of existing
.envfile during encrypted operations - Shows security warnings when copying production environments
Show project encryption status and recommendations. Automatically filters out non-secret environments based on your ignore patterns.
envx statusOptions:
-c, --cwd <path>- Working directory
Manage project configuration stored in .envxrc without editing JSON manually.
Display the current .envxrc configuration, showing both custom settings and defaults.
envx config showList all current ignore patterns (from .envxrc or defaults).
envx config ignore listAdd a pattern to the ignore list. Environments matching this pattern will be excluded from operations like --all, list, and status.
# Ignore the "test" environment
envx config ignore add test
# Ignore a custom environment name
envx config ignore add local-devRemove a pattern from the ignore list.
envx config ignore remove testList all excluded directories (from .envxrc or defaults). These directories are skipped during environment file discovery, which is useful in monorepos and projects with build artifacts.
envx config exclude listAdd a directory to the exclusion list.
# Exclude Vercel build output
envx config exclude add .vercel
# Exclude a custom build directory
envx config exclude add outRemove a directory from the exclusion list.
envx config exclude remove buildReset the configuration to defaults, removing all custom ignore patterns and directory exclusions.
envx config resetEnvX uses .envrc files to store encryption secrets. The format follows the direnv convention:
# Environment secrets generated by envx
export DEVELOPMENT_SECRET="your-development-secret"
export STAGING_SECRET="your-staging-secret"
export PRODUCTION_SECRET="your-production-secret"EnvX supports a .envxrc JSON file in your project root for per-project configuration. This file is automatically managed by envx init and envx config commands.
{
"ignore": ["example", "sample", "template", "local-dev"],
"environments": ["development", "staging", "production"],
"excludeDirs": ["node_modules", ".git", "dist", ".next", ".turbo", "build"]
}Fields:
| Field | Type | Description |
|---|---|---|
ignore |
string[] |
Patterns to exclude from environment discovery. Environments whose names match any pattern (case-insensitive) are filtered from --all, list, and status operations. Defaults to ["example", "sample", "template"] if not set. |
environments |
string[] |
List of managed environments. Set during envx init based on your selection. |
excludeDirs |
string[] |
Directories to exclude from file discovery. Prevents scanning into build artifacts and dependency directories. Defaults to ["node_modules", ".git", "dist", ".next", ".turbo", ".output", ".nuxt", ".cache", "build", "coverage", ".svelte-kit"]. |
You can manage this file through the CLI:
# View current config
envx config show
# Add a custom ignore pattern
envx config ignore add test
# Remove a pattern
envx config ignore remove sample
# Add a directory exclusion
envx config exclude add .vercel
# Remove a directory exclusion
envx config exclude remove build
# Reset to defaults
envx config resetOr edit .envxrc directly as JSON.
EnvX follows the convention: <STAGE>_SECRET
Examples:
DEVELOPMENT_SECRETSTAGING_SECRETPRODUCTION_SECRETLOCAL_SECRET
EnvX automatically filters non-secret environment files from discovery operations. By default, files matching example, sample, or template are excluded.
This filtering applies to:
envx encrypt --all/envx decrypt --all(batch operations)envx list(environment listing)envx status(project status)envx init(environment discovery)
How it works:
- If
.envxrcexists with anignorefield, those patterns are used - If no
.envxrcexists orignoreis not set, the defaults are used:["example", "sample", "template"] - Pattern matching is case-insensitive (
.env.Examplematches patternexample)
Customizing filters:
# Add a custom pattern
envx config ignore add test
# Remove a default pattern (to include it in operations)
envx config ignore remove template
# See current patterns
envx config ignore listBypass filtering: Pass an explicit empty ignore list programmatically via findAllEnvironments(cwd, []) to include all environments.
EnvX automatically excludes build artifact and dependency directories from file discovery. This prevents .env.* files duplicated inside node_modules, .next, dist, .turbo, and other directories from appearing as spurious results.
Default excluded directories: node_modules, .git, dist, .next, .turbo, .output, .nuxt, .cache, build, coverage, .svelte-kit
Customizing exclusions:
# View current exclusions
envx config exclude list
# Add a directory
envx config exclude add .vercel
# Remove a directory (e.g., to scan build output)
envx config exclude remove buildyour-project/
├── .env.development # Unencrypted (local only)
├── .env.staging.gpg # Encrypted (committed)
├── .env.production.gpg # Encrypted (committed)
├── .envrc # Secrets (local only)
├── .envxrc # Project config (local only)
└── .gitignore # Excludes .env.* but allows *.gpg
- Create environment files:
envx create -e development
envx create -e production- Edit your environment files:
# Edit .env.development
echo "DATABASE_URL=postgresql://localhost:5432/myapp_dev" >> .env.development
echo "API_KEY=dev-api-key" >> .env.development
# Edit .env.production
echo "DATABASE_URL=postgresql://prod-server:5432/myapp" >> .env.production
echo "API_KEY=prod-api-key-secret" >> .env.production- Set up encryption secrets:
envx interactive- Encrypt production secrets:
envx encrypt -e production- Copy environment for application use:
# For development
envx copy -e development
# For production deployment
envx copy -e production- Add to version control:
echo ".env.*" >> .gitignore
echo "!*.gpg" >> .gitignore
git add .env.production.gpg .envrc
git commit -m "Add encrypted production environment"- Single service deployment:
# On production server after pulling latest code
envx copy -e production --overwrite- Multi-service deployment (from project root):
# Copy production environment to ALL services at once
envx copy -e production --all --overwrite- For local development with production data:
# Copy production environment locally (be careful!)
envx copy -e production
# Or copy to all services locally
envx copy -e production --all- Switch between environments easily:
# Use development environment across all services
envx copy -e development --all --overwrite
# Switch to staging across all services
envx copy -e staging --all --overwrite
# Switch to production (with warning)
envx copy -e production --all --overwrite- Clone repository and set up environment:
git clone <your-repo>
cd <your-repo>
# For development
envx copy -e development
# For production deployment
envx copy -e production- Make changes and re-encrypt:
# Edit .env.production directly or copy from .env after changes
cp .env .env.production # if you made changes to .env
envx encrypt -e production
git add .env.production.gpg
git commit -m "Update production configuration"From project root, manage all services at once:
# Copy production environment to all services
envx copy -e production --all
# Copy staging environment to all services
envx copy -e staging --all --overwrite
# Perfect for deployment scripts
#!/bin/bash
envx copy -e production --all --overwrite
docker-compose up -dProcess all environments at once:
# Encrypt all environment files
envx encrypt --all
# Decrypt all environment files
envx decrypt --all
# Decrypt all with overwrite protection disabled
envx decrypt --all --overwriteBenefits of using --all:
- Efficiency: Process multiple environments in one command
- Consistency: Same passphrase/secret handling across all environments
- Automation: Perfect for CI/CD pipelines and scripts
- Safety: Each environment is processed independently - failures in one don't stop others
- Reporting: Comprehensive summary showing results for each environment
- Filtering: Automatically skips non-secret environments (example, sample, template)
Key Features of --all Flag:
- Sequential Processing: Environments are processed one by one to avoid resource conflicts
- Independent Operations: Failure in one environment doesn't stop processing of others
- Smart Passphrase Resolution: Uses provided passphrase, environment-specific secrets, or prompts as needed
- Comprehensive Reporting: Shows detailed results for each environment plus overall summary
- Safety Checks: Validates compatibility with other flags (incompatible with
--environmentand--interactive) - Flexible Configuration: Works with all existing options like
--passphrase,--secret,--cwd, and--overwrite
Activate environments for your application:
# Activate development environment for local work
envx copy -e development
# Activate staging for testing
envx copy -e staging --overwrite
# Activate production for deployment
envx copy -e production --overwriteUse cases for envx copy:
- Deployment: Copy environment configuration to
.envfor application use - Environment Switching: Quickly switch between different configurations
- Local Development: Use production/staging config locally for debugging
- Docker/Containers: Set up environment in containerized deployments
- CI/CD: Activate specific environments during pipeline stages
- Multi-Service: Manage environment files across multiple services from project root
- Batch Operations: Copy same environment to all services with one command
Preview encrypt/decrypt operations before executing them:
# See what files would be encrypted
envx encrypt -e production --dry-run
# Preview batch encryption
envx encrypt --all -p "your-passphrase" --dry-run
# Preview decryption
envx decrypt -e production --dry-runDry run mode shows:
- Which files would be processed
- The passphrase source (provided,
.envrc, or interactive) - Total file count
No files are created, modified, or deleted during a dry run.
- Always encrypt production and staging environment files
- Commit encrypted
.gpgfiles to version control - Add
.envrcand.envxrcto your.gitignore - Use strong, unique secrets for each environment
- Regularly rotate encryption secrets
- Use
envx statusto check your security posture - Use
--dry-runto preview operations before executing
- Never commit unencrypted
.env.*files (except templates) - Don't commit
.envrcor.envxrcfiles to version control - Don't use weak or predictable passphrases
- Don't share secrets through insecure channels
- Don't leave decrypted files in production environments
# Environment files
.env.*
!.env.example
!.env.template
!*.gpg
# EnvX secrets and config
.envrc
.envxrcEnvX works great with direnv for automatic environment loading:
- Install direnv:
# macOS
brew install direnv
# Ubuntu/Debian
sudo apt install direnv- Add to your shell profile:
# For bash
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
# For zsh
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc- Allow direnv in your project:
direnv allowNow your secrets will be automatically loaded when you enter the project directory!
Problem: gpg: command not found
# Install GPG (see Prerequisites section)Problem: gpg: decryption failed: Bad session key
# Wrong passphrase - try again or check your .envrc file
envx decrypt -e productionProblem: gpg: can't connect to the agent
# Restart GPG agent
gpgconf --kill gpg-agent
gpgconf --launch gpg-agentProblem: EACCES: permission denied
# Check file permissions
ls -la .env.*
chmod 644 .env.*Problem: Template file not found
# Check if template exists
ls -la .env.example
# Or create without template
envx create -e developmentEnvX respects the following environment variables:
ENVX_DEFAULT_CWD- Default working directoryENVX_GPG_BINARY- Custom GPG binary pathNODE_ENV- Affects error reporting verbosity
| Code | Constant | Description |
|---|---|---|
0 |
SUCCESS |
Operation completed successfully |
1 |
GENERAL_ERROR |
General error |
2 |
INVALID_ARGS |
Invalid arguments provided |
3 |
FILE_ERROR |
File operation failed |
4 |
GPG_ERROR |
GPG operation failed |
5 |
USER_CANCELLED |
Operation cancelled by user |
EnvX includes a comprehensive test suite covering core functionality, configuration management, and real-world CLI usage scenarios.
# Run all tests
npm test
# Run core functionality tests
npm run test:core
# Run integration tests
npm run test:integration
# Run tests with coverage
npm run test:coverage
# Run tests in watch mode (for development)
npm run test:watchThe test suite prioritizes essential functionality over comprehensive coverage:
- Core business logic - Command validation, file utilities, path manipulation
- Configuration management -
.envxrcread/write/merge, ignore patterns, defaults - Real CLI scenarios - Actual command execution in various environments
- Critical workflows - User-facing functionality that must work reliably
Current Status: 181 tests passing across 7 test suites
-
Core Tests: 165 tests covering essential functionality
- Schema validation: 25 tests (command input validation)
- File utilities: 39 tests (path manipulation, secret generation, gitignore)
- Command logic: 25 tests (workflow patterns and decision logic)
- All-flag functionality: 15 tests (batch operations, error handling)
- EnvxrcConfig infrastructure: 23 tests (read/write/merge, ignore patterns, filtering)
- Config command: 7 tests (show, add, remove, reset operations)
- Copy command: 31 tests (single/multi-directory, encrypted/unencrypted)
-
Integration Tests: 16 tests covering real CLI usage
- Help/version commands
- Create command functionality
- Init command validation
- Config subcommand (show, ignore, reset)
- Dry run flag (encrypt/decrypt)
- Copy
--allflag - Environment filtering (list, status)
- Error handling scenarios
- Environment validation
__tests__/
├── core/ # Essential functionality tests
│ ├── schemas.test.ts # Input validation for all commands
│ ├── file.test.ts # File utilities, path manipulation, gitignore
│ ├── commands.test.ts # Command workflow logic patterns
│ ├── all-flag.test.ts # Batch operations and --all flag functionality
│ ├── envxrc.test.ts # .envxrc config read/write/merge/filtering
│ └── config.test.ts # Config command operations
└── integration/ # End-to-end CLI tests
└── cli.test.ts # Real CLI execution scenarios
For detailed testing information, see TESTING.md.
git clone https://github.com/rahulretnan/envx-cli
cd envx-cli
npm install
npm run build
npm linksrc/
├── index.ts # Entry point, CLI framework, inline commands
├── commands/ # Command implementations
│ ├── config.ts # envx config subcommand
│ ├── copy.ts # envx copy
│ ├── create.ts # envx create
│ ├── decrypt.ts # envx decrypt
│ ├── encrypt.ts # envx encrypt
│ └── interactive.ts # envx interactive
├── schemas/
│ └── index.ts # Zod validation schemas
├── types/
│ └── index.ts # TypeScript interfaces and enums
└── utils/
├── exec.ts # GPG operations, CLI output (ExecUtils, CliUtils)
├── file.ts # File discovery, .envrc/.envxrc, gitignore (FileUtils)
└── interactive.ts # User prompts via inquirer (InteractiveUtils)
Key patterns:
- Each command file exports
createXxxCommand()(Commander command) andexecuteXxx()(core logic) - All utility classes use static methods, no instances
- Zod schemas validate all command inputs;
--alldynamically alters schema requirements - Configuration resolution:
--passphraseflag >.envrcfile > interactive prompt - Working directory:
--cwdflag >process.cwd()
# Start development mode
npm run dev
# Run tests in watch mode
npm run test:watch
# Build and test
npm run build && npm test
# Lint and format
npm run lint:fix && npm run format- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and add tests
- Run tests:
npm test - Ensure test coverage remains high:
npm run test:coverage - Submit a pull request
- New CLI commands must include integration tests
- Core utility functions must include unit tests
- Focus on user-facing functionality over implementation details
- Keep tests simple and maintainable
- Ensure tests verify real CLI behavior
See CHANGELOG.md for detailed release notes.
MIT © rahulretnan
- Issues
- Discussions
- Email: hi@rahulretnan.me
Made with ❤️ by developers, for developers.
Remember: Security is not a feature, it's a requirement. EnvX helps you maintain security without sacrificing developer experience.