Menu

デプロイ

おめでとうございます。本番環境にリリースする時が来ました。

Vercelでマネージドされた Next.js でデプロイするか、Node.jsサーバー、Dockerイメージ、または静的HTMLファイルで自己ホストできます。next start を使用してデプロイする場合、すべての Next.js 機能がサポートされます。

本番ビルド

next build を実行すると、本番用に最適化されたアプリケーションが生成されます。ページに基づいて、HTML、CSS、JavaScriptファイルが作成されます。JavaScriptは Next.js コンパイラを使用してコンパイルされ、ブラウザバンドルはミニファイされ、最高のパフォーマンスを達成し、すべての最新ブラウザをサポートします。

Next.js は、マネージドおよび自己ホストされた Next.js の両方で使用される標準的なデプロイメント出力を生成します。これにより、両方のデプロイ方法で全機能がサポートされることを保証します。次のメジャーバージョンでは、この出力を Build Output API 仕様に変換する予定です。

Vercelでマネージドされた Next.js

Vercelは、Next.jsの作成者および保守者で、Next.jsアプリケーション用の管理インフラストラクチャと開発者エクスペリエンスプラットフォームを提供します。

Vercelへのデプロイは設定不要で、グローバルでのスケーラビリティ、可用性、パフォーマンスに関する追加の拡張機能を提供します。ただし、自己ホストする場合でもすべての Next.js 機能がサポートされます。

Vercel上のNext.jsについて詳しく学ぶか、無料でテンプレートをデプロイして試してみてください。

自己ホスト

Next.jsは3つの異なる方法で自己ホストできます:

🎥 視聴: Next.jsの自己ホストについてさらに学ぶ → YouTube (45分)

Node.jsサーバー

Next.jsは、Node.jsをサポートする任意のホスティングプロバイダーにデプロイできます。package.json"build""start" スクリプトがあることを確認してください:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}

次に、npm run build を実行してアプリケーションをビルドします。最後に、npm run start を実行してNode.jsサーバーを起動します。このサーバーはすべての Next.js 機能をサポートします。

Dockerイメージ

Next.jsは、Dockerコンテナをサポートする任意のホスティングプロバイダーにデプロイできます。Kubernetesなどのコンテナオーケストレーターにデプロイする場合や、任意のクラウドプロバイダーでコンテナ内で実行する場合に、このアプローチを使用できます。

  1. マシンにDockerをインストール
  2. サンプルをクローン(またはマルチ環境サンプル
  3. コンテナをビルド: docker build -t nextjs-docker .
  4. コンテナを実行: docker run -p 3000:3000 nextjs-docker

Docker経由のNext.jsは、すべてのNext.js機能をサポートします。

静的HTMLエクスポート

Next.jsは、静的サイトまたはSingle-Page Application(SPA)として開始し、後でサーバーを必要とする機能を任意でアップグレードすることを可能にします。

Next.jsは静的エクスポートをサポートしているため、HTML/CSS/JS静的アセットを提供できる任意のWebサーバーにデプロイおよびホストできます。これにはAWS S3、Nginx、Apacheなどのツールが含まれます。

静的エクスポートとして実行すると、サーバーを必要とするNext.js機能はサポートされません。詳細はこちら

補足:

機能

画像最適化

next/image による画像最適化は、next start を使用してデプロイする場合、追加設定なしで自己ホストされます。画像を最適化するための別のサービスを使用する場合は、画像ローダーを設定できます。

画像最適化は、next.config.js でカスタム画像ローダーを定義することで、静的エクスポートで使用できます。画像は構築時ではなく、実行時に最適化されることに注意してください。

補足:

  • glibcベースのLinuxシステムでは、過剰なメモリ使用を防ぐために、画像最適化に追加の設定が必要な場合があります。
  • 最適化された画像のキャッシュ動作とTTLの設定方法について詳しく学びます。
  • 好む場合、画像最適化を無効にして、next/imageの他の利点は保持できます。たとえば、画像を別途自分で最適化する場合など。

ミドルウェア

ミドルウェアは、next start を使用してデプロイする場合、追加設定なしで自己ホストされます。着信リクエストへのアクセスを必要とするため、静的エクスポートを使用する場合はサポートされません。

ミドルウェアは、アプリケーション内の各ルートまたはアセットの前で実行される可能性があるため、低遅延を確保するために、利用可能なすべてのNode.js APIのサブセットであるランタイムを使用します。このランタイムは「エッジで」実行する必要はなく、単一リージョンのサーバーで動作します。複数のリージョンでミドルウェアを実行するには、追加の設定とインフラストラクチャが必要です。

すべてのNode.js APIを必要とするロジック(または外部パッケージを使用する)を追加したい場合、このロジックをサーバーコンポーネントとしてレイアウトに移動できる場合があります。例えば、ヘッダーをチェックし、リダイレクトすることなどです。また、next.config.js を通じて、ヘッダー、Cookie、クエリパラメータを使用してリダイレクトまたはリライトできます。それでも対応できない場合は、カスタムサーバーを使用できます。

環境変数

Next.jsは、ビルド時と実行時の両方の環境変数をサポートできます。

デフォルトでは、環境変数はサーバー上でのみ利用可能です。環境変数をブラウザに公開するには、NEXT_PUBLIC_ プレフィックスを付ける必要があります。ただし、これらの公開環境変数は next build 中にJavaScriptバンドルにインライン展開されます。

サーバー上の動的レンダリング中に、環境変数を安全に読み取ることができます。

app/page.ts
TypeScript
import { connection } from 'next/server'
 
export default async function Component() {
  await connection()
  // cookies、headers、その他のダイナミックAPIは
  // 動的レンダリングにオプトインし、
  // この環境変数は実行時に評価されます
  const value = process.env.MY_VALUE
  // ...
}

これにより、異なる値を持つ複数の環境を通じて昇格できる単一のDockerイメージを使用できます。

補足:

  • register関数を使用して、サーバー起動時にコードを実行できます。
  • スタンドアロン出力モードで機能しないため、runtimeConfigオプションの使用は推奨しません。代わりに、漸進的にApp Routerを採用することをお勧めします。

キャッシングとISR

Next.jsは、レスポンス、生成された静的ページ、ビルド出力、画像、フォント、スクリプトなどの静的アセットをキャッシュできます。

キャッシングとページの再検証(インクリメンタル静的再生成を使用)は、同じ共有キャッシュを使用します。デフォルトでは、このキャッシュはNext.jsサーバーのファイルシステム(ディスク)に保存されます。これは、PagesルーターとApp Routerの両方を使用する自己ホスティング時に自動的に動作します。

キャッシュされたページとデータを耐久性のあるストレージに永続化したり、Next.jsアプリケーションの複数のコンテナまたはインスタンス間でキャッシュを共有したい場合は、Next.jsのキャッシュ場所を構成できます。

自動キャッシング

  • Next.jsは、完全に変更不可能なアセットに対してCache-Controlヘッダーをpublic, max-age=31536000, immutableに設定します。これは上書きできません。これらの変更不可能なファイルには、ファイル名にSHA-ハッシュが含まれているため、無期限に安全にキャッシュできます。例えば、静的画像のインポートなどです。画像のTTLを設定できます。
  • インクリメンタル静的再生成(ISR)は、Cache-Controlヘッダーをs-maxage: <getStaticPropsの再検証>, stale-while-revalidateに設定します。この再検証時間は、getStaticProps関数で秒単位で定義されます。revalidate: falseに設定すると、デフォルトで1年のキャッシュ期間になります。
  • 動的にレンダリングされるページは、ユーザー固有のデータがキャッシュされないように、Cache-Controlヘッダーをprivate, no-cache, no-store, max-age=0, must-revalidateに設定します。これはApp RouterとPages Routerの両方に適用されます。これにはドラフトモードも含まれます。

静的アセット

静的アセットを別のドメインやCDNでホストする場合は、next.config.jsassetPrefix設定を使用できます。Next.jsは、JavaScriptまたはCSSファイルを取得する際にこのアセットプレフィックスを使用します。アセットを別のドメインに分離すると、DNSとTLSの解決に余分な時間がかかるというデメリットがあります。

assetPrefixの詳細

キャッシングの設定

デフォルトでは、生成されたキャッシュアセットはメモリ(デフォルトで50MB)とディスクに保存されます。Kubernetesなどのコンテナオーケストレーションプラットフォームを使用してNext.jsをホスティングする場合、各ポッドにキャッシュのコピーがあります。デフォルトでキャッシュがポッド間で共有されないため、古いデータが表示されるのを防ぐために、Next.jsキャッシュのハンドラーを設定し、メモリ内キャッシュを無効にできます。

自己ホスティング時にISR/データキャッシュの場所を設定するには、next.config.jsファイルにカスタムハンドラーを設定できます:

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // デフォルトのメモリ内キャッシュを無効化
}

次に、プロジェクトのルートにcache-handler.jsを作成します。例:

cache-handler.js
const cache = new Map()
 
module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }
 
  async get(key) {
    // これは任意の場所に保存できます(耐久性のあるストレージなど)
    return cache.get(key)
  }
 
  async set(key, data, ctx) {
    // これは任意の場所に保存できます(耐久性のあるストレージなど)
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }
 
  async revalidateTag(tags) {
    // tagsは文字列または文字列の配列
    tags = [tags].flat()
    // キャッシュのすべてのエントリを反復
    for (let [key, value] of cache) {
      // 値のタグに指定されたタグが含まれる場合、このエントリを削除
      if (value.tags.some((tag) => tags.include(tag))) {
        cache.delete(key)
      }
    }
  }
}

カスタムキャッシュハンドラーを使用すると、Next.jsアプリケーションをホスティングするすべてのポッド間で一貫性を確保できます。例えば、RedisやAWS S3など、任意の場所にキャッシュされた値を保存できます。

補足:

  • revalidatePathはキャッシュタグの上位にある便利なレイヤーです。revalidatePathを呼び出すと、指定されたページの特別なデフォルトタグを使用してrevalidateTag関数が呼び出されます。

ビルドキャッシュ

Next.jsはnext build中にIDを生成し、どのバージョンのアプリケーションが提供されているかを識別します。同じビルドを使用して複数のコンテナを起動する必要があります。

環境の各ステージで再ビルドする場合、コンテナ間で使用する一貫したビルドIDを生成する必要があります。next.config.jsgenerateBuildIdコマンドを使用します:

next.config.js
module.exports = {
  generateBuildId: async () => {
    // これは任意のものになります。最新のgitハッシュを使用
    return process.env.GIT_HASH
  },
}

バージョンスキュー

Next.jsは、バージョンスキューのほとんどのインスタンスを自動的に軽減し、検出された際に新しいアセットを取得するためにアプリケーションを自動的に再読み込みします。例えば、deploymentIdに不一致がある場合、ページ間の遷移はプリフェッチされた値ではなく、ハードナビゲーションを実行します。

アプリケーションが再読み込みされると、ページ遷移間で状態を保持するように設計されていない場合、アプリケーションの状態が失われる可能性があります。例えば、URLの状態またはローカルストレージを使用すると、ページリフレッシュ後も状態が保持されます。ただし、useStateのようなコンポーネントの状態は、そのような遷移で失われます。

Vercelは、新しいバージョンがデプロイされた後も、古いクライアントに対して前のバージョンのアセットと関数を引き続き利用できるように、Next.jsアプリケーションに追加のスキュー保護を提供します。

next.config.jsファイルでdeploymentIdプロパティを手動で設定して、各リクエストが?dplクエリ文字列またはx-deployment-idヘッダーを使用するようにできます。

ストリーミングとサスペンス

Next.jsのApp Routerは、自己ホスティング時にストリーミングレスポンスをサポートします。Nginxなどのプロキシを使用している場合、ストリーミングを有効にするためにバッファリングを無効にする必要があります。

例えば、Nginxでは、X-Accel-Bufferingnoに設定してバッファリングを無効にできます:

next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*{/}?',
        headers: [
          {
            key: 'X-Accel-Buffering',
            value: 'no',
          },
        ],
      },
    ]
  },
}

Partial Prerendering

Partial Prerendering(実験的機能)は、デフォルトでNext.jsで動作し、CDN機能ではありません。これには、Node.jsサーバー(next startを通じて)としてのデプロイと、Dockerコンテナと共に使用する場合が含まれます。

CDNでの使用

Next.jsアプリケーションの前面にCDNを使用する場合、動的APIにアクセスすると、ページにはCache-Control: privateレスポンスヘッダーが含まれます。これにより、結果のHTMLページが非キャッシュ可能としてマークされます。ページが完全に静的にプレレンダリングされている場合、CDNでページをキャッシュできるようにCache-Control: publicが含まれます。

静的コンポーネントと動的コンポーネントの混在が不要な場合、ルート全体を静的にし、出力されたHTML をCDNにキャッシュできます。この自動静的最適化は、動的APIが使用されない場合にnext buildを実行する際のデフォルトの動作です。