メインコンテンツまでスキップ

Incremental Static Regeneration (ISR)

Incremental Static Regeneration (ISR)によって、以下のことが可能です:

  • サイト全体をリビルドすることなく静的コンテンツを更新する
  • プリレンダリングされた静的ページをほとんどのリクエストに提供することで、サーバー負荷を軽減する
  • ページに正しいcache-controlヘッダーを自動的に加えるようにする
  • next buildが長時間かかることなく、膨大なコンテンツページを処理する

これが最小の例です:

app/blog/[id]/page.tsx
interface Post {
id: string
title: string
content: string
}

// リクエストが来た際、Next.jsはキャッシュを無効化し、
// 最大60秒ごとに一度だけ更新します。
export const revalidate = 60

// ビルド時には`generateStaticParams`によるパラメータのみをプリレンダリングします。
// ランダムなリクエストがまだ生成されていないパスの場合、
// Next.jsはそのページを要求時にサーバーレンダリングします。
export const dynamicParams = true // またはfalseにして未確認パスで404を表示

export async function generateStaticParams() {
const posts: Post[] = await fetch('https://api.vercel.app/blog').then((res) =>
res.json()
)
return posts.map((post) => ({
id: String(post.id),
}))
}

export default async function Page({ params }: { params: { id: string } }) {
const post: Post = await fetch(
`https://api.vercel.app/blog/${params.id}`
).then((res) => res.json())
return (
<main>
<h1>{post.title}</h1>
<p>{post.content}</p>
</main>
)
}

この例の動作は次のとおりです:

  1. next buildの際、既知のブログ投稿がすべて生成されます(この例では25件あります)
  2. これらのページへのすべてのリクエスト(例:/blog/1)はキャッシュされ、瞬時に応答します
  3. 60秒が経過した後も、次のリクエストはキャッシュされた(古い)ページを表示します
  4. キャッシュが無効化され、新しいバージョンのページがバックグラウンドで生成され始めます
  5. 正常に生成されると、Next.jsは更新されたページを表示し、キャッシュします
  6. /blog/26へのリクエストがあった場合、Next.jsはこのページを要求時に生成してキャッシュします

リファレンス

Route segment config

関数

時間に基づく再検証

これは/blogにブログ投稿のリストを表示します。1時間後、このページのキャッシュは次の訪問で無効化されます。そして、バックグラウンドで新しいバージョンのページが最新のブログ投稿を伴って生成されます。

app/blog/page.tsx
interface Post {
id: string
title: string
content: string
}

export const revalidate = 3600 // 毎時間無効化

export default async function Page() {
const data = await fetch('https://api.vercel.app/blog')
const posts: Post[] = await data.json()
return (
<main>
<h1>Blog Posts</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</main>
)
}

高い再検証時間を設定することをお勧めします。例えば、1秒ではなく1時間にします。より正確な制御が必要な場合は、オンデマンドの再検証を検討してください。リアルタイムデータが必要な場合は、dynamic renderingに切り替えることを検討してください。

revalidatePathを使ったオンデマンドの再検証

再検証のより正確な方法として、revalidatePath関数を使用してオンデマンドでページを無効化します。

例えば、新しい投稿を追加した後にこのServer Actionが呼び出されるとします。Server Componentでデータを取得する方法に関係なく、either fetchやデータベースへの接続を使用して、これはルート全体のキャッシュをクリアし、Server Componentが最新のデータを取得できるようにします。

app/actions.ts
'use server'

import { revalidatePath } from 'next/cache'

export async function createPost() {
// キャッシュ内の/postsルートを無効化
revalidatePath('/posts')
}

デモを見るソースコードを探る.

revalidateTagを使ったオンデマンドの再検証

ほとんどのユースケースでは、パス全体を再検証することをお勧めします。より細かい制御が必要な場合は、revalidateTag関数を使用できます。例えば、個別のfetch呼び出しにタグを付けることができます:

app/blog/page.tsx
export default async function Page() {
const data = await fetch('https://api.vercel.app/blog', {
next: { tags: ['posts'] },
})
const posts = await data.json()
// ...
}

ORMを使用している場合やデータベースに接続している場合は、unstable_cacheを使用できます:

app/blog/page.tsx
import { unstable_cache } from 'next/cache'
import { db, posts } from '@/lib/db'

const getCachedPosts = unstable_cache(
async () => {
return await db.select().from(posts)
},
['posts'],
{ revalidate: 3600, tags: ['posts'] }
)

export default async function Page() {
const posts = getCachedPosts()
// ...
}

その後、Server ActionsRoute HandlerrevalidateTagを使用できます:

app/actions.ts
'use server'

import { revalidateTag } from 'next/cache'

export async function createPost() {
// キャッシュ内の'tags'でタグ付けされた
// すべてのデータを無効化
revalidateTag('posts')
}

キャッシュされていない例外を処理する

データを再検証しようとするときにエラーが発生した場合、最後に正常に生成されたデータがキャッシュから提供され続けます。次のリクエスト時に、Next.jsはデータの再検証を試みます。エラー処理についての詳細を学ぶ.

キャッシュの保存場所をカスタマイズする

(Incremental Static Regenerationを使用して)ページをキャッシュし再検証するには、同じ共有キャッシュが使用されます。 Vercelへデプロイする場合、ISRキャッシュは自動的に耐久性のあるストレージに永続化されます。

自己ホスティングする場合、ISRキャッシュはNext.jsサーバーでファイルシステム(ディスク上)に保存されます。これは、PagesやApp Routerを使用した自己ホスティング時に自動的に機能します。

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

トラブルシューティング

ローカル開発時にキャッシュデータをデバッグする

fetch APIを使用している場合、どのようなリクエストがキャッシュされているか非キャッシュされているかを理解するために追加のロギングを加えることができます。logging オプションについて詳しく学ぶ.

next.config.js
module.exports = {
logging: {
fetches: {
fullUrl: true,
},
},
}

正しい本番動作を確認する

本番環境でページが正しくキャッシュされ再検証されることを確認するには、next buildを実行してからnext startで本番のNext.jsサーバーをローカルで実行することでテストできます。

これにより、本番環境で動作するようにISRの動作をテストできます。さらにデバッグするには、以下の環境変数を.envファイルに追加してください:

.env
NEXT_PRIVATE_DEBUG_CACHE=1

これにより、Next.jsサーバーのコンソールログでISRキャッシュヒットとミスが表示されます。どのページがnext build中に生成されるか、およびオンデマンドでパスがアクセスされる際にページがどのように更新されるかを出力を調査できます。

制約

  • ISRは、Node.jsランタイム(デフォルト)の使用時のみサポートされています。
  • ISRは、 Static Exportを作成する際にはサポートされていません。
  • 静的にレンダリングされたルートに複数のfetchリクエストがあり、それぞれ異なるrevalidate頻度を持つ場合、最低の時間がISRに使われます。ただし、これらの再検証頻度はData Cacheによって引き続き尊重されます。
  • ルートで使用されているfetchリクエストのいずれかがrevalidate時間を0に設定している場合、または明示的にno-storeを使用している場合、そのルートは dynamic renderingとしてレンダリングされます
  • オンデマンドISRリクエストではMiddlewareが実行されないため、Middleware内の任意のパス書き換えやロジックは適用されません。正確なパスを再検証していることを確認してください。例えば、書き換えられた/post-1ではなく、/post/1です。

バージョン履歴

バージョン変更内容
v14.1.0カスタムcacheHandlerが安定版になりました。
v13.0.0App Routerが導入されました。
v12.2.0Pages Router:オンデマンドISRが安定しています
v12.0.0Pages Router:Bot-aware ISR fallback 追加。
v9.5.0Pages Router:安定したISRが導入されました