[{"data":1,"prerenderedAt":2765},["ShallowReactive",2],{"page:\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites":3,"all-docs-nav":1635,"filed:\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites":2764},{"id":4,"title":5,"body":6,"breadcrumb":1609,"dateModified":1616,"datePublished":1616,"description":1617,"extension":1618,"faq":1619,"meta":1627,"navigation":1628,"path":1629,"seo":1630,"slug":1631,"stem":1632,"type":1633,"__hash__":1634},"content\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Findex.md","Security Headers and Hardening for Static Sites",{"type":7,"value":8,"toc":1585},"minimark",[9,13,17,40,251,256,259,269,302,305,309,316,323,329,341,477,481,503,507,510,571,581,585,588,609,619,713,717,720,734,744,758,772,782,786,789,904,930,934,937,1106,1114,1118,1137,1159,1162,1166,1169,1191,1205,1222,1234,1247,1251,1259,1263,1266,1366,1370,1420,1424,1444,1448,1453,1456,1460,1463,1467,1470,1474,1477,1481,1484,1488,1581],[10,11,5],"h1",{"id":12},"security-headers-and-hardening-for-static-sites",[14,15,16],"p",{},"\"It's just static files\" is the most common reason static sites ship without security headers. There is no database to inject into and no server-side code to exploit, so the threat model feels empty. It is not. Browsers run whatever JavaScript a page loads, and static sites load plenty: analytics, embeds, consent managers, chat widgets and their own bundles, all built from hundreds of npm packages by a CI pipeline holding a token that can overwrite every page. Security for a static site is about limiting what that JavaScript can do, making sure the right JavaScript is served over the right connection, and keeping the pipeline that publishes it from being turned against you.",[14,18,19,20,24,25,28,29,34,35,39],{},"This topic covers both halves. The ",[21,22,23],"strong",{},"edge half"," is response headers — Content-Security-Policy, Strict-Transport-Security, Subresource Integrity, framing and referrer controls — set once at the host and applied to every page. The ",[21,26,27],{},"pipeline half"," is dependency auditing and deploy credentials. It sits inside ",[30,31,33],"a",{"href":32},"\u002Fproduction-ready-deployment-cicd-workflows\u002F","Production-Ready Deployment & CI\u002FCD Workflows"," and builds on the header mechanics from ",[30,36,38],{"href":37},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002F","Cloudflare Pages Edge Caching Setup",".",[41,42,43,247],"figure",{},[44,45,52,53,52,57,52,61,52,68,52,233],"svg",{"viewBox":46,"role":47,"ariaLabelledBy":48,"xmlns":51},"0 0 780 320","img",[49,50],"shs-threat-title","shs-threat-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[54,55,56],"title",{"id":49},"Threats to a static site and the control for each",[58,59,60],"desc",{"id":50},"A pipeline from source to reader with threats and controls at each stage. At the dependency stage, a malicious npm package is countered by lockfiles, audits and provenance. At the CI stage, a leaked deploy token is countered by short-lived OIDC credentials. At the network stage, a downgrade to HTTP is countered by HSTS. In the browser, injected or compromised scripts are countered by CSP and SRI, and clickjacking by frame-ancestors.",[62,63],"rect",{"x":64,"y":64,"width":65,"height":66,"fill":67},"0","780","320","#ffffff",[69,70,72,73,72,81,72,90,72,96,72,102,72,105,72,109,72,112,72,115,72,119,72,122,72,125,72,129,72,132,72,148,72,156,72,162,72,166,72,168,72,171,72,174,72,176,72,179,72,182,72,184,72,187,72,190,72,197,72,201,72,205,72,207,72,210,72,213,72,215,72,218,72,221,72,223,72,226,72,229,52],"g",{"style":71},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[74,75,80],"text",{"x":76,"y":77,"fill":78,"style":79},"390","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","Four places an attacker can get in, four controls",[62,82],{"x":83,"y":84,"width":85,"height":84,"rx":86,"fill":87,"stroke":88,"style":89},"30","60","160","10","#f8fafc","#d9e2ef","stroke-width:1.5px",[74,91,95],{"x":92,"y":93,"fill":78,"style":94},"110","86","font-weight:700;text-anchor:middle","Dependencies",[74,97,101],{"x":92,"y":98,"fill":99,"style":100},"106","#556071","font-size:11px;text-anchor:middle","npm, themes, plugins",[62,103],{"x":104,"y":84,"width":85,"height":84,"rx":86,"fill":87,"stroke":88,"style":89},"220",[74,106,108],{"x":107,"y":93,"fill":78,"style":94},"300","CI pipeline",[74,110,111],{"x":107,"y":98,"fill":99,"style":100},"build + deploy token",[62,113],{"x":114,"y":84,"width":85,"height":84,"rx":86,"fill":87,"stroke":88,"style":89},"410",[74,116,118],{"x":117,"y":93,"fill":78,"style":94},"490","Network",[74,120,121],{"x":117,"y":98,"fill":99,"style":100},"reader to edge",[62,123],{"x":124,"y":84,"width":85,"height":84,"rx":86,"fill":87,"stroke":88,"style":89},"600",[74,126,128],{"x":127,"y":93,"fill":78,"style":94},"680","Browser",[74,130,131],{"x":127,"y":98,"fill":99,"style":100},"scripts, frames",[69,133,136,137,136,142,136,145,72],{"stroke":99,"fill":134,"style":135},"none","stroke-width:2px","\n      ",[138,139],"path",{"d":140,"style":141},"M192 90 L216 90","marker-end:url(#shs-arrow)",[138,143],{"d":144,"style":141},"M382 90 L406 90",[138,146],{"d":147,"style":141},"M572 90 L596 90",[62,149],{"x":83,"y":150,"width":85,"height":151,"rx":152,"fill":153,"opacity":154,"stroke":155,"style":89},"140","50","8","#ff595e","0.12","#d83b41",[74,157,161],{"x":92,"y":158,"fill":159,"style":160},"162","#b32b30","font-size:11px;font-weight:700;text-anchor:middle","malicious package",[74,163,165],{"x":92,"y":164,"fill":99,"style":100},"178","runs at build time",[62,167],{"x":104,"y":150,"width":85,"height":151,"rx":152,"fill":153,"opacity":154,"stroke":155,"style":89},[74,169,170],{"x":107,"y":158,"fill":159,"style":160},"leaked token",[74,172,173],{"x":107,"y":164,"fill":99,"style":100},"publishes anything",[62,175],{"x":114,"y":150,"width":85,"height":151,"rx":152,"fill":153,"opacity":154,"stroke":155,"style":89},[74,177,178],{"x":117,"y":158,"fill":159,"style":160},"HTTP downgrade",[74,180,181],{"x":117,"y":164,"fill":99,"style":100},"content tampered",[62,183],{"x":124,"y":150,"width":85,"height":151,"rx":152,"fill":153,"opacity":154,"stroke":155,"style":89},[74,185,186],{"x":127,"y":158,"fill":159,"style":160},"injected script",[74,188,189],{"x":127,"y":164,"fill":99,"style":100},"clickjacking",[62,191],{"x":83,"y":192,"width":85,"height":193,"rx":152,"fill":194,"opacity":195,"stroke":196,"style":89},"210","70","#8ac926","0.16","#5a8a16",[74,198,200],{"x":92,"y":199,"fill":78,"style":94},"236","lockfile, audit,",[74,202,204],{"x":92,"y":203,"fill":78,"style":94},"254","provenance",[62,206],{"x":104,"y":192,"width":85,"height":193,"rx":152,"fill":194,"opacity":195,"stroke":196,"style":89},[74,208,209],{"x":107,"y":199,"fill":78,"style":94},"OIDC, scoped,",[74,211,212],{"x":107,"y":203,"fill":78,"style":94},"short-lived",[62,214],{"x":114,"y":192,"width":85,"height":193,"rx":152,"fill":194,"opacity":195,"stroke":196,"style":89},[74,216,217],{"x":117,"y":199,"fill":78,"style":94},"HSTS",[74,219,220],{"x":117,"y":203,"fill":78,"style":94},"+ preload",[62,222],{"x":124,"y":192,"width":85,"height":193,"rx":152,"fill":194,"opacity":195,"stroke":196,"style":89},[74,224,225],{"x":127,"y":199,"fill":78,"style":94},"CSP, SRI,",[74,227,228],{"x":127,"y":203,"fill":78,"style":94},"frame-ancestors",[74,230,232],{"x":76,"y":231,"fill":99,"style":100},"306","Headers protect the right half; pipeline hygiene protects the left half",[234,235,72,236,52],"defs",{},[237,238,136,244,72],"marker",{"id":239,"viewBox":240,"refX":152,"refY":241,"markerWidth":242,"markerHeight":242,"orient":243},"shs-arrow","0 0 10 10","5","7","auto-start-reverse",[138,245],{"d":246,"fill":99},"M0 0 L10 5 L0 10 z",[248,249,250],"figcaption",{},"Static sites remove the server from the threat model, not the browser or the pipeline — which is where the controls in this topic apply.",[252,253,255],"h2",{"id":254},"a-baseline-header-set","A Baseline Header Set",[14,257,258],{},"Every static site should ship these headers on every HTML response. They cost nothing in performance, and none of them requires changes to page content:",[260,261,266],"pre",{"className":262,"code":264,"language":74,"meta":265},[263],"language-text","# _headers (Cloudflare Pages \u002F Netlify syntax)\n\u002F*\n  Strict-Transport-Security: max-age=31536000; includeSubDomains\n  X-Content-Type-Options: nosniff\n  Referrer-Policy: strict-origin-when-cross-origin\n  X-Frame-Options: DENY\n  Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=()\n  Cross-Origin-Opener-Policy: same-origin\n","",[267,268,264],"code",{"__ignoreMap":265},[14,270,271,272,274,275,278,279,282,283,286,287,290,291,293,294,297,298,301],{},"What each does, in one line: ",[21,273,217],{}," tells browsers to use HTTPS for your domain for a year, closing the downgrade window on the first plain-HTTP request. ",[21,276,277],{},"nosniff"," stops browsers guessing content types, so a file served as ",[267,280,281],{},"text\u002Fplain"," is never executed as script. ",[21,284,285],{},"Referrer-Policy"," stops full URLs — which may include query parameters with tokens — leaking to other sites. ",[21,288,289],{},"X-Frame-Options"," (and the CSP ",[267,292,228],{}," directive that supersedes it) prevents your pages being framed for clickjacking. ",[21,295,296],{},"Permissions-Policy"," disables powerful browser features no page on the site uses, so an injected script cannot request them. ",[21,299,300],{},"COOP"," isolates your browsing context from cross-origin windows it opens.",[14,303,304],{},"On a documentation site, adding this set moved the Mozilla Observatory grade from F to B, and the securityheaders.com grade from F to A-, with zero content changes. The remaining gap in both was the Content-Security-Policy.",[252,306,308],{"id":307},"content-security-policy","Content-Security-Policy",[14,310,311,312,315],{},"CSP is the most powerful header and the one that takes real work, because it describes which sources of script, style, image, font and connection the page may use. A good policy makes an injected ",[267,313,314],{},"\u003Cscript>"," or a compromised third-party script unable to load code from anywhere unexpected or to send data anywhere unexpected.",[14,317,318,319,322],{},"Static sites are well suited to strict CSP because their HTML is fixed at build time: every inline script can be hashed during the build, so the policy can forbid ",[267,320,321],{},"unsafe-inline"," entirely.",[260,324,327],{"className":325,"code":326,"language":74,"meta":265},[263],"Content-Security-Policy:\n  default-src 'self';\n  script-src 'self' 'sha256-Qm9vdHN0cmFwIHRoZW1lIHNjcmlwdA==' https:\u002F\u002Fplausible.io;\n  style-src 'self';\n  img-src 'self' data: https:\u002F\u002Fimg.example-cdn.net;\n  font-src 'self';\n  connect-src 'self' https:\u002F\u002Fplausible.io;\n  frame-ancestors 'none';\n  base-uri 'self';\n  form-action 'self' https:\u002F\u002Fforms.example.com;\n  upgrade-insecure-requests\n",[267,328,326],{"__ignoreMap":265},[14,330,331,332,336,337,39],{},"Writing one from scratch and rolling it out safely is covered in ",[30,333,335],{"href":334},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fwriting-a-content-security-policy-for-a-static-site\u002F","Writing a Content Security Policy for a Static Site","; computing the hashes automatically at build time for Astro's inline scripts is in ",[30,338,340],{"href":339},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fhash-based-csp-for-inline-scripts-in-astro\u002F","Hash-Based CSP for Inline Scripts in Astro",[41,342,343,471],{},[44,344,52,349,52,352,52,355,52,358,52,464],{"viewBox":345,"role":47,"ariaLabelledBy":346,"xmlns":51},"0 0 780 290",[347,348],"shs-csp-title","shs-csp-desc",[54,350,351],{"id":347},"What a strict CSP allows and blocks",[58,353,354],{"id":348},"A page's script requests pass through a CSP check. The site's own bundle from self is allowed. An inline theme script whose hash is listed is allowed. The analytics script from an allow-listed origin is allowed. An injected inline script without a matching hash is blocked. A script from an unknown origin is blocked. A data exfiltration request to an unlisted origin is blocked by connect-src.",[62,356],{"x":64,"y":64,"width":65,"height":357,"fill":67},"290",[69,359,72,360,72,363,72,369,72,372,72,375,72,379,72,384,72,387,72,391,72,394,72,398,72,402,72,406,72,409,72,413,72,430,72,434,72,440,72,444,72,447,72,451,72,455,52],{"style":71},[74,361,362],{"x":76,"y":77,"fill":78,"style":79},"The policy is an allow-list the browser enforces",[62,364],{"x":365,"y":92,"width":85,"height":193,"rx":366,"fill":367,"opacity":368,"stroke":367,"style":89},"310","12","#6a4c93","0.14",[74,370,371],{"x":76,"y":150,"fill":78,"style":94},"CSP check",[74,373,374],{"x":76,"y":85,"fill":99,"style":100},"per request",[62,376],{"x":83,"y":151,"width":104,"height":377,"rx":152,"fill":87,"stroke":88,"style":378},"36","stroke-width:1px",[74,380,383],{"x":150,"y":381,"fill":78,"style":382},"73","text-anchor:middle","\u002F_astro\u002Fapp.js ('self')",[62,385],{"x":83,"y":386,"width":104,"height":377,"rx":152,"fill":87,"stroke":88,"style":378},"98",[74,388,390],{"x":150,"y":389,"fill":78,"style":382},"121","inline theme script (hash)",[62,392],{"x":83,"y":393,"width":104,"height":377,"rx":152,"fill":87,"stroke":88,"style":378},"146",[74,395,397],{"x":150,"y":396,"fill":78,"style":382},"169","plausible.io\u002Fjs (listed)",[62,399],{"x":83,"y":400,"width":104,"height":377,"rx":152,"fill":153,"opacity":401,"stroke":155,"style":378},"194","0.1",[74,403,405],{"x":150,"y":404,"fill":78,"style":382},"217","injected inline \u003Cscript>",[62,407],{"x":83,"y":408,"width":104,"height":377,"rx":152,"fill":153,"opacity":401,"stroke":155,"style":378},"242",[74,410,412],{"x":150,"y":411,"fill":78,"style":382},"265","evil.example\u002Fx.js",[69,414,136,415,136,418,136,421,136,424,136,427,72],{"stroke":99,"fill":134,"style":89},[138,416],{"d":417},"M252 68 L306 126",[138,419],{"d":420},"M252 116 L306 136",[138,422],{"d":423},"M252 164 L306 150",[138,425],{"d":426},"M252 212 L306 162",[138,428],{"d":429},"M252 260 L306 172",[62,431],{"x":432,"y":193,"width":104,"height":84,"rx":86,"fill":194,"opacity":433,"stroke":196,"style":89},"530","0.18",[74,435,439],{"x":436,"y":437,"fill":438,"style":94},"640","96","#3f6410","allowed (3)",[74,441,443],{"x":436,"y":442,"fill":99,"style":100},"116","own code, hashed inline, listed vendor",[62,445],{"x":432,"y":446,"width":104,"height":84,"rx":86,"fill":153,"opacity":368,"stroke":155,"style":89},"170",[74,448,450],{"x":436,"y":449,"fill":159,"style":94},"196","blocked (2)",[74,452,454],{"x":436,"y":453,"fill":99,"style":100},"216","and reported to report-to",[69,456,136,457,136,461,72],{"stroke":99,"fill":134,"style":135},[138,458],{"d":459,"style":460},"M472 130 L526 104","marker-end:url(#shs-csp-arrow)",[138,462],{"d":463,"style":460},"M472 160 L526 196",[234,465,72,466,52],{},[237,467,136,469,72],{"id":468,"viewBox":240,"refX":152,"refY":241,"markerWidth":242,"markerHeight":242,"orient":243},"shs-csp-arrow",[138,470],{"d":246,"fill":99},[248,472,473,474,476],{},"Hashing inline scripts at build time is what lets a static site drop ",[267,475,321],{},", the directive that makes most real-world policies ineffective.",[252,478,480],{"id":479},"hsts-and-preload","HSTS and Preload",[14,482,483,486,487,490,491,494,495,498,499,39],{},[267,484,485],{},"Strict-Transport-Security"," only protects visitors after their first successful HTTPS visit, because they must receive the header once. The HSTS preload list, built into browsers, removes that first-visit gap by hard-coding your domain as HTTPS-only. Getting onto it requires ",[267,488,489],{},"max-age"," of at least a year, ",[267,492,493],{},"includeSubDomains"," and the ",[267,496,497],{},"preload"," directive — and it is hard to reverse, because removal propagates through browser releases over months. The staged rollout that avoids locking out a forgotten HTTP-only subdomain is in ",[30,500,502],{"href":501},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fenabling-hsts-and-preload-safely\u002F","Enabling HSTS and Preload Safely",[252,504,506],{"id":505},"subresource-integrity-for-third-party-assets","Subresource Integrity for Third-Party Assets",[14,508,509],{},"If your pages load a script or stylesheet from a CDN you do not control, SRI lets the browser verify the file's hash before executing it. A tampered file fails the check and does not run.",[260,511,515],{"className":512,"code":513,"language":514,"meta":265,"style":265},"language-html shiki shiki-themes github-light github-dark","\u003Cscript src=\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fchart.js@4.4.4\u002Fdist\u002Fchart.umd.min.js\"\n        integrity=\"sha384-…\" crossorigin=\"anonymous\" defer>\u003C\u002Fscript>\n","html",[267,516,517,541],{"__ignoreMap":265},[518,519,522,526,530,534,537],"span",{"class":520,"line":521},"line",1,[518,523,525],{"class":524},"sVt8B","\u003C",[518,527,529],{"class":528},"s9eBZ","script",[518,531,533],{"class":532},"sScJk"," src",[518,535,536],{"class":524},"=",[518,538,540],{"class":539},"sZZnC","\"https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002Fchart.js@4.4.4\u002Fdist\u002Fchart.umd.min.js\"\n",[518,542,544,547,549,552,555,557,560,563,566,568],{"class":520,"line":543},2,[518,545,546],{"class":532},"        integrity",[518,548,536],{"class":524},[518,550,551],{"class":539},"\"sha384-…\"",[518,553,554],{"class":532}," crossorigin",[518,556,536],{"class":524},[518,558,559],{"class":539},"\"anonymous\"",[518,561,562],{"class":532}," defer",[518,564,565],{"class":524},">\u003C\u002F",[518,567,529],{"class":528},[518,569,570],{"class":524},">\n",[14,572,573,574,577,578,39],{},"SRI only works for versioned, immutable URLs — a ",[267,575,576],{},"latest"," URL changes content and breaks the hash. On static sites the better default is to self-host third-party code at build time, which removes the external origin entirely; SRI is for the cases where that is not possible. The details, including generating hashes in the build, are in ",[30,579,506],{"href":580},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsubresource-integrity-for-third-party-assets\u002F",[252,582,584],{"id":583},"the-pipeline-dependencies-and-deploy-credentials","The Pipeline: Dependencies and Deploy Credentials",[14,586,587],{},"Response headers cannot help if the attacker publishes the page. For static sites, two pipeline risks dominate.",[14,589,590,593,594,597,598,601,602,604,605,39],{},[21,591,592],{},"Dependencies."," A typical Astro or Next.js site installs 400–1,200 npm packages. Every one can run code during ",[267,595,596],{},"npm install"," (via lifecycle scripts) and during the build, with access to environment variables — including deploy tokens if they are present. Lockfiles with integrity hashes, ",[267,599,600],{},"npm ci"," instead of ",[267,603,596],{},", disabling lifecycle scripts where possible, automated audit in CI, and a review step for new dependencies reduce this risk substantially; see ",[30,606,608],{"href":607},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fauditing-npm-dependencies-in-ssg-pipelines\u002F","Auditing npm Dependencies in SSG Pipelines",[14,610,611,614,615,39],{},[21,612,613],{},"Deploy credentials."," A long-lived API token stored as a CI secret is a standing key to every page on the site. Short-lived credentials issued via OpenID Connect, scoped to one project and one branch, cannot be reused if leaked and expire within minutes. The setup for GitHub Actions to Cloudflare, AWS and Netlify is in ",[30,616,618],{"href":617},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecuring-deploy-credentials-with-github-oidc\u002F","Securing Deploy Credentials with GitHub OIDC",[41,620,621,710],{},[44,622,52,627,52,630,52,633,52,636,52,703],{"viewBox":623,"role":47,"ariaLabelledBy":624,"xmlns":51},"0 0 780 280",[625,626],"shs-pipe-title","shs-pipe-desc",[54,628,629],{"id":625},"Where build-time code runs and what it can reach",[58,631,632],{"id":626},"The CI job runs npm ci, which executes install scripts from hundreds of packages, then the build, which executes plugin and bundler code, then the deploy step. If a long-lived deploy token is in the job's environment from the start, every earlier step can read it. With OIDC, the credential is minted only in the deploy step and expires in minutes.",[62,634],{"x":64,"y":64,"width":65,"height":635,"fill":67},"280",[69,637,72,638,72,641,72,648,72,652,72,656,72,658,72,661,72,664,72,667,72,671,72,674,72,683,72,688,72,692,72,695,72,699,52],{"style":71},[74,639,640],{"x":76,"y":77,"fill":78,"style":79},"Keep the publish credential away from third-party code",[62,642],{"x":83,"y":84,"width":643,"height":644,"rx":86,"fill":645,"opacity":646,"stroke":647,"style":89},"200","56","#ffca3a","0.22","#a97b00",[74,649,600],{"x":650,"y":651,"fill":78,"style":94},"130","84",[74,653,655],{"x":650,"y":654,"fill":99,"style":100},"102","~900 packages' scripts",[62,657],{"x":357,"y":84,"width":643,"height":644,"rx":86,"fill":645,"opacity":646,"stroke":647,"style":89},[74,659,660],{"x":76,"y":651,"fill":78,"style":94},"build",[74,662,663],{"x":76,"y":654,"fill":99,"style":100},"plugins, bundler, loaders",[62,665],{"x":666,"y":84,"width":643,"height":644,"rx":86,"fill":367,"opacity":368,"stroke":367,"style":89},"550",[74,668,670],{"x":669,"y":651,"fill":78,"style":94},"650","deploy",[74,672,673],{"x":669,"y":654,"fill":99,"style":100},"first-party step only",[69,675,136,676,136,680,72],{"stroke":99,"fill":134,"style":135},[138,677],{"d":678,"style":679},"M232 88 L286 88","marker-end:url(#shs-p-arrow)",[138,681],{"d":682,"style":679},"M492 88 L546 88",[62,684],{"x":83,"y":685,"width":686,"height":687,"rx":152,"fill":153,"opacity":368,"stroke":155,"style":89},"144","720","34",[74,689,691],{"x":76,"y":690,"fill":159,"style":94},"166","long-lived token in job env: readable by every step, valid for months",[62,693],{"x":666,"y":449,"width":643,"height":687,"rx":152,"fill":194,"opacity":694,"stroke":196,"style":89},"0.2",[74,696,698],{"x":669,"y":697,"fill":438,"style":94},"218","OIDC: minted here, ~15 min",[74,700,702],{"x":76,"y":701,"fill":99,"style":100},"262","A dependency cannot steal a credential that does not exist yet when it runs",[234,704,72,705,52],{},[237,706,136,708,72],{"id":707,"viewBox":240,"refX":152,"refY":241,"markerWidth":242,"markerHeight":242,"orient":243},"shs-p-arrow",[138,709],{"d":246,"fill":99},[248,711,712],{},"Moving credential issuance into the deploy step shrinks the window from \"whole job, for months\" to \"one step, for minutes\".",[252,714,716],{"id":715},"headers-beyond-the-baseline","Headers Beyond the Baseline",[14,718,719],{},"A few more headers are worth knowing about, even if not every site needs them.",[14,721,722,725,726,729,730,733],{},[21,723,724],{},"Cross-Origin-Resource-Policy"," (",[267,727,728],{},"same-origin"," or ",[267,731,732],{},"same-site",") stops other sites embedding your images, scripts and fonts as subresources. It protects against a class of side-channel attacks and, as a side benefit, stops hotlinking of large assets. Apply it to asset paths, not to pages meant to be linked.",[14,735,736,739,740,743],{},[21,737,738],{},"Cross-Origin-Embedder-Policy"," is only needed if the site uses features such as ",[267,741,742],{},"SharedArrayBuffer",". Setting it without that need tends to break third-party embeds, so leave it unset on most content sites.",[14,745,746,749,750,753,754,39],{},[21,747,748],{},"Cache-Control on sensitive responses."," Static sites rarely serve personal data, but preview deployments sometimes contain unreleased content. ",[267,751,752],{},"X-Robots-Tag: noindex"," on preview hostnames, plus access control, keeps drafts out of search engines and shared caches; see ",[30,755,757],{"href":756},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpassword-protecting-preview-deployments\u002F","Password-Protecting Preview Deployments",[14,759,760,763,764,767,768,771],{},[21,761,762],{},"Remove what you do not need."," Many hosts and frameworks add headers that advertise software versions (",[267,765,766],{},"X-Powered-By",", ",[267,769,770],{},"Server"," with a version string). They give attackers free reconnaissance and nothing to readers. Strip them where the host allows.",[14,773,774,775,778,779,781],{},"Finally, prefer one source of truth. Headers scattered across a ",[267,776,777],{},"_headers"," file, a meta tag and a middleware function drift apart; generate the ",[267,780,777],{}," file from a single configuration object at build time so the policy is reviewable in one diff.",[252,783,785],{"id":784},"setting-headers-on-each-host","Setting Headers on Each Host",[14,787,788],{},"The same header set translates directly between hosts:",[790,791,792,808],"table",{},[793,794,795],"thead",{},[796,797,798,802,805],"tr",{},[799,800,801],"th",{},"Host",[799,803,804],{},"Where headers live",[799,806,807],{},"Notes",[809,810,811,829,852,872,883],"tbody",{},[796,812,813,817,822],{},[814,815,816],"td",{},"Cloudflare Pages \u002F Workers static assets",[814,818,819,821],{},[267,820,777],{}," file in the output directory",[814,823,824,825,828],{},"path patterns with ",[267,826,827],{},"*","; later rules add to earlier ones",[796,830,831,834,846],{},[814,832,833],{},"Netlify",[814,835,836,838,839,842,843],{},[267,837,777],{}," file or ",[267,840,841],{},"[[headers]]"," in ",[267,844,845],{},"netlify.toml",[814,847,848,849,851],{},"same ",[267,850,777],{}," syntax as Cloudflare",[796,853,854,857,866],{},[814,855,856],{},"Vercel",[814,858,859,862,863],{},[267,860,861],{},"headers"," array in ",[267,864,865],{},"vercel.json",[814,867,868,871],{},[267,869,870],{},"source"," patterns; applies to static and functions",[796,873,874,877,880],{},[814,875,876],{},"S3 + CloudFront",[814,878,879],{},"Response headers policy",[814,881,882],{},"managed \"SecurityHeadersPolicy\" as a starting point",[796,884,885,888,898],{},[814,886,887],{},"nginx \u002F Caddy",[814,889,890,893,894,897],{},[267,891,892],{},"add_header"," \u002F ",[267,895,896],{},"header"," directives",[814,899,900,901,903],{},"nginx drops parent ",[267,902,892],{},"s in nested blocks unless repeated",[14,905,906,907,909,910,913,914,917,918,921,922,925,926,39],{},"The nginx behaviour catches many self-hosters: an ",[267,908,892],{}," in a ",[267,911,912],{},"location"," block replaces, rather than extends, the ones set at the ",[267,915,916],{},"server"," level, so a location that adds a ",[267,919,920],{},"Cache-Control"," header silently loses all the security headers. Repeat them or use an ",[267,923,924],{},"include"," file, as shown in ",[30,927,929],{"href":928},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-nginx\u002F","Serving a Static Site with Nginx",[252,931,933],{"id":932},"verifying-headers-in-ci","Verifying Headers in CI",[14,935,936],{},"Headers are configuration, so test them like configuration. A smoke test against each preview deploy can assert that every template returns the full set:",[260,938,942],{"className":939,"code":940,"language":941,"meta":265,"style":265},"language-bash shiki shiki-themes github-light github-dark","for path in \u002F \u002Fguides\u002F \u002Fguides\u002Fdeploying-hugo\u002F \u002F404.html; do\n  h=$(curl -sI \"$PREVIEW$path\")\n  for want in strict-transport-security content-security-policy x-content-type-options referrer-policy; do\n    echo \"$h\" | grep -qi \"^$want:\" || { echo \"FAIL $path missing $want\"; exit 1; }\n  done\ndone\n","bash",[267,943,944,974,1003,1030,1094,1100],{"__ignoreMap":265},[518,945,946,950,953,956,959,962,965,968,971],{"class":520,"line":521},[518,947,949],{"class":948},"szBVR","for",[518,951,952],{"class":524}," path ",[518,954,955],{"class":948},"in",[518,957,958],{"class":539}," \u002F",[518,960,961],{"class":539}," \u002Fguides\u002F",[518,963,964],{"class":539}," \u002Fguides\u002Fdeploying-hugo\u002F",[518,966,967],{"class":539}," \u002F404.html",[518,969,970],{"class":524},"; ",[518,972,973],{"class":948},"do\n",[518,975,976,979,981,984,987,991,994,997,1000],{"class":520,"line":543},[518,977,978],{"class":524},"  h",[518,980,536],{"class":948},[518,982,983],{"class":524},"$(",[518,985,986],{"class":532},"curl",[518,988,990],{"class":989},"sj4cs"," -sI",[518,992,993],{"class":539}," \"",[518,995,996],{"class":524},"$PREVIEW$path",[518,998,999],{"class":539},"\"",[518,1001,1002],{"class":524},")\n",[518,1004,1006,1009,1012,1014,1017,1020,1023,1026,1028],{"class":520,"line":1005},3,[518,1007,1008],{"class":948},"  for",[518,1010,1011],{"class":524}," want ",[518,1013,955],{"class":948},[518,1015,1016],{"class":539}," strict-transport-security",[518,1018,1019],{"class":539}," content-security-policy",[518,1021,1022],{"class":539}," x-content-type-options",[518,1024,1025],{"class":539}," referrer-policy",[518,1027,970],{"class":524},[518,1029,973],{"class":948},[518,1031,1033,1036,1038,1041,1043,1046,1049,1052,1055,1058,1061,1064,1067,1070,1073,1076,1079,1081,1083,1085,1088,1091],{"class":520,"line":1032},4,[518,1034,1035],{"class":989},"    echo",[518,1037,993],{"class":539},[518,1039,1040],{"class":524},"$h",[518,1042,999],{"class":539},[518,1044,1045],{"class":948}," |",[518,1047,1048],{"class":532}," grep",[518,1050,1051],{"class":989}," -qi",[518,1053,1054],{"class":539}," \"^",[518,1056,1057],{"class":524},"$want",[518,1059,1060],{"class":539},":\"",[518,1062,1063],{"class":948}," ||",[518,1065,1066],{"class":524}," { ",[518,1068,1069],{"class":989},"echo",[518,1071,1072],{"class":539}," \"FAIL ",[518,1074,1075],{"class":524},"$path",[518,1077,1078],{"class":539}," missing ",[518,1080,1057],{"class":524},[518,1082,999],{"class":539},[518,1084,970],{"class":524},[518,1086,1087],{"class":989},"exit",[518,1089,1090],{"class":989}," 1",[518,1092,1093],{"class":524},"; }\n",[518,1095,1097],{"class":520,"line":1096},5,[518,1098,1099],{"class":948},"  done\n",[518,1101,1103],{"class":520,"line":1102},6,[518,1104,1105],{"class":948},"done\n",[14,1107,1108,1109,1113],{},"This belongs in the same job as the smoke tests from ",[30,1110,1112],{"href":1111},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url\u002F","Running Smoke Tests Against a Preview URL",". The 404 page is included deliberately: error responses are frequently served by a different code path that skips header rules.",[252,1115,1117],{"id":1116},"collecting-and-reading-csp-reports","Collecting and Reading CSP Reports",[14,1119,1120,1121,1124,1125,1128,1129,1132,1133,39],{},"A policy without reporting is a policy you cannot improve. Add a ",[267,1122,1123],{},"report-to"," directive (with a matching ",[267,1126,1127],{},"Reporting-Endpoints"," header) and, for older browsers, ",[267,1130,1131],{},"report-uri",", pointing at an endpoint you control. A small edge function that validates the JSON, drops obviously malformed reports, and writes the rest to a log store is enough; the pattern is the same as the form handler in ",[30,1134,1136],{"href":1135},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fhandling-form-submissions-on-a-static-site\u002F","Handling Form Submissions on a Static Site",[14,1138,1139,1140,1143,1144,729,1147,1150,1151,1154,1155,1158],{},"Expect noise. On the documentation site measured below, 94% of reports in the first week came from browser extensions injecting scripts and styles into every page — password managers, ad blockers, translation tools — identifiable by ",[267,1141,1142],{},"source-file"," values such as ",[267,1145,1146],{},"chrome-extension",[267,1148,1149],{},"moz-extension",". Filter those out before anyone reads the data. What remains is signal: a forgotten inline script in one template, a vendor that moved its assets to a new domain, an embed that loads a font from a CDN you never listed. Group reports by ",[267,1152,1153],{},"effective-directive"," and ",[267,1156,1157],{},"blocked-uri",", and review the top ten weekly until the list is empty except for extensions.",[14,1160,1161],{},"Keep reporting on after switching to enforcing mode. A spike in violations after a deploy is one of the fastest indicators that something changed that should not have — either a legitimate change nobody updated the policy for, or an injection attempt the policy just blocked.",[252,1163,1165],{"id":1164},"embeds-forms-and-other-exceptions","Embeds, Forms and Other Exceptions",[14,1167,1168],{},"Most static sites have a handful of features that do not fit a strict policy by default. Handle each one deliberately rather than loosening the whole policy.",[14,1170,1171,1174,1175,1178,1179,767,1182,1185,1186,1190],{},[21,1172,1173],{},"Video and social embeds"," need ",[267,1176,1177],{},"frame-src"," entries for their domains (",[267,1180,1181],{},"https:\u002F\u002Fwww.youtube-nocookie.com",[267,1183,1184],{},"https:\u002F\u002Fplayer.vimeo.com","). Loading them behind a click-to-load facade, as in ",[30,1187,1189],{"href":1188},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites\u002F","Lazy-Loading YouTube Embeds on Static Sites",", is also a security win: the third-party frame never loads for readers who do not ask for it.",[14,1192,1193,1196,1197,1200,1201,1204],{},[21,1194,1195],{},"Forms"," posting to a third-party service need that origin in ",[267,1198,1199],{},"form-action",". Posting to your own edge function instead keeps ",[267,1202,1203],{},"form-action 'self'"," intact and keeps submissions under your control.",[14,1206,1207,1210,1211,842,1214,1217,1218,1221],{},[21,1208,1209],{},"Search tools"," that use WebAssembly, such as Pagefind, need ",[267,1212,1213],{},"'wasm-unsafe-eval'",[267,1215,1216],{},"script-src",". That keyword permits compiling WebAssembly only, not JavaScript ",[267,1219,1220],{},"eval",", so it is a narrow and acceptable exception.",[14,1223,1224,1227,1228,729,1230,1233],{},[21,1225,1226],{},"Analytics and consent managers"," are the hardest. Many inject inline scripts at runtime, which no build-time hash can cover. Prefer vendors that load as a single external script, self-host their code where the licence allows, and treat any vendor that requires ",[267,1229,321],{},[267,1231,1232],{},"unsafe-eval"," as a cost to be justified in writing.",[14,1235,1236,1237,1239,1240,1243,1244,1246],{},"Scope exceptions by path where the host allows it. On Cloudflare Pages or Netlify, a ",[267,1238,777],{}," rule for ",[267,1241,1242],{},"\u002Fvideos\u002F*"," can extend ",[267,1245,1177],{}," for the few pages that embed video, while every other page keeps the stricter policy.",[252,1248,1250],{"id":1249},"when-something-goes-wrong","When Something Goes Wrong",[14,1252,1253,1254,1258],{},"Static sites make incident response unusually simple, and it is worth writing the steps down before they are needed. If a compromised dependency or a leaked token has published malicious content, the order is: roll back to the last known-good deploy (on atomic hosts this takes seconds, as described in ",[30,1255,1257],{"href":1256},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute\u002F","Rolling Back a Bad Static Deploy in Under a Minute","); revoke every credential the pipeline could reach; purge the CDN cache so no edge keeps serving the bad version; and only then investigate. Because every deploy is an immutable artifact tied to a commit, the investigation can diff the bad deploy's output against the previous one file by file to see exactly what was injected. Keep at least thirty days of deploy history for this reason, and make sure the rollback does not depend on the same credential that may have leaked.",[252,1260,1262],{"id":1261},"measured-impact","Measured Impact",[14,1264,1265],{},"A 700-page Astro documentation site on Cloudflare Pages applied the full set over three weeks: baseline headers, a hash-based CSP rolled out via report-only, HSTS with preload, self-hosted third-party scripts, OIDC deploys and dependency auditing.",[790,1267,1268,1281],{},[793,1269,1270],{},[796,1271,1272,1275,1278],{},[799,1273,1274],{},"Measure",[799,1276,1277],{},"Before",[799,1279,1280],{},"After",[809,1282,1283,1294,1305,1315,1326,1336,1345,1356],{},[796,1284,1285,1288,1291],{},[814,1286,1287],{},"Mozilla Observatory score",[814,1289,1290],{},"0\u002F100 (F)",[814,1292,1293],{},"115\u002F100 (A+)",[796,1295,1296,1299,1302],{},[814,1297,1298],{},"securityheaders.com grade",[814,1300,1301],{},"F",[814,1303,1304],{},"A+",[796,1306,1307,1310,1313],{},[814,1308,1309],{},"Inline scripts allowed without hash",[814,1311,1312],{},"all",[814,1314,64],{},[796,1316,1317,1320,1323],{},[814,1318,1319],{},"Third-party script origins",[814,1321,1322],{},"4",[814,1324,1325],{},"1",[796,1327,1328,1331,1334],{},[814,1329,1330],{},"Long-lived deploy secrets in CI",[814,1332,1333],{},"2",[814,1335,64],{},[796,1337,1338,1341,1343],{},[814,1339,1340],{},"Known-vulnerable dependencies (high\u002Fcritical)",[814,1342,242],{},[814,1344,64],{},[796,1346,1347,1350,1353],{},[814,1348,1349],{},"CSP violation reports per day (enforcing, week 4)",[814,1351,1352],{},"—",[814,1354,1355],{},"3–8, all browser extensions",[796,1357,1358,1361,1363],{},[814,1359,1360],{},"Change in LCP p75",[814,1362,1352],{},[814,1364,1365],{},"none measurable",[252,1367,1369],{"id":1368},"common-pitfalls","Common Pitfalls",[1371,1372,1373,1384,1392,1398,1408,1414],"ul",{},[1374,1375,1376,1379,1380,1383],"li",{},[21,1377,1378],{},"Enforcing CSP on day one."," Always ship ",[267,1381,1382],{},"Content-Security-Policy-Report-Only"," first and read the reports.",[1374,1385,1386,1391],{},[21,1387,1388,1390],{},[267,1389,321],{}," for convenience."," It defeats most of the protection. Hash inline scripts at build time instead.",[1374,1393,1394,1397],{},[21,1395,1396],{},"HSTS preload before auditing subdomains."," An internal tool on plain HTTP becomes unreachable for months.",[1374,1399,1400,1403,1404,1407],{},[21,1401,1402],{},"Headers only on HTML."," Error pages and some assets are served via different rules; check ",[267,1405,1406],{},"404.html"," and redirects explicitly.",[1374,1409,1410,1413],{},[21,1411,1412],{},"Secrets available to every CI step."," Scope deploy credentials to the deploy step, and prefer OIDC to stored tokens.",[1374,1415,1416,1419],{},[21,1417,1418],{},"Treating grades as the goal."," Observatory and securityheaders.com are checklists, not threat models. The CSP and the pipeline controls are where the real risk reduction is.",[252,1421,1423],{"id":1422},"key-takeaways","Key Takeaways",[1371,1425,1426,1429,1432,1438,1441],{},[1374,1427,1428],{},"Static sites still run third-party JavaScript and still have a publishing pipeline; both need hardening.",[1374,1430,1431],{},"A baseline of HSTS, nosniff, Referrer-Policy, frame protection and Permissions-Policy costs nothing and belongs on every site.",[1374,1433,1434,1435,1437],{},"A hash-based CSP without ",[267,1436,321],{}," is achievable on static sites because inline scripts are known at build time.",[1374,1439,1440],{},"Self-host third-party code where possible; use SRI where it must stay external.",[1374,1442,1443],{},"Dependency auditing and short-lived OIDC deploy credentials protect against the attacks headers cannot stop.",[252,1445,1447],{"id":1446},"faq","FAQ",[1449,1450,1452],"h3",{"id":1451},"does-a-static-site-need-security-headers-at-all","Does a static site need security headers at all?",[14,1454,1455],{},"Yes. There is no server-side code to exploit, but browsers still execute whatever scripts the page loads, including injected or compromised third-party scripts. Headers such as Content-Security-Policy and HSTS limit what an attacker can do if content or a dependency is tampered with.",[1449,1457,1459],{"id":1458},"which-headers-matter-most","Which headers matter most?",[14,1461,1462],{},"Strict-Transport-Security, a Content-Security-Policy, X-Content-Type-Options set to nosniff, a Referrer-Policy, and frame-ancestors or X-Frame-Options against clickjacking. A Permissions-Policy that disables unused browser features is a useful addition.",[1449,1464,1466],{"id":1465},"where-are-headers-configured-on-a-static-host","Where are headers configured on a static host?",[14,1468,1469],{},"In the host's header configuration rather than in HTML: a _headers file on Cloudflare Pages and Netlify, the headers key in vercel.json, response header policies on CloudFront, or add_header directives in nginx. A few, such as CSP, can also be set with a meta tag, with limitations.",[1449,1471,1473],{"id":1472},"what-is-the-biggest-real-risk-for-a-static-site","What is the biggest real risk for a static site?",[14,1475,1476],{},"The build pipeline and its dependencies. A compromised npm package or leaked deploy token can publish malicious content to every page. Pinning dependencies, auditing them and using short-lived deploy credentials matter as much as response headers.",[1449,1478,1480],{"id":1479},"will-a-strict-csp-break-my-site","Will a strict CSP break my site?",[14,1482,1483],{},"It can if it is deployed in enforcing mode without testing. Roll it out with Content-Security-Policy-Report-Only first, collect violation reports for a week or two, fix or allow what is legitimate, then switch to enforcing.",[252,1485,1487],{"id":1486},"related","Related",[1371,1489,1490,1499,1504,1509,1514,1519,1524,1529,1539,1546,1553,1560,1567,1574],{},[1374,1491,1492,1495,1496,1498],{},[21,1493,1494],{},"Up:"," ",[30,1497,33],{"href":32}," — where security fits in the deploy pipeline.",[1374,1500,1501,1503],{},[30,1502,335],{"href":334}," — from report-only to enforcing.",[1374,1505,1506,1508],{},[30,1507,340],{"href":339}," — computing hashes at build time.",[1374,1510,1511,1513],{},[30,1512,502],{"href":501}," — the staged rollout.",[1374,1515,1516,1518],{},[30,1517,506],{"href":580}," — verifying code you do not host.",[1374,1520,1521,1523],{},[30,1522,608],{"href":607}," — supply-chain controls.",[1374,1525,1526,1528],{},[30,1527,618],{"href":617}," — no more long-lived tokens.",[1374,1530,1531,1535,1536,1538],{},[30,1532,1534],{"href":1533},"\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"," — the same ",[267,1537,777],{}," file for caching.",[1374,1540,1541,1545],{},[30,1542,1544],{"href":1543},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fpermissions-policy-and-cross-origin-headers\u002F","Permissions-Policy and Cross-Origin Headers"," — set Permissions-Policy, COOP, CORP and COEP on a static site.",[1374,1547,1548,1552],{},[30,1549,1551],{"href":1550},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecurity-txt-and-disclosure-for-static-sites\u002F","security.txt and Disclosure for Static Sites"," — publish a valid security.",[1374,1554,1555,1559],{},[30,1556,1558],{"href":1557},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Ffixing-mixed-content-warnings-after-moving-to-https\u002F","Fixing Mixed Content Warnings After Moving to HTTPS"," — find every http:\u002F\u002F reference in a static site's content, templates and data after moving to HTTPS, fix it at the source, and block new ones in CI.",[1374,1561,1562,1566],{},[30,1563,1565],{"href":1564},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecurity-headers-for-static-sites-served-by-caddy\u002F","Security Headers for Static Sites Served by Caddy"," — configure HSTS, CSP, framing, referrer and permissions headers in a Caddyfile for a static site, with per-path rules, a snippet and header tests.",[1374,1568,1569,1573],{},[30,1570,1572],{"href":1571},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Ffixing-content-security-policy-violations-from-inline-scripts\u002F","Fixing Content Security Policy Violations From Inline Scripts"," — trace CSP inline-script violations on a static site from reports to sources, then fix each with hashes, external files or removed handlers.",[1374,1575,1576,1580],{},[30,1577,1579],{"href":1578},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecurity-headers-on-vercel-for-static-sites\u002F","Security Headers on Vercel for Static Sites"," — add HSTS, CSP, framing, referrer and permissions headers to a static site on Vercel with vercel.json, relax them only on previews, and test each deploy.",[1582,1583,1584],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":265,"searchDepth":543,"depth":543,"links":1586},[1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,1600,1601,1608],{"id":254,"depth":543,"text":255},{"id":307,"depth":543,"text":308},{"id":479,"depth":543,"text":480},{"id":505,"depth":543,"text":506},{"id":583,"depth":543,"text":584},{"id":715,"depth":543,"text":716},{"id":784,"depth":543,"text":785},{"id":932,"depth":543,"text":933},{"id":1116,"depth":543,"text":1117},{"id":1164,"depth":543,"text":1165},{"id":1249,"depth":543,"text":1250},{"id":1261,"depth":543,"text":1262},{"id":1368,"depth":543,"text":1369},{"id":1422,"depth":543,"text":1423},{"id":1446,"depth":543,"text":1447,"children":1602},[1603,1604,1605,1606,1607],{"id":1451,"depth":1005,"text":1452},{"id":1458,"depth":1005,"text":1459},{"id":1465,"depth":1005,"text":1466},{"id":1472,"depth":1005,"text":1473},{"id":1479,"depth":1005,"text":1480},{"id":1486,"depth":543,"text":1487},[1610,1613,1614],{"name":1611,"item":1612},"Home","\u002F",{"name":33,"item":32},{"name":5,"item":1615},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002F","2026-09-18","Harden a static site end to end: CSP, HSTS, SRI, framing and referrer policies at the edge, plus a supply chain and deploy pipeline built to resist abuse.","md",[1620,1621,1622,1625,1626],{"q":1452,"a":1455},{"q":1459,"a":1462},{"q":1466,"a":1623},{"In the host's header configuration rather than in HTML":1624},"a _headers file on Cloudflare Pages and Netlify, the headers key in vercel.json, response header policies on CloudFront, or add_header directives in nginx. A few, such as CSP, can also be set with a meta tag, with limitations.",{"q":1473,"a":1476},{"q":1480,"a":1483},{},true,"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites",{"title":5,"description":1617},"security-headers-for-static-sites","production-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Findex","guide","WckA-rJYtPp3Lcw2t6m46zKZ4D3DbJN6U_JGbaj7GV0",[1636,1639,1642,1645,1648,1651,1654,1657,1660,1663,1666,1669,1672,1675,1678,1681,1684,1687,1690,1693,1696,1699,1702,1705,1708,1711,1714,1717,1720,1723,1726,1729,1732,1735,1738,1741,1744,1747,1750,1753,1756,1759,1762,1765,1768,1771,1774,1777,1780,1783,1786,1789,1792,1795,1798,1801,1804,1807,1810,1813,1816,1819,1822,1825,1828,1831,1834,1837,1840,1843,1846,1849,1852,1855,1858,1861,1864,1867,1870,1873,1876,1879,1882,1885,1888,1891,1894,1897,1900,1903,1906,1909,1912,1915,1918,1921,1924,1927,1930,1933,1936,1939,1942,1945,1948,1951,1954,1957,1960,1963,1966,1969,1972,1975,1978,1981,1984,1987,1990,1993,1996,1999,2002,2005,2008,2011,2014,2017,2020,2023,2026,2029,2032,2035,2038,2041,2044,2047,2050,2053,2056,2059,2062,2065,2068,2071,2074,2077,2080,2083,2086,2089,2092,2095,2098,2101,2104,2107,2110,2113,2116,2119,2122,2125,2128,2131,2134,2137,2140,2143,2146,2149,2152,2155,2158,2161,2164,2167,2170,2173,2176,2179,2182,2185,2188,2191,2194,2197,2200,2203,2206,2209,2212,2215,2218,2221,2224,2227,2230,2233,2236,2239,2242,2245,2248,2251,2254,2257,2260,2263,2266,2269,2272,2275,2278,2281,2284,2287,2290,2293,2296,2299,2302,2305,2308,2311,2314,2317,2320,2323,2326,2329,2332,2335,2338,2341,2344,2347,2350,2353,2356,2359,2361,2364,2367,2370,2373,2376,2379,2382,2385,2388,2391,2394,2397,2400,2403,2405,2408,2411,2414,2417,2420,2423,2426,2429,2432,2435,2438,2441,2444,2447,2450,2453,2456,2459,2462,2465,2468,2471,2474,2477,2480,2483,2486,2489,2492,2495,2498,2501,2504,2507,2510,2513,2516,2519,2522,2525,2528,2531,2534,2537,2540,2543,2546,2549,2552,2555,2558,2561,2564,2567,2570,2573,2576,2579,2582,2585,2588,2591,2594,2597,2600,2602,2605,2608,2611,2614,2617,2620,2623,2626,2629,2632,2635,2638,2640,2643,2646,2648,2650,2652,2654,2656,2658,2659,2661,2663,2665,2667,2669,2671,2673,2676,2679,2682,2685,2688,2691,2694,2697,2700,2703,2705,2708,2711,2714,2717,2719,2722,2725,2728,2731,2734,2737,2740,2743,2746,2749,2752,2755,2758,2761],{"path":1637,"title":1638},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Faccessible-code-blocks-in-documentation-sites","Accessible Code Blocks in Documentation Sites",{"path":1640,"title":1641},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Faccessible-dark-mode-toggles-for-static-sites","Accessible Dark Mode Toggles for Static Sites",{"path":1643,"title":1644},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Faccessible-svg-diagrams-on-static-sites","Accessible SVG Diagrams on Static Sites",{"path":1646,"title":1647},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Fenforcing-alt-text-for-markdown-images-at-build-time","Enforcing Alt Text for Markdown Images at Build Time",{"path":1649,"title":1650},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Ffixing-heading-order-problems-in-markdown-content","Fixing Heading Order Problems in Markdown Content",{"path":1652,"title":1653},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Ffixing-low-color-contrast-flagged-by-lighthouse","Fixing Low Color Contrast Flagged by Lighthouse",{"path":1655,"title":1656},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites","Accessibility for Static Sites",{"path":1658,"title":1659},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Fkeyboard-navigation-and-focus-order-on-static-sites","Keyboard Navigation and Focus Order on Static Sites",{"path":1661,"title":1662},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Faccessibility-for-static-sites\u002Fskip-links-and-landmarks-in-ssg-layouts","Skip Links and Landmarks in SSG Layouts",{"path":1664,"title":1665},"\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":1667,"title":1668},"\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":1670,"title":1671},"\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":1673,"title":1674},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fdev-server-performance-astro-vs-eleventy","Dev Server Performance: Astro vs Eleventy",{"path":1676,"title":1677},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Ffixing-astro-build-errors-after-upgrading-to-astro-5","Fixing Astro Build Errors After Upgrading to Astro 5",{"path":1679,"title":1680},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Ffixing-duplicate-permalink-errors-in-eleventy","Fixing Duplicate Permalink Errors in Eleventy",{"path":1682,"title":1683},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Ffixing-eleventy-out-of-memory-errors-on-large-collections","Fixing Eleventy Out-of-Memory Errors on Large Collections",{"path":1685,"title":1686},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Ffixing-slow-astro-builds-caused-by-large-mdx-collections","Fixing Slow Astro Builds Caused by Large MDX Collections",{"path":1688,"title":1689},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":1691,"title":1692},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Floading-remote-content-with-astro-content-layer-loaders","Loading Remote Content With Astro Content Layer Loaders",{"path":1694,"title":1695},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fmarkdown-pipelines-remark-vs-markdown-it","Markdown Pipelines: remark vs markdown-it",{"path":1697,"title":1698},"\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":1700,"title":1701},"\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":1703,"title":1704},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fsyntax-highlighting-with-shiki-in-astro-and-eleventy","Syntax Highlighting with Shiki in Astro and Eleventy",{"path":1706,"title":1707},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fupgrading-eleventy-2-to-3-with-esm-configuration","Upgrading Eleventy 2 to 3 With ESM Configuration",{"path":1709,"title":1710},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fadding-local-search-to-a-vitepress-site","Adding Local Search to a VitePress Site",{"path":1712,"title":1713},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fcomparing-docs-framework-build-times","Comparing Docs Framework Build Times",{"path":1715,"title":1716},"\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":1718,"title":1719},"\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":1721,"title":1722},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Ffixing-broken-links-reported-by-docusaurus-builds","Fixing Broken Links Reported by Docusaurus Builds",{"path":1724,"title":1725},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fgenerating-api-reference-pages-in-starlight-from-openapi","Generating API Reference Pages in Starlight From OpenAPI",{"path":1727,"title":1728},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress","Docs Frameworks: Docusaurus, Starlight and VitePress",{"path":1730,"title":1731},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Finternationalizing-starlight-docs","Internationalizing Starlight Docs",{"path":1733,"title":1734},"\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":1736,"title":1737},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight","Migrating from MkDocs to Starlight",{"path":1739,"title":1740},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-mkdocs-documentation-to-vitepress","Migrating MkDocs Documentation to VitePress",{"path":1742,"title":1743},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fspeeding-up-docusaurus-builds-with-rspack","Speeding Up Docusaurus Builds With Rspack",{"path":1745,"title":1746},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fversioned-documentation-with-docusaurus","Versioned Documentation with Docusaurus",{"path":1748,"title":1749},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fversioning-vitepress-documentation-without-a-plugin","Versioning VitePress Documentation Without a Plugin",{"path":1751,"title":1752},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fvitepress-for-library-documentation","VitePress for Library Documentation",{"path":1754,"title":1755},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fvitepress-vs-starlight-for-vue-and-astro-teams","VitePress vs Starlight for Vue and Astro Teams",{"path":1757,"title":1758},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Ffixing-hugo-builds-that-fail-after-a-version-upgrade","Fixing Hugo Builds That Fail After a Version Upgrade",{"path":1760,"title":1761},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Ffixing-hugo-builds-that-slow-down-after-adding-taxonomies","Fixing Hugo Builds That Slow Down After Adding Taxonomies",{"path":1763,"title":1764},"\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":1766,"title":1767},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhugo-image-processing-cache-in-ci","Hugo Image Processing Cache in CI",{"path":1769,"title":1770},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhugo-modules-and-dependency-caching","Hugo Modules and Dependency Caching",{"path":1772,"title":1773},"\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":1775,"title":1776},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":1778,"title":1779},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fparallel-hugo-builds-across-ci-jobs","Parallel Hugo Builds Across CI Jobs",{"path":1781,"title":1782},"\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":1784,"title":1785},"\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":1787,"title":1788},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fsharing-a-theme-across-hugo-sites-with-modules","Sharing a Theme Across Hugo Sites With Modules",{"path":1790,"title":1791},"\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":1793,"title":1794},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fsplitting-large-hugo-sites-with-segments","Splitting Large Hugo Sites with Segments",{"path":1796,"title":1797},"\u002Fchoosing-the-right-static-site-generator-for-production","Choosing the Right Static Site Generator for Production",{"path":1799,"title":1800},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Ffixing-hreflang-errors-reported-in-search-console","Fixing Hreflang Errors Reported in Search Console",{"path":1802,"title":1803},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Fhreflang-and-language-alternates-on-static-sites","hreflang and Language Alternates on Static Sites",{"path":1805,"title":1806},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Fi18n-routing-in-astro","i18n Routing in Astro",{"path":1808,"title":1809},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites","Internationalization for Static Sites",{"path":1811,"title":1812},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Flanguage-detection-and-redirects-at-the-edge","Language Detection and Redirects at the Edge",{"path":1814,"title":1815},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Fmultilingual-eleventy-sites-with-the-i18n-plugin","Multilingual Eleventy Sites With the i18n Plugin",{"path":1817,"title":1818},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Fmultilingual-sites-with-hugo","Multilingual Sites with Hugo",{"path":1820,"title":1821},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Fright-to-left-layouts-on-static-sites","Right-to-Left Layouts on Static Sites",{"path":1823,"title":1824},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Fsubdirectories-vs-subdomains-for-translated-static-sites","Subdirectories vs Subdomains for Translated Static Sites",{"path":1826,"title":1827},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Finternationalization-for-static-sites\u002Ftranslation-workflows-with-git-and-crowdin","Translation Workflows with Git and Crowdin",{"path":1829,"title":1830},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fcustom-domains-and-https-for-jekyll-on-github-pages","Custom Domains and HTTPS for Jekyll on GitHub Pages",{"path":1832,"title":1833},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fdeploying-jekyll-with-github-actions","Deploying Jekyll with GitHub Actions",{"path":1835,"title":1836},"\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":1838,"title":1839},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Ffixing-jekyll-builds-that-break-after-a-ruby-upgrade","Fixing Jekyll Builds That Break After a Ruby Upgrade",{"path":1841,"title":1842},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":1844,"title":1845},"\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":1847,"title":1848},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Frunning-jekyll-in-docker-for-reproducible-builds","Running Jekyll in Docker for Reproducible Builds",{"path":1850,"title":1851},"\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":1853,"title":1854},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fspeeding-up-slow-jekyll-builds","Speeding Up Slow Jekyll Builds",{"path":1856,"title":1857},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fupgrading-jekyll-and-ruby-versions-safely","Upgrading Jekyll and Ruby Versions Safely",{"path":1859,"title":1860},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fauditing-content-parity-after-a-migration","Auditing Content Parity After a Migration",{"path":1862,"title":1863},"\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":1865,"title":1866},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators","Migrating Between Static Site Generators",{"path":1868,"title":1869},"\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":1871,"title":1872},"\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":1874,"title":1875},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-a-wordpress-export-to-eleventy","Migrating a WordPress Export to Eleventy",{"path":1877,"title":1878},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-docusaurus-to-starlight","Migrating from Docusaurus to Starlight",{"path":1880,"title":1881},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-gatsby-to-astro","Migrating from Gatsby to Astro",{"path":1883,"title":1884},"\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":1886,"title":1887},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-nextjs-pages-router-to-astro","Migrating from Next.js Pages Router to Astro",{"path":1889,"title":1890},"\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":1892,"title":1893},"\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":1895,"title":1896},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Frecovering-search-traffic-lost-after-a-generator-migration","Recovering Search Traffic Lost After a Generator Migration",{"path":1898,"title":1899},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Freplacing-gatsby-graphql-queries-during-a-migration","Replacing Gatsby GraphQL Queries During a Migration",{"path":1901,"title":1902},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Ffixing-404s-on-refresh-in-nextjs-static-export","Fixing 404s on Refresh in Next.js Static Export",{"path":1904,"title":1905},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fgenerating-sitemaps-and-rss-in-nextjs-static-export","Generating Sitemaps and RSS in Next.js Static Export",{"path":1907,"title":1908},"\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":1910,"title":1911},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":1913,"title":1914},"\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":1916,"title":1917},"\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":1919,"title":1920},"\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":1922,"title":1923},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-static-export-vs-gatsby-for-existing-react-sites","Next.js Static Export vs Gatsby for Existing React Sites",{"path":1925,"title":1926},"\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":1928,"title":1929},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Ftrailing-slash-and-basepath-in-nextjs-static-export","Trailing Slash and basePath in Next.js Static Export",{"path":1931,"title":1932},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fusing-mdx-in-nextjs-static-export","Using MDX in Next.js Static Export",{"path":1934,"title":1935},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Faccessible-search-ui-for-static-sites","Accessible Search UI for Static Sites",{"path":1937,"title":1938},"\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":1940,"title":1941},"\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":1943,"title":1944},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fcustomizing-the-pagefind-ui","Customizing the Pagefind UI",{"path":1946,"title":1947},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Ffixing-missing-results-in-pagefind-indexes","Fixing Missing Results in Pagefind Indexes",{"path":1949,"title":1950},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites","Search for Static Sites",{"path":1952,"title":1953},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Findexing-hugo-sites-with-pagefind","Indexing Hugo Sites with Pagefind",{"path":1955,"title":1956},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fmultilingual-search-on-static-sites","Multilingual Search on Static Sites",{"path":1958,"title":1959},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fpagefind-vs-algolia-docsearch","Pagefind vs Algolia DocSearch",{"path":1961,"title":1962},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fpagefind-vs-lunr-for-small-documentation-sites","Pagefind vs Lunr for Small Documentation Sites",{"path":1964,"title":1965},"\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":1967,"title":1968},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fself-hosting-typesense-for-a-static-site","Self-Hosting Typesense for a Static Site",{"path":1970,"title":1971},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Ftracking-zero-result-searches","Tracking Zero-Result Searches",{"path":1973,"title":1974},"\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":1976,"title":1977},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fchoosing-an-ssg-for-a-marketing-site-with-non-technical-editors","Choosing an SSG for a Marketing Site with Non-Technical Editors",{"path":1979,"title":1980},"\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":1982,"title":1983},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fevaluating-ssg-accessibility-defaults","Evaluating SSG Accessibility Defaults",{"path":1985,"title":1986},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fgatsby-vs-astro-for-content-sites-in-2026","Gatsby vs Astro for Content Sites in 2026",{"path":1988,"title":1989},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":1991,"title":1992},"\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":1994,"title":1995},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fscoring-ssg-long-term-maintenance-risk","Scoring SSG Long-Term Maintenance Risk",{"path":1997,"title":1998},"\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":2000,"title":2001},"\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":2003,"title":2004},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fwhen-a-static-site-generator-is-the-wrong-choice","When a Static Site Generator Is the Wrong Choice",{"path":2006,"title":2007},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Fadding-json-ld-structured-data-at-build-time","Adding JSON-LD Structured Data at Build Time",{"path":2009,"title":2010},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Fcanonical-urls-and-duplicate-content-on-static-sites","Canonical URLs and Duplicate Content on Static Sites",{"path":2012,"title":2013},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Ffixing-pages-crawled-but-not-indexed-on-static-sites","Fixing Pages Crawled but Not Indexed on Static Sites",{"path":2015,"title":2016},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Ffixing-soft-404s-on-static-hosts","Fixing Soft 404s on Static Hosts",{"path":2018,"title":2019},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Fgenerating-breadcrumb-structured-data-in-astro","Generating Breadcrumb Structured Data in Astro",{"path":2021,"title":2022},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Fgenerating-sitemaps-for-large-static-sites","Generating Sitemaps for Large Static Sites",{"path":2024,"title":2025},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites","Technical SEO for Static Sites",{"path":2027,"title":2028},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Frobots-txt-and-noindex-for-preview-and-staging","robots.txt and noindex for Preview and Staging",{"path":2030,"title":2031},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Frss-and-atom-feeds-for-static-blogs","RSS and Atom Feeds for Static Blogs",{"path":2033,"title":2034},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Ftechnical-seo-for-static-sites\u002Fseo-safe-pagination-and-tag-pages","SEO-Safe Pagination and Tag Pages",{"path":2036,"title":2037},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-busting-with-content-hashed-filenames","Cache Busting with Content-Hashed Filenames",{"path":2039,"title":2040},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-control-headers-for-static-sites-in-nginx","Cache-Control Headers for Static Sites in Nginx",{"path":2042,"title":2043},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-control-headers-on-s3-and-cloudfront","Cache-Control Headers on S3 and CloudFront",{"path":2045,"title":2046},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-control-headers-on-vercel-for-static-sites","Cache-Control Headers on Vercel for Static Sites",{"path":2048,"title":2049},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-keys-and-query-strings-on-cdns","Cache Keys and Query Strings on CDNs",{"path":2051,"title":2052},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcaching-404s-and-redirects-at-the-edge","Caching 404s and Redirects at the Edge",{"path":2054,"title":2055},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcloudflare-vs-cloudfront-cache-hit-ratios-for-static-sites","Cloudflare vs CloudFront Cache Hit Ratios for Static Sites",{"path":2057,"title":2058},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Ffixing-stale-html-after-deploys-on-cloudflare","Fixing Stale HTML After Deploys on Cloudflare",{"path":2060,"title":2061},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs","CDN Caching Rules for SSGs",{"path":2063,"title":2064},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy","Purging the CDN Cache After a Static Deploy",{"path":2066,"title":2067},"\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":2069,"title":2070},"\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":2072,"title":2073},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html","Stale-While-Revalidate for Static HTML",{"path":2075,"title":2076},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Ftiered-caching-and-origin-shield","Tiered Caching and Origin Shield",{"path":2078,"title":2079},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fcode-splitting-and-module-preload-in-vite-based-ssgs","Code Splitting and Module Preload in Vite-Based SSGs",{"path":2081,"title":2082},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Ffixing-missing-tailwind-classes-in-production-builds","Fixing Missing Tailwind Classes in Production Builds",{"path":2084,"title":2085},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Ffixing-unused-javascript-warnings-on-static-pages","Fixing Unused JavaScript Warnings on Static Pages",{"path":2087,"title":2088},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization","CSS and JavaScript Asset Optimization",{"path":2090,"title":2091},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Finlining-critical-css-on-static-sites","Inlining Critical CSS on Static Sites",{"path":2093,"title":2094},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fkeeping-tailwind-css-output-small-on-static-sites","Keeping Tailwind CSS Output Small on Static Sites",{"path":2096,"title":2097},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fminifying-html-css-and-js-in-eleventy","Minifying HTML, CSS and JS in Eleventy",{"path":2099,"title":2100},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fprecompressing-assets-with-brotli-and-zstd","Precompressing Assets with Brotli and Zstd",{"path":2102,"title":2103},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fpurging-unused-css-with-tailwind-and-lightningcss","Purging Unused CSS with Tailwind and Lightning CSS",{"path":2105,"title":2106},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Fsvg-icon-sprites-vs-inline-icons","SVG Icon Sprites vs Inline Icons",{"path":2108,"title":2109},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcss-and-javascript-asset-optimization\u002Ftailwind-v4-in-astro-without-postcss-plugins","Tailwind v4 in Astro Without PostCSS Plugins",{"path":2111,"title":2112},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Fcls-from-client-side-rendered-components","CLS from Client-Side Rendered Components",{"path":2114,"title":2115},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Fdebugging-cls-with-the-layout-instability-api","Debugging CLS with the Layout Instability API",{"path":2117,"title":2118},"\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":2120,"title":2121},"\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":2123,"title":2124},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-dynamic-table-of-contents-widgets","Fixing CLS From Dynamic Table of Contents Widgets",{"path":2126,"title":2127},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-images-without-dimensions-in-markdown","Fixing CLS From Images Without Dimensions in Markdown",{"path":2129,"title":2130},"\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":2132,"title":2133},"\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":2135,"title":2136},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":2138,"title":2139},"\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":2141,"title":2142},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Freserving-space-for-ad-and-promo-slots","Reserving Space for Ad and Promo Slots",{"path":2144,"title":2145},"\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":2147,"title":2148},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fauditing-font-payload-per-page","Auditing Font Payload per Page",{"path":2150,"title":2151},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Ffixing-invisible-text-while-web-fonts-load","Fixing Invisible Text While Web Fonts Load",{"path":2153,"title":2154},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Ffont-display-optional-vs-swap","font-display: optional vs swap",{"path":2156,"title":2157},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":2159,"title":2160},"\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":2162,"title":2163},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fpreloading-fonts-without-double-downloads","Preloading Fonts Without Double Downloads",{"path":2165,"title":2166},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fself-hosted-fonts-vs-google-fonts-for-static-sites","Self-Hosted Fonts vs Google Fonts for Static Sites",{"path":2168,"title":2169},"\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":2171,"title":2172},"\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":2174,"title":2175},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fusing-system-font-stacks-to-skip-webfonts","Using System Font Stacks to Skip Web Fonts",{"path":2177,"title":2178},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fvariable-fonts-vs-static-weights","Variable Fonts vs Static Weights",{"path":2180,"title":2181},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fart-direction-with-the-picture-element","Art Direction with the Picture Element",{"path":2183,"title":2184},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fblur-up-placeholders-with-lqip","Blur-Up Placeholders with LQIP",{"path":2186,"title":2187},"\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":2189,"title":2190},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fcaching-processed-images-between-builds","Caching Processed Images Between Builds",{"path":2192,"title":2193},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Ffixing-blurry-images-from-astro-assets-resizing","Fixing Blurry Images From astro:assets Resizing",{"path":2195,"title":2196},"\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":2198,"title":2199},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":2201,"title":2202},"\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":2204,"title":2205},"\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":2207,"title":2208},"\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":2210,"title":2211},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fserving-astro-images-through-cloudflare-image-resizing","Serving Astro Images Through Cloudflare Image Resizing",{"path":2213,"title":2214},"\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":2216,"title":2217},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":2219,"title":2220},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":2222,"title":2223},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fbreaking-up-long-tasks-on-static-sites","Breaking Up Long Tasks on Static Sites",{"path":2225,"title":2226},"\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":2228,"title":2229},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Ffixing-hydration-mismatch-errors-in-astro-islands","Fixing Hydration Mismatch Errors in Astro Islands",{"path":2231,"title":2232},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Ffixing-poor-inp-on-static-pages-with-heavy-widgets","Fixing Poor INP on Static Pages With Heavy Widgets",{"path":2234,"title":2235},"\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":2237,"title":2238},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":2240,"title":2241},"\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":2243,"title":2244},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fpreact-vs-react-islands-bundle-size","Preact vs React Islands Bundle Size",{"path":2246,"title":2247},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Freplacing-react-islands-with-web-components","Replacing React Islands with Web Components",{"path":2249,"title":2250},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fserver-islands-in-astro","Server Islands in Astro",{"path":2252,"title":2253},"\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":2255,"title":2256},"\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":2258,"title":2259},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Ffixing-lcp-regressions-caused-by-cookie-consent-tools","Fixing LCP Regressions Caused by Cookie Consent Tools",{"path":2261,"title":2262},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Ffixing-lcp-when-the-hero-is-a-background-image","Fixing LCP When the Hero Is a Background Image",{"path":2264,"title":2265},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Ffixing-slow-lcp-on-pages-with-embedded-video","Fixing Slow LCP on Pages With Embedded Video",{"path":2267,"title":2268},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Fimproving-ttfb-for-static-html","Improving TTFB for Static HTML",{"path":2270,"title":2271},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":2273,"title":2274},"\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":2276,"title":2277},"\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":2279,"title":2280},"\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":2282,"title":2283},"\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":2285,"title":2286},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci","Performance Budgets and Lighthouse CI",{"path":2288,"title":2289},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Flighthouse-ci-vs-webpagetest-for-regression-gates","Lighthouse CI vs WebPageTest for Regression Gates",{"path":2291,"title":2292},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fmeasuring-web-vitals-in-playwright-tests","Measuring Web Vitals in Playwright Tests",{"path":2294,"title":2295},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fper-template-performance-budgets","Per-Template Performance Budgets",{"path":2297,"title":2298},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fperformance-testing-on-throttled-mobile-profiles","Performance Testing on Throttled Mobile Profiles",{"path":2300,"title":2301},"\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":2303,"title":2304},"\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":2306,"title":2307},"\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":2309,"title":2310},"\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":2312,"title":2313},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Ftracking-page-weight-over-time","Tracking Page Weight Over Time",{"path":2315,"title":2316},"\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":2318,"title":2319},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fauditing-unused-preloads","Auditing Unused Preloads",{"path":2321,"title":2322},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fearly-hints-103-on-cloudflare","Early Hints (103) on Cloudflare",{"path":2324,"title":2325},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Ffetchpriority-beyond-the-hero-image","Fetchpriority Beyond the Hero Image",{"path":2327,"title":2328},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Ffixing-wasted-preloads-flagged-by-chrome","Fixing Wasted Preloads Flagged by Chrome",{"path":2330,"title":2331},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed","Resource Hints and Navigation Speed",{"path":2333,"title":2334},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Finstant-navigation-with-speculation-rules","Instant Navigation with Speculation Rules",{"path":2336,"title":2337},"\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":2339,"title":2340},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fprefetching-links-in-astro","Prefetching Links in Astro",{"path":2342,"title":2343},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fview-transitions-in-astro-without-hurting-vitals","View Transitions in Astro Without Hurting Vitals",{"path":2345,"title":2346},"\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":2348,"title":2349},"\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":2351,"title":2352},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Ffacades-for-chat-widgets-and-maps","Facades for Chat Widgets and Maps",{"path":2354,"title":2355},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Ffixing-main-thread-blocking-from-chat-widgets","Fixing Main-Thread Blocking From Chat Widgets",{"path":2357,"title":2358},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites","Third-Party Script Performance on Static Sites",{"path":2360,"title":1189},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites",{"path":2362,"title":2363},"\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":2365,"title":2366},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fmeasuring-third-party-cost-with-request-blocking","Measuring Third-Party Cost with Request Blocking",{"path":2368,"title":2369},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Fprivacy-friendly-analytics-compared-by-page-weight","Privacy-Friendly Analytics Compared by Page Weight",{"path":2371,"title":2372},"\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":2374,"title":2375},"\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":2377,"title":2378},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":2380,"title":2381},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fbranch-deploy-controls-on-cloudflare-pages","Branch Deploy Controls on Cloudflare Pages",{"path":2383,"title":2384},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fcloudflare-pages-functions-middleware","Cloudflare Pages Functions Middleware",{"path":2386,"title":2387},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fconfiguring-redirects-on-cloudflare-pages","Configuring Redirects on Cloudflare Pages",{"path":2389,"title":2390},"\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":2392,"title":2393},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fdeploying-astro-to-cloudflare-workers-static-assets","Deploying Astro to Cloudflare Workers Static Assets",{"path":2395,"title":2396},"\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":2398,"title":2399},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fdeploying-to-cloudflare-from-github-actions-with-wrangler","Deploying to Cloudflare From GitHub Actions With Wrangler",{"path":2401,"title":2402},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Ffixing-redirect-loops-on-cloudflare-pages","Fixing Redirect Loops on Cloudflare Pages",{"path":2404,"title":38},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup",{"path":2406,"title":2407},"\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":2409,"title":2410},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fchecking-links-in-pull-requests","Checking Links in Pull Requests",{"path":2412,"title":2413},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fcontent-linting-with-markdownlint","Content Linting with markdownlint",{"path":2415,"title":2416},"\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":2418,"title":2419},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Feditorial-checks-with-vale-in-ci","Editorial Checks with Vale in CI",{"path":2421,"title":2422},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fgit-based-cms-options-for-static-sites-compared","Git-Based CMS Options for Static Sites Compared",{"path":2424,"title":2425},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams","Content Workflows for Documentation Teams",{"path":2427,"title":2428},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fmanaging-images-in-docs-as-code-repos","Managing Images in Docs-as-Code Repos",{"path":2430,"title":2431},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Frelease-notes-and-changelogs-from-git","Release Notes and Changelogs from Git",{"path":2433,"title":2434},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fscheduled-content-publishing-with-github-actions","Scheduled Content Publishing With GitHub Actions",{"path":2436,"title":2437},"\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":2439,"title":2440},"\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":2442,"title":2443},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fbuilding-astro-sites-with-github-actions","Building Astro Sites with GitHub Actions",{"path":2445,"title":2446},"\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":2448,"title":2449},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fconcurrency-groups-to-cancel-stale-builds","Concurrency Groups to Cancel Stale Builds",{"path":2451,"title":2452},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-github-pages-with-actions","Deploying to GitHub Pages with Actions",{"path":2454,"title":2455},"\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":2457,"title":2458},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Ffixing-flaky-static-site-builds-in-github-actions","Fixing Flaky Static Site Builds in GitHub Actions",{"path":2460,"title":2461},"\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":2463,"title":2464},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":2466,"title":2467},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fmatrix-builds-for-multi-site-monorepos","Matrix Builds for Multi-Site Monorepos",{"path":2469,"title":2470},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fpinning-actions-by-commit-sha","Pinning Actions by Commit SHA",{"path":2472,"title":2473},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fpublishing-any-generator-to-github-pages-with-actions","Publishing Any Generator to GitHub Pages With Actions",{"path":2475,"title":2476},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Freusable-workflows-for-ssg-builds","Reusable Workflows for SSG Builds",{"path":2478,"title":2479},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fbuild-caching-on-netlify-and-vercel","Build Caching on Netlify and Vercel",{"path":2481,"title":2482},"\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":2484,"title":2485},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fdeploying-only-changed-files","Deploying Only Changed Files",{"path":2487,"title":2488},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":2490,"title":2491},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Ffixing-stale-pages-from-incremental-builds","Fixing Stale Pages From Incremental Builds",{"path":2493,"title":2494},"\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":2496,"title":2497},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fincremental-rebuild-times-across-astro-eleventy-and-hugo","Incremental Rebuild Times Across Astro, Eleventy and Hugo",{"path":2499,"title":2500},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":2502,"title":2503},"\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":2505,"title":2506},"\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":2508,"title":2509},"\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":2511,"title":2512},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":2514,"title":2515},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Falerting-on-cache-hit-ratio-drops","Alerting on Cache Hit Ratio Drops",{"path":2517,"title":2518},"\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":2520,"title":2521},"\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":2523,"title":2524},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Ffinding-the-cause-of-a-sudden-field-lcp-drop","Finding the Cause of a Sudden Field LCP Drop",{"path":2526,"title":2527},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production","Monitoring Static Sites in Production",{"path":2529,"title":2530},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Flogging-404s-at-the-edge","Logging 404s at the Edge",{"path":2532,"title":2533},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fmonitoring-tls-certificate-expiry","Monitoring TLS Certificate Expiry",{"path":2535,"title":2536},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Freal-user-error-tracking-on-static-sites","Real-User Error Tracking on Static Sites",{"path":2538,"title":2539},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fsynthetic-monitoring-with-scheduled-playwright-checks","Synthetic Monitoring With Scheduled Playwright Checks",{"path":2541,"title":2542},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Ftracking-deploy-markers-in-analytics","Tracking Deploy Markers in Analytics",{"path":2544,"title":2545},"\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":2547,"title":2548},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fbandwidth-pricing-for-static-sites-across-netlify-vercel-and-cloudflare","Static Site Bandwidth Pricing: Netlify, Vercel, Cloudflare",{"path":2550,"title":2551},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fconfiguring-redirects-on-vercel-for-static-sites","Configuring Redirects on Vercel for Static Sites",{"path":2553,"title":2554},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fconfiguring-vercel-for-hugo-and-eleventy","Configuring Vercel for Hugo and Eleventy",{"path":2556,"title":2557},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fdeploying-astro-to-vercel-as-a-fully-static-site","Deploying Astro to Vercel as a Fully Static Site",{"path":2559,"title":2560},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Ffixing-netlify-builds-that-exceed-the-time-limit","Fixing Netlify Builds That Exceed the Time Limit",{"path":2562,"title":2563},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Ffixing-vercel-builds-that-run-out-of-memory","Fixing Vercel Builds That Run Out of Memory",{"path":2565,"title":2566},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":2568,"title":2569},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":2571,"title":2572},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-edge-functions-for-static-sites","Netlify Edge Functions for Static Sites",{"path":2574,"title":2575},"\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":2577,"title":2578},"\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":2580,"title":2581},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fvercel-build-output-api-for-custom-ssgs","Vercel Build Output API for Custom SSGs",{"path":2583,"title":2584},"\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":2586,"title":2587},"\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":2589,"title":2590},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":2592,"title":2593},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcommenting-on-preview-deploys","Commenting on Preview Deploys",{"path":2595,"title":2596},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Ffixing-preview-deploys-leaking-into-search-results","Fixing Preview Deploys Leaking Into Search Results",{"path":2598,"title":2599},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests","Preview Environments for Pull Requests",{"path":2601,"title":757},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpassword-protecting-preview-deployments",{"path":2603,"title":2604},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpreview-deploys-for-monorepos","Preview Deploys for Monorepos",{"path":2606,"title":2607},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpreviewing-headless-cms-drafts","Previewing Headless CMS Drafts",{"path":2609,"title":2610},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpull-request-previews-for-github-pages-sites","Pull Request Previews for GitHub Pages Sites",{"path":2612,"title":2613},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fvisual-regression-testing-on-preview-deploys","Visual Regression Testing on Preview Deploys",{"path":2615,"title":2616},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":2618,"title":2619},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fblue-green-deploys-for-static-sites","Blue-Green Deploys for Static Sites",{"path":2621,"title":2622},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fcanary-releases-for-static-sites","Canary Releases for Static Sites",{"path":2624,"title":2625},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Ffeature-flags-on-static-sites","Feature Flags on Static Sites",{"path":2627,"title":2628},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites","Rollbacks and Deploy Safety for Static Sites",{"path":2630,"title":2631},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fkeeping-old-assets-alive-after-deploy","Keeping Old Assets Alive After Deploy",{"path":2633,"title":2634},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fpost-deploy-verification-checklists","Post-Deploy Verification Checklists",{"path":2636,"title":2637},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frecovering-from-a-deploy-that-deleted-live-assets","Recovering From a Deploy That Deleted Live Assets",{"path":2639,"title":1257},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute",{"path":2641,"title":2642},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-netlify-deploys-from-the-cli-and-api","Rolling Back Netlify Deploys From the CLI and API",{"path":2644,"title":2645},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-s3-and-cloudfront-deploys-with-versioned-prefixes","Rolling Back S3 and CloudFront Deploys With Versioned Prefixes",{"path":2647,"title":1112},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url",{"path":2649,"title":608},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fauditing-npm-dependencies-in-ssg-pipelines",{"path":2651,"title":502},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fenabling-hsts-and-preload-safely",{"path":2653,"title":1572},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Ffixing-content-security-policy-violations-from-inline-scripts",{"path":2655,"title":1558},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Ffixing-mixed-content-warnings-after-moving-to-https",{"path":2657,"title":340},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fhash-based-csp-for-inline-scripts-in-astro",{"path":1629,"title":5},{"path":2660,"title":1544},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fpermissions-policy-and-cross-origin-headers",{"path":2662,"title":618},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecuring-deploy-credentials-with-github-oidc",{"path":2664,"title":1565},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecurity-headers-for-static-sites-served-by-caddy",{"path":2666,"title":1579},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecurity-headers-on-vercel-for-static-sites",{"path":2668,"title":1551},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecurity-txt-and-disclosure-for-static-sites",{"path":2670,"title":506},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsubresource-integrity-for-third-party-assets",{"path":2672,"title":335},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fwriting-a-content-security-policy-for-a-static-site",{"path":2674,"title":2675},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fbrotli-and-gzip-precompression-served-by-nginx","Brotli and Gzip Precompression Served by Nginx",{"path":2677,"title":2678},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fclean-urls-and-trailing-slashes-on-s3","Clean URLs and Trailing Slashes on S3",{"path":2680,"title":2681},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fcloudfront-functions-for-redirects","CloudFront Functions for Redirects",{"path":2683,"title":2684},"\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":2686,"title":2687},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fhosting-on-azure-static-web-apps","Hosting on Azure Static Web Apps",{"path":2689,"title":2690},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites","Self-Hosting Static Sites on S3, Nginx and Caddy",{"path":2692,"title":2693},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fnginx-vs-caddy-for-serving-static-sites","Nginx vs Caddy for Serving Static Sites",{"path":2695,"title":2696},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-from-a-docker-container-with-nginx","Serving a Static Site From a Docker Container With Nginx",{"path":2698,"title":2699},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-caddy-and-automatic-https","Serving a Static Site With Caddy and Automatic HTTPS",{"path":2701,"title":2702},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-caddy","Serving a Static Site with Caddy",{"path":2704,"title":929},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-nginx",{"path":2706,"title":2707},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fstatic-hosting-on-google-cloud-storage","Static Hosting on Google Cloud Storage",{"path":2709,"title":2710},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fzero-downtime-deploys-with-symlink-swaps","Zero-Downtime Deploys with Symlink Swaps",{"path":2712,"title":2713},"\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":2715,"title":2716},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Ffixing-cold-starts-in-netlify-functions-for-forms","Fixing Cold Starts in Netlify Functions for Forms",{"path":2718,"title":1136},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fhandling-form-submissions-on-a-static-site",{"path":2720,"title":2721},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites","Serverless Functions for Static Sites",{"path":2723,"title":2724},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fnetlify-functions-vs-cloudflare-workers","Netlify Functions vs Cloudflare Workers",{"path":2726,"title":2727},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fnewsletter-signup-with-an-edge-function","Newsletter Signup with an Edge Function",{"path":2729,"title":2730},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fprotecting-a-static-site-behind-authentication","Protecting a Static Site Behind Authentication",{"path":2732,"title":2733},"\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",{"path":2735,"title":2736},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Frate-limiting-edge-functions","Rate Limiting Edge Functions",{"path":2738,"title":2739},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Faccessibility-testing-with-axe-and-pa11y-in-ci","Accessibility Testing with axe and pa11y in CI",{"path":2741,"title":2742},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Fend-to-end-tests-for-static-sites-with-playwright","End-to-End Tests for Static Sites with Playwright",{"path":2744,"title":2745},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Ffixing-flaky-playwright-tests-against-preview-deploys","Fixing Flaky Playwright Tests Against Preview Deploys",{"path":2747,"title":2748},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci","Testing Static Sites in CI",{"path":2750,"title":2751},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Fsnapshot-testing-build-output","Snapshot Testing Build Output",{"path":2753,"title":2754},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Ftesting-redirects-and-headers-before-deploy","Testing Redirects and Headers Before Deploy",{"path":2756,"title":2757},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Ftesting-search-and-navigation-flows-with-playwright","Testing Search and Navigation Flows With Playwright",{"path":2759,"title":2760},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Ftesting-structured-data-and-meta-tags","Testing Structured Data and Meta Tags",{"path":2762,"title":2763},"\u002Fproduction-ready-deployment-cicd-workflows\u002Ftesting-static-sites-in-ci\u002Fvalidating-html-output-in-ci","Validating HTML Output in CI",null,1790943190979]