我的好朋友 Claude
第 122 期|Claude Code|創作者|

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 接住。

難度 ★★時間 35 分鐘用具 Claude Code CLI、.env files 同 Vercel / Railway env management
【編者撰】一個香港人

情境

你 solo dev 或者細 team,部署上 Vercel / Railway / Fly。一個 project 起碼三個 environment:

每個 env 一堆 env var:DATABASE_URLSTRIPE_SECRET_KEYANTHROPIC_API_KEYNEXT_PUBLIC_POSTHOG_KEYFEATURE_FLAGS_*⋯ 加埋成 20–30 個。

過去你嘅做法:

  1. Local 有 .env.local,自己一份
  2. Staging / prod 喺 Vercel dashboard click click 撳入 env var
  3. 加新 feature 加新 env var → 手動入 3 個地方
  4. 同事 onboard → 你喺 Slack 抄畀佢
  5. 某日 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:

呢份 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:

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 signinpnpm env:pull → 即刻跑得起。Vercel 嘅 env 由 Doppler 直接 push(佢有 integration),dashboard 唔再係 source of truth、secret manager 先至係。

變化 3:Monorepo per-package env

apps/webapps/apiapps/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 嗰條入去。

2. vercel env add 撞名唔會幫你覆蓋,會報錯或者開多份 /env-add 假設條 var 係新嘅。但你 re-run 一次、或者個 var 已經存在,CLI 嘅行為同「update」唔一樣——輕則中途 fail,重則同名兩份留喺度,讀到邊個睇彩數。

3. CI 把關需要 token,個 token 本身就係新嘅 secret 你叫 CI 跑 vercel env ls,要畀佢 VERCEL_TOKEN。呢個 token 有讀晒你成個 project env 嘅權限——佢一漏,等於成袋 secret 漏。

4. .env.local 同 secret manager 各講各話 你接咗 1Password / Doppler 之後,本機仲有舊嘅 .env.localpnpm env:pull 覆蓋唔覆蓋、定 append,要睇你點寫——寫得唔清楚就會出現「manager 改咗、你部機冇跟」嘅靜默 drift。

5. Rotate 一條 key,三個 env 唔同步換會中途撞期 /rotate 順序換 dev → staging → prod,但舊 key revoke 同新 key 生效之間有個窗口。prod 仲用緊舊 key 嘅 instance 未 redeploy 完,你就 revoke 咗,真用戶嗰一刻會撞到 401。

呢幾個位,就係「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 —— 諗起就唔合理。

最後提醒:

今個 weekend 抽 35 分鐘搭好呢套。下次同事問你「點解 staging 又死」,你會發現答案唔再係「我夜晚改下」。

文中工具 · 連結

  • 開發者用 — terminal 入面同 Claude pair coding

  • Vercel· 免費 / 付費 plan

    Next.js 部署平台 — 呢個 site 都用緊

睇完想同 Claude 一齊行一次?

撳一撳,就將成段 tutor 指示(連埋成篇文嘅內容)抄入剪貼簿。 貼入 Claude.ai 或 Claude Desktop,佢會用廣東話帶你一步一步行, 每步問你填關鍵位,最後畀返一個專為你情況寫嘅 prompt 帶走。

下期預告 · 相關情境
訂閱本副刊

每週日早上,
一道新菜送到你 inbox。

一篇 use case、一個香港情境、一個跟得到嘅做法。 冇 sell course、冇話你「再唔學就會失業」。

訂閱通道執緊緊
newsletter service 仲未接通。想第一時間收到新文章——
直接 email 我哋寫一句「訂閱」就得。

Email 「訂閱」畀我