環境変数を読み込めない原因|.env・PowerShell・GitHub Actionsを順に確認する

環境変数がundefinedや空になるときに、変数名、スコープ、.envの場所、PowerShell、GitHub ActionsのSecretsを安全に切り分ける手順を解説します。

環境変数を設定したのにアプリから読めないときは、値を入れ直すより「名前・実行プロセス・読み込み場所」を順番に確認する方が原因へ近づけます。.env、PowerShell、GitHub ActionsのSecretsは別の仕組みです。この記事では、秘密の値を表示せずに切り分けます。APIキーは値そのものを画面へ出さず、設定されているかどうかの真偽だけを確認します。

読み込み失敗の症状

最初に症状を3種類へ分けます。

  1. 未定義:JavaScriptでundefined、PowerShellで$nullになる
  2. 空文字:変数は存在するが値が空になっている
  3. 古い値:変更前や別環境の値が返る

未定義なら変数名、読み込み処理、実行環境の違いを疑います。空文字ならSecretsの未登録や代入元の空値、古い値なら設定前から起動中のターミナルやアプリ、同名変数による上書きが候補です。

「ローカルでは成功するがCIでは失敗する」のように、成功経路と失敗経路を1組にすると差分が見えます。環境変数以外の終了理由も疑う場合は、Codexが途中で止まるときの原因と対処法を確認してください。

症状から確認先を絞る

症状最初に確認する場所よくある原因値を伏せた確認方法
undefinedまたは$null変数名、読み込み処理名前の不一致、.env未読込存在を真偽値で出す
空文字代入元、GitHub Secrets未登録のSecret、空の代入文字列の長さが0か確認する
古い値起動中のプロセス設定前に起動、同名変数の上書き再起動後も同じか比べる
ローカルだけ成功workflowのenvと実行イベントSecretの渡し忘れ、fork・Dependabot・再利用workflowの制約Secret名とstepだけ確認する
CIだけ成功ローカルの.envと起動位置ファイルの場所、実行モードの違い作業ディレクトリと読込ファイル名を確認する

変数名とスコープを確認する

API_KEYAPIKEYDATABASE_URLDATABASE_URIは別名です。設定元とコードの名前をコピーして一致させます。Windowsで問題にならなくても、macOSやLinuxでは環境変数名の大文字と小文字が区別されます。

環境変数は、親プロセスから後で起動した子プロセスへ渡されます。設定前から開いていたターミナル、エディター、開発サーバーには新しい値が反映されない場合があります。設定済みのターミナルからアプリを起動し直します。

存在確認では値を出さず、真偽値だけを記録します。

const value = process.env.APP_TOKEN;
console.log({
  exists: typeof value === 'string',
  nonEmpty: typeof value === 'string' && value.length > 0,
});

exists: falseなら未定義、exists: trueかつnonEmpty: falseなら空文字です。実際のキーをコード、ログ、スクリーンショットへ貼らないでください。

.envの置き場所を確認する

.envは、置くだけですべてのアプリが自動的に読む共通機能ではありません。利用中のフレームワークや実行コマンドが、どのファイルをどのディレクトリから読むかを確認します。Node.js公式資料も、dotenvファイルには正式な共通仕様がなく、Node.jsとしての仕様を定めていると説明しています。

プロジェクト直下を想定する構成なら、次のように.envと実行設定を同じ階層へ置きます。1階層下からコマンドを実行すると見つからない実装もあります。.env.local.env.productionを使う場合は、現在の実行モードとファイル名を合わせます。

project/
├─ .env
├─ package.json
└─ src/
   └─ app.js

Node.jsの.env仕様では、変数名に使えるのは英字、数字、アンダースコアで、先頭を数字にはできません。#は引用符の外ではコメント開始になります。値に#を含む場合は引用符で囲むなど、採用している読み込み実装の規則に合わせます。

Node.jsには--env-fileprocess.loadEnvFileがありますが、対応版や既存フレームワークとの併用はプロジェクトごとに確認が必要です。複数の方法を重ねず、読み込み口を1つに固定すると上書き元を追えます。

PowerShellで一時設定する

PowerShellでは、現在のセッションへ設定してから同じ画面でアプリを起動します。

$env:APP_TOKEN = 'sample_for_local_check'
node .\src\app.js

通常変数の$APP_TOKENと環境変数の$env:APP_TOKENは別物です。Microsoft公式資料によると、PowerShellでの変更は現在のセッションに影響し、そこから起動した子プロセスへ継承されます。別のターミナルや起動済みアプリから読めないのは、スコープ(値が有効な範囲)の違いが原因になり得ます。

値を出さない存在確認は次のようにします。

if (Test-Path Env:\APP_TOKEN) {
  'APP_TOKEN: 設定あり'
} else {
  'APP_TOKEN: 未設定'
}

切り分け中はユーザーやマシン全体へ永続保存せず、一時設定で影響を限定します。パスや引用符も怪しい場合はWindowsのパスエラー対処法も確認してください。

CIのSecrets参照を確認する

ローカルで読めてGitHub Actionsだけ失敗するなら、Secretを登録した場所とworkflowの参照名を確認します。必要なstepへenvとして渡す最小例は次のとおりです。

steps:
  - name: 環境変数の存在確認
    shell: pwsh
    env:
      APP_TOKEN: ${{ secrets.APP_TOKEN }}
    run: |
      if ([string]::IsNullOrEmpty($env:APP_TOKEN)) {
        throw 'APP_TOKEN is not configured'
      }
      'APP_TOKEN is configured'

GitHub公式資料では、作成したSecretはsecretsコンテキストからinputまたは環境変数として渡します。未設定のSecretを参照すると結果は空文字です。forkからのworkflow、Dependabotイベント、再利用workflowではSecretが通常どおり渡らない条件もあるため、実行イベントとアクセス範囲まで確認します。

Secretをデバッグ出力へ直接書いてはいけません。ログの自動マスクだけに頼らず、存在の真偽だけを出します。CI全体を組むときは、秘密の値を出力へ出さないことを検査の1項目として先に固定しておきます。

値を表示せず疎通を試す

最後は「登録済み」と「目的の処理で利用可能」を分けます。

  1. 存在と空文字を真偽値で確認する
  2. 対象サービスへ最小の読み取り処理を送る
  3. 成功・認証失敗・通信失敗を別の終了コードにする
  4. ログにはSecret名、実行段階、HTTPステータスだけを残す

認証失敗ならキーの権限、期限、対象環境を公式管理画面で確認します。通信失敗なら接続先URL、DNS、プロキシを調べます。漏えいが疑われるときは値を表示して照合せず、対象サービスの公式手順で失効・再発行を検討してください。

確認順は、名前 → 実行プロセス → .envの場所と読込方法 → PowerShellのスコープ → CIの登録先と参照 → 値を伏せた疎通です。

よくある質問

.envを置いたのにNode.jsで読み込めないのはなぜですか?

.envは、置くだけで必ず読み込まれるファイルではありません。フレームワークの読込機能、パッケージ、Node.jsの--env-fileなど、どの方法で読むかを1つずつ確認してください。コマンドを実行するディレクトリと.envの位置も照合します。

PowerShellを開き直すと環境変数が消えるのはなぜですか?

$env:APP_TOKEN = '...'で設定した値は、基本的に現在のPowerShellセッションだけで有効です。切り分け中はこの一時設定が安全です。永続化が必要な場合も、秘密を保存してよい端末か、対象をユーザーとマシンのどちらにするかを先に判断してください。

GitHub ActionsのSecretが空になるのはなぜですか?

参照名の不一致や未登録に加え、forkからの実行、Dependabotイベント、再利用workflowへの未受け渡しが候補です。GitHub公式資料では、未設定のSecretを参照した式は空文字になり、これらの実行条件ではSecretが渡らない場合があると説明されています。

環境変数を変更したのに古い値が返るのはなぜですか?

設定前から起動しているターミナル、エディター、開発サーバーが古い環境を保持している可能性があります。設定したターミナルから対象プロセスを起動し直し、.env、OS、CIの同名変数による上書きも確認します。

APIキーを表示せずに正しく読めたか確認できますか?

存在、空文字かどうか、文字列長など、値そのものではない情報で確認できます。その後、権限の小さい読み取り処理を1回だけ試し、認証失敗と通信失敗を分けます。キーの一部表示やログの自動マスクだけに頼る方法は避けます。

関連記事

一次情報

以下は2026年7月24日に確認しました。

続き(結論と実データ)はnoteに置いています

ここでは手順のところまで書きました。実際に出た数字、うまくいかなかった条件、そのまま使える設定ファイルは、 note の記事にまとめてあります。

noteで続きを読む Xをフォローする