この記事の要点
next buildしてからnext startで動かす Node.js サーバー方式が基本。全機能が使える。- Docker でまとめるなら
output: "standalone"。実行に必要な最小構成だけが出力される。 NEXT_PUBLIC_付きの環境変数はビルド時にコードへ埋め込まれる。実行時に切り替えたい値には使えない。- 複数インスタンスで動かすなら、暗号鍵・デプロイ ID・共有キャッシュの 3 点セットを揃える。
- リバースプロキシがレスポンスをためこむとストリーミングが機能しない。バッファリングを切る。
開発が終わったら本番環境に出します。Next.js は Node.js が動く環境なら基本的にどこでも動きますが、キャッシュや環境変数の扱いに独特の前提があり、そこを知らないと「ローカルでは動くのに本番でおかしい」という状態になります。この記事では自前サーバーで運用する場合を中心に扱います。
1デプロイ方式の選択
| 方式 | 使える機能 | 向いている場面 |
|---|---|---|
| Node.js サーバー | すべて | VPS・専用サーバーでの通常運用 |
| Docker コンテナ | すべて | コンテナ基盤、環境の再現性を重視する場合 |
| 静的書き出し | 制限あり | サーバーを持てない環境、純粋な静的サイト |
静的書き出し(output: "export")は HTML と静的ファイルだけを出力する方式で、任意の Web サーバーに置けます。ただしサーバーを必要とする機能は使えません。proxy.ts のようにリクエストを見る仕組みは動かず、画像最適化も専用のローダーを別途用意する必要があります。
2Node.js サーバーとして動かす
npm run build
npm run start
これだけで全機能が使えます。ただし、Next.js のサーバーを直接インターネットに晒すのは推奨されていません。Nginx などのリバースプロキシを前段に置き、不正なリクエストの遮断、接続数の制限、ペイロードサイズの上限といった役割を任せます。Next.js 側は描画に専念させる、という考え方です。
3Docker 向けの standalone 出力
コンテナに入れる場合、node_modules を丸ごと持ち込むとイメージが肥大します。output: "standalone" を指定すると、実行に必要なファイルだけがまとめて出力されます。
// next.config.ts
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
output: 'standalone',
}
export default nextConfig
複数のコンテナを立てる場合、同じビルド成果物を使い回すのが原則です。ステージごとにビルドし直すと、後述するビルド ID が食い違って問題が起きます。どうしてもビルドを分ける必要があるなら、generateBuildId で git のコミットハッシュなどを固定値として与えます。
// next.config.js
module.exports = {
generateBuildId: async () => {
return process.env.GIT_HASH
},
}
4環境変数はいつ読まれるか
ここが最も誤解されやすい部分です。環境変数には、ビルド時に固定されるものと、実行時に読まれるものがあります。
実行時に確実に読みたい場合は、connection() を先に await します。これによりその処理がリクエスト時の実行に切り替わり、ビルド時の値が固定されるのを防げます。
import { connection } from 'next/server'
export default async function Page() {
await connection()
const value = process.env.RUNTIME_CONFIG // 実行時に評価される
return <p>{value}</p>
}
なお、バージョン 16 で serverRuntimeConfig と publicRuntimeConfig は削除されました。環境変数に置き換えてください。
5キャッシュの置き場所
生成済みページやキャッシュは、既定でインスタンスごとのメモリとローカルディスクに保存されます。1 台で動かし、ディスクが永続化されているなら、これで問題ありません。
問題になるのは複数台構成です。コンテナごとに別々のキャッシュを持つため、あるインスタンスで再検証しても他には伝わらず、古い内容が出続けます。この場合は共有ストアを使うカスタムのキャッシュハンドラを設定します。
// next.config.js
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
cacheMaxMemorySize: 0, // 既定のメモリキャッシュを無効化
}
ハンドラ側では get / set / revalidateTag を実装し、Redis などの外部ストアに保存します。加えて、タグの無効化を全インスタンスへ伝えるための refreshTags も実装しておくと、再検証の取りこぼしを防げます。
6複数インスタンスで必要な 3 点
| 項目 | 設定するもの | 怠るとどうなるか |
|---|---|---|
| 暗号鍵 | NEXT_SERVER_ACTIONS_ENCRYPTION_KEY | 「Server Action が見つからない」エラーが散発する |
| デプロイ ID | deploymentId | ローリング更新中に古い資産を要求して失敗する |
| 共有キャッシュ | cacheHandler | インスタンスごとに表示内容がずれる |
暗号鍵はビルドごとに自動生成されるため、インスタンス間で食い違うと Server Function の復号に失敗します。base64 で 16・24・32 バイトのいずれかの鍵を用意し、ビルド時に環境変数で与えます。
デプロイ ID を設定すると、静的資産の URL にデプロイ識別子が付き、クライアントの持つ ID と食い違ったときは通常のページ遷移ではなく完全な再読み込みに切り替わります。新旧のバージョンが混在する時間帯を安全に乗り切るための仕組みです。
7ストリーミングを止めない
ストリーミングは、レスポンスを分割して送り続けることで成立します。前段のプロキシがバッファリングしていると、分割の意味が失われて最後にまとめて届きます。
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/:path*{/}?',
headers: [{ key: 'X-Accel-Buffering', value: 'no' }],
},
]
},
}
ロードバランサーやその手前の機器も、分割転送に対応している必要があります。1 か所でもためこむ設定があると、経路全体でストリーミングが無効になります。
8停止と再起動
after() で登録した後処理は、レスポンスを返した後に実行されます。プロセスを止めるときは SIGINT か SIGTERM を送り、処理中のリクエストと保留中の後処理が終わるのを待ちます。停止までの猶予は 10〜30 秒程度を確保しておくのが目安です。いきなり強制終了すると、書き込み途中の処理が失われる可能性があります。
9つまずきやすいところ
- 環境変数を変えたのに反映されない:
NEXT_PUBLIC_付きはビルド時に埋め込まれます。再ビルドが必要です。 - CDN を挟んだら個人情報が他人に見えた:リクエスト依存の描画では
Cache-Control: privateが付きますが、CDN 側がこれを尊重する設定になっているか確認してください。 - 画像最適化でメモリを食う:glibc 系の Linux では、メモリアロケータの設定が必要になる場合があります。
- ビルドが Webpack 設定で失敗する:バージョン 16 では Turbopack が既定です。設定を移行するか
--webpackを指定します。 - デプロイ直後だけ遅い:キャッシュキーにビルド ID が含まれるため、新しいデプロイでは作り直しから始まります。仕様どおりの挙動です。
これでひととおりの流れが揃いました。最後に、既存プロジェクトをバージョン 16 へ持っていく際の注意点をまとめます。
子ページはありません
人気ページ
- 1 Eclipseで「サーバーに追加または除去できるリソースがありません。」の原因と対処法
- 2 tomcat の起動 / 停止ログと catalina.log・catalina.out の違い
- 3 JavaScript で base URL を取得する方法|window.location.origin
- 4 YouTube Data API v3 エラー一覧|403・400・404 の原因と対処
- 5 Laravel エラー一覧|500/Blade/DB 接続/ルーティングの代表エラー
- 6 3Dグラフィックスとは|モデリング/レンダリング/主要ソフトウェア (Blender / Maya)
- 7 Spring Frameworkのアノテーション一覧
- 8 【Spring】@Valueアノテーションとは
- 9 CATALINA_HOME の確認方法 (Linux / Mac)
- 10 【Spring】@Autowiredアノテーションとは
最近更新/作成されたページ
- プロジェクトをTomcatプロジェクトとして認識させる方法 2026-10-07 22:32:50
- MySQLの1366 Incorrect string value|Laravelの文字コード・絵文字エラー 2026-10-07 21:54:03
- curlの証明書ホスト名不一致|旧エラー51・現行60の確認と対処 2026-10-07 21:54:03
- LaravelのMassAssignmentException|fillableの原因と安全な対処 2026-10-07 21:54:03
- Eclipse で Tomcat の起動ログがコンソールに出ない時の確認手順 2026-10-07 21:54:02
- MySQLにおける中央値(Median)の導き方(バージョン8未満) 2026-10-07 13:49:45
- getInputForward 2026-10-07 13:41:15
- JSONから配列に変換 2026-10-07 13:41:15
- ビューから値をモデルに格納しコントローラーで受け取る方法 2026-10-07 13:23:41
- Laravelのテーブル作成と定義変更|マイグレーション・up/down・注意点 2026-10-07 13:23:41
- NumPy 配列に要素を追加する方法 (append / concatenate) 2026-10-07 13:23:41
- MariaDB・MySQLで現在日時を取得する方法|NOW・タイムゾーン・保存型 2026-10-07 13:13:36
- 【django】テンプレートで定数を使用する方法 2026-10-07 13:10:15
- Spring BootにおけるApplication.propertiesの環境依存設定の分割方法 2026-10-07 12:09:35
- Not supported for DML operations【Springエラー】 2026-10-07 11:09:38