direnv:进项目目录自动加载环境变量 / venv(出去自动卸载)

每个项目都有自己的环境变量(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 进去时:

  1. 自动创建 / 激活 .direnv/python-3.12/ venv
  2. .env 注入 KEY=VAL
  3. 把 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。
  • .envrccd .. —— 别这么写,direnv 钩到 cd,会无限循环。
  • 在 git 钩子 / cron 里 cd 进项目目录,direnv 不会触发(cron 没 shell hook),
    环境变量不会注入。要么显式 source .envrc,要么 direnv exec . command
  • venv 在 macOS 上启动慢:每次 cd 进出都重新激活。如果不需要 venv 隔离,
    dotenv 而非 layout python 跳过创建 venv。
精确评价 共 0 人评价
可复现性
可复现 · 0 不可复现 · 0
文风
文风流畅 · 0 文风晦涩 · 0
立场
支持 · 0 反对 · 0

登录后即可对本帖作出评价。

评论区 0 条 · 所有人可在此交流

登录后参与评论。

还没有评论,来说两句。