Vercel ISR vs SSG 内容站怎么选

内容站在 Vercel 上该用 ISR 还是纯 SSG?从构建时间、新鲜度、函数成本、回滚四个维度讲清取舍,附 2026 年最新 Vercel 限额和可直接抄的配置。

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 buildastro 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 当前限额文档核实。

限额HobbyPro
单次部署 build 时长45 分钟45 分钟
包含的 build 执行时长6000 分钟/月按量计费额度
并发 build 数112
每天部署次数1006000
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 发一个 GETHEAD 请求,把 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 是上面那个单独的 adapter isr 选项。

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/vercelisr 选项(expirationbypassTokenexclude)。按需失效靠 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 Vercel adapter 文档

标签: #独立开发 #Vercel #部署 / 托管 #isr #性能