每个项目都有自己的环境变量(API key / DB URL / venv 路径 / Node 版本)。
手动 source .env 麻烦且容易跨项目污染。direnv 让 shell 在 cd 进项目
目录时自动加载 .envrc,离开时自动卸载。
安装
sudo apt install -y direnv
# 或 brew install direnv
direnv version
集成 shell
# bash
echo 'eval "$(direnv hook bash)"' >> ~/.bashrc
# zsh
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
# fish
echo 'direnv hook fish | source' >> ~/.config/fish/config.fish
重新加载 shell。
第一次用
cd ~/projects/myapp
echo 'export DATABASE_URL=postgresql://localhost/myapp' > .envrc
echo 'export STRIPE_KEY=sk_test_xxxxx' >> .envrc
echo 'export FLASK_DEBUG=1' >> .envrc
# direnv 提示:
# direnv: error /home/me/projects/myapp/.envrc is blocked.
# Run `direnv allow` to approve its content
direnv allow
# 之后每次 cd 进来:
# direnv: loading ~/projects/myapp/.envrc
# direnv: export +DATABASE_URL +STRIPE_KEY +FLASK_DEBUG
env | grep DATABASE_URL
# DATABASE_URL=postgresql://localhost/myapp
cd 离开目录:
cd ..
# direnv: unloading
env | grep DATABASE_URL # 没了
allow 机制
direnv 不会自动加载未授权的 .envrc(防止 git clone 别人仓库就执行
恶意代码)。每次 .envrc 内容变了都要重新 direnv allow。
direnv allow . # 授权
direnv deny . # 撤销
direnv reload # 强制重新加载
stdlib:常用 helper
direnv 自带一组 helper 函数:
# .envrc
use python 3.12 # 自动用 pyenv 切到 3.12
layout python python3.12 # 创建 .direnv/python-3.12 venv 并激活
dotenv # 自动读 .env 文件里的 KEY=VAL
PATH_add bin # 把项目 bin/ 加进 PATH(自动相对路径)
source_up # 也加载上一层目录的 .envrc
完整:direnv stdlib | less。
真实例子:Python 项目
# .envrc
layout python python3.12
dotenv
# 加 project 本地 bin 到 PATH
PATH_add bin
PATH_add scripts
# Django settings
export DJANGO_SETTINGS_MODULE=myapp.settings.dev
export DJANGO_SECRET_KEY=$(cat .secret-key 2>/dev/null || echo 'dev-key')
cd 进去时:
- 自动创建 / 激活
.direnv/python-3.12/venv - 读
.env注入 KEY=VAL - 把 bin/ 加进 PATH
pip install ... 装的依赖就在这个 venv 里,不污染全局。
Node 项目
# .envrc
use node 20 # 配合 nvm / fnm / asdf 切版本
PATH_add node_modules/.bin # 让 npx 命令直接 in PATH
Rust 项目
# .envrc
PATH_add target/debug
PATH_add target/release
多版本工具切换(asdf / mise)
# .envrc
use mise # 让 direnv 触发 mise 的环境
mise 会按 .tool-versions 自动切 Node/Python/Go/etc 版本,
direnv 让这套在 cd 时自动应用。
.env vs .envrc
| 文件 | 作用 |
|---|---|
.envrc |
direnv 配置(bash 脚本,可写逻辑) |
.env |
简单 KEY=VAL 列表,被 dotenv 读 |
.envrc.local |
个人覆盖(建议加 .gitignore) |
# .envrc
dotenv .env
dotenv_if_exists .env.local # 个人覆盖
source_env_if_exists .envrc.local
与 IDE 集成
VSCode 不会自动用 direnv。装插件 mkhl.direnv 让 VSCode 在打开项目
时执行 .envrc 并把变量塞给 terminal / debugger。
JetBrains 系也有 direnv 插件。
安全注意
.envrc 是 bash 脚本,能执行任意命令。git clone 后 direnv 不会自动 load,
必须 direnv allow——这是 feature。
但养成习惯:clone 完之后 先 cat .envrc 看一眼 再 allow。
某些恶意 .envrc 在你 allow 时执行 rm -rf / 你没法找回来。
调试
direnv status # 当前目录的 direnv 状态
direnv exec . env # 看 direnv 实际注入了哪些变量
DIRENV_LOG_FORMAT=... # 让加载日志更详细
踩过的坑
- 在 docker / SSH session 里没生效:
direnv hook没运行,rc 文件不被
source。bash -ic '...'可以强制 interactive。 .envrc里cd ..—— 别这么写,direnv 钩到 cd,会无限循环。- 在 git 钩子 / cron 里 cd 进项目目录,direnv 不会触发(cron 没 shell hook),
环境变量不会注入。要么显式source .envrc,要么direnv exec . command。 - venv 在 macOS 上启动慢:每次 cd 进出都重新激活。如果不需要 venv 隔离,
用dotenv而非layout python跳过创建 venv。
登录后参与评论。