できない.dev

Node.js で dotenv の値が読み込めない

.env が読まれない原因はほぼ「呼ぶ順序が遅い」「ファイルの場所が違う」「Node 20.6+ の --env-file と二重読み」のいずれか。
エントリで最初に dotenv.config() を呼び、import 順を意識すれば解決する。

#nodejs#dotenv#env#process.env#--env-file

公開:

要約

dotenv が読まれないと感じる場面のほとんどは「読み込みのタイミング」が遅い。
他モジュールの import 評価より 先に dotenv.config() を実行する必要があり、ESM では特に順序が問題になる。
Node.js 20.6 以降は標準で --env-file を持っているため、新規プロジェクトでは dotenv 自体不要なケースも増えている。

よくある原因

  1. 呼び順が遅い: import config from "./config" の中で process.env.FOO を読むのに、dotenv.config() がその後ろにある
  2. カレントディレクトリのズレ: npm start を別ディレクトリから走らせ、.env がプロジェクトルートに無いと dotenv は見つけられない
  3. ESM の評価順: ESM の import はトップレベルで実行されるが、同じファイル内の通常文より前に動く。dotenv.config()import の後ろに書いても、他 import には間に合わない
  4. --env-file との二重読み: node --env-file=.env app.jsdotenv.config() の両方を併用すると、片方が空文字で上書きすることがある

解決策

1. エントリ最上部で読み込む

CommonJS の場合。

// index.js
require("dotenv").config();
const app = require("./app");   // この時点で process.env が揃っている

ESM の場合。

// main.mjs
import "dotenv/config";          // ← 最初の import
import { app } from "./app.mjs";

dotenv/config を import するだけで config() が自動実行される。

2. パスを絶対指定する

import { config } from "dotenv";
import path from "node:path";
import { fileURLToPath } from "node:url";
 
const __dirname = path.dirname(fileURLToPath(import.meta.url));
config({ path: path.resolve(__dirname, "../.env") });

npm start の起動位置に依存しなくなる。

3. --import で preload する(ESM)

node --import "dotenv/config" app.mjs

--import フラグで指定したモジュールは、アプリの最初の import より前に評価される。package.jsonscripts に書いておく。

{
  "scripts": {
    "start": "node --import dotenv/config app.mjs"
  }
}

4. Node 20.6+ なら --env-file 単独に

node --env-file=.env app.js

dotenv ライブラリを外し、Node 標準機能だけで完結させる。
複数の env ファイルを読みたい場合は --env-file を複数回指定できる(後勝ち)。

この記事は役立ちましたか?