config、dotenv、dotenv-expand、dotenv-safe はすべて Node.js アプリケーションにおける設定管理を目的とした npm パッケージですが、アプローチが大きく異なります。config は JSON/YAML ファイルベースの階層的な設定管理を提供し、環境ごとの設定ファイルを自動でマージします。一方、dotenv は .env ファイルから環境変数を process.env にロードするシンプルなライブラリです。dotenv-expand は dotenv の出力を拡張し、環境変数内で他の変数を参照できるようにします。dotenv-safe は dotenv の上位互換で、必須環境変数を .env.example で定義し、実行時にその存在を検証します。これらのツールは単独でも、あるいは組み合わせて使うこともでき、プロジェクトの複雑さや要件に応じて選択すべきです。
config vs dotenv vs dotenv-expand vs dotenv-safeNode.js アプリケーションでは、設定値を環境に応じて柔軟に切り替える必要があります。この課題に対処する代表的な npm パッケージとして config、dotenv、dotenv-expand、dotenv-safe がありますが、それぞれ設計思想や用途が大きく異なります。実際の開発現場でどう使い分けるべきか、技術的観点から詳しく見ていきましょう。
config は JSON や YAML などの静的ファイルをベースに階層的な設定を提供します。環境ごとに別々の設定ファイルを用意し、アプリ起動時に自動でマージします。
// config/default.json
{
"db": {
"host": "localhost",
"port": 5432
}
}
// config/production.json
{
"db": {
"host": "prod-db.example.com"
}
}
// app.js
const config = require('config');
console.log(config.get('db.host')); // 環境に応じて自動切り替え
dotenv は .env ファイルから環境変数を process.env に直接ロードします。シンプルで軽量ですが、構造化された設定には向いていません。
// .env
DB_HOST=localhost
DB_PORT=5432
// app.js
require('dotenv').config();
console.log(process.env.DB_HOST); // 'localhost'
dotenv-expand は dotenv の出力を拡張し、環境変数内で他の変数を参照できるようにします。
// .env
BASE_URL=http://localhost:3000
API_URL=${BASE_URL}/api
// app.js
const dotenv = require('dotenv');
const dotenvExpand = require('dotenv-expand');
const myEnv = dotenv.config();
dotenvExpand.expand(myEnv);
console.log(process.env.API_URL); // 'http://localhost:3000/api'
dotenv-safe は dotenv の上位互換で、必須環境変数を .env.example で定義し、実行時に存在確認を行います。
// .env.example
DB_HOST=
DB_PORT=
// .env
DB_HOST=localhost
DB_PORT=5432
// app.js
require('dotenv-safe').config({
allowEmptyValues: true
});
// DB_HOST または DB_PORT が欠けていたらエラー
config は config.has('key') でキーの存在をチェックできますが、起動時の強制検証機能はありません。
const config = require('config');
if (!config.has('requiredKey')) {
throw new Error('requiredKey is missing');
}
dotenv には必須変数の検証機能が一切ありません。開発者が自前でチェックする必要があります。
require('dotenv').config();
if (!process.env.REQUIRED_VAR) {
throw new Error('REQUIRED_VAR is not set');
}
dotenv-expand は展開機能のみを提供するため、必須変数の検証は含まれていません。
// dotenv-expand は検証機能を持たない
const dotenv = require('dotenv');
const expand = require('dotenv-expand');
expand(dotenv.config());
// 必須変数のチェックは別途実装が必要
dotenv-safe は .env.example に定義されたすべてのキーが .env に存在することを保証します。CI/CD 環境で特に有用です。
// dotenv-safe は自動で検証
require('dotenv-safe').config();
// .env.example にあるキーが不足していれば即時エラー
config は複数の設定ファイルを環境に応じて自動マージします。例えば default.json → local.json → production.json の順で上書きされます。
// config/default.json
{ "feature": { "enabled": false } }
// config/development.json
{ "feature": { "flag": "dev" } }
// 結果: { "feature": { "enabled": false, "flag": "dev" } }
dotenv は単一の .env ファイルしか読みません(明示的に複数指定しない限り)。階層的な設定はサポートされていません。
// dotenv は1ファイルのみ
require('dotenv').config(); // デフォルトは .env のみ
dotenv-expand も同様に単一ファイルが基本ですが、dotenv と組み合わせることで複数ファイル読み込みは可能(ただしマージ機能なし)。
// dotenv-expand 自体はマージ機能を持たない
const fs = require('fs');
const dotenv = require('dotenv');
const expand = require('dotenv-expand');
const envConfig = dotenv.parse(fs.readFileSync('.env.base'));
Object.assign(envConfig, dotenv.parse(fs.readFileSync('.env.local')));
expand.expand({ parsed: envConfig });
dotenv-safe も単一ファイルが基本で、階層的設定はサポートしていません。
// dotenv-safe も1ファイルがデフォルト
require('dotenv-safe').config();
config は NODE_ENV を見て自動で対応する設定ファイルを読み込みます。また、custom-environment-variables.json で process.env から特定の値をマッピングできます。
// config/custom-environment-variables.json
{
"db": {
"password": "DB_PASSWORD"
}
}
// process.env.DB_PASSWORD が config.get('db.password') になる
dotenv は path オプションでファイルを指定できますが、環境ごとの自動切り替えはありません。
// dotenv で環境ごとのファイル指定
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`
});
dotenv-expand と dotenv-safe も同様に、環境切り替えは手動で行う必要があります。
// dotenv-safe で環境ファイル指定
require('dotenv-safe').config({
path: `.env.${process.env.NODE_ENV}`,
example: '.env.example'
});
複数環境(開発・ステージング・本番)で異なる設定を持ち、階層的な構造が必要な場合。
config環境変数だけで完結するシンプルなアプリで、.env ファイルをローカル開発用に使いたい場合。
dotenv例: DATABASE_URL=postgresql://${DB_USER}:${DB_PASS}@${DB_HOST} のようなケース。
dotenv-expand + dotenvデプロイ時に必須環境変数が漏れていないかを保証したい場合。
dotenv-safe.env.example に基づく必須変数チェックで人為ミスを防止| パッケージ | 設定形式 | 階層的設定 | 必須変数検証 | 変数展開 | 環境自動切り替え |
|---|---|---|---|---|---|
config | JSON/YAML | ✅ | ❌ (手動) | ❌ | ✅ (NODE_ENV) |
dotenv | .env | ❌ | ❌ | ❌ | ❌ (手動) |
dotenv-expand | .env | ❌ | ❌ | ✅ | ❌ (手動) |
dotenv-safe | .env | ❌ | ✅ | ❌ | ❌ (手動) |
dotenv で十分です。多くの小規模プロジェクトではこれで問題ありません。dotenv + dotenv-expand の組み合わせを使いましょう。dotenv-safe を選びましょう。特にチーム開発やCI環境では必須です。config が最適です。ただし、process.env 以外の設定ソースを扱うため、12要素アプリの原則とはやや距離があります。これらのパッケージは相互排他的ではなく、組み合わせて使うことも可能です(例: dotenv-safe で必須変数を検証しつつ dotenv-expand で展開)。プロジェクトの要件に応じて、最も適したツールまたは組み合わせを選びましょう。
config を選ぶべきなのは、複数環境(開発・ステージング・本番など)で複雑な階層的設定が必要な場合です。JSON や YAML ファイルによる設定管理を好み、環境変数だけでなく静的ファイルベースの設定を活用したいプロジェクトに最適です。ただし、12要素アプリの原則に厳密に従う必要がある場合は、process.env 以外の設定ソースを使う点に注意が必要です。
dotenv を選ぶべきなのは、シンプルな .env ファイルによる環境変数管理で十分なプロジェクトです。軽量で依存関係が少なく、ローカル開発環境で環境変数を簡単に設定したい場合に最適です。本番環境では環境変数を直接設定する前提で、開発時のみ .env を利用する典型的な12要素アプリ向けです。
dotenv-expand を選ぶべきなのは、.env ファイル内で他の環境変数を参照して値を構築したい場合です。例えば API_URL=${BASE_URL}/api のような変数展開が必要なシナリオで、dotenv 単体では実現できない柔軟性を提供します。必ず dotenv と組み合わせて使用します。
dotenv-safe を選ぶべきなのは、必須環境変数の存在を実行時に確実に検証したい場合です。特にチーム開発やCI/CD環境で、設定漏れによるデプロイ障害を防ぎたいプロジェクトに最適です。.env.example にテンプレートを定義することで、必要な環境変数を明示的に管理できます。
Node-config organizes hierarchical configurations for your app deployments.
It lets you define a set of default parameters, and extend them for different deployment environments (development, qa, staging, production, etc.).
Configurations are stored in configuration files within your application, and can be overridden and extended by environment variables, command line parameters, or external sources.
This gives your application a consistent configuration interface shared among a growing list of npm modules also using node-config.
The following examples are in JSON format, but configurations can be in other file formats.
Install in your app directory, and edit the default config file.
$ npm install config
$ mkdir config
$ vi config/default.json
{
// Customer module configs
"Customer": {
"dbConfig": {
"host": "localhost",
"port": 5984,
"dbName": "customers"
},
"credit": {
"initialLimit": 100,
// Set low for development
"initialDays": 1
}
}
}
Edit config overrides for production deployment:
$ vi config/production.json
{
"Customer": {
"dbConfig": {
"host": "prod-db-server"
},
"credit": {
"initialDays": 30
}
}
}
Use configs in your code:
const config = require('config');
//...
const dbConfig = config.get('Customer.dbConfig');
db.connect(dbConfig, ...);
if (config.has('optionalFeature.detail')) {
const detail = config.get('optionalFeature.detail');
//...
}
config.get() will throw an exception for undefined keys to help catch typos and missing values.
Use config.has() to test if a configuration value is defined.
Start your app server:
$ export NODE_ENV=production
$ node my-app.js
Running in this configuration, the port and dbName elements of dbConfig
will come from the default.json file, and the host element will
come from the production.json override file.
Type declarations are published under types/ and resolved via typesVersions. Subpath typings are included for config/async, config/defer, config/parser, config/raw, and config/lib/util in addition to the main config entrypoint.
If you still don't see what you are looking for, here are some more resources to check:
node-config contributors.May be freely distributed under the MIT license.
Copyright (c) 2010-2026 Loren West and other contributors