Next.js 14/15/16 的 SSR、SSG、ISR 与缓存实现细节

Created on

本文聚焦 App Router,按版本拆解 SSR/SSG/ISR 与缓存实现细节。核心资料来自 Next.js 官方文档与发布说明。

渲染选择速查

总览:App Router 的“渲染 + 缓存”底层结构

App Router 的 SSR/SSG/ISR 并不是三套独立机制,而是由“渲染策略 + 缓存层”组合而成。官方把缓存分成四层:

默认情况下,Next.js 会尽量静态化并缓存,只有在使用动态 API 或 cache: 'no-store' 时才会转为动态渲染。

补充说明:在静态渲染路径下,fetch 的结果会进入 Data Cache,并驱动 Full Route Cache。动态渲染下,fetch 默认不缓存。

SSR/SSG/ISR 与缓存关系

来源:https://nextjs.org/docs/app/guides/caching


Next.js 14(2023):经典 App Router 模型

SSR(动态渲染)实现

触发动态渲染的常见方式:

// app/dashboard/page.tsx
export const dynamic = "force-dynamic";

export default async function Page() {
  const data = await fetch("https://api.example.com/me", {
    cache: "no-store",
  });
  return <pre>{JSON.stringify(await data.json())}</pre>;
}

来源:https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config

SSG(静态渲染)实现

静态渲染默认由框架自动推断。对动态路由,可通过 generateStaticParams 预生成:

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch("https://api.example.com/posts").then((r) =>
    r.json()
  );
  return posts.map((post: { slug: string }) => ({ slug: post.slug }));
}

也可以强制静态:

export const dynamic = "force-static";

来源:https://nextjs.org/docs/app/guides/caching

ISR(增量静态再生成)实现

常用两类入口:

// app/news/page.tsx
export const revalidate = 300; // 5 分钟

export default async function Page() {
  const res = await fetch("https://api.example.com/news");
  return <NewsList items={await res.json()} />;
}

来源:https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config

缓存实现细节(14 核心)

来源:https://nextjs.org/docs/app/guides/caching

PPR 预览

Next.js 14 开始预览 PPR(Partial Prerendering),通过 Suspense 做静态壳体 + 动态流式加载。官方在 14 中强调其为预览特性。

来源:https://nextjs.org/blog/next-14


Next.js 15(2024-2025):模型延续,工具链更稳

SSR / SSG / ISR

渲染与缓存模型与 14 基本一致,仍以 App Router 的动态 API 与 fetch 缓存配置为核心。15.5 提示的弃用项主要面向 16 的升级,渲染语义本身无实质变化。

缓存与渲染实践建议

来源:https://nextjs.org/docs/app/guides/caching


Next.js 16(2025):Cache Components 让缓存显式化

SSR(请求时渲染)实现

开启 Cache Components 后,运行时数据必须放在 Suspense 内,未处理会报错。动态区域按请求渲染,静态壳体仍可预渲染。

// app/profile/page.tsx
import { cookies } from "next/headers";
import { Suspense } from "react";

async function RuntimeProfile() {
  const session = (await cookies()).get("session");
  return <div>{session?.value}</div>;
}

export default function Page() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <RuntimeProfile />
    </Suspense>
  );
}

来源:https://nextjs.org/docs/app/getting-started/cache-components

SSG(静态壳体 + 缓存内容)实现

Cache Components 使静态壳体 + 缓存内容成为默认路径:

// app/page.tsx
import { cacheLife } from "next/cache";

export default async function Page() {
  "use cache";
  cacheLife("hours");
  const data = await fetch("https://api.example.com/posts");
  return <Posts items={await data.json()} />;
}

来源:https://nextjs.org/docs/app/getting-started/cache-components

ISR(缓存再验证)实现

Next.js 16 将再验证能力从“路由级”进一步收敛到显式缓存 API:

// app/actions.ts
"use server";
import { updateTag } from "next/cache";

export async function updateProfile() {
  // 写入数据
  updateTag("profile");
}

来源:https://nextjs.org/docs/app/getting-started/cache-components

路由段配置的变化

启用 cacheComponents 后,dynamic / revalidate / fetchCache 等路由段配置会被禁用,并逐步弃用。

来源:https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config


版本差异总结(14 -> 15 -> 16)


参考链接