| name | direnv |
| description | Guide for using direnv - a shell extension for loading directory-specific environment variables. Use when setting up project environments, creating .envrc files, configuring per-project environment variables, integrating with Python/Node/Ruby/Go layouts, working with Nix flakes, or troubleshooting environment loading issues on macOS and Linux. |
direnv Skill
Shell extension for loading and unloading environment variables based on the current directory.
Overview
direnv enables:
- Per-project environment configurations
- Automatic loading of 12-factor app environment variables
- Isolated development environments with language-specific layouts
- Secure allowlist-based security model
- Integration with Nix, asdf, and version managers
Quick Start
Installation
brew install direnv
sudo apt install direnv
curl -sfL https://direnv.net/install.sh | bash
direnv version
Shell Hook Configuration
Zsh (~/.zshrc):
eval "$(direnv hook zsh)"
Bash (~/.bashrc):
eval "$(direnv hook bash)"
Fish (~/.config/fish/config.fish):
direnv hook fish | source
Place hook at end of file, after other shell extensions.
Basic Usage
echo 'export MY_VAR=value' > .envrc
direnv allow
direnv deny
direnv reload
direnv status
Essential Commands
| Command | Description |
|---|
direnv allow [path] | Allow/trust an .envrc file |
direnv deny [path] | Revoke trust from .envrc |
direnv reload | Force reload current .envrc |
direnv status | Show current direnv state |
direnv edit | Open .envrc in $EDITOR |
direnv prune | Remove expired/revoked .envrc |
direnv version | Show installed version |
Standard Library (stdlib)
direnv includes a powerful stdlib. Use these functions instead of raw exports.
PATH Management
PATH_add bin
PATH_add node_modules/.bin
PATH_add scripts
PATH_add bin scripts tools
PATH_rm "*/.git/bin"
Environment File Loading
dotenv
dotenv .env.local
dotenv_if_exists .env.local
source_up
source_env ../.envrc
source_env_if_exists .envrc.local
Language Layouts
layout python
layout python3
layout python python3.11
layout node
layout ruby
layout go
layout perl
layout pipenv
Nix Integration
use nix
use flake
use flake "nixpkgs#hello"
For better flakes support: nix-direnv
Version Managers
use rbenv
use node 18
use node 18.17.0
use node
Validation
env_vars_required API_KEY DATABASE_URL
watch_file package.json
watch_file config/*.yaml
watch_dir config
if on_git_branch main; then
export DEPLOY_ENV=production
fi
direnv_version 2.32.0
strict_env
Recommended .envrc Template
#!/usr/bin/env bash
direnv_version 2.32.0
dotenv_if_exists
source_env_if_exists .envrc.local
layout node
PATH_add bin
PATH_add scripts
export NODE_ENV=development
export LOG_LEVEL=debug
watch_file package.json
watch_file .tool-versions
Project Structure Best Practice
my-project/
├── .envrc # Development environment (committed)
├── .envrc.local # Local overrides (gitignored)
├── .env # Environment variables (gitignored)
├── .env.example # Template for team members (committed)
└── .direnv/ # Cache directory (gitignored)
.gitignore
# Environment files with secrets
.env
.env.local
.envrc.local
# direnv cache
.direnv/
Layered Configuration
Use parent directory inheritance:
export EDITOR=vim
export PAGER=less
source_up
export API_PORT=3000
layout node
source_up
export FEATURE_FLAG=true
Custom Extensions
Create at ~/.config/direnv/direnvrc:
use_kubernetes() {
local context="${1:-default}"
export KUBECONFIG="${HOME}/.kube/config"
kubectl config use-context "$context" >/dev/null 2>&1
log_status "kubernetes context: $context"
}
use_aws() {
local profile="${1:-default}"
export AWS_PROFILE="$profile"
log_status "aws profile: $profile"
}
use_azure() {
local subscription="$1"
export AZURE_SUBSCRIPTION="$subscription"
az account set --subscription "$subscription" >/dev/null 2>&1
log_status "azure subscription: $subscription"
}
layout_uv() {
if ! has uv; then
log_error "uv not found. Install: curl -LsSf https://astral.sh/uv/install.sh | sh"
return 1
fi
VIRTUAL_ENV="$(pwd)/.venv"
if [[ ! -d "$VIRTUAL_ENV" ]]; then
uv venv
fi
PATH_add "$VIRTUAL_ENV/bin"
export VIRTUAL_ENV
}
Usage in .envrc:
use kubernetes dev-cluster
use aws production
layout uv
Common Patterns
Python with uv
direnv_version 2.32.0
dotenv_if_exists
if has uv; then
layout_uv
else
layout python3
fi
export PYTHONDONTWRITEBYTECODE=1
Node.js Project
direnv_version 2.32.0
dotenv_if_exists
source_env_if_exists .envrc.local
layout node
export NODE_ENV=development
export PORT=3000
watch_file package.json
Kubernetes Development
dotenv_if_exists
use_kubernetes dev-cluster
export KUBECONFIG="${HOME}/.kube/config"
export KUBE_NAMESPACE=my-app
PATH_add bin
Multi-Environment Support
direnv_version 2.32.0
if on_git_branch main; then
ENV=production
elif on_git_branch staging; then
ENV=staging
else
ENV=development
fi
export APP_ENV="$ENV"
dotenv_if_exists ".env.$ENV"
source_env_if_exists ".envrc.$ENV"
log_status "environment: $ENV"
Troubleshooting Quick Reference
direnv status
direnv reload
direnv allow
direnv dump
direnv show_dump
direnv export bash
Common Issues
| Issue | Solution |
|---|
| Environment not loading | Run direnv allow |
| Hook not working | Verify hook in shell config, restart shell |
| Slow loading | Use nix-direnv for Nix; reduce watch_file calls |
| Variables not unloading | Check for export -f functions; restart shell |
IDE Integration
VS Code
Install direnv extension.
JetBrains IDEs
Install direnv integration plugin.
Emacs
(use-package envrc
:hook (after-init . envrc-global-mode))
Vim/Neovim
" Use direnv.vim plugin
Plug 'direnv/direnv.vim'
Security Notes
- Always review .envrc before allowing - direnv executes arbitrary code
- Never commit secrets - Use .env files in .gitignore
- Use .envrc.local for sensitive overrides - Keep local, never commit
- Trust hierarchy - Parent directories can override child settings
References