SSG 在 build 时把每一页预生成、走 CDN 直发,直到下次 build。ISR 也预生成,但 Vercel 会在后台重新渲染页面,可以按计时也可以按需。内容站怎么选,不是哲学问题,而是四个能量化的指标:构建多久、页面要多新鲜、serverless 函数会花你多少钱、回滚有多麻烦。
一句话结论
- 文章数 500 以内、一周改几次、build 3 分钟以内:用 SSG。 更便宜、更简单,一键原子回滚。
- 文章数 2000 以上、或一天改很多次、或 build 逼近 10 分钟:用 ISR。 build 时预生成热门 slug,其余按需再生成。
- 中间地带:按你的编辑流程选,别拿 benchmark 较劲。 只要重新部署不痛,就留在 SSG。
- 截至 2026 年 6 月,Vercel 的 build 上限在所有套餐上都是 45 分钟(Hobby、Pro、Enterprise 一样),所以”build 撞上限了”是迁到 ISR 最响亮的唯一理由。
SSG 和 ISR 在 Vercel 上到底做了什么
SSG(Static Site Generation)在 next build 或 astro build 时写出 HTML,每个 URL 在 out/ 或 dist/ 里成为一个文件,上传到 CDN。请求时不跑任何函数,所以成本基本就是 CDN 带宽。
ISR(Incremental Static Regeneration)同样预生成页面,但页面会”过期”并触发后台重新渲染。按时间 revalidation:先把缓存页直接发出去,当页面比 revalidate 窗口更旧时再在后台拉起一次新渲染(stale-while-revalidate)。按需 revalidation:你显式让某个路径或某个 tag 失效(比如从 CMS webhook 触发),下一次请求就渲染最新内容。两种方式 ISR 都需要部署一个 Node serverless 函数当渲染器,这会改变成本模型。
ISR 最早是 Next.js 的特性,但截至 2026 年 6 月,Astro 的 Vercel adapter 也带 ISR 了。后面会细讲——因为”Astro 没有真正的 ISR”这个老说法现在已经过时。
真正帮你拍板的 Vercel 限额(2026 年 6 月)
下面这些平台数字才是真正逼你做选择的。已对照 Vercel 当前限额文档核实。
| 限额 | Hobby | Pro |
|---|---|---|
| 单次部署 build 时长 | 45 分钟 | 45 分钟 |
| 包含的 build 执行时长 | 6000 分钟/月 | 按量计费额度 |
| 并发 build 数 | 1 | 12 |
| 每天部署次数 | 100 | 6000 |
| ISR Reads 免费额度 | 不适用(受 Hobby 总额限制) | 前 10,000,000 次 |
| ISR Writes 免费额度 | 不适用 | 前 2,000,000 次 |
| 函数最大时长 | 60 秒 | 300 秒 |
这里有两点最容易搞错。第一,45 分钟 build 上限在所有套餐上都一样;升级到 Pro 不会换来更长的 build,换来的是并发(12 路并行 build vs 1 路)和按量计费的余量。第二,ISR 是单独计量的 ISR Reads 和 ISR Writes,所以一个设得很激进的再生成页面是持续产生的账单项,而不是一份免费的静态资源。
什么时候 SSG 就是对的答案
下面大部分成立,就留在 SSG:
- build 3 分钟以内,为改个错字重新部署一点都不痛。
- 编辑会用 git,或者 CMS 保存时已经自动触发部署。
- 想要最无聊的生产环境:CDN 直发文件、零函数调用、凌晨两点没东西要 debug。
- 回滚就是”把上一个部署 promote 回去”,瞬时、所有页面原子切换、不用清任何缓存。
- 想让账单大致就等于一份 CDN 的钱,没别的。
Astro 默认 SSG,output: 'static'。Next.js 在某路由有 generateStaticParams 且没有请求时动态 API 时,会静态渲染该路由。
本站自己就是几千页的纯 SSG,build 稳稳在上限之内。绝大多数内容站永远撞不到这个上限。
什么时候 ISR 赚得回成本
三个函数成本花得值的具体场景。
1. build 时间是瓶颈。 5000+ 文章时,冷 build 可能跑 15-20 分钟,每次改错字都要等很久,而且离 45 分钟上限就差一次慢 build。ISR 只预生成热门 slug,其余懒生成:
// app/articles/[slug]/page.tsx
export const revalidate = 3600; // 最多每小时再生成一次
export async function generateStaticParams() {
// build 时预渲染 top 200,长尾在首次请求时渲染
return (await getTopArticles(200)).map((a) => ({ slug: a.slug }));
}
2. CMS webhook 触发按需 revalidation。 编辑在 Sanity 或 Contentful 里点发布,webhook 调你的路由,只有那一个 URL 几秒内重新生成。不用全站重新部署,也没有一天 20 次部署的折腾:
// app/api/revalidate/route.ts
import { revalidatePath, revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
const secret = req.nextUrl.searchParams.get('secret');
if (secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ ok: false }, { status: 401 });
}
const { slug, tag } = await req.json();
if (tag) revalidateTag(tag); // 让共享同一 tag 的多个页面一起失效
if (slug) revalidatePath(`/articles/${slug}/`);
return NextResponse.json({ ok: true, revalidated: slug ?? tag });
}
当一次编辑应当刷新一组页面(比如某分类下的所有文章)而你又不想逐个跟踪 URL 时,用 revalidateTag;只刷一个已知路由时用 revalidatePath。
3. 按计划刷新局部内容。 正文不变,但”相关文章”模块或一张价格表要每周更新。把 revalidate = 604800(7 天)设上,页面会在后台自己重建。
Astro ISR 现在是真的(配置可直接抄)
“Astro 没有真正的 ISR”这个广为流传的说法,截至 2026 年 6 月已经过时。@astrojs/vercel adapter 提供了 isr 选项,会把按需渲染的页面在首次请求后像预渲染页面一样缓存起来。
// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel';
export default defineConfig({
output: 'server',
adapter: vercel({
isr: {
// 按时间:每页缓存一天
expiration: 60 * 60 * 24,
// 按需:用 x-prerender-revalidate 头让缓存失效
bypassToken: process.env.ISR_BYPASS_TOKEN,
// 这些路径永不缓存
exclude: ['/preview', /^\/api\/.+/],
},
}),
});
要按需失效,向页面 URL 发一个 GET 或 HEAD 请求,把 x-prerender-revalidate 头设成你的 bypassToken,这就是 Astro 版的 revalidatePath。所以 2026 年的老实答案是:Astro 内容站走 SSG 通常就够了,但如果你想要 ISR,adapter 已经给齐了,含按需失效。
回滚才是它们真正的差别
- SSG 回滚一键搞定。Vercel 把上一个 build promote 回去,所有页面原子切换。上一版部署本来就已完整构建好。
- ISR 回滚麻烦点。promote 旧部署并不会把在新部署下重新生成过的页面回退掉,运行时缓存里可能还存着旧 HTML。promote 之后要补一发
revalidatePath/revalidateTag(或调 Astro 的 bypassToken 失效端点)来刷掉受影响的页面,否则就等 TTL 过。
如果”瞬时、保证干净的回滚”比 build 速度更重要,光这一条就能让你留在 SSG。
容易踩的坑
- “保险起见”每页都设
revalidate = 60。 你刚把每分钟之后的第一次请求都变成了函数调用加一次计费的 ISR Write。对一个月才变一次的内容来说,账单往上爬、CDN 命中率往下掉。 - 用了 ISR 但没接按需 hook。 编辑仍要熬过
revalidate窗口才看得到自己改的,把 webhook 接上。 - 忘了 ISR 需要 Node serverless 函数,不只是静态文件。 这既改成本模型,也会消耗计量的 ISR Reads/Writes。
- SSG 和 ISR 混用却搞不清某页为什么是旧的。 查那段路由的
export const revalidate(Next.js)或 adapter 的isr配置(Astro)。 - 把 Astro 的
output: 'hybrid'当 ISR。 hybrid 只是”默认静态、对 SSR 路由单独设prerender = false”。ISR 是上面那个单独的 adapterisr选项。
FAQ
ISR 对 SEO 是不是比 SSG 差? 不。两者给爬虫的都是完整预渲染的 HTML。唯一区别是部署后的第一次再生成可能对某一个访客稍慢一点;之后每次访问都是 CDN 速度,而且 Googlebot 几乎不会正好落在那次冷渲染上。
ISR 是不是比 SSG 贵?
可能。SSG 基本就是 CDN 带宽。ISR 额外加上计量的 ISR Reads(截至 2026 年 6 月 Pro 前 1000 万次免费)、ISR Writes(前 200 万次免费)和函数调用。对低流量、很少变的站,这些是噪音;对高流量、激进 revalidation 的站,会累积起来。把 revalidate 窗口设保守些,优先用按需失效。
现在真能在 Astro 里用 ISR 了吗?
能。设 output: 'server',给 @astrojs/vercel 传 isr 选项(expiration、bypassToken、exclude)。按需失效靠 x-prerender-revalidate 头实现。“Astro 没有 ISR”那套说法早于这个特性。
Vercel 的 Data Cache 是什么?
和 ISR 正交。Data Cache 缓存单个 fetch() 调用,ISR 缓存整页渲染结果。两者能一起用:ISR 缓存页面输出,Data Cache 缓存这次渲染里发的 API 调用,让一次再生成更省。
再生成失败会怎样? 上一次正常的 HTML 继续提供服务。你能在 Vercel 运行时日志里看到错误(Hobby 留 1 小时、Pro 留 1 天),但用户永远看不到坏页面。优雅降级正是 stale-while-revalidate 的全部意义。
相关阅读
- Vercel 部署 Astro(10 分钟流程)
- Vercel Edge Functions 用在内容站:什么时候值得
- Next.js 内容更新按需重新验证(On-Demand Revalidation)
- Vercel 内容站上线清单
外部参考:Vercel 限额文档 与 Astro Vercel adapter 文档。