Next.js SSR vs SSG vs ISR:渲染策略选择指南

“为什么首页加载要3秒?“老板盯着屏幕,我盯着Chrome DevTools的瀑布图——红色的TTFB长得像条蛇。那是我第一次意识到,可能一开始就选错了渲染策略。
这不是个案。在Next.js的GitHub Issues里,每天都有人问:“我该用SSR还是SSG?""ISR配置了为啥不生效?“说实话,我之前也一头雾水。明明文档都看了,遇到具体项目还是不知道该选哪个。
你可能也遇到过类似的困惑:
- 用了SSR,结果首屏加载慢得让人抓狂
- 选了SSG,每次更新内容都要重新构建整个站点
- ISR看起来很美好,配置完却发现根本不生效
其实这三种渲染策略没有”最好”的,只有”最合适”的。今天我们就来彻底搞清楚,什么场景该用哪种策略,以及怎么避开常见的坑。
先搞清楚:三种渲染策略到底是什么
在讨论怎么选之前,咱们先把这三个概念搞清楚。我试着用最直白的方式来讲。
SSG(静态站点生成):提前做好的便当
想象你开了个便当店,每天早上提前做好100份便当放在柜台,客人来了直接拿就走。这就是SSG的工作方式。
具体来说:
- 什么时候生成:在你执行
next build的时候,Next.js就把所有页面的HTML都生成好了 - 用户访问时:CDN直接返回提前生成的HTML文件,超快
- 什么时候适合:内容不常变的页面,比如企业官网、产品介绍页、博客文章
优势明显:
- 速度快到飞起。根据AWS的数据,SSG页面加载速度比SSR快40-60%
- TTFB(首字节时间)通常在50ms以内,Vercel官方测过
- 服务器压力几乎为0,流量再大也不怕
- 成本低,静态文件托管便宜得多
但也有限制:
- 内容更新了?不好意思,得重新构建整个站点
- 页面多了构建时间会很长,几千个页面可能要等半小时
- 不支持个性化内容,所有用户看到的都一样
说白了,SSG就是用”提前准备”换来的速度。
SSR(服务端渲染):现炒现卖
还是便当店的例子,但这次你不提前做便当了。客人点什么,你现场炒什么。这就是SSR。
具体来说:
- 什么时候生成:每次用户请求时,服务器实时生成HTML
- 用户访问时:等服务器查数据库、调API、渲染HTML,然后返回
- 什么时候适合:内容实时变化或需要个性化的页面
优势在这:
- 内容永远是最新的,用户看到的是此时此刻的数据
- 支持个性化,可以根据用户的Cookie、权限展示不同内容
- 可以访问请求时才有的信息,比如请求头、查询参数
但代价不小:
- 慢。TTFB通常在200-500ms,Vercel官方数据
- 服务器压力大,流量一上来服务器可能扛不住
- 成本高,需要一直跑着服务器
有个真实案例:某电商网站用SSR,首屏加载要2.3秒。后来改成ISR,直接降到0.8秒。
ISR(增量静态再生):便当+现炒的混合模式
这次你聪明了:提前做好便当,但每隔一段时间(比如每小时)更新一次。客人大部分时候拿到的是提前做好的,但内容又不会太旧。这就是ISR。
具体来说:
- 初次构建:
next build时生成静态HTML(像SSG) - 后续更新:根据你设置的
revalidate时间,后台自动重新生成页面 - 用户访问时:大部分时候返回缓存的HTML(快),过期了就后台更新
这是个平衡点:
- 有SSG的速度(用户拿到的是静态文件)
- 又有SSR的新鲜度(内容会定期更新)
- 不需要每次都重新构建整个站点
配置很简单(App Router语法):
// app/posts/[id]/page.tsx
export const revalidate = 60; // 60秒后重新验证
export default async function Post({ params }) {
const post = await getPost(params.id);
return <div>{post.content}</div>;
}但有些坑:
- 配置了不生效?可能是你在开发环境(
next dev)测试,ISR只在生产环境(next build+next start)才工作 - 部署平台不支持?Vercel原生支持,其他平台可能需要额外配置
说实话,ISR是我现在最常用的策略。它解决了SSG和SSR各自的痛点,真的很香。
决策树:什么场景用什么策略
好了,概念搞清楚了。现在最关键的问题来了:我的项目该用哪个?
别慌,我给你整理了一个决策流程。你可以对照自己的项目,一步步往下走。
第一步:问自己三个问题
问题1:内容需要个性化吗?
如果你的页面需要根据用户的身份、权限、偏好展示不同内容,那直接用SSR。
典型场景:
- 用户仪表盘(每个人看到的数据不一样)
- 个人资料页
- 购物车页面
- 任何需要认证后才能访问的页面
为啥?个性化内容没法提前生成,只能在用户请求时动态生成。
问题2:内容多久更新一次?
这个问题决定了你用SSG还是ISR。
几秒到几分钟更新一次:用SSR
- 比如股票行情、体育赛事比分、聊天消息
- 这种实时性要求高的,SSR是唯一选择
几分钟到几小时更新一次:用ISR
- 比如新闻网站、博客首页、产品列表、电商库存
- ISR可以设置
revalidate: 300(5分钟),既快又新鲜
很少更新,或者手动触发更新:用SSG
- 比如企业官网、产品介绍页、帮助文档
- 这些内容可能几周甚至几个月才改一次
问题3:流量有多大?
流量大小会影响成本和性能考量。
超高流量(每天百万级PV):优先SSG或ISR
- 静态文件可以直接走CDN,成本低性能好
- 如果用SSR,服务器压力会很大,成本飙升
中低流量:三种都可以
- 如果内容实时性要求高,SSR也完全能接受
- 但既然能用ISR,为啥不用呢?
第二步:常见场景速查表
我把一些典型场景整理了出来,你可以直接对号入座:
用SSG的场景:
- ✅ 企业官网
- ✅ 产品介绍页、定价页
- ✅ 营销落地页
- ✅ 博客文章详情页(内容发布后不再修改)
- ✅ 技术文档、API文档
- ✅ 帮助中心、FAQ
记住一个关键词:静态、公共、不常更新
用SSR的场景:
- ✅ 社交媒体信息流(Facebook、Twitter式)
- ✅ 用户个人仪表盘
- ✅ 购物车、订单页面
- ✅ 实时数据面板
- ✅ 搜索结果页(根据查询参数生成)
- ✅ 需要认证的页面(基于Cookie判断)
记住一个关键词:动态、个性化、实时
用ISR的场景(我的最爱):
- ✅ 博客首页、文章列表(定期有新文章)
- ✅ 新闻网站
- ✅ 电商产品详情页(价格、库存定期更新)
- ✅ 论坛帖子页(评论、点赞数延迟几分钟更新可以接受)
- ✅ UGC内容平台(内容更新频繁但不需要秒级实时)
- ✅ 天气预报、汇率信息
记住一个关键词:定期更新、可接受延迟、高流量
第三步:混合使用才是王道
有个误区要打破:你不用全站只用一种策略。
实际上,大部分项目都是混合使用的:
- 首页和产品列表用ISR(流量大,内容定期更新)
- 产品详情页用SSG(内容稳定)或ISR(价格库存会变)
- 用户仪表盘用SSR(个性化)
- 关于我们、联系我们用SSG(完全静态)
我们团队的一个电商项目就是这么做的:
- 首页(ISR,10分钟更新)
- 商品列表(ISR,5分钟更新)
- 商品详情(ISR,3分钟更新,因为库存会变)
- 购物车(SSR,必须实时)
- 用户中心(SSR,个性化)
- 关于我们、隐私政策(SSG,几乎不变)
这样搭配下来,性能和实时性都兼顾到了。
一句话决策口诀
如果你还是拿不准,记住这个:
静态用SSG,实时用SSR,定期更新用ISR
当你不确定时,先用ISR试试。它是三者中最平衡的选择,出错概率最低。
三大常见坑和解决方案
讲完理论,咱们聊点实际的。这三个坑,我都踩过,估计你也会遇到。
坑1:ISR的revalidate不生效
症状:你兴冲冲地配置了revalidate: 60,以为页面会每分钟更新,结果等了半天,内容还是老样子。
我当时的崩溃:真的,我第一次用ISR时在这里卡了整整两天。查了无数文档,改了N次配置,就是不work。
原因有三个:
开发环境不支持ISR
这是最常见的原因。
next dev开发模式下,ISR根本不工作!它只在生产模式下才生效。解决办法:
# 不要用 next dev 测试ISR # 必须先构建再启动 npm run build npm run start # 然后访问页面测试部署平台不支持
不是所有平台都原生支持ISR。Vercel支持得很好(毕竟是Next.js官方),但其他平台可能需要额外配置。
比如Netlify:需要安装
@netlify/plugin-nextjs插件才能支持ISR。检查方法:去你的部署平台文档搜”Next.js ISR support”。
CDN缓存覆盖了ISR
如果你在Next.js前面加了一层CDN或反向代理(如Cloudflare),它们可能缓存了整个响应,导致ISR的更新机制失效。
解决办法:配置CDN,让它尊重
Cache-Control头,或者针对ISR页面设置较短的CDN缓存时间。
我的建议:配置ISR后,一定要在生产环境测试。可以用console.log(new Date())打印页面生成时间,来验证revalidate是否生效。
坑2:SSR首屏加载慢到怀疑人生
症状:用了SSR后,首屏白屏时间长达2-3秒,用户都快跑了。
真实案例:我们有个项目,首页用了SSR去获取用户信息和推荐内容。结果首屏TTFB直接1.2秒,加上渲染时间,用户要等3秒才能看到内容。老板看了直摇头。
原因分析:
SSR慢,通常是因为服务器端数据获取慢。可能是:
- API调用慢(外部API延迟高)
- 数据库查询慢(没索引、查询复杂)
- 串行请求(一个接口等另一个接口)
- 服务器性能差或地理位置远
解决方案有四个:
用Streaming SSR和Suspense(React 18+)
不要等所有数据都拿到再渲染,可以先返回页面框架,数据到了再流式传输。
// app/dashboard/page.tsx import { Suspense } from 'react'; export default function Dashboard() { return ( <div> <h1>用户仪表盘</h1> {/* 快速渲染的部分 */} <UserInfo /> {/* 慢速数据用Suspense包裹 */} <Suspense fallback={<div>加载统计数据...</div>}> <SlowStats /> </Suspense> </div> ); }这样用户能更快看到页面,体验好很多。
并行请求数据
把多个API调用改成并行执行:
// ❌ 串行:慢 const user = await getUser(); const posts = await getPosts(user.id); // ✅ 并行:快 const [user, posts] = await Promise.all([ getUser(), getPosts() ]);考虑改用ISR
很多时候你以为需要SSR,但其实ISR就够了。
问问自己:这个页面的数据真的需要实时吗?如果延迟1分钟更新可以接受,那就用ISR。
我们那个首页后来改成了ISR(
revalidate: 60),首屏加载直接从3秒降到0.7秒。部署到Edge
如果你在用Vercel,可以试试Edge Functions。它会把你的SSR函数部署到全球CDN节点,离用户更近,延迟更低。
// app/api/data/route.ts export const runtime = 'edge'; // 就这一行
坑3:SSG构建时间太长
症状:网站有几千个页面,每次next build要等20-30分钟,甚至超时失败。
痛点场景:电商网站有5000个商品,博客有3000篇文章,用SSG的话构建时要为每个页面生成HTML。
为啥会慢:
SSG在构建时生成所有页面的HTML。页面越多,构建时间越长。而且很多页面可能根本没人访问(长尾商品、老文章)。
解决方案:
用fallback策略
不要一次性生成所有页面,只生成热门页面,其他页面按需生成。
// app/posts/[id]/page.tsx export async function generateStaticParams() { // 只返回热门的100篇文章 const posts = await getTopPosts(100); return posts.map(post => ({ id: post.id })); } // 其他页面第一次访问时生成 export const dynamicParams = true;结合ISR
构建时只生成首页和热门页面,其他页面用ISR按需生成。
这样构建时间大大缩短,用户访问时也不会慢(因为有缓存)。
增量构建(Incremental Builds)
Vercel支持增量构建,只重新构建变化的页面。如果你更新了一篇文章,不需要重新构建整个站点。
其他平台可能需要自己实现这个逻辑。
实际效果:
我们的一个博客项目有2000篇文章。最开始用纯SSG,构建要15分钟。后来改成:
- 构建时只生成最新的50篇
- 其他文章用
dynamicParams = true按需生成 - 所有文章页用ISR(
revalidate: 3600)
现在构建时间降到2分钟,用户访问速度也没变慢。
Next.js 15的新特性:React Server Components和PPR
聊到这,顺便提一下Next.js 15带来的两个新东西。虽然它们不完全是”渲染策略”,但确实影响了我们怎么构建页面。
React Server Components(RSC):组件级的SSR
如果你用过Next.js 13+的App Router,你已经在用Server Components了。
它和传统SSR有啥区别?
- 传统SSR:整个页面在服务器端渲染
- RSC:默认情况下,组件在服务器端渲染,只有需要交互的组件才在客户端运行
好处很明显:
JS bundle变小了
Server Component的代码不会被打包到客户端。Next.js官方数据显示,用了RSC后,客户端JavaScript体积能减少30-50%。
页面加载更快,用户手机也不那么烫了。
直接访问后端资源
Server Component可以直接查数据库、读文件系统,不需要建API端点。
// app/posts/page.tsx // 这是个Server Component,可以直接查数据库 async function getPosts() { const posts = await db.posts.findMany(); return posts; } export default async function PostsPage() { const posts = await getPosts(); return ( <div> {posts.map(post => ( <PostCard key={post.id} post={post} /> ))} </div> ); }
实战建议:
- 默认用Server Component(App Router下就是默认的)
- 只在需要交互的地方用Client Component(加
'use client') - 数据获取和静态UI用Server Component,按钮、表单、动画用Client Component
这样一来,你的应用既有SSR的SEO优势,又有很小的JS bundle。
Partial Prerendering(PPR):静态+动态的混合体
PPR是Next.js 15引入的实验性功能,让你在同一个页面里混用静态和动态部分。
举个例子:
电商产品页:
- 产品描述、图片(静态,构建时生成)
- 库存、价格(动态,请求时获取)
用PPR的话,静态部分在构建时就生成好了,动态部分每次请求时才计算。这样既快又新鲜。
怎么用:
// next.config.js
module.exports = {
experimental: {
ppr: true,
},
};
// app/products/[id]/page.tsx
export const experimental_ppr = true;
export default function ProductPage({ params }) {
return (
<div>
{/* 静态部分:构建时生成 */}
<ProductDescription id={params.id} />
{/* 动态部分:请求时生成 */}
<Suspense fallback={<div>加载中...</div>}>
<DynamicStock id={params.id} />
</Suspense>
</div>
);
}但有个大前提:
PPR目前还是实验性功能,不建议在生产环境用。可以在非关键页面试试水,但别全站上。
等它稳定了(可能Next.js 16?),绝对是个大杀器。
这些新特性怎么和SSR/SSG/ISR配合?
- RSC + SSG:Server Component默认就是静态的,和SSG配合完美
- RSC + ISR:Server Component +
revalidate,既静态又能定期更新 - RSC + SSR:动态路由或设置
dynamic = 'force-dynamic',就变成SSR了 - PPR:可以看作SSG和SSR的终极融合
我的理解是:RSC是Next.js的底层架构升级,而SSG/SSR/ISR是基于这个架构的渲染策略。它们不冲突,反而相辅相成。
结论
说了这么多,咱们回到最开始的问题:SSR、SSG、ISR到底该怎么选?
其实没有标准答案。每个项目的需求不一样,流量不一样,预算也不一样。但只要你搞清楚这三个核心问题,选择就不难了:
- 内容需要个性化吗? → 需要就用SSR
- 内容多久更新一次? → 实时用SSR,定期更新用ISR,很少变化用SSG
- 流量有多大? → 超高流量优先SSG或ISR
还记得文章开头老板问我”为什么这么慢”的场景吗?后来我们把那个首页从SSR改成了ISR(revalidate: 60),首屏加载从3秒降到0.8秒。老板满意了,用户体验也好了。
我的建议是:
- 如果你不确定,先用ISR试试。它是三者中最平衡的,既快又能保持内容新鲜
- 项目上线后,用Chrome DevTools的Performance面板实际测试一下,看看TTFB、FCP这些指标
- 不同页面可以用不同策略,不要教条
最后,渲染策略不是一成不变的。项目发展了,用户量上去了,需求变了,策略也可以调整。别怕改,Next.js在这方面的切换成本其实挺低的。
希望这篇文章能帮你少踩点坑。如果你有什么实战经验或踩坑故事,欢迎留言分享!
常见问题
SSR、SSG、ISR 的核心区别是什么?
什么时候用 SSG,什么时候用 SSR,什么时候用 ISR?
ISR 的 revalidate 配置了为什么不生效?
SSR 首屏加载慢怎么办?
SSG 构建时间太长怎么办?
可以混合使用不同的渲染策略吗?
React Server Components 和 SSR/SSG/ISR 是什么关系?
16 分钟阅读 · 发布于: 2025年12月19日 · 修改于: 2026年1月22日
相关文章
Next.js 电商实战:购物车与 Stripe 支付完整实现指南

Next.js 电商实战:购物车与 Stripe 支付完整实现指南
Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战

Next.js 文件上传完整指南:S3/七牛云预签名URL直传实战
Next.js 单元测试实战:Jest + React Testing Library 完整配置指南


评论
使用 GitHub 账号登录后即可评论