「ローカルの npm run dev では完璧に動いていたのに、Vercel にデプロイした瞬間、画面が真っ白になった」
初めて自分のアプリをインターネットに公開しようとした未経験者が、ほぼ全員が一度は通る瞬間です。最近は「週末2日で家計簿アプリを作って Vercel で公開してみた」系の記事も増えて、"作って公開する" ハードルはどんどん下がっています。でも実際に自分でデプロイボタンを押すと、チュートリアルには載っていない小さな地雷を踏みます。しかもそのエラー、ローカルでは一度も出なかったやつです。
この記事は「デプロイ前のチェックリスト」ではありません。環境構築や .gitignore・環境変数の基本設定は前に別記事(Next.js+Supabaseアプリを初めてVercel公開する時の4大つまずきと最小の直し方)に書いたので、そちらに譲ります。
ここでは一歩進んで、実際にデプロイして「詰まった瞬間」に、エラー文をどう Claude Code に渡して抜けるかを実況します。各地雷を「症状 → 実際に出るエラー文 → AIへの聞き方(プロンプト) → 最小の直し方」の順で並べました。前提スタックは Next.js(App Router)+ Supabase + Vercel。未経験がこの構成で人生初のデプロイをする想定です。
地雷1: ローカルでは動くのに、Vercel のビルドで落ちる
いちばん最初にぶつかるのがこれです。手元では npm run dev がずっと緑だったのに、Vercel のデプロイログが赤くなって止まる。
出るエラーはだいたいこの2種類です。
Failed to compile.
./app/tasks/page.tsx:12:44
Type error: Property 'titl' does not exist on type 'Task'. Did you mean 'title'?
12 | {tasks.map((t) => <li key={t.id}>{t.titl}</li>)}
| ^
Module not found: Can't resolve '@/components/taskList'
なぜローカルでは気づけないのか。 理由は2つあります。
-
next dev(開発サーバー)は型エラーがあっても動き続けますが、next build(本番ビルド)は型チェックで止まります。つまり手元で TypeScript の赤い波線を無視していると、Vercel で初めて表面化します。 - macOS / Windows のファイルシステムは大文字小文字を区別しませんが、Vercel(Linux)は区別します。
TaskList.tsxをtaskListと import してもローカルは通り、Vercel だけModule not foundになります。
Claude Code にはこう貼ります。エラーは省略せず全文を渡すのがコツです。
Vercel のデプロイでビルドが失敗しました。
ローカルの `npm run dev` では動いています。
以下が Vercel のビルドログの全文です。
考えられる原因を3つ、確認する順番つきで挙げてください。
(ここに赤いログを丸ごと貼る)
そして根本の対策は、ローカルで本番と同じビルドを一度走らせること。体感では、ビルドエラーの多くはこれで push 前に潰せます。
# push する前に、本番と同じビルドを手元で再現する
npm run build
「dev で動く」と「build が通る」は別物、と体で覚えるのがこの地雷の卒業条件です。
地雷2: ビルドは成功したのに、開くと真っ白
ビルドログは緑。デプロイ成功。URL を開いたら……真っ白。何も出ない。エラーページですらない。これも定番です。
まず F12 でブラウザのコンソールを開きます。だいたいこのどちらかが出ています。
Error: supabaseUrl is required.
Error: Hydration failed because the server rendered HTML didn't match the client.
パターンA: クライアント側の環境変数が undefined
Supabase のクライアントをブラウザから使うとき、環境変数に NEXT_PUBLIC_ を付け忘れると、本番で undefined になって落ちます。ローカルでは .env.local が効いていて気づけません。
// ❌ ブラウザからは undefined になる
import { createBrowserClient } from '@supabase/ssr'
export const supabase = createBrowserClient(
process.env.SUPABASE_URL!, // NEXT_PUBLIC_ が無い
process.env.SUPABASE_ANON_KEY!,
)
// ✅ ブラウザに渡す値は NEXT_PUBLIC_ を付ける
export const supabase = createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
)
さらに見落としがちなのが、Vercel 側に環境変数を足したあとは再デプロイが必要という点。環境変数を追加しただけでは既存のビルドには反映されません。Vercel の管理画面で該当デプロイを Redeploy してください。
パターンB: ハイドレーションエラー
new Date() や Math.random()、localStorage をレンダー中に読むと、サーバーとブラウザで結果がズレて真っ白になります。Claude Code にはこう聞きます。
Vercel にデプロイしたら画面が真っ白で、コンソールに次のエラーが出ています。
`Error: Hydration failed because the server rendered HTML didn't match the client.`
Next.js App Router を使っています。
このエラーが出やすいパターンを挙げて、どこを直せばいいか教えてください。
「直して」と丸投げする前に「出やすいパターンを挙げて」と聞くと、自分のコードのどこが該当するかを自分で照合できるので、次から同じ罠を避けられます。
地雷3: ログインした瞬間、localhost に飛ばされる
Supabase 認証を入れたアプリでよくあるのがこれ。本番でログインボタンを押すと、なぜか http://localhost:3000 に飛ばされる、あるいはログイン画面に戻ってループする。
原因はほぼ Supabase 側の URL 設定です。Dashboard → Authentication → URL Configuration で、
-
Site URL を本番URL(
https://your-app.vercel.app)に変更 - Redirect URLs に本番URLを追加
これで直ります。詳しい設定手順とコード側の emailRedirectTo の扱いは前回のデプロイ記事にまとめたので、ここでは「localhost に飛んだら真っ先に Supabase の URL 設定を疑う」とだけ覚えてください。
地雷4: 本番だけ「Application error: a server-side exception」
画面いっぱいにこの一文だけが出るパターン。
Application error: a server-side exception has occurred while loading
your-app.vercel.app (see the server logs for more information).
これは Next.js が本番ではエラーの中身を隠すために出す汎用ページです。開発中なら真っ赤なスタックトレースが見えますが、本番では「詳細はサーバーログを見て」としか言ってくれません。だから初見だと手も足も出ない。
正解は、案内どおりサーバーログを見に行くこと。Vercel の管理画面で該当デプロイを開き、**Logs(Runtime Logs)**タブを見ます。多いのは、
- サーバー専用の環境変数(
SUPABASE_SERVICE_ROLE_KEYなど)を Vercel に登録し忘れている - Server Component / Server Action の中で実行時エラーが起きている
ログの本文が取れたら、そのまま Claude Code に渡します。
本番(Vercel)でページを開くと
`Application error: a server-side exception has occurred` と出ます。
ローカルでは出ません。Vercel の Runtime Logs には以下が出ていました。
(ランタイムログを貼る)
Server Component で Supabase を使っています。
原因の候補と、確認する手順を教えてください。
「本番だけ落ちる」ときは、経験上たいてい環境変数のスコープ(サーバー用の設定漏れ/クライアント用との混同)が原因です。ログという一次情報を取りに行けるようになると、AIへの質問も一気に的確になります。
地雷5: APIキーがブラウザに丸見えになっている
最後は事故りやすいやつ。NEXT_PUBLIC_ を付けた環境変数は、ビルド時にブラウザ向けのコードに焼き込まれます。つまり、公開したアプリを開いて開発者ツールを見れば、誰でもその値を読めます。
Supabase の anon key はこれで問題ありません(公開される前提で、RLS で守るキーだからです)。危険なのは、service_role キーをうっかりクライアントで使ってしまうケース。
// ❌ 絶対NG: service_role をブラウザに出す = DB全権限が漏れる
const admin = createClient(
url,
process.env.NEXT_PUBLIC_SERVICE_ROLE!, // NEXT_PUBLIC_ を付けた時点で公開
)
service_role は Server Component / Server Action / Route Handler の中だけで使い、NEXT_PUBLIC_ は絶対に付けない。これが鉄則です。「公開して大丈夫なキー / ダメなキー」の線引きと RLS の話はAIが書いたコードを本番に出す前の落とし穴に詳しく書いたので、そちらもどうぞ。
エラー文を AI に渡すときの3つのコツ
地雷そのものより大事なのが、詰まった瞬間に AI からいい答えを引き出す聞き方です。これは公開デプロイに限らず一生使えます。
- エラーは省略せず全文貼る。 「...以下同様」で切らない。ファイルパス・行番号・スタックトレースが最大の手がかりで、AIはそこから原因を絞ります。
- 再現条件を1行足す。 「ローカルの dev では動く/本番だけ落ちる」の一言があるだけで、AIの当たりが劇的に良くなります。環境差が原因の地雷は、これだけで原因の当たりがぐっと良くなります。
- 「直して」より「原因の候補を確認順に3つ」と聞く。 いきなり修正コードをもらうと、なぜ直ったか分からないまま次で詰みます。候補を出させて自分で切り分けると、コードを読む力=自走力が残ります。
デプロイのトラブルシューティングは、じつはプログラミングと AI協働スキルを同時に鍛える最高の実戦です。エラーを読み、仮説を立て、AIに検証させ、自分で選ぶ——この往復を数回まわすと、次のアプリは驚くほどスムーズに公開できるようになります。
まとめ: 症状から逆引きするデプロイ地雷マップ
| 症状 | まず疑う所 | AIに渡すもの |
|---|---|---|
| ローカルは動くのに Vercel でビルド失敗 |
npm run build をローカルで再現/型・import の大文字小文字 |
ビルドログ全文 |
| ビルド成功なのに真っ白 | クライアント環境変数(NEXT_PUBLIC_)/ハイドレーション |
コンソールのエラー全文 |
| ログイン後 localhost へ飛ぶ・ループ | Supabase の Site URL / Redirect URLs | 遷移先URLと設定画面 |
| 本番だけ Application error | Vercel の Runtime Logs/サーバー用env の設定漏れ | ランタイムログ全文 |
| APIキーがブラウザに見える |
NEXT_PUBLIC_ の付けすぎ/service_role の誤用 |
該当のenv名とコード |
「ローカルで動く」と「世界に公開できる」の間には、この5つくらいの段差があります。でも一つずつは、エラー文を落ち着いて AI に渡せば必ず抜けられるレベルのものです。デプロイは上級者だけの特権ではなく、AIと一緒なら未経験の最初の一歩に十分向いています。真っ白な画面で固まったら、まずコンソールを開いて、その一文をコピーするところから始めてみてください。
未経験者向けの講座を運営しています
未経験から Next.js + Supabase + Claude Code で Webアプリを公開するまで を、全20セッションで体系化した教材です。今日の記事のような「詰まったらAIに聞いて抜ける」実戦の型を、最初のアプリ公開までまるごと伴走します。
- 無料体験版(git clone してすぐ動く・最初の数セッション分・⭐ Star もよろしくお願いします)→ https://github.com/ayies128/next-ai-camp-trial
- 教材完全版+月5,500円のメンタリング(全20セッション+チャットで質問し放題)→ https://menta.work/plan/20251?ref=qiita
※ Qiita 読者の方には易しすぎる内容だと思います。未経験の知り合いへの紹介や、社内研修・後輩育成の参考としてどうぞ。