コンテンツへスキップ

デプロイ

おめでとうございます。本番環境にデプロイする時が来ました。

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

Next.jsの作成者でありメンテナーであるVercelは、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は、静的サイトまたはシングルページアプリケーション (SPA) として開始し、後でオプションでサーバーを必要とする機能を使用するようにアップグレードすることを可能にします。

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

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

知っておくと良いこと

機能

画像最適化

next startを使用してデプロイする場合、next/imageによる画像最適化は、設定なしでセルフホストで動作します。画像を最適化するために別のサービスを使用したい場合は、画像ローダーを設定できます。

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

知っておくと良いこと

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

ミドルウェア

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

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

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

環境変数

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

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

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

app/page.ts
import { connection } from 'next/server'
 
export default async function Component() {
  await connection()
  // cookies, headers, and other Dynamic APIs
  // will also opt into dynamic rendering, meaning
  // this env variable is evaluated at runtime
  const value = process.env.MY_VALUE
  // ...
}

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

知っておくと良いこと

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

キャッシングとISR

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

ページのキャッシングと再検証(Incremental Static Regenerationを使用)は、同じ共有キャッシュを使用します。デフォルトでは、このキャッシュはNext.jsサーバーのファイルシステム(ディスク上)に保存されます。これは、Pages RouterとApp Routerの両方を使用してセルフホストする場合に自動的に機能します

キャッシュされたページとデータを永続ストレージに保存したい場合、またはNext.jsアプリケーションの複数のコンテナやインスタンス間でキャッシュを共有したい場合は、Next.jsのキャッシュ場所を設定できます。

自動キャッシング

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

静的アセット

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

assetPrefixについて詳しく学ぶ.

キャッシュの構成

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

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

next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // disable default in-memory caching
}

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

cache-handler.js
const cache = new Map()
 
module.exports = class CacheHandler {
  constructor(options) {
    this.options = options
  }
 
  async get(key) {
    // This could be stored anywhere, like durable storage
    return cache.get(key)
  }
 
  async set(key, data, ctx) {
    // This could be stored anywhere, like durable storage
    cache.set(key, {
      value: data,
      lastModified: Date.now(),
      tags: ctx.tags,
    })
  }
 
  async revalidateTag(tags) {
    // tags is either a string or an array of strings
    tags = [tags].flat()
    // Iterate over all entries in the cache
    for (let [key, value] of cache) {
      // If the value's tags include the specified tag, delete this entry
      if (value.tags.some((tag) => tags.includes(tag))) {
        cache.delete(key)
      }
    }
  }
 
  // If you want to have temporary in memory cache for a single request that is reset
  // before the next request you can leverage this method
  resetRequestCache() {}
}

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

知っておくと良いこと

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

ビルドキャッシュ

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

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

next.config.js
module.exports = {
  generateBuildId: async () => {
    // This could be anything, using the latest git hash
    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',
          },
        ],
      },
    ]
  },
}

部分的なプリレンダリング

部分的なプリレンダリング(実験的)は、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を実行したときのデフォルトの動作です。

after

afterは、next startを使用したセルフホスティング時に完全にサポートされます。

サーバーを停止する際は、SIGINTまたはSIGTERMシグナルを送信して待機することにより、グレースフルシャットダウンを確実に実行してください。これにより、Next.jsサーバーは、after内で使用されている保留中のコールバック関数やプロミスが終了するまで待機できます。

カスタムインフラストラクチャでafterを使用したい場合は、プロバイダーのドキュメントを確認してafterのサポート状況を確認してください。

参考:サーバーレスプラットフォームでのafterのサポートサーバーレスコンテキストでafterを使用するには、レスポンスが送信された後も非同期タスクが終了するまで待機する必要があります。Next.jsとVercelでは、これはwaitUntil(promise)と呼ばれるプリミティブを使用して実現されます。これは、waitUntilに渡されたすべてのプロミスが解決されるまで、サーバーレス呼び出しのライフタイムを延長します。

ユーザーがafterを実行できるようにしたい場合は、同様に動作するwaitUntilの実装を提供する必要があります。

afterが呼び出されると、Next.jsはこのようにwaitUntilにアクセスします。

const RequestContext = globalThis[Symbol.for('@next/request-context')]
const contextValue = RequestContext?.get()
const waitUntil = contextValue?.waitUntil

これは、globalThis[Symbol.for('@next/request-context')]が次のようなオブジェクトを含むことを想定していることを意味します。

type NextRequestContext = {
  get(): NextRequestContextValue | undefined
}
 
type NextRequestContextValue = {
  waitUntil?: (promise: Promise<any>) => void
}

以下に実装例を示します。

import { AsyncLocalStorage } from 'node:async_hooks'
 
const RequestContextStorage = new AsyncLocalStorage<NextRequestContextValue>()
 
// Define and inject the accessor that next.js will use
const RequestContext: NextRequestContext = {
  get() {
    return RequestContextStorage.getStore()
  },
}
globalThis[Symbol.for('@next/request-context')] = RequestContext
 
const handler = (req, res) => {
  const contextValue = { waitUntil: YOUR_WAITUNTIL }
  // Provide the value
  return RequestContextStorage.run(contextValue, () => nextJsHandler(req, res))
}