Environment variable drift happens when code and configuration get out of sync - teammates add new variables without updating configs, refactoring leaves orphaned variables, or onboarding misses undocumented requirements. These issues cause runtime failures and deployment headaches.
Envgrd uses Tree-Sitter AST analysis to accurately detect environment variable usage across your codebase and compare it with your configuration files. Unlike regex-based tools, AST parsing understands code structure, handles edge cases correctly, and supports dynamic patterns with fewer false positives.
💡 Tip: Automate drift detection by using envgrd as a post-merge git hook to catch issues automatically after pulling code.
- Detects missing environment variables (used in code but not found in any config files or exported environment)
- Detects unused environment variables (in config files but not used in code)
- Multiple language support: JavaScript, TypeScript, Go, Python, Rust, Java
- Multi-format environment detection: Automatically discovers and reads from
.envfiles,.envrc(direnv),docker-compose.yml, Kubernetes ConfigMaps/Secrets, systemd service files, and shell scripts - Shell environment integration: Reads exported environment variables from your shell (e.g.,
export VAR=value), preventing false positives for variables set via CI/CD, secret managers, or shell exports - Dynamic pattern detection: Identifies runtime-evaluated expressions like
process.env["prefix_" + var]andos.Getenv(key + "_suffix")that cannot be fully determined at static analysis time - Supports multiple output formats (human-readable, JSON)
- Configurable ignore rules: Ignore specific variables or folders via
.envgrd.configto reduce false positives - Lightning-fast parallel processing
Linux/macOS:
curl -sSL https://raw.githubusercontent.com/njenia/envgrd/main/install.sh | bashWindows (PowerShell):
Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/njenia/envgrd/main/install.ps1 | Invoke-ExpressionLinux (amd64):
curl -L https://github.com/njenia/envgrd/releases/latest/download/envgrd-linux-amd64.tar.gz | tar -xz && sudo mv envgrd /usr/local/bin/macOS (amd64 / Intel):
curl -L https://github.com/njenia/envgrd/releases/latest/download/envgrd-darwin-amd64.tar.gz | tar -xz && sudo mv envgrd /usr/local/bin/macOS (arm64 / Apple Silicon):
curl -L https://github.com/njenia/envgrd/releases/latest/download/envgrd-darwin-arm64.tar.gz | tar -xz && sudo mv envgrd /usr/local/bin/Windows:
# Option 1: Use install script (recommended)
Invoke-WebRequest -UseBasicParsing https://raw.githubusercontent.com/njenia/envgrd/main/install.ps1 | Invoke-Expression
# Option 2: Manual installation
# Download and extract
Invoke-WebRequest -Uri https://github.com/njenia/envgrd/releases/latest/download/envgrd-windows-amd64.zip -OutFile envgrd.zip
Expand-Archive envgrd.zip
# Move envgrd.exe to a directory in your PATH (e.g., C:\Program Files\envgrd\)Linux (arm64):
Pre-built binaries for ARM64 Linux are not available due to CGO cross-compilation requirements. Please build from source:
git clone https://github.com/njenia/envgrd.git
cd envgrd
make build
# Binary will be in bin/envgrd# Clone the repository
git clone https://github.com/njenia/envgrd.git
cd envgrd
# Build with Make (automatically detects version from git tags)
make build
# Or install directly
make installgo install github.com/njenia/envgrd/cmd/envgrd@latestNote: When building locally, use make build to automatically set the version from git tags. Building with go build directly will show version as "dev".
# Scan current dir recursively
envgrd scanenvgrd scan ./path/to/codebaseCreate a .envgrd.config file in the current directory:
envgrd init-configThis creates a template configuration file that you can customize to ignore specific variables or folders.
envgrd scan --env-file .env.productionenvgrd scan --jsonenvgrd scan --skip-unusedBy default, envgrd detects and reports both static and dynamic environment variable patterns. To disable dynamic pattern detection and only report static patterns (string literals), use the --no-dynamic flag:
envgrd scan --no-dynamicSee the Dynamic Expression Matching section for more details.
envgrd scan --silentAll languages support both static (string literal) and dynamic (runtime-evaluated) environment variable patterns:
- JavaScript / TypeScript:
process.env.KEY,process.env["KEY"],process.env["prefix_" + var],process.env[var] - Go:
os.Getenv("KEY"),os.Getenv("prefix_" + var),os.Getenv(var) - Python:
os.environ["KEY"],os.getenv("KEY"),os.environ["prefix_" + var],os.getenv(var) - Rust:
env::var("KEY"),std::env::var("KEY"),env::var_os("KEY"),std::env::var_os("KEY"), plus dynamic patterns - Java:
System.getenv("KEY"),System.getenv().get("KEY"), plus dynamic patterns
By default, envgrd detects both static and dynamic environment variable patterns:
- Static patterns: String literals like
process.env.API_KEYoros.Getenv("DATABASE_URL")where the variable name is known at compile time - Dynamic patterns: Runtime-evaluated expressions like:
process.env["prefix_" + var]- concatenation with variablesos.Getenv(key + "_suffix")- string concatenationenv::var(my_var)- variable references where the env var name is determined at runtime
Dynamic patterns are reported in a separate "Dynamic patterns" section since the exact environment variable name cannot be determined statically. Use the --no-dynamic flag to disable dynamic pattern detection and only report static patterns.
Create a .envgrd.config file in your project root to configure ignore rules:
ignores:
# Variables that are configured in custom ways (not in .env files or standard configs)
# These will not be reported as missing
missing:
- CUSTOM_API_KEY
- EXTERNAL_SERVICE_TOKEN
# Variables configured via custom tools/scripts
# Folders to ignore when scanning (useful for config directories that aren't actual code)
folders:
- config
- configs
- k8s
- kubernetes
- deployments
# Add more folder names here as neededignores.missing: Variables listed here will not be reported as missing, even if they're not found in any environment files. The tool will show a count of ignored variables in the output.ignores.folders: Folders listed here will be excluded from scanning. This is useful for configuration directories (like Kubernetes manifests, deployment configs) that contain environment variable references but aren't actual running code.
envgrd automatically detects and reads environment variables from multiple sources:
The tool automatically scans for and parses the following file formats:
.envfiles: Standard format (KEY=value).env.*files: Environment-specific files (.env.development,.env.production,.env.local, etc.).envrcfiles: direnv format (export VAR=value)docker-compose.yml: Environment sections in Docker Compose files- Kubernetes ConfigMaps and Secrets: YAML files containing
data:sections (secrets are automatically base64-decoded) - systemd
.servicefiles: Files withEnvironment=directives - Shell scripts:
.shand.bashfiles containingexport VAR=valuestatements
In addition to configuration files, envgrd also reads variables exported to your shell environment (via export VAR=value or set in your shell profile). This is particularly useful for:
- CI/CD pipelines: Variables set in GitHub Actions, GitLab CI, Jenkins, etc.
- Secret management tools: Variables injected by Doppler, HashiCorp Vault, AWS Secrets Manager, etc.
- Local development: Variables exported in your shell session or
.bashrc/.zshrc
Note: When the same variable exists in both a config file and the exported environment, the config file value takes precedence. Exported environment variables are marked as [from environment] in the analysis and are used to prevent false positives for missing variables, but are not included in the "unused variables" report (only variables from config files are checked for unused status).
MIT
