cdn-caching
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVercel Caching
Vercel 缓存机制
You are an expert in understanding Vercel's caching infrastructure, and how the CDN Cache, ISR, and PPR work.
你是Vercel缓存基础设施以及CDN缓存、ISR和PPR工作原理方面的专家。
Core Knowledge
核心知识
- ISR (and PPR, a rendering strategy built on it) is a framework feature — Next.js, SvelteKit, Nuxt, and Astro all use it on Vercel, and the layers, metrics, and CLI here apply regardless. (For caching data between your function and a backend, that's the Runtime Cache — a separate layer; see References.)
- PPR (Partial Prerendering) — a rendering strategy, not a cache layer: the static shell lives in the ISR cache while a function renders the dynamic holes per request and streams them into the same response. A route with holes still invokes the function on a shell hit; a holeless route is just ISR (a pure HIT).
prerender
- ISR(以及基于它构建的渲染策略PPR)是一种框架特性——Next.js、SvelteKit、Nuxt和Astro在Vercel上均支持该特性,本文提及的缓存层级、指标和CLI工具均通用。(若要在函数与后端之间缓存数据,需使用Runtime Cache——这是一个独立的缓存层级,详见参考文献。)
- PPR(Partial Prerendering,部分预渲染)——一种渲染策略,而非缓存层级:静态壳存储在ISR缓存中,同时函数会针对每个请求渲染动态内容片段并将其流式传输到同一响应中。包含动态片段的路由在命中静态壳时仍会触发函数执行;无动态片段的路由则完全属于ISR(纯命中)。
prerender
How caching works
缓存工作流程
Vercel caches at multiple layers between the visitor and your backend. A request reaches the nearest PoP, which routes to a Vercel region; the CDN then checks each layer in order and returns a cached response as soon as one is available, so your function runs only when nothing upstream has a valid copy.
Vercel在访问者与后端之间设置了多层缓存。请求会先到达最近的PoP(边缘节点),再路由到Vercel区域;CDN会按顺序检查每个层级,一旦找到有效缓存响应就立即返回,因此只有当上游所有层级都没有有效副本时,才会触发函数执行。
Cache layers
缓存层级
- CDN cache — regional, ephemeral. On a hit the region returns the response with no function call. Reads/writes are free.
- ISR cache — durable, in a single Function region. On a CDN miss, Vercel reads here before invoking your function (cache shielding), then replicates the result back to the CDN. Survives deploys for 31 days or until revalidated; reads/writes are billed in 8 KB units.
- Function invocation — runs only if neither cache has a valid copy. It may read the Runtime/data cache (a separate layer; see References) and your backend, then Vercel stores the response in the ISR cache.
- Image cache — optimized images, cached on the CDN after the first transform.
- Purges propagate globally in ~300 ms.
Request collapsing: when many requests hit the same uncached path at once, Vercel collapses them into one function invocation per region to protect the origin.
- CDN缓存——区域级、临时缓存。命中时,区域节点直接返回响应,无需调用函数。读写操作免费。
- ISR缓存——持久化缓存,存储在单个函数区域。当CDN缓存未命中时,Vercel会先读取ISR缓存(缓存屏蔽),再将结果同步回CDN。缓存内容会保留31天或直到被重新验证,读写操作按8 KB单位计费。
- 函数执行——仅当CDN和ISR缓存均无有效副本时才会触发。函数可能会读取Runtime/数据缓存(独立层级,详见参考文献)和后端数据,之后Vercel会将响应存储到ISR缓存中。
- 图片缓存——经过优化的图片,首次转换后会被CDN缓存。
- 缓存清除操作会在约300毫秒内全局生效。
请求合并:当多个请求同时访问同一未缓存路径时,Vercel会将其合并为每个区域一次函数执行,以保护源站。
Key concepts
关键概念
-
Cache hit rate — share served from cache (/
HIT/STALE) versus origin (PRERENDER/MISS). Measure it over cacheable requests — excludeREVALIDATEDandBYPASS(redirects, errors, uncacheable methods), or they drag the ratio down for non-cache reasons. Low hit rate means more origin load and higher latency.(not set) -
Revalidation — refreshing cached content. Time-based runs automatically after an interval; on-demand runs when you call an API. Both use stale-while-revalidate: visitors keep getting the cached version while the new one regenerates in the background.
-
Invalidate vs. dangerously-delete — two ways to clear content, with very different blast on hit rate:
- Invalidate (, Next.js
invalidateByTag/revalidateTag) = stale-while-revalidate. Keeps serving stale while refreshing in the background → response showsrevalidatePath.x-vercel-cache: STALE - Dangerously-delete (, Next.js
dangerouslyDeleteByTagor a revalidate with no lifetime) = hard removal. The next request blocks in the foreground to regenerate →updateTag.x-vercel-cache: REVALIDATED
- Invalidate (
-
Cache tags & blast radius — tags group cached entries so one call can clear many. A coarse tag attached to thousands of paths has a large blast radius: a single write drops them all and the hit rate collapses until they re-warm. Prefer granular tags () plus a roll-up tag.
product-${id} -
Cache status (response header) — the outcome:
x-vercel-cacheValue Meaning HITServed from cache; no function ran MISSNot cached; origin/function ran STALEServed stale while revalidating in background (SWR / invalidate) PRERENDERServed a prerendered ISR/PPR shell REVALIDATEDForeground revalidation after a delete (or )Pragma: no-cacheBYPASSCaching skipped ( ,no-store, cookies, etc.)private -
Cache reason () — the finer explanation of that outcome for a single request. The
cacheReasonmetric lumps allcache_resultes (and allMISSs) together; the reason is the only thing that tells them apart. Nine values, three per group:STALEcacheReasonRefines Meaning coldMISS Cache empty for this key/variant (first request or evicted); the function ran collapsedMISS Concurrent requests to one uncached path collapsed into a single invocation errorMISS An error prevented serving from cache draft_mode→ BYPASS Next.js Draft Mode active — bypassed so editors see live content prerender_bypass→ BYPASS Prerender-bypass cookie/token present crawler→ BYPASS SEO-crawler UA — full response served so bots index real content stale_timeSTALE Time-based interval elapsed; regenerating in background (SWR)revalidatestale_tagSTALE Tag invalidated ( /revalidateTag); regeneratinginvalidateByTagstale_errorSTALE A revalidation attempt failed; serving the last-good copy (a bug signal) A rawwith reasonMISS/draft_mode/prerender_bypassis displayed ascrawler(all usually expected). The threeBYPASSreasons separate a healthy time refresh (stale_*) from a broad-tag blast (stale_time) from a failing regen (stale_tag). Readstale_errorfromcacheReasonor the dashboard Logs "Reason" row — thevercel logsheader is internal-only and not visible viax-vercel-cache-reason.curl -
PPR state () — for a Partial Prerendering route, how much of the response was prerendered versus computed per request. Only set on
ppr_stateserves; blank for plainpartial_prerender/prerender/funcroutes and for cases the proxy can't classify (cold shell miss,static). Three states:BYPASSppr_stateMeaning Static Fully prerendered — no postponed state, so the function is not invoked for the body Partial A static shell serves from cache + a postponed hole the function resumes per request Dynamic The whole body is postponed and rendered by the function per request A Partial serve that still invokes the function is not a cache miss — the cached shell serves immediately while the function fills only the dynamic holes. Readfromppr_stateor the dashboard Logs panel, or aggregate withvercel logs. Likevercel metrics vercel.request.count --group-by ppr_state, thecacheReasonheader is internal-only and not visible viax-vercel-ppr-state.curl
-
缓存命中率——从缓存(/
HIT/STALE)提供服务的请求占比,对比从源站(PRERENDER/MISS)提供服务的请求占比。需针对可缓存请求统计——排除REVALIDATED和BYPASS(重定向、错误、不可缓存方法),否则这些非缓存原因会拉低命中率。低命中率意味着源站负载更高、延迟更长。(not set) -
重新验证——刷新缓存内容。基于时间的重新验证会在间隔时间后自动触发;按需重新验证会在调用API时触发。两者均采用stale-while-revalidate策略:访问者会继续获取缓存版本,同时后台生成新内容。
-
失效与危险删除——两种清除缓存的方式,对命中率的影响差异极大:
- 失效(、Next.js的
invalidateByTag/revalidateTag)= stale-while-revalidate。在后台刷新的同时继续提供过期内容 → 响应头显示revalidatePath。x-vercel-cache: STALE - 危险删除(、Next.js的
dangerouslyDeleteByTag或无生命周期的重新验证)= 强制移除缓存。下一次请求会在前台阻塞以重新生成内容 →updateTag。x-vercel-cache: REVALIDATED
- 失效(
-
缓存标签与影响范围——标签用于分组缓存条目,以便一次调用即可清除多个条目。附加到数千个路径的粗粒度标签会产生较大的_影响范围_:单次写入操作会清除所有关联条目,命中率会在缓存重新预热前大幅下降。建议优先使用细粒度标签(如),再搭配汇总标签。
product-${id} -
缓存状态(响应头)——缓存结果:
x-vercel-cache取值 含义 HIT从缓存返回响应;未触发函数执行 MISS无缓存内容;触发源站/函数执行 STALE返回过期内容的同时在后台重新验证(SWR / 失效操作) PRERENDER返回预渲染的ISR/PPR静态壳 REVALIDATED删除缓存后进行前台重新验证(或使用 )Pragma: no-cacheBYPASS跳过缓存(使用 、no-store、Cookie等)private -
缓存原因()——单个请求缓存结果的详细解释。
cacheReason指标会将所有cache_result(以及所有MISS)归为一类,而缓存原因是区分它们的唯一依据。共有9种取值,分为三组:STALEcacheReason对应结果 含义 coldMISS 该键/变体的缓存为空(首次请求或已被驱逐);触发了函数执行 collapsedMISS 对同一未缓存路径的并发请求被合并为一次函数执行 errorMISS 错误导致无法从缓存提供服务 draft_mode→ BYPASS Next.js草稿模式已激活——跳过缓存以便编辑者查看实时内容 prerender_bypass→ BYPASS 存在预渲染跳过Cookie/令牌 crawler→ BYPASS SEO爬虫用户代理——返回完整响应以便爬虫索引真实内容 stale_timeSTALE 基于时间的 间隔已到期;后台正在重新生成(SWR)revalidatestale_tagSTALE 标签已失效( /revalidateTag);正在重新生成invalidateByTagstale_errorSTALE 重新验证尝试失败;返回最后一次成功的副本(错误信号) 带有/draft_mode/prerender_bypass原因的原始crawler会显示为MISS(这些通常是预期情况)。三种BYPASS原因可区分健康的时间刷新(stale_*)、粗粒度标签影响(stale_time)和重新生成失败(stale_tag)。可通过stale_error或控制台日志的“Reason”行查看vercel logs——cacheReason头是内部专用的,无法通过x-vercel-cache-reason查看。curl -
PPR状态()——针对部分预渲染路由,响应中预渲染内容与每个请求计算内容的占比。仅在
ppr_state请求中设置;纯partial_prerender/prerender/func路由以及代理无法分类的情况(静态壳冷未命中、static)下为空。共有三种状态:BYPASSppr_state含义 Static 完全预渲染——无延迟状态,因此函数不会为响应体触发执行 Partial 静态壳从缓存返回 + 延迟片段由函数针对每个请求填充 Dynamic 整个响应体均为延迟内容,由函数针对每个请求渲染 仍触发函数执行的Partial请求并非缓存未命中——缓存的静态壳会立即返回,同时函数仅填充动态片段。可通过、控制台日志面板或使用vercel logs聚合查看vercel metrics vercel.request.count --group-by ppr_state。与ppr_state类似,cacheReason头是内部专用的,无法通过x-vercel-ppr-state查看。curl
Investigating cache issues
缓存问题排查
Reach for the Vercel CLI. gives aggregate numbers (requires Observability Plus); shows per-request behavior.
vercel metricsvercel logsMetrics need to be queried by team and project (). Filter production with (there is no flag). Run to discover dimensions; use for machine-readable output. With , remember is per time bucket — omit when you need totals across the whole window.
-S <team> -p <project>-f "environment eq 'production'"--prodvercel metrics schema <metric>-F json-g--limit-g指标需按团队和项目查询()。使用过滤生产环境(无标志)。运行查看维度;使用获取机器可读输出。使用时需注意**是每个时间桶的限制**——若需要整个时间段的总数,需省略。
-S <team> -p <project>-f "environment eq 'production'"--prodvercel metrics schema <metric>-F json-g--limit-gCache hit rate
缓存命中率
Start here for an overall picture of how well caching is working.
Step 1 — overall split. Group by . Treat , , and as cache-served; focus investigation on . Exclude and when computing a hit rate over cacheable traffic (see Debugging BYPASS traffic). means stale-while-revalidate is working — dig into revalidation frequency in Analyzing ISR costs, not here.
vercel.request.countcache_resultHITSTALEPRERENDERMISSBYPASS(not set)STALEbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production'" --group-by cache_result --since 24hStep 2 — where misses concentrate. Split the bucket (and optionally ) by , then by or :
MISSSTALEpath_typerouterequest_pathbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS'" \
--group-by path_type --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS' and path_type eq 'prerender'" \
--group-by request_path --since 24hWhat to expect: routes (static shells, ISR pages) should show a high share of /. A path with a disproportionate count is your short list for per-path header inspection ( above) and code review.
prerenderHITPRERENDERprerenderMISScurlstreaming_funcCache-ControlVaryprerender从整体缓存效果开始排查。
步骤1 — 整体分布。按分组统计。将、和视为缓存提供的服务;重点排查。计算可缓存流量的命中率时,需排除和(详见调试BYPASS流量)。意味着stale-while-revalidate策略正常工作——需在分析ISR成本中排查重新验证频率,而非此处。
cache_resultvercel.request.countHITSTALEPRERENDERMISSBYPASS(not set)STALEbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production'" --group-by cache_result --since 24h步骤2 — 未命中集中路径。将(可选)按拆分,再按或拆分:
MISSSTALEpath_typerouterequest_pathbash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS'" \
--group-by path_type --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "environment eq 'production' and cache_result eq 'MISS' and path_type eq 'prerender'" \
--group-by request_path --since 24h预期结果:路由(静态壳、ISR页面)应显示较高的/占比。路径中占比过高的是重点排查对象,需进行单路径头信息检查(上述命令)和代码审查。
prerenderHITPRERENDERprerenderMISScurlstreaming_funcCache-ControlVaryprerenderAnalyzing ISR costs
分析ISR成本
Once you know hit rate, quantify ISR spend and whether revalidation — not traffic volume — is driving it.
Utilization vs. ISR billing. Utilization is — total request volume. ISR cost is billed separately in 8 KB units: when the regional CDN misses and falls through to the ISR cache, and on every revalidation/regeneration. The regional CDN shields ISR heavily — most requests never touch the ISR layer, so read_units will be far below request count. Do not compare read_units to write_units as a utilization check; focus on write_units (revalidation cost) and how they relate to total traffic.
vercel.request.countread_unitswrite_unitsbash
vercel metrics vercel.request.count -S <team> -p <project> -a sum --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> -a sum --since 24hWrite utilization = cache serves ÷ ISR writes — cached reads per regeneration.
bash
undefined了解命中率后,量化ISR支出并确认是否是重新验证(而非流量规模)导致成本上升。
使用率与ISR计费。使用率是——总请求量。ISR成本按8 KB单位单独计费:区域CDN未命中时读取ISR缓存会产生,每次重新验证/重新生成会产生。区域CDN会大幅屏蔽ISR请求——大多数请求从未触达ISR层级,因此read_units会远低于请求量。不要将read_units与write_units对比来检查使用率;重点关注write_units(重新验证成本)及其与总流量的关系。
vercel.request.countread_unitswrite_unitsbash
vercel metrics vercel.request.count -S <team> -p <project> -a sum --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> -a sum --since 24h写入使用率 = 缓存服务次数 ÷ ISR写入次数——每次重新生成对应的缓存读取次数。
bash
undefinednumerator: cache serves — sum the HIT + STALE + PRERENDER buckets
分子:缓存服务次数——汇总HIT + STALE + PRERENDER的数量
vercel metrics vercel.request.count -S <team> -p <project>
-f "environment eq 'production' and (cache_result eq 'HIT' or cache_result eq 'STALE')"
--group-by route -a sum --since 24h
-f "environment eq 'production' and (cache_result eq 'HIT' or cache_result eq 'STALE')"
--group-by route -a sum --since 24h
vercel metrics vercel.request.count -S <team> -p <project>
-f "environment eq 'production' and (cache_result eq 'HIT' or cache_result eq 'STALE')"
--group-by route -a sum --since 24h
-f "environment eq 'production' and (cache_result eq 'HIT' or cache_result eq 'STALE')"
--group-by route -a sum --since 24h
denominator: ISR writes
分母:ISR写入次数
vercel metrics vercel.isr_operation.write_units -S <team> -p <project>
-f "environment eq 'production'" --group-by route -a sum --since 24h
-f "environment eq 'production'" --group-by route -a sum --since 24h
High is good; near or below ~1 means you regenerate about as fast as the page is read (wasted writes) → lengthen the revalidate interval or move time-based to on-demand tag revalidation.
**Which routes revalidate most.** Break write units down by `route` and `request_path` to find paths that regenerate often relative to traffic:
```bash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by route --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by request_path --since 24hRegeneration vs. serving. Group write units by — concentration in confirms revalidation (not per-request dynamic work) is the cost driver.
path_typebackground_funcTime-based vs. tag-based revalidation. Time-based intervals regenerate on a schedule whether or not content changed — often inefficient. Tag-based on-demand revalidation is usually better, but an overly broad tag has a large blast radius: one invalidate drops every entry that carries it.
- Tag blast radius — group write units by . If many unrelated routes show near-identical write counts, a shared hot tag is invalidating them in lockstep (e.g. every blog post rewriting at the same rate because they share one broad
cache_tagstag):blogPost
bash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by cache_tags --since 24h- What triggered revalidation — group by
vercel.request.countto see which tags fire most often (triggering_tagis on request count only, not ISR operation metrics. It is one of the tags that triggered the page to be stale):triggering_tag
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "triggering_tag ne null" --group-by triggering_tag --since 24hTags with a large blast radius that revalidate frequently are the usual root cause of high write_units. Prefer granular tags () and on-demand invalidation over short time-based intervals for event-driven content.
product-${id}Confirm in code. Metrics tell you which tag is hot; the repo tells you why. Grep for the tag's invalidation call site — , , , — and read the trigger. A CMS webhook or a sync cron that invalidates a broad tag on every event (instead of a specific ) is the classic amplifier.
revalidateTag(invalidateByTag(updateTag(dangerouslyDeleteByTag(${type}:${id}vercel metrics vercel.isr_operation.write_units -S <team> -p <project>
-f "environment eq 'production'" --group-by route -a sum --since 24h
-f "environment eq 'production'" --group-by route -a sum --since 24h
数值越高越好;接近或低于1意味着重新生成速度与页面读取速度相当(写入浪费)→ 延长重新验证间隔,或将基于时间的重新验证改为按需标签重新验证。
**重新验证最频繁的路由**。按`route`和`request_path`拆分write_units,找出相对于流量而言重新生成频繁的路径:
```bash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by route --since 24h
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by request_path --since 24h重新生成与服务。按分组write_units——集中在说明重新验证(而非每个请求的动态工作)是成本驱动因素。
path_typebackground_func基于时间与基于标签的重新验证。基于时间的间隔会按计划重新生成内容,无论内容是否变化——通常效率低下。按需基于标签的重新验证通常更好,但过于宽泛的标签会产生较大影响范围:一次失效操作会清除所有关联条目。
- 标签影响范围——按分组write_units。若许多_不相关_路由的写入次数几乎相同,说明存在共享的高频标签,会同步失效这些路由(例如,所有博客文章共享一个宽泛的
cache_tags标签,导致它们以相同频率重新生成):blogPost
bash
vercel metrics vercel.isr_operation.write_units -S <team> -p <project> \
-a sum --group-by cache_tags --since 24h- 重新验证触发源——按分组
triggering_tag,查看哪些标签触发最频繁(vercel.request.count仅存在于请求计数指标中,不存在于ISR操作指标中。它是导致页面过期的标签之一):triggering_tag
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "triggering_tag ne null" --group-by triggering_tag --since 24h影响范围大且重新验证频繁的标签通常是write_units过高的根本原因。对于事件驱动的内容,优先使用细粒度标签(如)和按需失效,而非短时间间隔的基于时间重新验证。
product-${id}代码层面确认。指标会告诉你哪个标签是高频触发源;代码仓库会告诉你原因。搜索标签的失效调用位置——、、、——并查看触发逻辑。典型问题是CMS webhook或同步定时任务在每次事件时失效宽泛标签(而非特定的)。
revalidateTag(invalidateByTag(updateTag(dangerouslyDeleteByTag(${type}:${id}Debugging BYPASS traffic
调试BYPASS流量
The largest legitimate sources of are Draft Mode and SEO crawlers. Draft Mode must bypass cache so editors see live content. SEO bots must receive the full response — especially on PPR routes where the static shell and dynamic holes are assembled at request time — so crawlers index what users actually see. That BYPASS is expected, not a misconfiguration.
BYPASSBefore tuning headers or revalidate intervals, confirm what's left after those two buckets:
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by bot_category --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by user_agent --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by request_method --since 24hThe Firewall/WAF with the skill can be used to manage verified SEO crawlers, block abusive bots, and rate-limit junk traffic before it distorts your hit-rate picture.
vercel-firewallBYPASS在调整头信息或重新验证间隔之前,先确认排除这两类后的剩余流量:
bash
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by bot_category --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by user_agent --since 24h
vercel metrics vercel.request.count -S <team> -p <project> \
-f "cache_result eq 'BYPASS'" --group-by request_method --since 24h带有技能的防火墙/WAF可用于管理已验证的SEO爬虫、阻止恶意机器人,并在垃圾流量影响命中率之前进行限流。
vercel-firewallReducing ISR cost
降低ISR成本
- Prefer tag-based over time-based revalidation. Replace short intervals with on-demand
revalidate/revalidateTagwhen content changes — time-based regeneration runs whether or not anything changed. If using Cache Components, analyzeinvalidateByTagcalls with thecacheLifeskill.next-cache-components - Scope tags to specific IDs. Invalidate , not a generic
blogPost:<id>/blogPosttag — one broad invalidate regenerates everything that carries it.page - Tune the revalidate interval where your framework declares it (Next.js /
revalidate, SvelteKitcacheLife, Nuxtisr, Astro). For Next.js Cache Components, see therouteRulesskill.next-cache-components - Use headers to cache dynamic functions.
CDN-Cache-Control
- 优先使用基于标签的重新验证。当内容变化时,用按需/
revalidateTag替换短invalidateByTag间隔——基于时间的重新生成会在内容未变化时仍执行。若使用缓存组件,可通过revalidate技能分析next-cache-components调用。cacheLife - 将标签限定到特定ID。失效,而非通用的
blogPost:<id>/blogPost标签——一次宽泛的失效操作会重新生成所有关联条目。page - 在框架声明处调整重新验证间隔(Next.js的/
revalidate、SvelteKit的cacheLife、Nuxt的isr、Astro的对应配置)。对于Next.js缓存组件,参考routeRules技能。next-cache-components - 使用头缓存动态函数。
CDN-Cache-Control
Inspect one path
检查单个路径
bash
curl -sSI https://<host>/<path> | grep -iE 'x-vercel-cache|x-matched-path|cache-control|vary|age|set-cookie'This zero-dependency first reach shows the status (), the cache directives ( / / ), and — crucially — , which reveals rewrites like that expose experiment/flag precomputation. flags personalization (RSC, cookies); forces . For a per-phase timing breakdown, (CLI v48.9.0+; needs the tool installed) adds latency stats. A path that should cache but shows / usually has , , , a per-request input (cookies/headers/), or an uncacheable method (see FAQ).
x-vercel-cacheCache-ControlCDN-Cache-ControlVercel-CDN-Cache-Controlx-matched-path/precomputed/exp~.../...varyset-cookieBYPASSvercel httpstat /some/pathhttpstatMISSBYPASSprivateno-storemax-age=0searchParamsInspect one request. When metrics or headers give you a request ID, pull the full log record:
bash
vercel logs --request-id <request-id> --jsonUse so the agent can parse cache status, path, and timing fields programmatically.
--jsonbash
curl -sSI https://<host>/<path> | grep -iE 'x-vercel-cache|x-matched-path|cache-control|vary|age|set-cookie'这个零依赖的命令可查看缓存状态()、缓存指令(//),以及至关重要的****——它会显示重写路径(如),暴露实验/特性标志的预计算逻辑。标志表示个性化内容(RSC、Cookie);会强制触发。如需分阶段的延迟统计,(CLI v48.9.0+;需安装工具)会添加延迟数据。应该缓存但显示/的路径通常包含、、、每个请求的输入(Cookie/头信息/)或不可缓存的方法(详见FAQ)。
x-vercel-cacheCache-ControlCDN-Cache-ControlVercel-CDN-Cache-Controlx-matched-path/precomputed/exp~.../...varyset-cookieBYPASSvercel httpstat /some/pathhttpstatMISSBYPASSprivateno-storemax-age=0searchParams检查单个请求。当指标或头信息提供请求ID时,拉取完整日志记录:
bash
vercel logs --request-id <request-id> --json使用以便工具可程序化解析缓存状态、路径和时间字段。
--jsonFAQ
FAQ
- What are prerender variant misses? When a route uses a dynamic param, each distinct cache-key variant is prerendered and cached separately, so each variant misses on its first hit per region and low-traffic ones rarely stay warm. The most common modern cause is feature-flag / experiment precomputation — middleware picks a variant per request (paths), and flags × routes × PPR segments multiply into thousands of ISR entries (also a middleware-invocation cost). Fix: collapse the variant matrix (retire finished experiments), or accept the cost.
/precomputed/exp~.../... - Does PPR avoid function invocations? No — a PPR route has dynamic holes by definition, so the cached shell hit still runs the function to fill them. (A route with no holes is just ISR and serves a pure HIT — see Key concepts.)
prerender - Why are there more function invocations than PPR requests? PPR requests have a static shell and a dynamic function invocation. When the static shell needs to be regenerated, it incurs a function invocation on top of the dynamic function for the content.
- 什么是预渲染变体未命中? 当路由使用动态参数时,每个不同的缓存键变体都会被预渲染并单独缓存,因此每个变体在每个区域的首次请求都会未命中,低流量变体很难保持缓存热度。最常见的现代原因是特性标志/实验预计算——中间件会针对每个请求选择变体(路径),标志×路由×PPR片段会生成数千个ISR条目(同时也会增加中间件调用成本)。解决方法:合并变体矩阵(结束已完成的实验),或接受该成本。
/precomputed/exp~.../... - PPR是否能避免函数调用? 不能——PPR路由本质上包含动态片段,因此命中缓存静态壳时仍会触发函数执行以填充片段。(无动态片段的路由完全属于ISR,会返回纯命中——详见关键概念。)
prerender - 为什么函数调用次数多于PPR请求次数? PPR请求包含静态壳和动态函数调用。当静态壳需要重新生成时,除了内容的动态函数调用外,还会额外触发一次函数执行。
Related skills
相关技能
- — manage verified SEO crawlers, block abusive bots, and rate-limit junk BYPASS traffic.
vercel-firewall - — caching data between your function and a backend (per-region key-value / data cache). A different layer from the CDN/ISR caches; use it to cache an API response or query result inside a function.
runtime-cache - — Next.js
next-cache-components,use cache,cacheLife, andcacheTagtuning (one framework's ISR/PPR controls).revalidate
- ——管理已验证的SEO爬虫、阻止恶意机器人,并对垃圾BYPASS流量进行限流。
vercel-firewall - ——在函数与后端之间缓存数据(区域级键值/数据缓存)。这是与CDN/ISR缓存不同的层级;可用于在函数内部缓存API响应或查询结果。
runtime-cache - ——Next.js的
next-cache-components、use cache、cacheLife和cacheTag配置调优(某一框架的ISR/PPR控制)。revalidate
References:
参考文献:
- Caching overview: https://vercel.com/docs/caching
- ISR: https://vercel.com/docs/incremental-static-regeneration
- Partial Prerendering (PPR): https://vercel.com/docs/partial-prerendering
- Cache-Control headers: https://vercel.com/docs/caching/cache-control-headers
- Diagnosing and fixing cache issues (full runbook): https://vercel.com/docs/caching/cdn-cache/debug-cache-issues
- vercel metrics CLI: https://vercel.com/docs/cli/metrics
- vercel logs CLI: https://vercel.com/docs/cli/logs
- 缓存概述:https://vercel.com/docs/caching
- ISR:https://vercel.com/docs/incremental-static-regeneration
- 部分预渲染(PPR):https://vercel.com/docs/partial-prerendering
- Cache-Control头:https://vercel.com/docs/caching/cache-control-headers
- 缓存问题诊断与修复(完整手册):https://vercel.com/docs/caching/cdn-cache/debug-cache-issues
- vercel metrics CLI:https://vercel.com/docs/cli/metrics
- vercel logs CLI:https://vercel.com/docs/cli/logs