Claude-skill-registry direnv
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.
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/direnv" ~/.claude/skills/majiayu000-claude-skill-registry-direnv && rm -rf "$T"
skills/data/direnv/SKILL.mddirenv Skill
This skill provides comprehensive guidance for working with direnv, covering installation, configuration, stdlib functions, and best practices for per-project environment management.
When to Use This Skill
Use this skill when:
- Installing and configuring direnv on macOS or Linux
- Creating or modifying
files for projects.envrc - Setting up per-project environment variables
- Configuring language-specific layouts (Python, Node.js, Ruby, Go, Perl)
- Integrating direnv with Nix or Nix Flakes
- Managing secrets and environment configuration for teams
- Troubleshooting environment loading issues
- Creating custom direnv extensions
Core Concepts
What is direnv?
direnv is a shell extension that loads and unloads environment variables based on the current directory. When you
cd into a directory with a .envrc file, direnv automatically loads the environment. When you leave, it unloads the changes.
Security Model
direnv uses an allowlist-based security approach:
- New or modified
files must be explicitly allowed with.envrcdirenv allow - Prevents automatic execution of untrusted scripts
- Use
to revoke accessdirenv deny
How It Works
- Shell hook intercepts directory changes
- Checks for
file in current or parent directories.envrc - If allowed, executes
in a bash subshell.envrc - Captures exported variables and applies them to current shell
Installation
macOS (Homebrew - Recommended)
brew install direnv
Linux
# Ubuntu/Debian sudo apt install direnv # Fedora sudo dnf install direnv # Arch sudo pacman -S direnv # Binary installer (any system) curl -sfL https://direnv.net/install.sh | bash
Verify Installation
direnv version
Shell Configuration
Add the hook to your shell's config file. This is required for direnv to function.
Zsh (~/.zshrc)
eval "$(direnv hook zsh)"
With Oh My Zsh:
plugins=(... direnv)
Bash (~/.bashrc)
eval "$(direnv hook bash)"
Important: Place after rvm, git-prompt, and other prompt-modifying extensions.
Fish (~/.config/fish/config.fish)
direnv hook fish | source
After Configuration
Restart your shell:
exec $SHELL
.envrc File Basics
Creating an .envrc
# In your project directory touch .envrc # Edit with your preferred editor vim .envrc
Basic Syntax
# Export environment variables export NODE_ENV=development export API_URL=http://localhost:3000 export DATABASE_URL=postgres://localhost/myapp # The export keyword is required for direnv to capture variables
Allowing the .envrc
# Allow current directory direnv allow # Allow specific path direnv allow /path/to/project # Deny/revoke access direnv deny
Standard Library Functions
direnv includes a powerful stdlib. Always prefer stdlib functions over manual exports.
PATH Management
# Prepend to PATH (safer than manual export) PATH_add bin PATH_add node_modules/.bin PATH_add scripts # Add to arbitrary path-like variable path_add PYTHONPATH lib path_add LD_LIBRARY_PATH /opt/lib # Remove from PATH PATH_rm "*/.git/bin"
Environment File Loading
# Load .env file (current directory) dotenv # Load specific file dotenv .env.local # Load only if exists (no error) dotenv_if_exists .env.local dotenv_if_exists .env.${USER} # Source another .envrc source_env ../.envrc source_env /path/to/.envrc # Search upward and source parent .envrc source_up # Source if exists source_env_if_exists .envrc.local
Language Layouts
Node.js:
# Adds node_modules/.bin to PATH layout node
Python:
# Creates virtualenv in .direnv/python-X.X/ layout python # Use specific Python version layout python python3.11 # Shortcut for Python 3 layout python3 # Use Pipenv (reads from Pipfile) layout pipenv
Ruby:
# Sets GEM_HOME to project directory layout ruby
Go:
# Modifies GOPATH and adds bin to PATH layout go
Perl:
# Configures local::lib environment layout perl
Nix Integration
# Load nix-shell environment use nix # With specific file use nix shell.nix # Load from Nix flake use flake # Load specific flake use flake "nixpkgs#hello" use flake ".#devShell"
For better Nix Flakes support, install nix-direnv:
# Provides faster, cached use_flake implementation # https://github.com/nix-community/nix-direnv
Version Managers
# rbenv use rbenv # Node.js (with fuzzy version matching) use node 18 use node 18.17.0 # Reads from .nvmrc if version not specified use node # Julia use julia 1.9
Validation
# Require environment variables (errors if missing) env_vars_required API_KEY DATABASE_URL SECRET_KEY # Enforce minimum direnv version direnv_version 2.32.0 # Check git branch if on_git_branch main; then export DEPLOY_ENV=production fi if on_git_branch develop; then export DEPLOY_ENV=staging fi
File Watching
# Reload when files change watch_file package.json watch_file requirements.txt watch_file .tool-versions watch_file config/*.yaml # Watch entire directory watch_dir config watch_dir migrations
Utility Functions
# Check if command exists if has docker; then export DOCKER_HOST=unix:///var/run/docker.sock fi # Expand relative path to absolute expand_path ./bin # Find file searching upward find_up package.json # Enable strict mode (exit on errors) strict_env # Load prefix (configures CPATH, LD_LIBRARY_PATH, etc.) load_prefix /usr/local/custom # Load remote script with integrity verification source_url https://example.com/script.sh "sha256-HASH..."
Best Practices
Recommended .envrc Template
#!/usr/bin/env bash # .envrc - Project environment configuration # Enforce direnv version for team consistency direnv_version 2.32.0 # Load .env if exists dotenv_if_exists # Load local overrides (not committed to git) source_env_if_exists .envrc.local # Language-specific layout layout node # or: layout python3 # Add project bin directories PATH_add bin PATH_add scripts # Development defaults export NODE_ENV="${NODE_ENV:-development}" export LOG_LEVEL="${LOG_LEVEL:-debug}" # Watch for dependency changes watch_file package.json watch_file .nvmrc
Git Configuration
.gitignore:
# Environment files with secrets .env .env.local .envrc.local # direnv virtualenv/cache .direnv/
Commit to repository:
(base configuration, no secrets).envrc
(template for team members).env.example
Secrets Management
Never commit secrets. Use environment variable fallbacks:
# .envrc (committed) export DATABASE_URL="${DATABASE_URL:-postgres://localhost/dev}" export API_KEY="${API_KEY:-}" # Validate required secrets env_vars_required API_KEY # .envrc.local (gitignored) export DATABASE_URL="postgres://user:secret@prod/app" export API_KEY="actual-secret-key"
Layered Configuration
# ~/projects/.envrc (global dev settings) export EDITOR=vim # ~/projects/api/.envrc source_up export API_PORT=3000 # ~/projects/api/feature/.envrc source_up export FEATURE_FLAG=true
Project Structure
my-project/ ├── .envrc # Base environment (committed) ├── .envrc.local # Local overrides (gitignored) ├── .env # Environment variables (gitignored) ├── .env.example # Template for team (committed) └── .direnv/ # direnv cache (gitignored)
Custom Extensions
Create
~/.config/direnv/direnvrc for custom functions:
#!/usr/bin/env bash # ~/.config/direnv/direnvrc # Custom function: Use specific Kubernetes context 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" } # Custom function: Load from AWS Secrets Manager use_aws_secrets() { local secret_name="$1" local region="${2:-us-east-1}" eval "$(aws secretsmanager get-secret-value \ --secret-id "$secret_name" \ --region "$region" \ --query SecretString \ --output text | jq -r 'to_entries | .[] | "export \(.key)=\"\(.value)\""')" log_status "loaded secrets from: $secret_name" } # Custom function: Use asdf versions from .tool-versions use_asdf() { watch_file .tool-versions source_env "$(asdf direnv local)" }
Usage in
.envrc:
use kubernetes dev-cluster use aws_secrets myapp/dev use asdf
Commands Reference
| Command | Description |
|---|---|
| Allow the current .envrc |
| Revoke .envrc access |
| Force reload environment |
| Show current status |
| Dump current environment |
| Open .envrc in editor |
| Show direnv version |
Troubleshooting
Environment Not Loading
# Check status direnv status # Force reload direnv reload # Re-allow .envrc direnv allow # Check if hook is installed echo $DIRENV_DIR
Shell Hook Issues
- Verify hook is in shell config file
- Ensure it's at the END of the file
- Restart shell completely:
exec $SHELL - Check for errors:
direnv hook zsh
Performance Issues
# Show what's being evaluated direnv show_dump # For Nix, use nix-direnv for caching # https://github.com/nix-community/nix-direnv
Debugging
# Verbose output export DIRENV_LOG_FORMAT='%s' # Show exported variables direnv dump | jq # Test .envrc syntax bash -n .envrc
IDE Integration
VS Code
Install direnv extension for automatic environment loading in integrated terminal.
JetBrains
Install direnv integration plugin.
Neovim
Use direnv.vim or configure with lua.
Common Patterns
Development vs Production
# .envrc export NODE_ENV="${NODE_ENV:-development}" if [[ "$NODE_ENV" == "development" ]]; then export DEBUG=true export LOG_LEVEL=debug else export DEBUG=false export LOG_LEVEL=info fi
Multi-Service Projects (Monorepo)
# root/.envrc export PROJECT_ROOT="$(pwd)" export COMPOSE_PROJECT_NAME=myapp # services/api/.envrc source_up export SERVICE_NAME=api export SERVICE_PORT=3000 # services/web/.envrc source_up export SERVICE_NAME=web export SERVICE_PORT=8080
Docker Integration
# .envrc export COMPOSE_FILE=docker-compose.yml export COMPOSE_PROJECT_NAME="${PWD##*/}" if has docker-compose; then export DOCKER_HOST="${DOCKER_HOST:-unix:///var/run/docker.sock}" fi # Add Docker bin for containers that install CLI tools PATH_add .docker/bin