第11章:環境変数設計:設定は外へ🧩
この章はひとことで言うと、**「同じイメージを、設定だけ変えて dev / prod で使い回せる状態にする」**回です😎✨ (コードをいじらず、環境変数で挙動を変えられるようにするやつ!)
1) そもそも「設定を外へ」って何?🤔📦
アプリには、ざっくり2種類の情報があります👇
- コード(ロジック):Gitで管理する、みんな同じ
- 設定(Config):環境ごとに変わる(ローカル/本番で違う)
この「設定」を **環境変数(env)**として外から渡すのが、クラウド&コンテナの基本作法です💡 「設定は環境に置け」が有名な考え方としてまとまっています。(12Factor)
2) 何を環境変数にする?しない?🧠✅
環境変数にするもの(例)🧩
PORT(待ち受けポート)PUBLIC_BASE_URL(自分の公開URL)LOG_LEVEL(ログの出し方)CORS_ORIGIN(許可するフロントURL)FEATURE_X=true(機能フラグ)
環境変数に「しがちだけど注意」⚠️
- APIキー / DBパスワードなどの秘密情報(Secrets) → “環境変数に入れる運用”もできますが、**次章(Secrets)で「安全に扱う正攻法」**をやります🔑😇 Cloud Runも「シークレットを環境変数として公開する」公式導線があります。(Google Cloud Documentation)
3) 命名ルール(迷子防止)🏷️🧭
おすすめはこのへん👇(迷子になりにくい)
-
大文字+アンダースコア:
LOG_LEVEL,PUBLIC_BASE_URL -
意味がぶれない名前:
BASE_URLよりPUBLIC_BASE_URL -
塊(カテゴリ)で揃える:
DB_HOST,DB_PORT,DB_NAMEAUTH_JWT_...MAIL_...
そして超大事👇
**「コードのあちこちで process.env.X を直接読まない」**🙅♂️
→ “設定読み取り専用の場所(config)” を1個作って、そこだけ見るのが安全です🧯✨
4) env設計のキモ:「文字列」問題と「起動時チェック」🧪🧱
環境変数は 全部文字列です😵💫
だから PORT=3000 も "3000"。
ここで差が出ます👇
- ✅ 起動時にまとめて読み取り&検証(足りない/壊れてるなら即エラー)
- ❌ リクエスト中にその場で読む(壊れてても気づくのが遅い)
5) ハンズオン:config.ts を作って「設定を外へ」する🛠️✨
以下は **TypeScript向けの“鉄板テンプレ”**です(コピペOK)😋
5-1) .env.example を用意する📄✨
プロジェクト直下に作る:
## .env.example(これはGitに入れる)
PORT=3000
PUBLIC_BASE_URL=http://localhost:3000
LOG_LEVEL=info
CORS_ORIGIN=http://localhost:5173
そしてローカル用は .env.local とかにして Gitに入れない🙈
## .env 系は基本コミットしない(例外で .env.example だけOK)
.env*
!.env.example
5-2) Nodeの標準機能で .env を読む(dotenv無しでもOK)📦✨
最近のNodeは .env を読む仕組みが標準で入っています。
CLIなら --env-file / --env-file-if-exists が使えます。(Node.js)
さらに コードから読み込むなら process.loadEnvFile() が使えます。(Node.js)
src/bootstrap-env.ts(最初に必ず実行される場所)を作って👇
// src/bootstrap-env.ts
import process from "node:process";
if (process.env.NODE_ENV !== "production") {
try {
// 例:ローカル専用の env ファイル
process.loadEnvFile(".env.local");
} catch {
// ファイルが無い環境(CI等)では無視でOK
}
}
ポイント💡:本番では env ファイルが無いのが普通なので、
try/catchで“無くても死なない”ようにします🙂
5-3) src/config.ts(設定の唯一の入口)を作る🚪🧩
// src/config.ts
import process from "node:process";
type LogLevel = "debug" | "info" | "warn" | "error";
function mustGet(name: string): string {
const v = process.env[name];
if (!v) throw new Error(`Missing env: ${name}`);
return v;
}
function getNumber(name: string, fallback?: number): number {
const v = process.env[name];
if (v == null || v === "") {
if (fallback != null) return fallback;
throw new Error(`Missing env: ${name}`);
}
const n = Number(v);
if (!Number.isFinite(n)) throw new Error(`Invalid number env: ${name}=${v}`);
return n;
}
export const config = {
nodeEnv: (process.env.NODE_ENV ?? "development") as
| "development"
| "production"
| "test",
port: getNumber("PORT", 3000),
publicBaseUrl: mustGet("PUBLIC_BASE_URL"),
logLevel: (process.env.LOG_LEVEL ?? "info") as LogLevel,
corsOrigin: process.env.CORS_ORIGIN ?? "",
} as const;
5-4) エントリポイントで “最初にenv → 次にconfig” の順にする🥇
src/index.ts みたいな起動ファイルで👇
import "./bootstrap-env";
import { config } from "./config";
import express from "express";
const app = express();
app.get("/healthz", (_, res) => {
res.json({ ok: true, env: config.nodeEnv });
});
app.listen(config.port, "0.0.0.0", () => {
console.log(`[start] ${config.publicBaseUrl} (port=${config.port})`);
});
これで「設定を外から変えられるアプリ」完成!🎉🎉
6) ローカルでの渡し方(Docker / Compose)🐳🔌
6-1) docker run で渡す(env-file)📄➡️🐳
docker run --rm -p 8080:3000 --env-file .env.local your-image:dev
6-2) docker compose で渡す(env_file / environment)🧱✨
Composeは env_file でファイルから注入できます。(Docker Documentation)
services:
api:
build: .
ports:
- "8080:3000"
env_file:
- .env.local
environment:
LOG_LEVEL: "debug"
小技😋:
environmentは上書きに使うと便利!
7) 本番での渡し方(Cloud Runを例に)☁️🚀
Cloud Runは サービス設定として環境変数を登録して、コンテナ起動時に注入します。(Google Cloud Documentation)
CLIだとだいたいこんなノリ👇(雰囲気でOK)
gcloud run services update SERVICE_NAME ^
--set-env-vars PORT=8080,LOG_LEVEL=info,PUBLIC_BASE_URL=https://example.com
そして秘密情報は Secret Manager連携が王道で、Cloud Run公式も「シークレットを環境変数として公開」する手順を用意しています。(Google Cloud Documentation) (ここは次章でガッツリやります🔑🔥)
8) ありがち事故トップ5 😵💫🧯
① 変数名ミス(PUBLIC_BASEURL とか)😭
→ mustGet() で 起動時に即死させるのが正解👍
② PORT を number にしてない🤯
→ getNumber() で変換&検証!
③ 「本番で .env を読み込む」前提にしちゃう🙅♂️
→ 本番は “環境が注入する” が基本。--env-file-if-exists や try/catch が効く!(Node.js)
④ Dockerfile の ARG で秘密を渡す💣
ARG はイメージ履歴などから漏れる可能性があり危険、という注意が繰り返しされています。(Microsoft for Developers)
→ ビルド時の秘密は Docker BuildKit の “build secrets” が公式ルートです。(Docker Documentation)
⑤ どこでも process.env を直読みしてグチャる🍝
→ config.ts 以外は触らないルールで一気に治ります😎✨
9) VS Codeデバッグで環境変数を渡す(超便利)🐞✨
デバッグ構成 launch.json では env や envFile が使えます。(Visual Studio Code)
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "API Debug",
"program": "${workspaceFolder}/dist/index.js",
"envFile": "${workspaceFolder}/.env.local",
"env": {
"LOG_LEVEL": "debug"
}
}
]
}
10) この章のまとめ📌✨
- 同じイメージを、設定だけ変えて動かすために env を設計する🧩
config.tsを作って 起動時に検証する🧪- ローカルは
.env.local、本番は Cloud Run 等の 設定画面/CLIで注入☁️ - 秘密情報は次章で Secret Manager/安全な渡し方へ🔑🔥
コピペ用:AIプロンプト集🤖📋✨
- 「このNode/TSアプリで環境変数に外出しすべき設定値を列挙して。命名案も付けて」
- 「
config.tsで required/optional を整理して、起動時に落ちるように実装して」 - 「この
.env.exampleを見て、足りない設定項目の候補を提案して」 - 「Cloud Runで env を設定する時の“ありがちミス”を10個、原因と対策つきで」
次の 第12章(Secrets超入門)🔑🙅 は、ここで触れた「秘密情報をどう安全に扱うか」を Docker/CI/Cloud Run ぜんぶ繋げてやります。 続きも同じテンションで作れるよ〜😆🔥