結構前に Node における NODE_ENV
と環境変数の設定方法について Slack で軽く議論したんだけど、その後色々と考えるものがあったのでここにまとめておく。
基本的にサーバサイドを前提とした話をするが、フロントエンドにも通じる話だと思うし、Next.js の話も出てくる。
NODE_ENV
に development
、production
以外が入るややこしさ
Node のエコシステムでよく使われる環境変数として NODE_ENV
がある。
様々なツールが NODE_ENV
を見て、development
であれば開発用のトレースやログを出してくれるし、production
であれば本番用に最適化された処理を行ってくれる。
これはこれで便利なんだけど、環境 (ENV
) という言葉に釣られて、デプロイ環境の名称を NODE_ENV
に設定し始めると、途端にややこしくなることが多い。
よくある例として、ステージング環境の NODE_ENV
を staging
に設定する例を考える。
このとき、あなた使っているビルドツールやライブラリが development
と production
のどちらの挙動をするか正しく把握しているだろうか?
個人的には development
の設定が優先されそう、って直感的に思うけど、確証はない。また、これはライブラリごとに挙動が統一されている保証がないので、それぞれ個別に調べる必要がある。
また、「ステージング環境だけど、本番環境と同じ環境にしたいからプロダクションビルドして欲しい」みたいな要望があると、ステージング環境なのに NODE_ENV=production
を設定するという歪みが生じて辛くなる。
こういった歪みを考えていくと、NODE_ENV
にデプロイ環境の名前をつけるの辞めたほうが良さそうに思える。 基本的に NODE_ENV
は development
と production
の 2 値しか取らないように設計し、より多様性を持たせたいものは NODE_ENV
によらない形(それ専用の環境変数など)で切り替えられるようにすると良い。
NODE_ENV
と環境変数
NODE_ENV
を 2 値に絞るにあたって、「そういえばなんで NODE_ENV
にいろんな値を入れてたんだっけ?」と改めて考えると、「設定値の変更」のためにやっているパターンが多い。
例えば、Node の設定ファイルの管理として有名で頻繁に使っている node-config は NODE_ENV
を見て、 development.json
や production.ts
といった設定ファイルを読み込む。
また、Next.js であれば NODE_ENV
を見て .env.development
や .env.production
を読み込む。
しかし、NODE_ENV
が 2 値しか取らないように制限をかけると、2 種類のファイルからしか読み込めないので、ステージング環境や QA 環境としった環境が新たに増えると、この方法では破綻してしまう。
そこで、ランタイムで設定されている環境変数から全ての設定を読み込むようにする。12 Factor App にも書かれているやつ。1
このように環境変数から読み込むようにすることで、設定の管理が NODE_ENV
と分離される。
結果として、 NODE_ENV
が 2 値しか取らなくても問題なくスケールする。
余談: 環境変数を .env
から読み込む是非
環境変数をセットする方法として、 .env
を使ってる人は多いと思う。全ての環境変数を手動でランタイムにセットするのはだるいから、 .env
に書いて direnv や シェルスクリプトで自動で読み込むパターン。
まあそれでも良いっちゃ良いんだけど、ファイルに書くのがダメだから環境変数を使ってるのに、結局 .env
というファイルを使ってしまってるところがもどかしい。
個人的には、アプリケーションの外部で .env
を読み込むのであれば特に問題ないと思っている。アプリケーション内部から見たときには上で書いたとおり、環境変数で切り替わるような設定になっていてほしいが、どのように環境変数をランタイムに設定するかは特に気にしていない。direnv で読み込もうが、GCP のコンソールから設定しようが、コードをいじる必要がなければそれで十分という考え。
この辺はいろんな人の意見が聞きたい。
まとめ
言いたかったことは、次の 2 点。
NODE_ENV
はdevelopment
とproduction
の 2 値しか取らないようにしたほうが良くない?.env
は使ってもいいけど、アプリケーション内部から読み込むのはやめたほうが良くない?
皆さんのご意見もお待ちしています。
Footnotes
-
12 Factor App の是非についてはまた別の機会に ↩