Claude Code 管理 env config:dev / staging / prod 三 environment 同 secret 點分
Solo / 細 team 通常有 dev / staging / prod 三個 env,手動維護 .env 同 Vercel env vars 一定走樣。教你用 Claude Code 將 .env.example 做 single source of truth、自動同步落 Vercel / Railway CLI、drift detection hook 接住。
情境
你 solo dev 或者細 team,部署上 Vercel / Railway / Fly。一個 project 起碼三個 environment:
- dev — 你部 Mac,跑
pnpm dev,用 test API key、local Postgres - staging — 你 push 上
stagingbranch 嗰個 preview,畀客戶睇、QA test - prod —
mainbranch,真實用戶用緊,真 Stripe key、真 DB
每個 env 一堆 env var:DATABASE_URL、STRIPE_SECRET_KEY、ANTHROPIC_API_KEY、NEXT_PUBLIC_POSTHOG_KEY、FEATURE_FLAGS_*⋯ 加埋成 20–30 個。
過去你嘅做法:
- Local 有
.env.local,自己一份 - Staging / prod 喺 Vercel dashboard click click 撳入 env var
- 加新 feature 加新 env var → 手動入 3 個地方
- 同事 onboard → 你喺 Slack 抄畀佢
- 某日 staging build 死,揾咗成晚先發覺:staging 漏咗
RESEND_API_KEY,dev 有、prod 有,淨係 staging 唔知幾時漏咗
問題核心:env var 散落 4–5 個地方(本機 file、Vercel dashboard、Railway dashboard、你個腦、Slack DM),冇 single source of truth,走樣係必然。
Claude Code 反過來幫你:將 .env.example 做 canonical schema,由 Claude 寫 slash command 自動推落 Vercel / Railway CLI,順手加 drift detection hook。下次有人加 env var,三個 environment 自動跟車。
跟住做
1. .env.example 做 single source of truth(5 分鐘)
.env.example 應該係你 project 入面唯一一份「呢個 app 需要乜 env var」嘅 declaration。寫到佢易讀、又拆解得到:
# .env.example
# ============================================
# Database
# ============================================
DATABASE_URL= # required | all envs | postgres connection
DIRECT_URL= # required | all envs | Prisma direct (migrations)
# ============================================
# Auth & API keys
# ============================================
ANTHROPIC_API_KEY= # required | all envs | sk-ant-... | rotate quarterly
STRIPE_SECRET_KEY= # required | dev=sk_test_ | prod=sk_live_
STRIPE_WEBHOOK_SECRET= # required | all envs | from Stripe dashboard
# ============================================
# Feature flags
# ============================================
NEXT_PUBLIC_FEATURE_NEW_CHECKOUT= # optional | dev=true staging=true prod=false
幾個關鍵 convention:
- 每個 var 有 comment:
required/optional、邊個 env 用、format 提示 - 冇 value(永遠空)—— 真 secret 唔好入 git
- 按範疇分組(DB / Auth / Feature flag),唔好亂晒龍
呢份 file commit 入 repo,係你 team 同 Claude 之間嘅約定。所有自動化都跟住佢嚟做。
2. /env-add slash command:三個 env 一齊 propagate(10 分鐘)
加新 env var 嘅阻力越低,走樣越少。喺 .claude/commands/env-add.md 整個 slash command:
# /env-add <var-name>
加一個新 env var 入晒 `.env.example`、`.env.local`、Vercel(dev/staging/prod)
同 Railway。流程:
1. 問我 4 樣嘢:
- Variable name
- Required 定 optional
- Group(DB / Auth / Feature / Other)
- 每個 env 嘅值(dev / staging / prod)
2. 跟住做:
- 喺 `.env.example` 對應 group 加一行帶 comment
- 喺 `.env.local` 加 dev 嗰個值
- 跑 `vercel env add <NAME> development` 入 dev 值
- 跑 `vercel env add <NAME> preview` 入 staging 值
- 跑 `vercel env add <NAME> production` 入 prod 值
- 印出 summary:邊 4 個地方加咗、值頭 4 個 char
3. 唔好 commit `.env.local`。確認 `.gitignore` 入面已經 ignore。
用法:
$ claude /env-add RESEND_API_KEY
Claude 問你齊 4 樣嘢,跟住 4 個地方一次過入。唔再有「dev 加咗、唔記得 prod」。
用 Railway 嘅人,將 vercel env add 換做 railway variables set、加 --environment flag。
3. Sync script:走樣一次過修返(10 分鐘)
.env.example 改咗、但某個 environment 漏咗 var?寫個 scripts/env-sync.ts,由 Claude 幫你生成。
開個 Claude session:
寫 scripts/env-sync.ts 做:
1. Parse .env.example 抽出所有 required var name
2. 跑 `vercel env ls --json` 三次(development / preview / production)
3. Compare 每個 env 缺乜 var
4. 印 table:
VAR_NAME dev staging prod
DATABASE_URL ✓ ✓ ✓
RESEND_API_KEY ✓ ✗ ✓ ← MISSING
5. 如果有 missing,問我每個逐個補上值,跑 `vercel env add`
唔好 hardcode 任何值。淨係 detect + prompt。
跑 pnpm tsx scripts/env-sync.ts:
Checking .env.example against Vercel...
VAR_NAME dev staging prod
DATABASE_URL ✓ ✓ ✓
ANTHROPIC_API_KEY ✓ ✓ ✓
RESEND_API_KEY ✓ ✗ ✓
POSTHOG_KEY ✓ ✓ ✗
2 drift detected. Fix now? (y/n)
3 分鐘解決一個夠你 debug 成晚嘅 staging build。
4. Drift detection hook:CI 把關(10 分鐘)
人會忘記跑 sync script。CI 唔會。喺 .github/workflows/env-check.yml:
name: env-drift-check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
- run: npm i -g vercel@latest
- name: Pull Vercel env list
env:
VERCEL_TOKEN: ${{ '{{' }} secrets.VERCEL_TOKEN {{ '}}' }}
run: vercel env ls --json > /tmp/vercel-env.json
- name: Diff against .env.example
run: pnpm tsx scripts/env-check-ci.ts /tmp/vercel-env.json
有走樣時 env-check-ci.ts 會 exit 1,PR 變紅。順手喺 Claude Code 加個 PreToolUse hook:每次 git push 之前自動本機檢查一次,喺你部機就攔住,唔使等 CI 失敗。
呢一層搭好之後,env 走樣由「定期發生」變成「制度上唔可能 ship 出去」。
變化
變化 1:多過 3 個 environment(preview / staging / canary / prod)
如果你係 growth-stage product,preview branch 可能有十幾條開緊、再加 canary deploy。手動管根本冇可能。
改用 「環境 tier」抽象 —— .env.example 入面 comment 唔再寫 dev/staging/prod,改寫 tier:
STRIPE_SECRET_KEY= # required | tier:test (dev,preview,canary) tier:live (prod)
寫個 scripts/env-policy.ts,由 tier 自動展開到每個實際 environment。新開條 preview branch?跑 pnpm env:provision <branch>,Claude 根據 tier policy 自動入晒。每多一個 environment,你個腦都唔使多記一樣嘢。
變化 2:Team shared secret(1Password / Doppler / Infisical)
人多咗,secret 唔可以「我嘅 Vercel CLI 入面有」就算數 —— 同事 onboard 要等你逐條畀。
接 secret manager:
- 1Password CLI(
op)— 細 team 最平、UI 最熟手 - Doppler — config-as-code、有 access control
- Infisical — open source,自己 host 得到
Claude 寫 scripts/env-pull.ts:
// 偽 code
const secrets = await op.read("op://Engineering/<project>/")
await fs.writeFile(".env.local", formatDotenv(secrets))
新同事 onboard:clone repo → op signin → pnpm env:pull → 即刻跑得起。Vercel 嘅 env 由 Doppler 直接 push(佢有 integration),dashboard 唔再係 source of truth、secret manager 先至係。
變化 3:Monorepo per-package env
apps/web、apps/api、apps/worker 各自要 env。一份 .env.local 亂放喺 root 會出事 —— apps/api 唔應該讀到 NEXT_PUBLIC_*,apps/web 唔應該讀到 STRIPE_SECRET_KEY。
每個 package 自己一份 .env.example:
apps/
├── web/.env.example # NEXT_PUBLIC_*, public API base URL
├── api/.env.example # DATABASE_URL, STRIPE_SECRET_KEY, queue creds
└── worker/.env.example # queue creds, Anthropic key, S3 creds
/env-add slash command 升級:第一個問題加埋「邊個 package?」,根據答案揀對應 .env.example 同 Vercel project(每個 app 喺 Vercel 通常獨立一個 project)。Claude 嘅 CLAUDE.md 寫清楚:「env var 只放對應 package,唔好共用;要分享就喺 build-time inject」。
拆解:點解 work,同邊度會仆街
跟到上面就已經用得。下面呢段係畀想由「跑一次 sync 綠燈」做到「跑足一年都信得過」嘅人——初學者可以跳過,唔影響你跟住做。
env 自動化最唔老實嘅地方係:第一次推靚仔,唔代表第十次同你個 secret 對得齊。呢套流程實際會喺呢幾個位爆,你要預咗:
1. drift check 只睇「有冇個 key」,唔睇「個值啱唔啱」
vercel env ls 印返嘅係 var 名同存唔存在,唔會解密畀你睇個值。所以三欄全部打勾,唔代表 staging 個 DATABASE_URL 真係指住 staging DB——好可能上次手快複製咗 prod 嗰條入去。
- 點解錯:你信咗個綠燈,但 staging 其實打緊 prod DB,跑 QA 嘅時候改到真用戶資料。
- 點救:drift check 加多一層 sanity——例如 prod 嘅 Stripe key 要
sk_live_開頭、其餘 env 要sk_test_;DB host 要 match 個 env 嘅命名。對唔到就標黃,唔好當綠燈。
2. vercel env add 撞名唔會幫你覆蓋,會報錯或者開多份
/env-add 假設條 var 係新嘅。但你 re-run 一次、或者個 var 已經存在,CLI 嘅行為同「update」唔一樣——輕則中途 fail,重則同名兩份留喺度,讀到邊個睇彩數。
- 點解錯:你以為更新咗值,其實舊值仲喺度生效,deploy 之後行為對唔上你改嘅嘢。
- 點救:slash command 入面寫明「先
vercel env rm再 add」,或者明確分「新增」同「更新」兩條路;每次入完即刻env ls確認得返一份。
3. CI 把關需要 token,個 token 本身就係新嘅 secret
你叫 CI 跑 vercel env ls,要畀佢 VERCEL_TOKEN。呢個 token 有讀晒你成個 project env 嘅權限——佢一漏,等於成袋 secret 漏。
- 會出事:token 喺 log、fork PR、或者第三方 action 度漏出去,攻擊者攞到你全部 env 嘅 metadata 同部分 access。
- 點救:用 scope 到最窄嘅 token、設到期日、淨係喺 protected branch 嘅 CI 行;fork 嘅 PR 唔好攞得到 secret。順手定期 rotate 呢個 token,當佢同其他高敏感 key 一樣。
4. .env.local 同 secret manager 各講各話
你接咗 1Password / Doppler 之後,本機仲有舊嘅 .env.local。pnpm env:pull 覆蓋唔覆蓋、定 append,要睇你點寫——寫得唔清楚就會出現「manager 改咗、你部機冇跟」嘅靜默 drift。
- 點解錯:你以為 pull 完就最新,實情 local 殘留咗一條舊 key,debug 半日先發覺問題喺你部機,唔喺 code。
- 點救:
env:pull寫成「整份覆蓋」而唔係「補漏」,pull 之前備份舊份;CLAUDE.md 講明 secret manager 係唯一真相,本機 file 隨時可棄。
5. Rotate 一條 key,三個 env 唔同步換會中途撞期
/rotate 順序換 dev → staging → prod,但舊 key revoke 同新 key 生效之間有個窗口。prod 仲用緊舊 key 嘅 instance 未 redeploy 完,你就 revoke 咗,真用戶嗰一刻會撞到 401。
- 會出事:rotate 嘅幾分鐘內,prod 間歇性 auth 失敗,你以為換 key 好安全,結果整咗段 downtime。
- 點救:用「先加新 key、deploy 核實食到、先 revoke 舊 key」嘅 overlap 次序,唔好 revoke 行先;高敏感 key 揀低峰時間 rotate。
呢幾個位,就係「sync 綠燈」同「一年都對得齊」之間嘅距離。
一個心態
Env config 走樣唔係紀律問題,係 system design 問題。 靠人類記性同 Slack 提醒一定輸;靠 single source of truth + 自動 propagate + CI 檢查就贏。
最反直覺嘅一點:dashboard 唔應該係 source of truth。Vercel / Railway 嘅 UI 好順手,但每次喺度撳一下就係一次潛在走樣。.env.example(或者 secret manager)入 git、入 PR review,先至有歷史、有 review、有得 rollback。
換個角度睇:env config 同 schema migration 一樣,係 infrastructure-as-code 嘅一部分。冇人會用手撳 migration,但好多人用手撳 env var —— 諗起就唔合理。
最後提醒:
- ✅
.env.example永遠跟 codebase 同步 commit。加新 var 嗰個 PR 入面同時更新。 - ⚠️ 真 secret 永遠唔好入
.env.example,連 placeholder 都唔好寫真 key 開頭。 - 🔁 每季 rotate 一次高敏感 key(Stripe / DB / Anthropic)。叫 Claude 寫條
/rotate <key>slash command,三個 env 順序換、舊 key revoke、deploy 核實,半個鐘搞掂。
今個 weekend 抽 35 分鐘搭好呢套。下次同事問你「點解 staging 又死」,你會發現答案唔再係「我夜晚改下」。
文中工具 · 連結
- Claude Code CLI· 付費
開發者用 — terminal 入面同 Claude pair coding
- Vercel· 免費 / 付費 plan
Next.js 部署平台 — 呢個 site 都用緊
睇完想同 Claude 一齊行一次?
撳一撳,就將成段 tutor 指示(連埋成篇文嘅內容)抄入剪貼簿。 貼入 Claude.ai 或 Claude Desktop,佢會用廣東話帶你一步一步行, 每步問你填關鍵位,最後畀返一個專為你情況寫嘅 prompt 帶走。
- 創作者 · 30 分鐘
Claude Code 喺新機 30 分鐘 onboarding:dotfiles、API key vault、project bootstrap script
新 Mac 開箱 / 入新公司 / 換機重新 setup Claude Code + 你 project 要幾個鐘?教用 Claude Code 自己寫個 onboarding script:dotfiles、API key 用 keychain 收好、bootstrap script clone + install + configure,30 分鐘新機開工。
- 創作者 · 30 分鐘
CLAUDE.md 寫得啱:Claude Code 自動跟你 project 規矩,唔再次次解釋
Claude Code 自動讀 CLAUDE.md 做背景,但寫到似 README 等於白寫。教你 4 個必備 section、點驗收、點逐步改善,由今日開始 Claude 跟你 project 規矩跑。
- 創作者 · 45 分鐘
Claude Code 做 security review:每個 PR 揾 OWASP top 10 + secrets exposure + permission bypass
Solo dev / 細 team 冇 security engineer,但又唔想 ship 出去先見報。教用 Claude Code 做 4 layer review:OWASP top 10、secrets exposure、permission bypass、CVE 掃描。/security-review slash command + headless mode 入 GitHub Actions,每個 PR 自動跑。