アプリケーション開発において、データベース接続情報やAPIキーなどの設定値をどのように管理するかは、セキュリティと保守性に直結する重要な課題です。コード内にハードコードされた設定値は、本番環境と開発環境の切り替えを困難にし、認証情報の漏洩リスクを高めます。

The Twelve-Factor Appの第3原則「Config」は、設定をコードから分離し、環境変数に格納することを推奨しています。Node.jsでは、dotenvパッケージを使用することで、この原則に沿った設定管理を簡潔に実装できます。

本記事では、dotenvの基本的な使い方から環境別設定の管理、機密情報の安全な取り扱い、CI/CD環境での設定まで、実践的な環境変数管理のノウハウを解説します。

実行環境

項目 バージョン
Node.js 20.x LTS以上
npm 10.x以上
dotenv 17.x
OS Windows/macOS/Linux

前提条件

  • JavaScriptの基礎文法を理解していること
  • Node.jsの基本的なAPIを理解していること
  • コマンドラインでの操作ができること

バージョン確認コマンドは以下のとおりです。

1
2
3
4
5
node -v
# v20.18.0

npm -v
# 10.8.2

12-factor appとは何か

12-factor appは、Heroku社のエンジニアによって提唱されたモダンなクラウドアプリケーション設計のベストプラクティスです。SaaSアプリケーションを構築するための12の原則を定義しており、環境変数管理に関連するのは第3原則「Config(設定)」です。

第3原則: 設定をコードから分離する

12-factor appは、設定を環境変数に格納することを推奨します。この原則に従うことで、以下のメリットが得られます。

メリット 説明
コードとの分離 設定値の変更がコードの変更を必要としない
環境の独立性 同一コードベースを開発・ステージング・本番で使用可能
セキュリティ 認証情報がソースコードに含まれない
スケーラビリティ デプロイごとに独立した設定管理が可能

以下の図は、12-factor appにおける設定管理のアーキテクチャを示します。

flowchart LR
    subgraph "ソースコード"
        APP[アプリケーション]
    end
    
    subgraph "環境変数"
        DEV[開発環境<br>.env]
        STAGING[ステージング<br>.env.staging]
        PROD[本番環境<br>システム環境変数]
    end
    
    APP --> |process.env| DEV
    APP --> |process.env| STAGING
    APP --> |process.env| PROD

設定と定数の違い

12-factor appで言う「設定」は、デプロイごとに変わる可能性のある値を指します。一方、コード内部のルーティング設定やフレームワークの設定など、デプロイ間で変わらない値は「設定」に含まれません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 環境変数で管理すべき設定(デプロイごとに変わる)
const databaseUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;
const port = process.env.PORT;

// コード内で管理すべき定数(デプロイ間で不変)
const MAX_RETRY_COUNT = 3;
const DEFAULT_TIMEOUT = 5000;
const ROUTES = {
  users: '/api/users',
  posts: '/api/posts'
};

dotenvパッケージの導入

dotenvは、.envファイルから環境変数を読み込み、process.envに設定するシンプルなパッケージです。週間ダウンロード数4600万以上を誇り、Node.jsエコシステムで最も広く使われている設定管理ツールです。

インストール

1
npm install dotenv

基本的な使い方

プロジェクトルートに.envファイルを作成し、環境変数を定義します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# .env
NODE_ENV=development
PORT=3000

# データベース設定
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=myuser
DATABASE_PASSWORD=mypassword
DATABASE_NAME=myapp_dev

# 外部API
API_KEY=your-api-key-here
API_SECRET=your-api-secret-here

アプリケーションの最初期にdotenvを読み込みます。

1
2
3
4
5
// CommonJS
require('dotenv').config();

// ES Modules
import 'dotenv/config';

読み込み後は、process.envから環境変数にアクセスできます。

1
2
3
4
5
6
7
8
// src/index.js
import 'dotenv/config';

const port = process.env.PORT || 3000;
const dbHost = process.env.DATABASE_HOST;

console.log(`Server starting on port ${port}`);
console.log(`Connecting to database at ${dbHost}`);

ES Modulesでの注意点

ES Modulesでは、import文がモジュール本文より先に評価されます。そのため、dotenvの読み込みは別ファイルで行うか、import 'dotenv/config'構文を使用します。

1
2
3
4
5
6
7
8
// 誤った使い方(環境変数が読み込まれる前にモジュールが評価される)
import dotenv from 'dotenv';
dotenv.config();
import { createClient } from './database.js'; // process.env.DATABASE_URLが未定義

// 正しい使い方(dotenv/configを最初にimport)
import 'dotenv/config';
import { createClient } from './database.js'; // process.env.DATABASE_URLが利用可能

dotenvの設定オプション

dotenv.config()には様々なオプションを渡すことができます。

pathオプション

デフォルトでは、カレントディレクトリの.envファイルを読み込みます。別のパスを指定するにはpathオプションを使用します。

1
2
3
4
5
6
7
import dotenv from 'dotenv';

// カスタムパスを指定
dotenv.config({ path: '/custom/path/.env' });

// 複数ファイルを順番に読み込む(先に読み込んだ値が優先)
dotenv.config({ path: ['.env.local', '.env'] });

overrideオプション

デフォルトでは、既に設定されている環境変数は上書きされません。overrideオプションをtrueにすると、.envファイルの値で上書きします。

1
2
3
4
import dotenv from 'dotenv';

// 既存の環境変数を上書きする
dotenv.config({ override: true });

debugオプション

環境変数が正しく読み込まれているか確認するには、debugオプションを有効にします。

1
2
3
4
import dotenv from 'dotenv';

// デバッグ出力を有効化
dotenv.config({ debug: true });

encodingオプション

デフォルトはUTF-8ですが、他のエンコーディングも指定できます。

1
2
3
import dotenv from 'dotenv';

dotenv.config({ encoding: 'latin1' });

.envファイルの構文

dotenvは柔軟な構文をサポートしています。

基本構文

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# キー=値の形式
SIMPLE_VALUE=hello

# 空白はトリムされる
TRIMMED_VALUE=  hello world  
# 結果: "hello world"

# 空の値は空文字列になる
EMPTY_VALUE=
# 結果: ""

クォーテーション

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# シングルクォート(特殊文字をエスケープしない)
SINGLE_QUOTED='hello $USER'
# 結果: "hello $USER"(変数展開されない)

# ダブルクォート(改行文字を解釈)
DOUBLE_QUOTED="hello\nworld"
# 結果: "hello
# world"

# 空白を保持したい場合はクォートを使用
PRESERVE_WHITESPACE="  hello world  "
# 結果: "  hello world  "

複数行の値

秘密鍵などの複数行の値もサポートされています。

1
2
3
4
5
6
7
8
# ダブルクォートで囲むと複数行を定義可能
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA...
...
-----END RSA PRIVATE KEY-----"

# またはエスケープ文字を使用
PRIVATE_KEY_ESCAPED="-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA...\n-----END RSA PRIVATE KEY-----"

コメント

1
2
3
4
5
6
7
8
9
# 行頭の#はコメント
# This is a comment
DATABASE_URL=postgres://localhost/mydb

# 値の後ろにもコメントを書ける
API_KEY=abc123 # This is the production key

# 値に#を含める場合はクォートで囲む
SPECIAL_VALUE="value#with#hash"

環境別設定の管理

開発・ステージング・本番といった複数の環境で異なる設定を管理する方法を解説します。

ファイル構成

環境ごとに.envファイルを分けて管理します。

1
2
3
4
5
6
7
8
project/
├── .env                 # 共通設定(デフォルト値)
├── .env.development     # 開発環境
├── .env.staging         # ステージング環境
├── .env.production      # 本番環境
├── .env.test            # テスト環境
├── .env.local           # ローカル個人設定(.gitignore対象)
└── .env.example         # テンプレート(リポジトリにコミット)

環境に応じたファイル読み込み

NODE_ENV環境変数を使って、適切なファイルを読み込みます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// src/config/env.js
import dotenv from 'dotenv';
import path from 'path';

const env = process.env.NODE_ENV || 'development';

// 環境固有のファイルを先に読み込み、次に共通ファイルを読み込む
// 先に読み込んだ値が優先される
dotenv.config({ 
  path: [
    path.resolve(process.cwd(), `.env.${env}.local`),
    path.resolve(process.cwd(), `.env.${env}`),
    path.resolve(process.cwd(), '.env.local'),
    path.resolve(process.cwd(), '.env'),
  ]
});

export const config = {
  env,
  port: parseInt(process.env.PORT || '3000', 10),
  database: {
    host: process.env.DATABASE_HOST,
    port: parseInt(process.env.DATABASE_PORT || '5432', 10),
    user: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    name: process.env.DATABASE_NAME,
  },
  api: {
    key: process.env.API_KEY,
    secret: process.env.API_SECRET,
  },
};

読み込み優先順位

環境変数の値は以下の優先順位で決定されます(上が最優先)。

  1. システム環境変数: OSレベルで設定された環境変数
  2. .env.{environment}.local: 環境固有のローカル設定
  3. .env.{environment}: 環境固有の設定
  4. .env.local: ローカル共通設定
  5. .env: 共通デフォルト設定

以下の図は、この優先順位を視覚的に示しています。

flowchart TB
    SYS["システム環境変数<br>(最優先)"]
    LOCAL_ENV[".env.production.local"]
    ENV[".env.production"]
    LOCAL[".env.local"]
    DEFAULT[".env<br>(最低優先)"]
    
    SYS --> LOCAL_ENV
    LOCAL_ENV --> ENV
    ENV --> LOCAL
    LOCAL --> DEFAULT

実際の設定例

.env(共通デフォルト)

1
2
3
4
5
6
7
8
9
# .env
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug

# デフォルトのデータベース設定
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_NAME=myapp_dev

.env.development(開発環境)

1
2
3
4
# .env.development
DATABASE_USER=dev_user
DATABASE_PASSWORD=dev_password
DEBUG=true

.env.production(本番環境)

1
2
3
4
5
6
7
# .env.production
NODE_ENV=production
PORT=8080
LOG_LEVEL=warn
DEBUG=false

# 本番DBは環境変数から取得(このファイルには記載しない)

.env.example(テンプレート)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# .env.example - 必要な環境変数のテンプレート
# このファイルをコピーして.envを作成してください

NODE_ENV=development
PORT=3000
LOG_LEVEL=debug

# データベース設定
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_USER=your_username
DATABASE_PASSWORD=your_password
DATABASE_NAME=your_database

# 外部API設定
API_KEY=your_api_key
API_SECRET=your_api_secret

機密情報の安全な管理

環境変数には認証情報や秘密鍵など、センシティブな情報が含まれます。これらを安全に管理するためのベストプラクティスを解説します。

.gitignoreによる除外

機密情報を含むファイルは必ずバージョン管理から除外します。

# .gitignore

# 環境変数ファイル
.env
.env.local
.env.*.local
.env.development
.env.staging
.env.production

# 例外: テンプレートファイルはコミット
!.env.example

機密情報のチェック

コミット前に機密情報が含まれていないか確認するGit Hookを設定します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/bash
# .husky/pre-commit

# .envファイルがステージングされていないかチェック
if git diff --cached --name-only | grep -E '\.env($|\.)' | grep -v '\.example$'; then
  echo "Error: .env file is being committed!"
  echo "Please remove it from staging with: git reset HEAD <file>"
  exit 1
fi

# 機密情報のパターンチェック
PATTERNS=(
  "password.*=.*['\"]?.{8,}"
  "secret.*=.*['\"]?.{8,}"
  "api.?key.*=.*['\"]?.{8,}"
  "token.*=.*['\"]?.{8,}"
)

for pattern in "${PATTERNS[@]}"; do
  if git diff --cached | grep -iE "$pattern"; then
    echo "Warning: Possible secret detected in staged changes"
    echo "Pattern matched: $pattern"
    exit 1
  fi
done

必須環境変数の検証

アプリケーション起動時に、必須の環境変数が設定されているかを検証します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/config/validate.js
export function validateEnv() {
  const required = [
    'DATABASE_HOST',
    'DATABASE_PORT',
    'DATABASE_USER',
    'DATABASE_PASSWORD',
    'DATABASE_NAME',
  ];

  const missing = required.filter((key) => !process.env[key]);

  if (missing.length > 0) {
    throw new Error(
      `Missing required environment variables:\n${missing.map((key) => `  - ${key}`).join('\n')}`
    );
  }

  // 型の検証
  const portNumber = parseInt(process.env.DATABASE_PORT, 10);
  if (isNaN(portNumber) || portNumber < 1 || portNumber > 65535) {
    throw new Error('DATABASE_PORT must be a valid port number (1-65535)');
  }
}
1
2
3
4
5
6
7
8
9
// src/index.js
import 'dotenv/config';
import { validateEnv } from './config/validate.js';

// アプリケーション起動前に検証
validateEnv();

// アプリケーション起動処理
console.log('All environment variables are valid');

Zodを使った型安全な検証

より堅牢な検証には、Zodスキーマを使用します。

1
npm install zod
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// src/config/schema.js
import { z } from 'zod';

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'staging', 'production', 'test']).default('development'),
  PORT: z.string().transform(Number).pipe(z.number().min(1).max(65535)).default('3000'),
  
  DATABASE_HOST: z.string().min(1),
  DATABASE_PORT: z.string().transform(Number).pipe(z.number().min(1).max(65535)).default('5432'),
  DATABASE_USER: z.string().min(1),
  DATABASE_PASSWORD: z.string().min(1),
  DATABASE_NAME: z.string().min(1),
  
  API_KEY: z.string().min(1).optional(),
  API_SECRET: z.string().min(1).optional(),
  
  LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});

export type Env = z.infer<typeof envSchema>;

export function parseEnv(): Env {
  const result = envSchema.safeParse(process.env);
  
  if (!result.success) {
    console.error('Environment validation failed:');
    result.error.issues.forEach((issue) => {
      console.error(`  - ${issue.path.join('.')}: ${issue.message}`);
    });
    process.exit(1);
  }
  
  return result.data;
}
1
2
3
4
5
6
7
// src/index.js
import 'dotenv/config';
import { parseEnv } from './config/schema.js';

const env = parseEnv();

console.log(`Starting server in ${env.NODE_ENV} mode on port ${env.PORT}`);

プリロード方式の活用

dotenvをコード内でrequire/importせず、Node.jsの起動オプションで読み込む方法があります。

-r オプションによるプリロード

1
2
3
4
5
6
7
8
# CommonJS
node -r dotenv/config src/index.js

# カスタムパスを指定
node -r dotenv/config src/index.js dotenv_config_path=/custom/.env

# デバッグモード
node -r dotenv/config src/index.js dotenv_config_debug=true

package.jsonスクリプトでの活用

1
2
3
4
5
6
7
8
{
  "scripts": {
    "start": "node -r dotenv/config src/index.js",
    "dev": "node -r dotenv/config --watch src/index.js",
    "start:prod": "NODE_ENV=production node src/index.js",
    "test": "node -r dotenv/config --test src/**/*.test.js"
  }
}

環境変数での設定

プリロード時の設定はDOTENV_CONFIG_*環境変数でも指定できます。

1
DOTENV_CONFIG_PATH=/custom/.env DOTENV_CONFIG_DEBUG=true node -r dotenv/config src/index.js

CI/CD環境での環境変数設定

本番環境やCI/CDパイプラインでは、.envファイルを使わず、プラットフォームの機能で環境変数を設定します。

GitHub Actionsでの設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

env:
  NODE_ENV: production

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test
        env:
          DATABASE_HOST: localhost
          DATABASE_PORT: 5432
          DATABASE_USER: test_user
          DATABASE_PASSWORD: ${{ secrets.TEST_DATABASE_PASSWORD }}
          DATABASE_NAME: test_db
      
      - name: Build
        run: npm run build
      
      - name: Deploy
        run: npm run deploy
        env:
          API_KEY: ${{ secrets.API_KEY }}
          API_SECRET: ${{ secrets.API_SECRET }}
          DATABASE_URL: ${{ secrets.DATABASE_URL }}

GitHub Secretsの設定

機密情報はGitHub Secretsに登録します。

  1. リポジトリの「Settings」を開く
  2. 「Secrets and variables」→「Actions」を選択
  3. 「New repository secret」をクリック
  4. 名前と値を入力して保存

Dockerでの環境変数設定

Dockerでは、.envファイルを使うか、環境変数を直接渡します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Dockerfile
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

# 環境変数はビルド時に設定しない(実行時に注入)
EXPOSE 3000

CMD ["node", "src/index.js"]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# compose.yaml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - PORT=3000
    env_file:
      - .env.production
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt
1
2
# 直接環境変数を渡して起動
docker run -e NODE_ENV=production -e DATABASE_URL=postgres://... myapp

Vercelでの環境変数設定

1
2
3
4
5
6
# Vercel CLIで設定
vercel env add DATABASE_URL production
vercel env add API_KEY production

# ローカル開発用に環境変数を取得
vercel env pull .env.local

AWS ECS/Fargateでの設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
  "containerDefinitions": [
    {
      "name": "app",
      "image": "myapp:latest",
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        },
        {
          "name": "PORT",
          "value": "3000"
        }
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:myapp/database-url"
        },
        {
          "name": "API_KEY",
          "valueFrom": "arn:aws:secretsmanager:region:account:secret:myapp/api-key"
        }
      ]
    }
  ]
}

dotenvxによる高度な機能

dotenvの作者が開発したdotenvxは、より高度な機能を提供します。

dotenvxのインストール

1
npm install @dotenvx/dotenvx --save-dev

.envファイルの暗号化

1
2
3
4
5
6
7
8
# .envファイルを暗号化
npx dotenvx encrypt

# 暗号化されたファイルから実行
npx dotenvx run -- node src/index.js

# 復号化
npx dotenvx decrypt

変数展開

1
2
3
4
5
# .env
BASE_URL=https://api.example.com
API_ENDPOINT=${BASE_URL}/v1/users

# 結果: API_ENDPOINT = "https://api.example.com/v1/users"

複数環境の管理

1
2
3
4
5
# 環境を指定して実行
npx dotenvx run --env-file=.env.production -- node src/index.js

# 複数ファイルを読み込み
npx dotenvx run --env-file=.env.local --env-file=.env -- node src/index.js

環境変数管理のベストプラクティス

命名規則

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# スクリーム・スネークケースを使用
DATABASE_HOST=localhost

# プレフィックスでグループ化
DB_HOST=localhost
DB_PORT=5432
DB_USER=myuser

AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...

# ブール値は明確に
ENABLE_FEATURE_X=true
DEBUG_MODE=false

デフォルト値の設定

1
2
3
4
5
6
// アプリケーションコードでデフォルト値を設定
const config = {
  port: parseInt(process.env.PORT || '3000', 10),
  logLevel: process.env.LOG_LEVEL || 'info',
  maxRetries: parseInt(process.env.MAX_RETRIES || '3', 10),
};

設定オブジェクトの集中管理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// src/config/index.js
import 'dotenv/config';

export const config = {
  env: process.env.NODE_ENV || 'development',
  isProduction: process.env.NODE_ENV === 'production',
  isDevelopment: process.env.NODE_ENV === 'development',
  
  server: {
    port: parseInt(process.env.PORT || '3000', 10),
    host: process.env.HOST || '0.0.0.0',
  },
  
  database: {
    host: process.env.DATABASE_HOST || 'localhost',
    port: parseInt(process.env.DATABASE_PORT || '5432', 10),
    user: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    name: process.env.DATABASE_NAME,
    url: process.env.DATABASE_URL,
  },
  
  redis: {
    url: process.env.REDIS_URL || 'redis://localhost:6379',
  },
  
  jwt: {
    secret: process.env.JWT_SECRET,
    expiresIn: process.env.JWT_EXPIRES_IN || '1h',
  },
  
  logging: {
    level: process.env.LOG_LEVEL || 'info',
  },
};

// 設定の凍結(書き換え防止)
Object.freeze(config);
Object.freeze(config.server);
Object.freeze(config.database);
Object.freeze(config.redis);
Object.freeze(config.jwt);
Object.freeze(config.logging);

process.envへの直接アクセスを避ける

1
2
3
4
5
6
7
8
9
// 悪い例: 各所でprocess.envに直接アクセス
app.listen(process.env.PORT);
const dbHost = process.env.DATABASE_HOST;

// 良い例: 設定オブジェクトを通じてアクセス
import { config } from './config/index.js';

app.listen(config.server.port);
const dbHost = config.database.host;

トラブルシューティング

環境変数が読み込まれない

  1. ファイルパスの確認: dotenvはデフォルトでカレントディレクトリの.envを読み込みます
1
2
3
4
5
6
import dotenv from 'dotenv';
import path from 'path';
import { fileURLToPath } from 'url';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
dotenv.config({ path: path.resolve(__dirname, '../.env') });
  1. 読み込み順序の確認: dotenvの読み込みは他のモジュールより先に行う

  2. デバッグモードの有効化:

1
dotenv.config({ debug: true });

システム環境変数が上書きされない

dotenvはデフォルトでシステム環境変数を上書きしません。上書きが必要な場合はoverrideオプションを使用します。

1
dotenv.config({ override: true });

改行を含む値が正しく読み込まれない

ダブルクォートで囲み、\nを使用するか、実際の改行を含めます。

1
2
3
4
5
6
7
# エスケープシーケンスを使用
MULTILINE="line1\nline2\nline3"

# 実際の改行を使用
MULTILINE="line1
line2
line3"

まとめ

本記事では、Node.jsにおける環境変数管理の実践的な方法を解説しました。

項目 要点
12-factor app 設定をコードから分離し、環境変数に格納する
dotenv .envファイルからprocess.envに環境変数を読み込む
環境別設定 .env.development, .env.productionなどで環境ごとに管理
機密情報 .gitignoreで除外し、CI/CDではSecretsを使用
検証 起動時に必須環境変数とフォーマットを検証
ベストプラクティス 設定オブジェクトに集約し、process.envへの直接アクセスを避ける

環境変数の適切な管理は、アプリケーションのセキュリティと保守性を大きく向上させます。12-factor appの原則に従い、コードと設定を明確に分離することで、異なる環境間でのデプロイが容易になり、認証情報の漏洩リスクも低減できます。

参考リンク