[{"data":1,"prerenderedAt":1380},["ShallowReactive",2],{"page:\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html":3,"all-docs-nav":837},{"id":4,"title":5,"body":6,"breadcrumb":812,"dateModified":822,"datePublished":822,"description":823,"extension":824,"faq":825,"meta":830,"navigation":831,"path":832,"seo":833,"slug":12,"stem":834,"type":835,"__hash__":836},"content\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html\u002Findex.md","Stale-While-Revalidate for Static HTML",{"type":7,"value":8,"toc":793},"minimark",[9,13,22,38,43,67,71,78,89,195,199,202,211,228,232,235,257,260,264,273,365,368,372,387,391,440,455,459,462,540,639,643,707,711,717,721,726,729,733,736,740,743,747,750,754,789],[10,11,5],"h1",{"id":12},"stale-while-revalidate-for-static-html",[14,15,16,17,21],"p",{},"Static HTML is usually served with ",[18,19,20],"code",{},"Cache-Control: max-age=0, must-revalidate",": every request asks the origin (or the CDN's copy) whether the page changed. It is safe — readers never see an old page — but each view pays a revalidation round trip, and CDN edges far from where the page was last fetched go back to origin. For content that changes a few times a day, that is a lot of checking for very little change.",[14,23,24,27,28,31,32,37],{},[18,25,26],{},"stale-while-revalidate"," offers a middle ground. A response stays fresh for a short ",[18,29,30],{},"max-age",", and after that the cache may keep serving it for a further window while it fetches a new copy in the background. Readers get cached-speed responses; content still updates within a bounded time. This guide applies it to a 1,200-page documentation site, measures TTFB and origin load, and shows how to keep deploys visible quickly. It is part of ",[33,34,36],"a",{"href":35},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002F","CDN Caching Rules for SSGs",".",[39,40,42],"h2",{"id":41},"prerequisites","Prerequisites",[44,45,46,58,64],"ul",{},[47,48,49,50,53,54,37],"li",{},"Hashed assets on a long ",[18,51,52],{},"immutable"," lifetime, so HTML is the only thing that needs this treatment — see ",[33,55,57],{"href":56},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-busting-with-content-hashed-filenames\u002F","Cache Busting with Content-Hashed Filenames",[47,59,60,61,63],{},"A CDN that honours ",[18,62,26],{}," for edge caching, or supports a separate CDN-specific header.",[47,65,66],{},"An agreed answer to \"how stale may a page be after a deploy?\" — minutes, not hours, for most sites.",[39,68,70],{"id":69},"how-it-behaves","How It Behaves",[14,72,73,74,77],{},"With ",[18,75,76],{},"Cache-Control: public, max-age=60, stale-while-revalidate=600",":",[44,79,80,83,86],{},[47,81,82],{},"For the first 60 seconds after a copy is cached, requests are served from cache with no revalidation.",[47,84,85],{},"Between 60 and 660 seconds, requests are still served from cache immediately, and the cache triggers one background revalidation; the next request gets the fresh copy.",[47,87,88],{},"After 660 seconds without a request, the copy is too stale and the next request waits for the origin.",[90,91,92,191],"figure",{},[93,94,101,102,101,106,101,110,101,117],"svg",{"viewBox":95,"role":96,"ariaLabelledBy":97,"xmlns":100},"0 0 760 270","img",[98,99],"swr-tl-title","swr-tl-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[103,104,105],"title",{"id":98},"Lifecycle of a cached HTML response",[107,108,109],"desc",{"id":99},"A timeline starting when a page is cached. From 0 to 60 seconds it is fresh and served directly. From 60 to 660 seconds it is stale but served immediately while a background revalidation fetches a new copy. After 660 seconds the next request must wait for the origin.",[111,112],"rect",{"x":113,"y":113,"width":114,"height":115,"fill":116},"0","760","270","#ffffff",[118,119,121,122,121,130,121,138,121,145,121,152,121,159,121,164,121,171,121,176,121,181,121,184,121,187,101],"g",{"style":120},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[123,124,129],"text",{"x":125,"y":126,"fill":127,"style":128},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","max-age=60, stale-while-revalidate=600",[131,132],"line",{"x1":133,"y1":134,"x2":135,"y2":134,"stroke":136,"style":137},"60","140","720","#556071","stroke-width:2px",[111,139],{"x":133,"y":140,"width":133,"height":133,"fill":141,"opacity":142,"stroke":143,"style":144},"110","#8ac926","0.35","#5a8a16","stroke-width:1px",[123,146,151],{"x":147,"y":148,"fill":149,"style":150},"90","98","#3f6410","font-weight:700;text-anchor:middle","fresh",[111,153],{"x":154,"y":140,"width":155,"height":133,"fill":156,"opacity":157,"stroke":158,"style":144},"120","500","#ffca3a","0.28","#a97b00",[123,160,163],{"x":161,"y":148,"fill":162,"style":150},"370","#8a6d0f","stale: serve now, refresh in background",[111,165],{"x":166,"y":140,"width":167,"height":133,"fill":168,"opacity":169,"stroke":170,"style":144},"620","100","#ff595e","0.18","#d83b41",[123,172,175],{"x":173,"y":148,"fill":174,"style":150},"670","#b32b30","wait for origin",[123,177,180],{"x":133,"y":178,"fill":136,"style":179},"190","font-size:11px;text-anchor:middle","0 s",[123,182,183],{"x":154,"y":178,"fill":136,"style":179},"60 s",[123,185,186],{"x":166,"y":178,"fill":136,"style":179},"660 s",[123,188,190],{"x":125,"y":189,"fill":136,"style":179},"236","A popular page is almost never in the red zone: some reader triggers the refresh first",[192,193,194],"figcaption",{},"For busy pages the reader never waits; for rarely visited pages the behaviour degrades gracefully to a normal fetch.",[39,196,198],{"id":197},"step-1-set-the-headers","Step 1: Set the Headers",[14,200,201],{},"Browser caching and edge caching often deserve different windows: browsers should not keep HTML long (a reader who refreshes expects the latest page), while edges can hold it longer if you can purge them on deploy. Many CDNs support a separate header for the edge:",[203,204,209],"pre",{"className":205,"code":207,"language":123,"meta":208},[206],"language-text","# _headers (Cloudflare Pages \u002F Netlify syntax)\n\u002F*\n  Cache-Control: public, max-age=0, must-revalidate\n  CDN-Cache-Control: public, max-age=60, stale-while-revalidate=600\n\n\u002F_astro\u002F*\n  Cache-Control: public, max-age=31536000, immutable\n","",[18,210,207],{"__ignoreMap":208},[14,212,213,214,216,217,220,221,223,224,37],{},"Here browsers always revalidate (cheaply, against the nearby edge), and edges serve HTML for up to 11 minutes with background refresh. Where the CDN does not support a separate header, put ",[18,215,26],{}," in ",[18,218,219],{},"Cache-Control"," with a small ",[18,222,30],{},", accepting that browsers may also serve a page up to that old. Host-specific details are in ",[33,225,227],{"href":226},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-cache-control-headers-on-cloudflare-pages\u002F","Setting Cache-Control Headers on Cloudflare Pages",[39,229,231],{"id":230},"step-2-make-deploys-visible-quickly","Step 2: Make Deploys Visible Quickly",[14,233,234],{},"The trade-off with any HTML caching is staleness after a deploy. Two options bound it:",[44,236,237,247],{},[47,238,239,243,244,246],{},[240,241,242],"strong",{},"Accept the window."," With a 60-second ",[18,245,30],{}," and 600-second SWR, a busy page shows new content within about a minute (the first request after 60 s triggers a refresh), and a quiet page within 11 minutes. For documentation and blogs that is usually fine.",[47,248,249,252,253,37],{},[240,250,251],{},"Purge HTML on deploy."," Purge by path prefix or cache tag after each deploy so edges fetch fresh HTML immediately, and use the longer windows purely for performance between deploys. See ",[33,254,256],{"href":255},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy\u002F","Purging the CDN Cache After a Static Deploy",[14,258,259],{},"The site here purges HTML on deploy and keeps SWR for the rest of the time, which gives both instant deploys and edge-speed responses.",[39,261,263],{"id":262},"choosing-the-windows","Choosing the Windows",[14,265,266,267,269,270,272],{},"The two numbers trade freshness against origin load and TTFB. A longer ",[18,268,30],{}," means fewer revalidations but a longer period in which a deploy is invisible without a purge; a longer ",[18,271,26],{}," window keeps more rarely visited pages instant, at the cost of those pages occasionally being older. The site measured several combinations for a week each before settling:",[90,274,275,362],{},[93,276,101,281,101,284,101,287,101,290],{"viewBox":277,"role":96,"ariaLabelledBy":278,"xmlns":100},"0 0 760 260",[279,280],"swr-win-title","swr-win-desc",[103,282,283],{"id":279},"Edge hit ratio against worst-case staleness for four settings",[107,285,286],{"id":280},"Four settings plotted by worst-case staleness without a purge and edge hit ratio. max-age 0: 0 minutes, 71 percent. max-age 60 with no SWR: 1 minute, 84 percent. max-age 60 with SWR 600: 11 minutes, 97 percent. max-age 300 with SWR 3600: 65 minutes, 98 percent. The chosen setting is the third, where hit ratio has nearly plateaued.",[111,288],{"x":113,"y":113,"width":114,"height":289,"fill":116},"260",[118,291,121,292,121,295,121,300,121,303,121,309,121,313,121,316,121,319,121,325,121,330,121,336,121,339,121,344,121,348,121,353,121,357,101],{"style":120},[123,293,294],{"x":125,"y":126,"fill":127,"style":128},"Hit ratio gained vs staleness accepted",[131,296],{"x1":297,"y1":298,"x2":135,"y2":298,"stroke":136,"style":299},"80","210","stroke-width:1.5px",[131,301],{"x1":297,"y1":302,"x2":297,"y2":298,"stroke":136,"style":299},"50",[123,304,308],{"x":305,"y":306,"fill":136,"style":307},"72","214","font-size:11px;text-anchor:end","70%",[123,310,312],{"x":305,"y":311,"fill":136,"style":307},"54","100%",[123,314,113],{"x":297,"y":315,"fill":136,"style":179},"228",[123,317,318],{"x":135,"y":315,"fill":136,"style":307},"65 min worst-case staleness",[320,321],"polyline",{"points":322,"fill":323,"stroke":324,"style":137},"80,205 90,135 190,71 720,66","none","#d9e2ef",[326,327],"circle",{"cx":297,"cy":328,"r":329,"fill":168,"stroke":170,"style":299},"205","7",[123,331,335],{"x":332,"y":333,"fill":127,"style":334},"94","200","font-size:11px","max-age 0 · 71%",[326,337],{"cx":147,"cy":338,"r":329,"fill":156,"stroke":158,"style":299},"135",[123,340,343],{"x":341,"y":342,"fill":127,"style":334},"104","139","60 s, no SWR · 84%",[326,345],{"cx":178,"cy":346,"r":347,"fill":141,"stroke":143,"style":137},"71","8",[123,349,352],{"x":350,"y":332,"fill":149,"style":351},"204","font-size:11px;font-weight:700","60 s + SWR 600 · 97% (chosen)",[326,354],{"cx":135,"cy":355,"r":329,"fill":356,"stroke":356,"style":299},"66","#1982c4",[123,358,361],{"x":359,"y":360,"fill":127,"style":307},"706","56","300 s + SWR 3600 · 98%",[192,363,364],{},"Past about ten minutes of stale window, extra staleness bought almost no extra hit ratio.",[14,366,367],{},"The curve flattens quickly because popular pages are requested often enough that someone always triggers the refresh within a minute; only the many rarely visited pages benefit from longer windows. Pick the knee of the curve, then add the purge on deploy so the worst case after a release is seconds rather than the window.",[39,369,371],{"id":370},"fixed-name-files-beyond-html","Fixed-Name Files Beyond HTML",[14,373,374,375,378,379,382,383,386],{},"A handful of non-HTML files keep the same URL while their content changes: ",[18,376,377],{},"sitemap.xml",", RSS and Atom feeds, ",[18,380,381],{},"robots.txt",", search index entry files such as ",[18,384,385],{},"pagefind-entry.json",", and web app manifests. They belong in the same tier as HTML. Feeds in particular benefit: feed readers poll aggressively, often every few minutes from thousands of clients, and with a 60-second edge lifetime plus background revalidation almost all of those polls are answered from the edge. On this site, feed requests reaching origin fell from 31,000 a day to under 1,500 with no change in how quickly new posts appeared in readers' apps.",[39,388,390],{"id":389},"step-3-verify","Step 3: Verify",[203,392,396],{"className":393,"code":394,"language":395,"meta":208,"style":208},"language-bash shiki shiki-themes github-light github-dark","curl -sI https:\u002F\u002Fdocs.example.com\u002Fguides\u002Finstall\u002F | grep -iE 'cache-control|cdn-cache-control|age|cf-cache-status'\n# cf-cache-status: HIT        age: 42\n# (after 60 s) cf-cache-status: UPDATING or STALE, then HIT with a small age\n","bash",[18,397,398,427,434],{"__ignoreMap":208},[399,400,402,406,410,414,418,421,424],"span",{"class":131,"line":401},1,[399,403,405],{"class":404},"sScJk","curl",[399,407,409],{"class":408},"sj4cs"," -sI",[399,411,413],{"class":412},"sZZnC"," https:\u002F\u002Fdocs.example.com\u002Fguides\u002Finstall\u002F",[399,415,417],{"class":416},"szBVR"," |",[399,419,420],{"class":404}," grep",[399,422,423],{"class":408}," -iE",[399,425,426],{"class":412}," 'cache-control|cdn-cache-control|age|cf-cache-status'\n",[399,428,430],{"class":131,"line":429},2,[399,431,433],{"class":432},"sJ8bj","# cf-cache-status: HIT        age: 42\n",[399,435,437],{"class":131,"line":436},3,[399,438,439],{"class":432},"# (after 60 s) cf-cache-status: UPDATING or STALE, then HIT with a small age\n",[14,441,442,443,446,447,450,451,454],{},"Check from more than one location, because each edge holds its own copy: a VPN, a multi-region probe or a tool such as WebPageTest shows whether distant edges are also serving hits. Check a rarely visited page as well as the homepage, since popular pages mask problems by always being warm. And after a deploy, request a changed page immediately and again after a few seconds to confirm the purge (or the refresh) delivers the new version as expected. The ",[18,444,445],{},"age"," header shows how long the edge has held the copy; a status of ",[18,448,449],{},"STALE"," or ",[18,452,453],{},"UPDATING"," (naming varies by CDN) confirms background revalidation is happening.",[39,456,458],{"id":457},"measured-impact","Measured Impact",[14,460,461],{},"The 1,200-page docs site, two weeks before and after adding edge SWR for HTML with purge on deploy. RUM for TTFB; CDN analytics for origin requests.",[463,464,465,481],"table",{},[466,467,468],"thead",{},[469,470,471,475,478],"tr",{},[472,473,474],"th",{},"Measure",[472,476,477],{},"max-age=0 everywhere",[472,479,480],{},"Edge SWR + purge on deploy",[482,483,484,496,507,518,529],"tbody",{},[469,485,486,490,493],{},[487,488,489],"td",{},"HTML edge hit ratio",[487,491,492],{},"71%",[487,494,495],{},"97%",[469,497,498,501,504],{},[487,499,500],{},"TTFB p75 (global RUM)",[487,502,503],{},"142 ms",[487,505,506],{},"51 ms",[469,508,509,512,515],{},[487,510,511],{},"TTFB p75, readers in Asia-Pacific",[487,513,514],{},"310 ms",[487,516,517],{},"58 ms",[469,519,520,523,526],{},[487,521,522],{},"Origin requests per day (HTML)",[487,524,525],{},"96,000",[487,527,528],{},"9,400",[469,530,531,534,537],{},[487,532,533],{},"Time for a deploy to be visible",[487,535,536],{},"immediate",[487,538,539],{},"~3 s (purge)",[90,541,542,636],{},[93,543,101,547,101,550,101,553,101,555],{"viewBox":95,"role":96,"ariaLabelledBy":544,"xmlns":100},[545,546],"swr-res-title","swr-res-desc",[103,548,549],{"id":545},"TTFB by region before and after",[107,551,552],{"id":546},"Paired bars of p75 time to first byte for HTML. Europe: 88 milliseconds before, 44 after. North America: 121 before, 49 after. Asia-Pacific: 310 before, 58 after. Global: 142 before, 51 after.",[111,554],{"x":113,"y":113,"width":114,"height":115,"fill":116},[118,556,121,557,121,560,121,564,121,569,121,575,121,579,121,584,121,588,121,592,121,595,121,600,121,604,121,608,121,612,121,617,121,620,121,623,121,627,121,632,101],{"style":120},[123,558,559],{"x":125,"y":126,"fill":127,"style":128},"HTML TTFB p75 (ms), before vs after",[131,561],{"x1":562,"y1":563,"x2":562,"y2":189,"stroke":324,"style":299},"170","46",[123,565,568],{"x":566,"y":305,"fill":127,"style":567},"40","font-weight:700","Europe",[111,570],{"x":562,"y":571,"width":572,"height":573,"rx":574,"fill":168,"opacity":157,"stroke":170,"style":144},"58","132","14","3",[111,576],{"x":562,"y":577,"width":355,"height":573,"rx":574,"fill":141,"opacity":578,"stroke":143,"style":144},"74","0.4",[123,580,583],{"x":581,"y":582,"fill":127,"style":334},"310","70","88 → 44",[123,585,587],{"x":566,"y":586,"fill":127,"style":567},"116","N. America",[111,589],{"x":562,"y":590,"width":591,"height":573,"rx":574,"fill":168,"opacity":157,"stroke":170,"style":144},"102","182",[111,593],{"x":562,"y":594,"width":577,"height":573,"rx":574,"fill":141,"opacity":578,"stroke":143,"style":144},"118",[123,596,599],{"x":597,"y":598,"fill":127,"style":334},"360","114","121 → 49",[123,601,603],{"x":566,"y":602,"fill":127,"style":567},"160","Asia-Pacific",[111,605],{"x":562,"y":606,"width":607,"height":573,"rx":574,"fill":168,"opacity":157,"stroke":170,"style":144},"146","465",[111,609],{"x":562,"y":610,"width":611,"height":573,"rx":574,"fill":141,"opacity":578,"stroke":143,"style":144},"162","87",[123,613,616],{"x":614,"y":615,"fill":127,"style":334},"643","158","310 → 58",[123,618,619],{"x":566,"y":350,"fill":127,"style":567},"Global",[111,621],{"x":562,"y":178,"width":622,"height":573,"rx":574,"fill":168,"opacity":157,"stroke":170,"style":144},"213",[111,624],{"x":562,"y":625,"width":626,"height":573,"rx":574,"fill":141,"opacity":578,"stroke":143,"style":144},"206","77",[123,628,631],{"x":629,"y":630,"fill":127,"style":334},"391","202","142 → 51",[123,633,635],{"x":125,"y":634,"fill":136,"style":179},"256","web-vitals TTFB beacons, two weeks each; red before, green after",[192,637,638],{},"Readers furthest from origin gained most: their edge now answers instead of forwarding every request.",[39,640,642],{"id":641},"pitfalls-rollback","Pitfalls & Rollback",[44,644,645,654,660,669,678,688,697],{},[47,646,647,650,651,653],{},[240,648,649],{},"Long browser caching of HTML."," Readers who refresh expect the latest page; keep browser ",[18,652,30],{}," at or near zero and put longer windows on the edge only.",[47,655,656,659],{},[240,657,658],{},"SWR without a staleness decision."," Decide how old a page may be after a deploy, and either accept that window or purge.",[47,661,662,665,666,37],{},[240,663,664],{},"Personalised or authenticated HTML."," Never apply shared caching to responses that differ per user; use ",[18,667,668],{},"private",[47,670,671,674,675,677],{},[240,672,673],{},"Assuming your CDN honours the directive."," Verify with ",[18,676,445],{}," and cache-status headers.",[47,679,680,683,684,687],{},[240,681,682],{},"Caching error pages."," A transient 5xx or 404 cached with the same windows keeps a broken page up for minutes. Give error responses ",[18,685,686],{},"no-store"," or a much shorter lifetime.",[47,689,690,696],{},[240,691,692,693,37],{},"Forgetting ",[18,694,695],{},"stale-if-error"," Adding it lets the edge keep serving the last good page if the origin fails, which is a cheap resilience gain on self-hosted origins.",[47,698,699,702,703,706],{},[240,700,701],{},"Rollback:"," restore ",[18,704,705],{},"max-age=0, must-revalidate"," for HTML; the effect is immediate for new requests and complete once the SWR window passes (or on purge).",[39,708,710],{"id":709},"conclusion","Conclusion",[14,712,713,714,716],{},"For static HTML that changes a few times a day, revalidating every request is caution without benefit. An edge policy of ",[18,715,129],{},", browser revalidation kept at zero, and an HTML purge on each deploy raised the edge hit ratio on a 1,200-page docs site from 71% to 97%, cut global TTFB p75 from 142 to 51 ms (310 to 58 ms in Asia-Pacific), and still showed every deploy within seconds.",[39,718,720],{"id":719},"faq","FAQ",[722,723,725],"h3",{"id":724},"what-does-stale-while-revalidate-do","What does stale-while-revalidate do?",[14,727,728],{},"It lets a cache serve a response that has just expired while it fetches a fresh copy in the background. The reader gets an instant response, and the next reader gets the updated version. It is set as a Cache-Control directive with a number of seconds.",[722,730,732],{"id":731},"is-it-safe-to-cache-html-if-content-changes-on-deploy","Is it safe to cache HTML if content changes on deploy?",[14,734,735],{},"Yes, if the staleness is bounded and acceptable. With max-age=60 and stale-while-revalidate=600, a reader might see a page up to about eleven minutes old after a deploy. If that is too long, purge HTML on deploy or shorten the windows.",[722,737,739],{"id":738},"do-cdns-and-browsers-both-honour-it","Do CDNs and browsers both honour it?",[14,741,742],{},"Modern browsers honour stale-while-revalidate in their HTTP cache. Many CDNs honour it too, some through a separate CDN-Cache-Control or Surrogate-Control header. Check your CDN's documentation and verify with response headers.",[722,744,746],{"id":745},"does-it-affect-hashed-assets","Does it affect hashed assets?",[14,748,749],{},"No. Hashed assets should keep a year-long immutable lifetime. stale-while-revalidate is for URLs that stay the same while their content changes, which on a static site means mainly HTML and a few fixed-name files.",[39,751,753],{"id":752},"related","Related",[44,755,756,765,770,775,782],{},[47,757,758,761,762,764],{},[240,759,760],{},"Parent:"," ",[33,763,36],{"href":35}," — the complete caching policy.",[47,766,767,769],{},[33,768,57],{"href":56}," — the immutable tier.",[47,771,772,774],{},[33,773,256],{"href":255}," — making deploys visible immediately.",[47,776,777,781],{},[33,778,780],{"href":779},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Finstant-navigation-with-speculation-rules\u002F","Instant Navigation with Speculation Rules"," — prefetches reuse cached HTML.",[47,783,784,788],{},[33,785,787],{"href":786},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Falerting-on-cache-hit-ratio-drops\u002F","Alerting on Cache Hit Ratio Drops"," — keeping the 97% hit ratio.",[790,791,792],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":208,"searchDepth":429,"depth":429,"links":794},[795,796,797,798,799,800,801,802,803,804,805,811],{"id":41,"depth":429,"text":42},{"id":69,"depth":429,"text":70},{"id":197,"depth":429,"text":198},{"id":230,"depth":429,"text":231},{"id":262,"depth":429,"text":263},{"id":370,"depth":429,"text":371},{"id":389,"depth":429,"text":390},{"id":457,"depth":429,"text":458},{"id":641,"depth":429,"text":642},{"id":709,"depth":429,"text":710},{"id":719,"depth":429,"text":720,"children":806},[807,808,809,810],{"id":724,"depth":436,"text":725},{"id":731,"depth":436,"text":732},{"id":738,"depth":436,"text":739},{"id":745,"depth":436,"text":746},{"id":752,"depth":429,"text":753},[813,816,819,820],{"name":814,"item":815},"Home","\u002F",{"name":817,"item":818},"Performance Optimization & Core Web Vitals for SSGs","\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002F",{"name":36,"item":35},{"name":5,"item":821},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html\u002F","2026-09-18","Cache static HTML at the edge with stale-while-revalidate: faster TTFB and repeat views, bounded staleness after deploys, and when to purge instead.","md",[826,827,828,829],{"q":725,"a":728},{"q":732,"a":735},{"q":739,"a":742},{"q":746,"a":749},{},true,"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html",{"title":5,"description":823},"performance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html\u002Findex","article","WQG8NUZnIS7txEXz6j0EmorYkKl8j9OzrOYdi1oBpoU",[838,841,844,847,850,853,856,859,862,865,868,871,874,877,880,883,886,889,892,895,898,901,904,907,910,913,916,919,922,925,928,931,934,937,940,943,946,949,952,955,958,961,964,967,970,973,976,979,982,985,988,991,994,997,1000,1002,1004,1006,1009,1012,1013,1016,1019,1022,1025,1028,1031,1034,1037,1040,1043,1046,1049,1052,1055,1058,1061,1064,1067,1070,1073,1076,1079,1082,1085,1088,1091,1094,1097,1100,1103,1106,1109,1112,1115,1118,1121,1124,1127,1130,1133,1136,1139,1141,1144,1147,1150,1153,1156,1159,1162,1165,1168,1171,1174,1177,1180,1183,1186,1189,1192,1195,1198,1201,1204,1207,1210,1213,1216,1219,1222,1225,1228,1231,1234,1237,1240,1243,1246,1249,1251,1254,1257,1260,1263,1266,1269,1272,1275,1278,1281,1284,1287,1290,1293,1296,1299,1302,1305,1308,1311,1314,1317,1320,1323,1326,1329,1332,1335,1338,1341,1344,1347,1350,1353,1356,1359,1362,1365,1368,1371,1374,1377],{"path":839,"title":840},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fastro-vs-eleventy-build-times-at-10000-pages","Astro vs Eleventy Build Times at 10,000 Pages",{"path":842,"title":843},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fchoosing-between-astro-and-eleventy-for-large-docs","Astro vs Eleventy for Large Docs (1000+ Pages)",{"path":845,"title":846},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade","Content Collections vs the Eleventy Data Cascade",{"path":848,"title":849},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":851,"title":852},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fshortcodes-vs-components-for-docs-authors","Shortcodes vs Components for Docs Authors",{"path":854,"title":855},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fsidebar-navigation-in-astro-and-eleventy","Sidebar Navigation in Astro and Eleventy",{"path":857,"title":858},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fcustomizing-starlight-without-forking-the-theme","Customizing Starlight Without Forking the Theme",{"path":860,"title":861},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fdocusaurus-vs-starlight-for-product-documentation","Docusaurus vs Starlight for Product Documentation",{"path":863,"title":864},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress","Docs Frameworks: Docusaurus, Starlight and VitePress",{"path":866,"title":867},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmdx-vs-markdoc-for-docs-content","MDX vs Markdoc for Docs Content",{"path":869,"title":870},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight","Migrating from MkDocs to Starlight",{"path":872,"title":873},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fversioned-documentation-with-docusaurus","Versioned Documentation with Docusaurus",{"path":875,"title":876},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fvitepress-for-library-documentation","VitePress for Library Documentation",{"path":878,"title":879},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhow-to-benchmark-hugo-vs-astro-build-speeds","How to Benchmark Hugo vs Astro Build Speeds",{"path":881,"title":882},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhugo-partialcached-for-faster-builds","Hugo partialCached for Faster Builds",{"path":884,"title":885},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":887,"title":888},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fprofiling-hugo-templates-with-template-metrics","Profiling Hugo Templates With Template Metrics",{"path":890,"title":891},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Freducing-hugo-memory-usage-on-ci-runners","Reducing Hugo Memory Usage on CI Runners",{"path":893,"title":894},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fspeeding-up-hugo-builds-with-render-hooks-and-caching","Speeding Up Hugo Builds with Render Hooks & Caching",{"path":896,"title":897},"\u002Fchoosing-the-right-static-site-generator-for-production","Choosing the Right Static Site Generator for Production",{"path":899,"title":900},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Feleventy-vs-jekyll-for-markdown-heavy-blogs","Eleventy vs Jekyll for Markdown-Heavy Blogs",{"path":902,"title":903},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":905,"title":906},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Freplacing-jekyll-plugins-when-migrating-to-eleventy","Replacing Jekyll Plugins When Migrating to Eleventy",{"path":908,"title":909},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Frunning-jekyll-on-github-pages-without-plugins","Running Jekyll on GitHub Pages Without Plugins",{"path":911,"title":912},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fspeeding-up-slow-jekyll-builds","Speeding Up Slow Jekyll Builds",{"path":914,"title":915},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fupgrading-jekyll-and-ruby-versions-safely","Upgrading Jekyll and Ruby Versions Safely",{"path":917,"title":918},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fconverting-front-matter-at-scale-during-migration","Converting Front Matter at Scale During Migration",{"path":920,"title":921},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators","Migrating Between Static Site Generators",{"path":923,"title":924},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fkeeping-redirects-working-after-an-ssg-migration","Keeping Redirects Working After an SSG Migration",{"path":926,"title":927},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-a-docs-site-from-jekyll-to-hugo","Migrating a Docs Site From Jekyll to Hugo",{"path":929,"title":930},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-gatsby-to-astro","Migrating from Gatsby to Astro",{"path":932,"title":933},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-hugo-to-astro-without-breaking-urls","Migrating From Hugo to Astro Without Breaking URLs",{"path":935,"title":936},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-wordpress-to-a-static-site-generator","Migrating WordPress to a Static Site Generator",{"path":938,"title":939},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fporting-shortcodes-and-includes-between-generators","Porting Shortcodes and Includes Between Generators",{"path":941,"title":942},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fhandling-dynamic-routes-in-nextjs-static-export","Handling Dynamic Routes in Next.js Static Export",{"path":944,"title":945},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":947,"title":948},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fmigrating-from-gatsby-to-nextjs-static-export","Migrating from Gatsby to Next.js Static Export",{"path":950,"title":951},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-app-router-static-export-limitations","Next.js App Router Static Export Limitations",{"path":953,"title":954},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-static-export-vs-astro-for-marketing-sites","Next.js Static Export vs Astro for Marketing",{"path":956,"title":957},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Foptimizing-images-in-nextjs-static-export","Optimizing Images in Next.js Static Export",{"path":959,"title":960},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fadding-pagefind-to-an-astro-site","Adding Pagefind to an Astro Site",{"path":962,"title":963},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fbuilding-a-lunr-index-at-build-time-in-eleventy","Building a Lunr Index at Build Time in Eleventy",{"path":965,"title":966},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites","Search for Static Sites",{"path":968,"title":969},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Findexing-hugo-sites-with-pagefind","Indexing Hugo Sites with Pagefind",{"path":971,"title":972},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fmultilingual-search-on-static-sites","Multilingual Search on Static Sites",{"path":974,"title":975},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fpagefind-vs-algolia-docsearch","Pagefind vs Algolia DocSearch",{"path":977,"title":978},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fsearch-index-size-budgets-for-large-docs","Search Index Size Budgets for Large Docs",{"path":980,"title":981},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fbest-ssg-for-technical-writers-without-coding-experience","Best SSG for Non-Developer Technical Writers",{"path":983,"title":984},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fchoosing-an-ssg-for-api-reference-documentation","Choosing an SSG for API Reference Documentation",{"path":986,"title":987},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fevaluating-ssg-accessibility-defaults","Evaluating SSG Accessibility Defaults",{"path":989,"title":990},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":992,"title":993},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fpicking-an-ssg-for-a-multi-language-documentation-site","Picking an SSG for a Multi-Language Docs Site",{"path":995,"title":996},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fssg-selection-checklist-for-engineering-teams","SSG Selection Checklist for Engineering Teams",{"path":998,"title":999},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Ftotal-cost-of-ownership-for-static-site-generators","Total Cost of Ownership for Static Site Generators",{"path":1001,"title":57},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-busting-with-content-hashed-filenames",{"path":1003,"title":36},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs",{"path":1005,"title":256},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy",{"path":1007,"title":1008},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-cache-control-headers-on-cloudflare-pages","Cache-Control Headers on Cloudflare Pages",{"path":1010,"title":1011},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fsetting-up-proper-cache-headers-on-netlify","Proper Cache Headers on Netlify for SSGs",{"path":832,"title":5},{"path":1014,"title":1015},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Feliminating-layout-shift-from-web-fonts","Eliminating Layout Shift From Web Fonts",{"path":1017,"title":1018},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners","Fixing CLS from Cookie Banners",{"path":1020,"title":1021},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-late-loading-embeds","Fixing CLS From Late-Loading Embeds",{"path":1023,"title":1024},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-sticky-headers-and-anchor-links","Fixing CLS from Sticky Headers and Anchor Links",{"path":1026,"title":1027},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":1029,"title":1030},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Fmeasuring-cls-in-the-field-with-web-vitals-js","Measuring CLS in the Field With web-vitals.js",{"path":1032,"title":1033},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Freserving-space-for-images-and-embeds-to-stop-layout-shift","Reserving Space for Images and Embeds",{"path":1035,"title":1036},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Ffont-display-optional-vs-swap","font-display: optional vs swap",{"path":1038,"title":1039},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":1041,"title":1042},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fmetric-matched-fallback-fonts-with-size-adjust","Metric-Matched Fallback Fonts with size-adjust",{"path":1044,"title":1045},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fpreloading-fonts-without-double-downloads","Preloading Fonts Without Double Downloads",{"path":1047,"title":1048},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fself-hosting-google-fonts-to-eliminate-layout-shift","Self-Host Google Fonts to Eliminate Layout Shift",{"path":1050,"title":1051},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fsubsetting-variable-fonts-for-faster-first-render","Subsetting Variable Fonts for Faster First Render",{"path":1053,"title":1054},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fbuilding-an-image-cdn-pipeline-for-static-sites","Building an Image CDN Pipeline for Static Sites",{"path":1056,"title":1057},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fgenerating-open-graph-images-at-build-time","Generating Open Graph Images at Build Time",{"path":1059,"title":1060},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":1062,"title":1063},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Flazy-loading-images-without-hurting-lcp","Lazy-Loading Images Without Hurting LCP",{"path":1065,"title":1066},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Foptimizing-webp-images-in-hugo-without-plugins","Optimizing WebP Images in Hugo Without Plugins",{"path":1068,"title":1069},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fresponsive-images-with-srcset-in-eleventy","Responsive Images with srcset in Eleventy",{"path":1071,"title":1072},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fserving-avif-with-fallbacks-on-static-sites","Serving AVIF With Fallbacks on Static Sites",{"path":1074,"title":1075},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":1077,"title":1078},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":1080,"title":1081},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fdeferring-hydration-with-client-visible-in-astro","Deferring Hydration with client:visible in Astro",{"path":1083,"title":1084},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fhow-to-reduce-bundle-size-in-eleventy-builds","How to Reduce Bundle Size in Eleventy Builds",{"path":1086,"title":1087},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":1089,"title":1090},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fmeasuring-inp-on-static-sites-with-real-user-monitoring","Measuring INP on Static Sites with RUM",{"path":1092,"title":1093},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Freplacing-react-islands-with-web-components","Replacing React Islands with Web Components",{"path":1095,"title":1096},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Feliminating-render-blocking-css-on-static-sites","Eliminating Render-Blocking CSS on Static Sites",{"path":1098,"title":1099},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Ffixing-lcp-on-text-heavy-documentation-pages","Fixing LCP on Text-Heavy Documentation Pages",{"path":1101,"title":1102},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":1104,"title":1105},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Fmeasuring-lcp-subparts-with-devtools","Measuring LCP Subparts with DevTools",{"path":1107,"title":1108},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Foptimizing-lcp-on-astro-with-priority-hints","Optimizing LCP on Astro with Priority Hints",{"path":1110,"title":1111},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Freducing-lcp-from-hero-images-on-static-sites","Reducing LCP from Hero Images on Static Sites",{"path":1113,"title":1114},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fcomparing-lab-and-field-data-with-crux","Comparing Lab and Field Data with CrUX",{"path":1116,"title":1117},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci","Performance Budgets and Lighthouse CI",{"path":1119,"title":1120},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Freducing-lighthouse-score-variance-in-ci","Reducing Lighthouse Score Variance in CI",{"path":1122,"title":1123},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Frunning-webpagetest-scripts-against-preview-deploys","Running WebPageTest Scripts Against Preview Deploys",{"path":1125,"title":1126},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fsetting-up-lighthouse-ci-for-a-static-site","Setting Up Lighthouse CI for a Static Site",{"path":1128,"title":1129},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Ftracking-bundle-size-per-pull-request","Tracking Bundle Size per Pull Request",{"path":1131,"title":1132},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fwriting-a-performance-budget-that-fails-builds","Writing a Performance Budget That Fails Builds",{"path":1134,"title":1135},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fauditing-unused-preloads","Auditing Unused Preloads",{"path":1137,"title":1138},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed","Resource Hints and Navigation Speed",{"path":1140,"title":780},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Finstant-navigation-with-speculation-rules",{"path":1142,"title":1143},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fpreconnect-vs-dns-prefetch-on-static-sites","Preconnect vs DNS-Prefetch on Static Sites",{"path":1145,"title":1146},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fprefetching-links-in-astro","Prefetching Links in Astro",{"path":1148,"title":1149},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fview-transitions-on-multi-page-static-sites","View Transitions on Multi-Page Static Sites",{"path":1151,"title":1152},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fauditing-third-party-scripts-with-lighthouse","Auditing Third-Party Scripts With Lighthouse",{"path":1154,"title":1155},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites","Third-Party Script Performance on Static Sites",{"path":1157,"title":1158},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites","Lazy-Loading YouTube Embeds on Static Sites",{"path":1160,"title":1161},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Floading-google-tag-manager-without-hurting-inp","Loading Google Tag Manager Without Hurting INP",{"path":1163,"title":1164},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Frunning-third-party-scripts-in-a-web-worker-with-partytown","Running Third-Party Scripts in a Web Worker with Partytown",{"path":1166,"title":1167},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fself-hosting-analytics-to-cut-third-party-requests","Self-Hosting Analytics to Cut Third-Party Requests",{"path":1169,"title":1170},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":1172,"title":1173},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fconfiguring-redirects-on-cloudflare-pages","Configuring Redirects on Cloudflare Pages",{"path":1175,"title":1176},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fcustom-domains-and-tls-on-cloudflare-pages","Custom Domains and TLS on Cloudflare Pages",{"path":1178,"title":1179},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fdeploying-hugo-to-cloudflare-pages-and-workers","Deploying Hugo to Cloudflare Pages and Workers",{"path":1181,"title":1182},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup","Cloudflare Pages Edge Caching Setup",{"path":1184,"title":1185},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fmigrating-from-cloudflare-pages-to-workers-static-assets","Migrating from Cloudflare Pages to Workers Static Assets",{"path":1187,"title":1188},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fchecking-links-in-pull-requests","Checking Links in Pull Requests",{"path":1190,"title":1191},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fdocs-as-code-review-workflow-for-writers","Docs-as-Code Review Workflow for Writers",{"path":1193,"title":1194},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Feditorial-checks-with-vale-in-ci","Editorial Checks with Vale in CI",{"path":1196,"title":1197},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams","Content Workflows for Documentation Teams",{"path":1199,"title":1200},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fscheduling-content-publication-with-cron-triggered-builds","Scheduling Content Publication With Cron-Triggered Builds",{"path":1202,"title":1203},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fwiring-a-headless-cms-to-a-static-build","Wiring a Headless CMS to a Static Build",{"path":1205,"title":1206},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fbuilding-astro-sites-with-github-actions","Building Astro Sites with GitHub Actions",{"path":1208,"title":1209},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fcaching-node-modules-in-github-actions-for-faster-ssg-builds","Caching node_modules in GitHub Actions",{"path":1211,"title":1212},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-github-pages-with-actions","Deploying to GitHub Pages with Actions",{"path":1214,"title":1215},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-multiple-environments-from-one-workflow","Deploying to Multiple Environments From One Workflow",{"path":1217,"title":1218},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fhow-to-set-up-github-actions-for-hugo-deployments","GitHub Actions for Hugo Deployments",{"path":1220,"title":1221},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":1223,"title":1224},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fmatrix-builds-for-multi-site-monorepos","Matrix Builds for Multi-Site Monorepos",{"path":1226,"title":1227},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fcaching-hugo-builds-in-github-actions","Caching Hugo Builds in GitHub Actions",{"path":1229,"title":1230},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":1232,"title":1233},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fincremental-builds-in-astro-with-the-content-layer","Incremental Builds in Astro with the Content Layer",{"path":1235,"title":1236},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":1238,"title":1239},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fmeasuring-build-time-regressions-in-ci","Measuring Build-Time Regressions in CI",{"path":1241,"title":1242},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fremote-caching-with-turborepo-for-ssg-monorepos","Remote Caching with Turborepo for SSG Monorepos",{"path":1244,"title":1245},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fsharing-build-cache-across-ci-runners","Sharing Build Cache Across CI Runners",{"path":1247,"title":1248},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":1250,"title":787},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Falerting-on-cache-hit-ratio-drops",{"path":1252,"title":1253},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fbuilding-a-core-web-vitals-dashboard-from-rum-data","Building a Core Web Vitals Dashboard from RUM Data",{"path":1255,"title":1256},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fcrawling-for-broken-links-on-a-schedule","Crawling for Broken Links on a Schedule",{"path":1258,"title":1259},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production","Monitoring Static Sites in Production",{"path":1261,"title":1262},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Flogging-404s-at-the-edge","Logging 404s at the Edge",{"path":1264,"title":1265},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fuptime-and-synthetic-checks-for-static-sites","Uptime and Synthetic Checks for Static Sites",{"path":1267,"title":1268},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fconfiguring-vercel-for-hugo-and-eleventy","Configuring Vercel for Hugo and Eleventy",{"path":1270,"title":1271},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":1273,"title":1274},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":1276,"title":1277},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-redirects-and-rewrites-for-static-sites","Netlify Redirects and Rewrites for Static Sites",{"path":1279,"title":1280},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fsetting-up-deploy-previews-on-netlify-for-every-pull-request","Netlify Deploy Previews for Every Pull Request",{"path":1282,"title":1283},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fvercel-isr-vs-static-generation-for-ssgs","Vercel ISR vs Static Generation for SSGs",{"path":1285,"title":1286},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fautomating-preview-deploy-pipelines-with-github-actions","Automating Preview Deploy Pipelines with GitHub Actions",{"path":1288,"title":1289},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":1291,"title":1292},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests","Preview Environments for Pull Requests",{"path":1294,"title":1295},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpassword-protecting-preview-deployments","Password-Protecting Preview Deployments",{"path":1297,"title":1298},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpreviewing-headless-cms-drafts","Previewing Headless CMS Drafts",{"path":1300,"title":1301},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fvisual-regression-testing-on-preview-deploys","Visual Regression Testing on Preview Deploys",{"path":1303,"title":1304},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":1306,"title":1307},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fcanary-releases-for-static-sites","Canary Releases for Static Sites",{"path":1309,"title":1310},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Ffeature-flags-on-static-sites","Feature Flags on Static Sites",{"path":1312,"title":1313},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites","Rollbacks and Deploy Safety for Static Sites",{"path":1315,"title":1316},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute","Rolling Back a Bad Static Deploy in Under a Minute",{"path":1318,"title":1319},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url","Running Smoke Tests Against a Preview URL",{"path":1321,"title":1322},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fauditing-npm-dependencies-in-ssg-pipelines","Auditing npm Dependencies in SSG Pipelines",{"path":1324,"title":1325},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fenabling-hsts-and-preload-safely","Enabling HSTS and Preload Safely",{"path":1327,"title":1328},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fhash-based-csp-for-inline-scripts-in-astro","Hash-Based CSP for Inline Scripts in Astro",{"path":1330,"title":1331},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites","Security Headers and Hardening for Static Sites",{"path":1333,"title":1334},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecuring-deploy-credentials-with-github-oidc","Securing Deploy Credentials with GitHub OIDC",{"path":1336,"title":1337},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsubresource-integrity-for-third-party-assets","Subresource Integrity for Third-Party Assets",{"path":1339,"title":1340},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fwriting-a-content-security-policy-for-a-static-site","Writing a Content Security Policy for a Static Site",{"path":1342,"title":1343},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fclean-urls-and-trailing-slashes-on-s3","Clean URLs and Trailing Slashes on S3",{"path":1345,"title":1346},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fcloudfront-functions-for-redirects","CloudFront Functions for Redirects",{"path":1348,"title":1349},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fdeploying-a-static-site-to-s3-and-cloudfront","Deploying a Static Site to S3 and CloudFront",{"path":1351,"title":1352},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites","Self-Hosting Static Sites on S3, Nginx and Caddy",{"path":1354,"title":1355},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-caddy","Serving a Static Site with Caddy",{"path":1357,"title":1358},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-nginx","Serving a Static Site with Nginx",{"path":1360,"title":1361},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fzero-downtime-deploys-with-symlink-swaps","Zero-Downtime Deploys with Symlink Swaps",{"path":1363,"title":1364},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fadding-a-contact-form-with-cloudflare-workers","Adding a Contact Form with Cloudflare Workers",{"path":1366,"title":1367},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fhandling-form-submissions-on-a-static-site","Handling Form Submissions on a Static Site",{"path":1369,"title":1370},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites","Serverless Functions for Static Sites",{"path":1372,"title":1373},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fnetlify-functions-vs-cloudflare-workers","Netlify Functions vs Cloudflare Workers",{"path":1375,"title":1376},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fprotecting-a-static-site-behind-authentication","Protecting a Static Site Behind Authentication",{"path":1378,"title":1379},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fproxying-third-party-apis-from-an-edge-function","Proxying Third-Party APIs from an Edge Function",1789722847094]