Flutter Web × Vercel で環境変数が渡らなかった話
3月になり、少しずつ暖かくなってきましたね。今年こそお花見に行きたいと思いつつ、毎年気づいたら散っている気がする、リテールアプリ共創部所属の haruka です。
最近、Flutter Web アプリを Vercel にデプロイする機会がありました。ローカルでは問題なく動くのに、Vercel 環境では API キーが空になってしまう現象に遭遇し、なかなか原因がわからず苦戦しました。
調べてみると Flutter 特有の仕組みを理解していなかっただけだったのですが、同じところで躓く方もいるかもしれないので、解決までの過程をまとめてみました。
構成
- Flutter Web
- バックエンド:AWS API Gateway + Lambda
- デプロイ先:Vercel
- API 認証:
X-API-KEYヘッダー(API Gateway のキー認証)
何が起きたか
Vercel にデプロイした Flutter Web アプリでログインしようとすると、403 Forbidden が返ってきます。不思議なことに、ローカル(flutter run -d chrome)では問題なく動きます。
ブラウザの開発者ツール(Network タブ)でリクエストヘッダーを確認してみると:
X-API-KEY:
API キーが空文字になっていました。
では、さらに空文字になった原因を調査していきます。
躓きポイント:Flutter Web の環境変数は「ビルド時注入」
Node.js や Python に慣れていると、process.env.API_KEY のように実行時に環境変数を読めるものだと、私は勝手にそう思っていました。
しかし、Flutter Web の仕組みは異なります。
Flutter Web はビルド時に Dart コードを JavaScript にコンパイルします。コンパイル後の成果物は静的ファイルになるため、サーバーサイドの環境変数にアクセスする手段がありません。
Flutter で環境変数に相当するものは String.fromEnvironment() ですが、これはビルド時に値が埋め込まれる仕組みです。Node.js の process.env とは根本的に違います。
// ビルド時に値が決まる。実行時には変更できない。
static const String apiKey = String.fromEnvironment('MY_API_KEY');
この値を渡すには、flutter build や flutter run に --dart-define フラグを使います。
flutter build web --dart-define=MY_API_KEY=your_api_key
つまり、環境変数を OS に設定するだけでは不十分で、--dart-define で明示的に渡す必要があります。ここを理解していなかったのが原因でした。
ローカル開発では Makefile で解決
ローカル開発では .env.local ファイルに API キーを書いて、Makefile で読み込む方法にしました。
# .env.local(gitignore 済み)
MY_API_KEY=your_api_key_here
# Makefile
-include .env.local
dev:
flutter run -d chrome --web-port 8080 \
--dart-define=MY_API_KEY=$(MY_API_KEY)
-include .env.local で .env.local を Make 変数として読み込み、$(MY_API_KEY) をビルドコマンドに展開しています。これで make dev するだけで API キーが設定された状態で起動できるようになりました。
補足:VS Code から起動する場合
VS Code の launch.json で F5 起動する場合は、${env:変数名} でシステム環境変数を参照できます。
{
"name": "Flutter Web",
"type": "dart",
"toolArgs": [
"--dart-define=MY_API_KEY=${env:MY_API_KEY}"
]
}
ただし注意点として、これは「VS Code が起動した時点でのシェル環境変数」を参照する仕組みです。.env.local を自動で読んでくれるわけではないので、~/.zshrc などで事前に export しておく必要があります。
# ~/.zshrc
set -a
source /path/to/project/.env.local
set +a
Vercel では 2 箇所の設定が必要
さて、ローカルは解決しましたが、本題の Vercel です。
「Dashboard に環境変数を追加すれば問題ないでしょう」と思っていたのですが、追加しても API キーは空のまま。vercel.json を見てみると:
{
"buildCommand": "flutter build web --release"
}
--dart-define がありませんでした。
Vercel の環境変数はビルド環境のシェル変数として設定されるだけで、Flutter に自動的に渡されるわけではありません。
結論として、必要な設定は「Vercel Dashboard」と「vercel.json」の 2 箇所です。
1. Vercel Dashboard で環境変数を追加
プロジェクト → Settings → Environment Variables で MY_API_KEY を追加します。
2. vercel.json を修正
{
"env": {
"MY_API_KEY": "${MY_API_KEY}"
},
"buildCommand": "flutter build web --release --dart-define=MY_API_KEY=$MY_API_KEY",
"outputDirectory": "build/web"
}
ここがちょっとややこしいのですが、vercel.json には "env" セクションと buildCommand 内の --dart-define の両方が必要です。
"env" セクションは、Dashboard で設定した環境変数を buildCommand のシェル環境で使えるようにするためのもの。これがないと $MY_API_KEY が空のまま展開されてしまいます。
Note: Vercel のドキュメントでは
envセクションは非推奨(レガシー)とされています。
しかし Vercel は Next.js や Nuxt など JavaScript フレームワークを主な対象としており、Flutter Web は公式テンプレートに存在しません。おそらく JS フレームワークでは Dashboard の環境変数がビルドプロセスに自動注入される仕組みがある一方、flutter build webのような単純なシェルコマンドではその仕組みが機能しないのではないかと推測しています。
いずれにせよ、Flutter Web のビルドではenvセクションで明示的にシェル変数へマッピングする必要がありました(2026年3月時点)。
環境変数が Flutter に渡るまでの流れを整理するとこうなります。
1. Vercel Dashboard の環境変数 → ビルド環境のシェル変数になる
2. vercel.json の "env" → シェル変数として明示的にマッピング
3. buildCommand 内の $MY_API_KEY → シェルが展開
4. --dart-define で Flutter ビルドに渡される
5. ビルド成果物に API キーが埋め込まれる
6. X-API-KEY ヘッダーとして送信
この変更を push して再デプロイしたところ、ようやく API キーが正しく渡るようになりました。長かった……。
まとめ
各環境での設定方法を表にまとめておきます。
| 環境 | 設定方法 |
|---|---|
| ローカル(make) | .env.local + Makefile の -include + --dart-define=VAR=$(VAR) |
| ローカル(VS Code) | ~/.zshrc で export + launch.json に --dart-define=VAR=${env:VAR} |
| Vercel | Dashboard で環境変数追加 + vercel.json の "env" + buildCommand に --dart-define=VAR=$VAR |
一番大事なのは、Flutter Web の環境変数は「実行時」ではなく「ビルド時」に注入するという点です。
Node.js などに慣れていると「環境変数を設定すれば勝手に読んでくれる」と思いがちですが、Flutter Web ではそうはいきません。Vercel に環境変数を設定するだけでなく、buildCommand で --dart-define に渡すのを忘れずに!
同じところで躓いた方の参考になれば幸いです。
参考資料








