Skip to content

Next.js 16 アップデート:脆弱性 0 への道とビルドエラーの回避

Next.js の公式チュートリアルをベースにしたダッシュボードアプリにおいて、セキュリティ脆弱性の解消をきっかけに Next.js 16 へのアップデートを敢行しました。

最新の React 19 や Next.js 16 では、これまでの書き方が通用しない「破壊的変更」や、ビルド時の挙動の変化がいくつかあります。フリーランスエンジニアとして、実務でも遭遇しそうなこれらのトラブルをどう解決したか、その全記録を共有します。

1. 脆弱性 0 件へ:パッケージの強制アップデート

Section titled “1. 脆弱性 0 件へ:パッケージの強制アップデート”

まず着手したのは、pnpm audit で指摘された 16 件の脆弱性対応です。

古いチュートリアルコードでは依存ライブラリが固定されていることが多く、単純な pnpm update では解消しきれない場合があります。今回は package.jsonpnpm.overrides を活用し、安全なバージョンを強制的に指定することで、脆弱性を 0 件まで抑え込みました。

2. React 19 の洗礼:Server Actions の型定義

Section titled “2. React 19 の洗礼:Server Actions の型定義”

Next.js 16(React 19)に上げた直後、TypeScript のビルドエラーが発生しました。

./app/ui/invoices/edit-form.tsx などの form action 属性において、以下の型不一致が起きました。

Type Promise<{ message: string; }> is not assignable to type void | Promise<void>.

React 19 から、form action に渡す関数は戻り値が void または Promise<void> であることが厳格に求められるようになりました。従来のコードでオブジェクト(メッセージなど)を返している場合、エラーになります。

これを解決するために、以下のようにラッパー関数で囲む修正を行いました。

// 修正前
<form action={updateInvoiceWithId}>
// 修正後(ラッパーで囲んで戻り値を無視させる)
<form action={async (formData) => { await updateInvoiceWithId(formData); }}>

3. ビルドの壁:Neon DB 接続エラーと PPR

Section titled “3. ビルドの壁:Neon DB 接続エラーと PPR”

一番苦労したのが、pnpm run build 時のデータベース接続エラーです。

ビルド中に Neon DB へ接続しようとして HANGING_PROMISE_REJECTION が発生。WSL2(GALLERIA)のローカル環境から外部 DB への接続が、プリレンダリング工程でタイムアウトしてしまうのが原因でした。

Next.js 16 の cacheComponents (Partial Prerendering) を有効にしていると、ビルド時に DB を叩きに行こうとします。今回はビルドを確実に成功させるため、一旦 app/layout.tsx に以下の設定を投入しました。

export const dynamic = 'force-dynamic';

これにより、「ビルド時に静的にページを作る」のをやめ、「リクエスト時に動的に生成する」挙動に強制変更。ビルド時のネットワーク起因によるエラーを完全に回避できました。

※注意:cacheComponents が有効だと dynamic = 'force-dynamic' はエラーになるため、ビルドを優先する場合は next.config.mjs で一旦 PPR をオフにする調整も必要です。

今回のアップデートを通じて、以下の 3 点が重要だと再認識しました。

  • 脆弱性対応は定期的に: overrides を駆使してでも環境を清潔に保つ。

  • 型定義の変化に敏感に: React 19 の form action などの仕様変更を把握する。

  • 環境差分を考慮する: ローカル(WSL2)とデプロイ先(Vercel)でビルド時の挙動が異なる場合、force-dynamic などのフラグを戦略的に使う。

次は、Vercel 上で本来のパフォーマンスを発揮させるための「PPR 戻し」に挑戦する予定です。