[{"data":1,"prerenderedAt":1410},["ShallowReactive",2],{"page:\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute":3,"all-docs-nav":1168},{"id":4,"title":5,"body":6,"breadcrumb":1142,"dateModified":1152,"datePublished":1152,"description":1153,"extension":1154,"faq":1155,"meta":1161,"navigation":1162,"path":1163,"seo":1164,"slug":12,"stem":1165,"type":1166,"__hash__":1167},"content\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute\u002Findex.md","Rolling Back a Bad Static Deploy in Under a Minute",{"type":7,"value":8,"toc":1118},"minimark",[9,13,17,26,31,49,53,223,228,274,277,281,284,343,347,450,453,457,567,571,609,612,616,623,639,696,700,703,780,793,797,800,806,812,818,821,825,828,915,983,987,1025,1029,1034,1038,1042,1045,1049,1052,1056,1059,1063,1066,1070,1073,1077,1114],[10,11,5],"h1",{"id":12},"rolling-back-a-bad-static-deploy-in-under-a-minute",[14,15,16],"p",{},"Rolling back a static site is genuinely fast — the previous build already exists, complete and immutable, at a URL your host can promote. What makes real rollbacks slow is everything around the command: establishing what is live, finding the right deployment ID, remembering the syntax, and stopping the pipeline from redeploying the broken build while you work.",[14,18,19,20,25],{},"This is the runbook. It assumes the safety practices in ",[21,22,24],"a",{"href":23},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002F","Rollbacks and Deploy Safety for Static Sites"," are in place — atomic deploys, retained artifacts, a build stamp in the HTML.",[27,28,30],"h2",{"id":29},"prerequisites","Prerequisites",[32,33,34,38,41],"ul",{},[35,36,37],"li",{},"A host that keeps previous deployments addressable: Cloudflare Pages or Workers, Netlify, Vercel, or your own versioned upload scheme.",[35,39,40],{},"Deploy credentials available to whoever is on call, not only to CI.",[35,42,43,44,48],{},"A build stamp in the output (",[45,46,47],"code",{},"\u003Cmeta name=\"build\" content=\"a91f3c2\">",") so you can identify the live version from a browser.",[27,50,52],{"id":51},"the-sequence","The Sequence",[54,55,56,219],"figure",{},[57,58,65,66,65,70,65,74,65,81],"svg",{"viewBox":59,"role":60,"ariaLabelledBy":61,"xmlns":64},"0 0 760 300","img",[62,63],"rbk-seq-title","rbk-seq-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[67,68,69],"title",{"id":62},"Rollback sequence with timings",[71,72,73],"desc",{"id":63},"Five steps with elapsed times: confirm the symptom and read the build stamp at ten seconds, pause the deployment pipeline at fifteen seconds, list deployments and identify the last good one at twenty-five seconds, promote it at forty seconds, and verify plus communicate at fifty-five seconds.",[75,76],"rect",{"x":77,"y":77,"width":78,"height":79,"fill":80},"0","760","300","#ffffff",[82,83,85,86,85,94,85,105,85,111,85,117,85,122,85,127,85,131,85,134,85,137,85,141,85,145,85,148,85,151,85,157,85,161,85,164,85,167,85,171,85,175,85,178,85,181,85,186,85,193,85,199,85,203,85,207,85,211,85,214,65],"g",{"style":84},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[87,88,93],"text",{"x":89,"y":90,"fill":91,"style":92},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","Under a minute, if nothing has to be decided on the spot",[75,95],{"x":96,"y":97,"width":98,"height":99,"rx":100,"fill":101,"opacity":102,"stroke":103,"style":104},"40","60","130","76","10","#ffca3a","0.3","#a97b00","stroke-width:1.5px",[87,106,110],{"x":107,"y":108,"fill":91,"style":109},"105","86","font-size:12px;font-weight:700;text-anchor:middle","1 · Confirm",[87,112,116],{"x":107,"y":113,"fill":114,"style":115},"106","#556071","font-size:11px;text-anchor:middle","read build stamp",[87,118,121],{"x":107,"y":119,"fill":91,"style":120},"124","font-size:11px;font-weight:700;text-anchor:middle","0:10",[75,123],{"x":124,"y":97,"width":98,"height":99,"rx":100,"fill":125,"opacity":126,"stroke":125,"style":104},"186","#6a4c93","0.14",[87,128,130],{"x":129,"y":108,"fill":91,"style":109},"251","2 · Pause CI",[87,132,133],{"x":129,"y":113,"fill":114,"style":115},"no redeploys",[87,135,136],{"x":129,"y":119,"fill":91,"style":120},"0:15",[75,138],{"x":139,"y":97,"width":98,"height":99,"rx":100,"fill":140,"opacity":126,"stroke":140,"style":104},"332","#1982c4",[87,142,144],{"x":143,"y":108,"fill":91,"style":109},"397","3 · Identify",[87,146,147],{"x":143,"y":113,"fill":114,"style":115},"last good ID",[87,149,150],{"x":143,"y":119,"fill":91,"style":120},"0:25",[75,152],{"x":153,"y":97,"width":98,"height":99,"rx":100,"fill":154,"opacity":155,"stroke":156,"style":104},"478","#8ac926","0.18","#5a8a16",[87,158,160],{"x":159,"y":108,"fill":91,"style":109},"543","4 · Promote",[87,162,163],{"x":159,"y":113,"fill":114,"style":115},"pointer flip",[87,165,166],{"x":159,"y":119,"fill":91,"style":120},"0:40",[75,168],{"x":169,"y":97,"width":170,"height":99,"rx":100,"fill":154,"opacity":126,"stroke":156,"style":104},"624","96",[87,172,174],{"x":173,"y":108,"fill":91,"style":109},"672","5 · Verify",[87,176,177],{"x":173,"y":113,"fill":114,"style":115},"+ tell people",[87,179,180],{"x":173,"y":119,"fill":156,"style":120},"0:55",[87,182,185],{"x":96,"y":183,"fill":91,"style":184},"182","font-size:13px;font-weight:700","What is NOT in the critical path",[75,187],{"x":96,"y":188,"width":189,"height":190,"rx":100,"fill":191,"opacity":192,"stroke":114,"style":104},"196","330","66","#d9e2ef","0.5",[87,194,198],{"x":195,"y":196,"fill":91,"style":197},"205","220","font-size:12px;text-anchor:middle","diagnosing the cause",[87,200,202],{"x":195,"y":201,"fill":91,"style":197},"242","writing or reviewing a fix",[75,204],{"x":205,"y":188,"width":206,"height":190,"rx":100,"fill":191,"opacity":192,"stroke":114,"style":104},"400","320",[87,208,210],{"x":209,"y":196,"fill":91,"style":197},"560","rebuilding anything",[87,212,213],{"x":209,"y":201,"fill":91,"style":197},"waiting for CI",[87,215,218],{"x":96,"y":216,"fill":114,"style":217},"288","font-size:11px","Every item in the lower boxes is what turns a one-minute recovery into a thirty-minute one",[220,221,222],"figcaption",{},"The times are achievable because nothing in the sequence produces anything new — it selects an artifact that already exists and points production at it.",[224,225,227],"h3",{"id":226},"_1-confirm-what-is-live-10-s","1. Confirm what is live (10 s)",[229,230,235],"pre",{"className":231,"code":232,"language":233,"meta":234,"style":234},"language-bash shiki shiki-themes github-light github-dark","curl -s https:\u002F\u002Fexample.com\u002F | grep -o '\u003Cmeta name=\"build\"[^>]*>'\n# \u003Cmeta name=\"build\" content=\"a91f3c2\" data-built=\"2026-08-01T09:14:22Z\">\n","bash","",[45,236,237,267],{"__ignoreMap":234},[238,239,242,246,250,254,258,261,264],"span",{"class":240,"line":241},"line",1,[238,243,245],{"class":244},"sScJk","curl",[238,247,249],{"class":248},"sj4cs"," -s",[238,251,253],{"class":252},"sZZnC"," https:\u002F\u002Fexample.com\u002F",[238,255,257],{"class":256},"szBVR"," |",[238,259,260],{"class":244}," grep",[238,262,263],{"class":248}," -o",[238,265,266],{"class":252}," '\u003Cmeta name=\"build\"[^>]*>'\n",[238,268,270],{"class":240,"line":269},2,[238,271,273],{"class":272},"sJ8bj","# \u003Cmeta name=\"build\" content=\"a91f3c2\" data-built=\"2026-08-01T09:14:22Z\">\n",[14,275,276],{},"Two facts matter: which build is serving, and whether the symptom started when it went out. If the symptom predates this deployment, rolling back will not fix it and you have wasted the fastest minute you had.",[224,278,280],{"id":279},"_2-stop-the-pipeline-5-s","2. Stop the pipeline (5 s)",[14,282,283],{},"This step is skipped more often than any other, and it is why some incidents recur mid-rollback. If the default branch still contains the bad commit, any retried workflow or subsequent push republishes it.",[229,285,287],{"className":231,"code":286,"language":233,"meta":234,"style":234},"gh workflow disable deploy.yml          # GitHub Actions\n# or revert first, which also fixes the branch:\ngit revert --no-edit \u003Cbad-sha> && git push\n",[45,288,289,306,311],{"__ignoreMap":234},[238,290,291,294,297,300,303],{"class":240,"line":241},[238,292,293],{"class":244},"gh",[238,295,296],{"class":252}," workflow",[238,298,299],{"class":252}," disable",[238,301,302],{"class":252}," deploy.yml",[238,304,305],{"class":272},"          # GitHub Actions\n",[238,307,308],{"class":240,"line":269},[238,309,310],{"class":272},"# or revert first, which also fixes the branch:\n",[238,312,314,317,320,323,326,329,332,335,338,340],{"class":240,"line":313},3,[238,315,316],{"class":244},"git",[238,318,319],{"class":252}," revert",[238,321,322],{"class":248}," --no-edit",[238,324,325],{"class":256}," \u003C",[238,327,328],{"class":252},"bad-sh",[238,330,21],{"class":331},"sVt8B",[238,333,334],{"class":256},">",[238,336,337],{"class":331}," && ",[238,339,316],{"class":244},[238,341,342],{"class":252}," push\n",[224,344,346],{"id":345},"_3-find-the-last-good-deployment-10-s","3. Find the last good deployment (10 s)",[229,348,350],{"className":231,"code":349,"language":233,"meta":234,"style":234},"# Cloudflare Workers \u002F Pages\nnpx wrangler deployments list\n# Netlify\nnetlify api listSiteDeploys --data '{\"site_id\":\"'\"$SITE_ID\"'\"}' \\\n  | jq -r '.[0:5][] | \"\\(.id)  \\(.created_at)  \\(.commit_ref[0:7])  \\(.state)\"'\n# Vercel\nnpx vercel ls --prod --json | jq -r '.deployments[0:5][] | \"\\(.uid)  \\(.created)  \\(.meta.githubCommitSha[0:7])\"'\n",[45,351,352,357,371,376,403,418,424],{"__ignoreMap":234},[238,353,354],{"class":240,"line":241},[238,355,356],{"class":272},"# Cloudflare Workers \u002F Pages\n",[238,358,359,362,365,368],{"class":240,"line":269},[238,360,361],{"class":244},"npx",[238,363,364],{"class":252}," wrangler",[238,366,367],{"class":252}," deployments",[238,369,370],{"class":252}," list\n",[238,372,373],{"class":240,"line":313},[238,374,375],{"class":272},"# Netlify\n",[238,377,379,382,385,388,391,394,397,400],{"class":240,"line":378},4,[238,380,381],{"class":244},"netlify",[238,383,384],{"class":252}," api",[238,386,387],{"class":252}," listSiteDeploys",[238,389,390],{"class":248}," --data",[238,392,393],{"class":252}," '{\"site_id\":\"'\"",[238,395,396],{"class":331},"$SITE_ID",[238,398,399],{"class":252},"\"'\"}'",[238,401,402],{"class":248}," \\\n",[238,404,406,409,412,415],{"class":240,"line":405},5,[238,407,408],{"class":256},"  |",[238,410,411],{"class":244}," jq",[238,413,414],{"class":248}," -r",[238,416,417],{"class":252}," '.[0:5][] | \"\\(.id)  \\(.created_at)  \\(.commit_ref[0:7])  \\(.state)\"'\n",[238,419,421],{"class":240,"line":420},6,[238,422,423],{"class":272},"# Vercel\n",[238,425,427,429,432,435,438,441,443,445,447],{"class":240,"line":426},7,[238,428,361],{"class":244},[238,430,431],{"class":252}," vercel",[238,433,434],{"class":252}," ls",[238,436,437],{"class":248}," --prod",[238,439,440],{"class":248}," --json",[238,442,257],{"class":256},[238,444,411],{"class":244},[238,446,414],{"class":248},[238,448,449],{"class":252}," '.deployments[0:5][] | \"\\(.uid)  \\(.created)  \\(.meta.githubCommitSha[0:7])\"'\n",[14,451,452],{},"Match the commit column against your build stamp: the entry immediately before the current one is normally the target.",[224,454,456],{"id":455},"_4-promote-it-15-s","4. Promote it (15 s)",[229,458,460],{"className":231,"code":459,"language":233,"meta":234,"style":234},"# Cloudflare\nnpx wrangler rollback \u003Cdeployment-id> --message \"incident: nav partial missing\"\n# Netlify\nnetlify api restoreSiteDeploy --data '{\"site_id\":\"'\"$SITE_ID\"'\",\"deploy_id\":\"'\"$DEPLOY_ID\"'\"}'\n# Vercel\nnpx vercel promote \u003Cdeployment-url>\n# Own infrastructure (symlink swap)\nssh deploy@origin \"ln -sfn \u002Fvar\u002Fwww\u002Freleases\u002F$PREV \u002Fvar\u002Fwww\u002Fcurrent.new && mv -Tf \u002Fvar\u002Fwww\u002Fcurrent.new \u002Fvar\u002Fwww\u002Fcurrent\"\n",[45,461,462,467,492,496,520,524,544,549],{"__ignoreMap":234},[238,463,464],{"class":240,"line":241},[238,465,466],{"class":272},"# Cloudflare\n",[238,468,469,471,473,476,478,481,484,486,489],{"class":240,"line":269},[238,470,361],{"class":244},[238,472,364],{"class":252},[238,474,475],{"class":252}," rollback",[238,477,325],{"class":256},[238,479,480],{"class":252},"deployment-i",[238,482,483],{"class":331},"d",[238,485,334],{"class":256},[238,487,488],{"class":248}," --message",[238,490,491],{"class":252}," \"incident: nav partial missing\"\n",[238,493,494],{"class":240,"line":313},[238,495,375],{"class":272},[238,497,498,500,502,505,507,509,511,514,517],{"class":240,"line":378},[238,499,381],{"class":244},[238,501,384],{"class":252},[238,503,504],{"class":252}," restoreSiteDeploy",[238,506,390],{"class":248},[238,508,393],{"class":252},[238,510,396],{"class":331},[238,512,513],{"class":252},"\"'\",\"deploy_id\":\"'\"",[238,515,516],{"class":331},"$DEPLOY_ID",[238,518,519],{"class":252},"\"'\"}'\n",[238,521,522],{"class":240,"line":405},[238,523,423],{"class":272},[238,525,526,528,530,533,535,538,541],{"class":240,"line":420},[238,527,361],{"class":244},[238,529,431],{"class":252},[238,531,532],{"class":252}," promote",[238,534,325],{"class":256},[238,536,537],{"class":252},"deployment-ur",[238,539,540],{"class":331},"l",[238,542,543],{"class":256},">\n",[238,545,546],{"class":240,"line":426},[238,547,548],{"class":272},"# Own infrastructure (symlink swap)\n",[238,550,552,555,558,561,564],{"class":240,"line":551},8,[238,553,554],{"class":244},"ssh",[238,556,557],{"class":252}," deploy@origin",[238,559,560],{"class":252}," \"ln -sfn \u002Fvar\u002Fwww\u002Freleases\u002F",[238,562,563],{"class":331},"$PREV",[238,565,566],{"class":252}," \u002Fvar\u002Fwww\u002Fcurrent.new && mv -Tf \u002Fvar\u002Fwww\u002Fcurrent.new \u002Fvar\u002Fwww\u002Fcurrent\"\n",[224,568,570],{"id":569},"_5-verify-and-say-so-15-s","5. Verify and say so (15 s)",[229,572,574],{"className":231,"code":573,"language":233,"meta":234,"style":234},"node scripts\u002Fsmoke.mjs https:\u002F\u002Fexample.com && \\\n  curl -s https:\u002F\u002Fexample.com\u002F | grep -o '\u003Cmeta name=\"build\"[^>]*>'\n",[45,575,576,592],{"__ignoreMap":234},[238,577,578,581,584,587,589],{"class":240,"line":241},[238,579,580],{"class":244},"node",[238,582,583],{"class":252}," scripts\u002Fsmoke.mjs",[238,585,586],{"class":252}," https:\u002F\u002Fexample.com",[238,588,337],{"class":331},[238,590,591],{"class":248},"\\\n",[238,593,594,597,599,601,603,605,607],{"class":240,"line":269},[238,595,596],{"class":244},"  curl",[238,598,249],{"class":248},[238,600,253],{"class":252},[238,602,257],{"class":256},[238,604,260],{"class":244},[238,606,263],{"class":248},[238,608,266],{"class":252},[14,610,611],{},"Then post one message: what broke, that production is restored to build X, and that the cause is being investigated. The message costs ten seconds and prevents three people from independently starting their own rollback.",[27,613,615],{"id":614},"write-the-runbook-where-people-look","Write the Runbook Where People Look",[14,617,618,619,622],{},"The commands above are useless at 2 a.m. if they live in someone's shell history. Put a ",[45,620,621],{},"RUNBOOK.md"," at the repository root with the exact commands for your host, the site or account identifiers filled in, and the location of credentials. Link it from the deploy workflow's summary output so the person watching a failed deploy sees it without searching.",[14,624,625,626,630,631,634,635,638],{},"Three details make a runbook usable under pressure. Write commands to be ",[627,628,629],"strong",{},"copy-pasteable with no placeholders"," — put the real site ID in, since a runbook is not a secret and the credentials are separate. Include the ",[627,632,633],{},"expected output"," of each command, so a responder knows whether it worked without interpreting. And state the ",[627,636,637],{},"decision rule"," at the top: \"if the homepage or any template page is broken for readers, roll back first and diagnose after\" removes the hesitation that costs the most time.",[54,640,641,693],{},[57,642,65,647,65,650,65,653,65,656],{"viewBox":643,"role":60,"ariaLabelledBy":644,"xmlns":64},"0 0 760 280",[645,646],"rbk-book-title","rbk-book-desc",[67,648,649],{"id":645},"Anatomy of a usable rollback runbook",[71,651,652],{"id":646},"A runbook page divided into four blocks: a decision rule at the top, the exact commands with real identifiers, expected output for each command, and where credentials live. A note marks that anything requiring interpretation belongs in the post-incident review instead.",[75,654],{"x":77,"y":77,"width":78,"height":655,"fill":80},"280",[82,657,85,658,85,661,85,669,85,674,85,676,85,680,85,683,85,687,85,690,65],{"style":84},[87,659,660],{"x":89,"y":90,"fill":91,"style":92},"Four blocks, in this order",[75,662],{"x":97,"y":663,"width":664,"height":665,"rx":666,"fill":667,"opacity":126,"stroke":668,"style":104},"52","640","44","8","#ff595e","#d83b41",[87,670,673],{"x":89,"y":671,"fill":91,"style":672},"80","font-size:13px;font-weight:700;text-anchor:middle","1 · Decision rule — when to roll back without asking anyone",[75,675],{"x":97,"y":113,"width":664,"height":665,"rx":666,"fill":154,"opacity":155,"stroke":156,"style":104},[87,677,679],{"x":89,"y":678,"fill":91,"style":672},"134","2 · Commands — real identifiers, no placeholders to fill in",[75,681],{"x":97,"y":682,"width":664,"height":665,"rx":666,"fill":140,"opacity":126,"stroke":140,"style":104},"160",[87,684,686],{"x":89,"y":685,"fill":91,"style":672},"188","3 · Expected output — so success is recognisable, not inferred",[75,688],{"x":97,"y":689,"width":664,"height":665,"rx":666,"fill":125,"opacity":126,"stroke":125,"style":104},"214",[87,691,692],{"x":89,"y":201,"fill":91,"style":672},"4 · Credentials — where they are, who has them, how to get them",[220,694,695],{},"Anything that requires judgement belongs in the post-incident review, not in the runbook. The runbook exists to remove decisions from the minute when decisions are most expensive.",[27,697,699],{"id":698},"caches-usually-leave-them-alone","Caches: Usually Leave Them Alone",[14,701,702],{},"The instinct during an incident is to purge everything. On a static site that is usually wrong and occasionally harmful.",[704,705,706,722],"table",{},[707,708,709],"thead",{},[710,711,712,716,719],"tr",{},[713,714,715],"th",{},"Asset type",[713,717,718],{},"Typical policy",[713,720,721],{},"Action on rollback",[723,724,725,737,751,766],"tbody",{},[710,726,727,731,734],{},[728,729,730],"td",{},"HTML",[728,732,733],{},"short TTL or revalidated",[728,735,736],{},"Nothing; next revalidation serves the restored build",[710,738,739,742,748],{},[728,740,741],{},"Hashed JS\u002FCSS",[728,743,744,747],{},[45,745,746],{},"immutable",", one year",[728,749,750],{},"Nothing; old filenames were never overwritten",[710,752,753,760,763],{},[728,754,755,756,759],{},"Unhashed assets (",[45,757,758],{},"\u002Flogo.svg",")",[728,761,762],{},"medium TTL",[728,764,765],{},"Purge these specific paths if they changed",[710,767,768,774,777],{},[728,769,770,773],{},[45,771,772],{},"_redirects"," \u002F headers",[728,775,776],{},"part of the deployment",[728,778,779],{},"Restored with the deployment on most hosts",[14,781,782,783,787,788,792],{},"A full purge sends every edge location to the origin at once, which is a self-inflicted traffic spike at the worst possible moment. Purge paths, not everything — the policy background is in ",[21,784,786],{"href":785},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002F","CDN Caching Rules for SSGs"," and ",[21,789,791],{"href":790},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy\u002F","Purging the CDN Cache After a Static Deploy",".",[27,794,796],{"id":795},"after-the-rollback","After the Rollback",[14,798,799],{},"The incident is over for readers; it is not over for you. Three things follow, in order.",[14,801,802,805],{},[627,803,804],{},"Keep the broken build addressable."," Do not delete or overwrite it. It is the evidence, and reproducing the failure from the artifact is far easier than reproducing it from a description. Note its deployment ID in the incident record.",[14,807,808,811],{},[627,809,810],{},"Diagnose against the artifact, not production."," Deploy the bad build to a preview URL and debug there. This removes all time pressure and means the investigation cannot accidentally affect readers.",[14,813,814,817],{},[627,815,816],{},"Close the loop with a check."," Almost every rollback points at a missing gate. A dropped navigation partial should have been caught by a smoke-test marker; a broken redirect by the redirect verifier; a schema violation by the build. Adding that one check is what stops the same class of failure recurring, and it is the only part of the process that compounds.",[14,819,820],{},"Resist the urge to redeploy the fixed version immediately after the rollback. The site is currently serving a build known to be good, which is a fine place to be for an hour. Ship the fix through the normal pipeline, with review and previews, rather than through the emergency path that just failed.",[27,822,824],{"id":823},"measured-impact","Measured Impact",[14,826,827],{},"Timings from four rehearsals and two real incidents on a documentation site hosted on Cloudflare Workers, recorded from the moment the responder started acting:",[704,829,830,843],{},[707,831,832],{},[710,833,834,837,840],{},[713,835,836],{},"Step",[713,838,839],{},"Rehearsed team",[713,841,842],{},"Team without a runbook",[723,844,845,856,867,877,888,898],{},[710,846,847,850,853],{},[728,848,849],{},"Confirm what is live",[728,851,852],{},"10 s",[728,854,855],{},"2–4 min (no build stamp)",[710,857,858,861,864],{},[728,859,860],{},"Pause the pipeline",[728,862,863],{},"5 s",[728,865,866],{},"often skipped",[710,868,869,872,874],{},[728,870,871],{},"Identify last good deployment",[728,873,852],{},[728,875,876],{},"3–6 min (finding credentials, syntax)",[710,878,879,882,885],{},[728,880,881],{},"Promote",[728,883,884],{},"15 s",[728,886,887],{},"1–2 min",[710,889,890,893,895],{},[728,891,892],{},"Verify",[728,894,884],{},[728,896,897],{},"ad hoc, by eye",[710,899,900,905,910],{},[728,901,902],{},[627,903,904],{},"Total to restored site",[728,906,907],{},[627,908,909],{},"55 s",[728,911,912],{},[627,913,914],{},"12–20 min",[54,916,917,980],{},[57,918,65,922,65,925,65,928,65,930],{"viewBox":643,"role":60,"ariaLabelledBy":919,"xmlns":64},[920,921],"rbk-time-title","rbk-time-desc",[67,923,924],{"id":920},"Recovery time with and without a rehearsed runbook",[71,926,927],{"id":921},"A horizontal bar chart on a shared scale. The rehearsed team restores the site in 55 seconds. The team without a runbook takes between 12 and 20 minutes, with the largest components being identifying what is live and finding the right deployment.",[75,929],{"x":77,"y":77,"width":78,"height":655,"fill":80},[82,931,85,932,85,936,85,940,85,945,85,949,85,954,85,957,85,961,85,965,85,969,85,973,85,977,65],{"style":84},[87,933,935],{"x":89,"y":934,"fill":91,"style":92},"26","Same host, same command — different preparation",[240,937],{"x1":938,"y1":665,"x2":938,"y2":939,"stroke":191,"style":104},"250","200",[87,941,944],{"x":97,"y":942,"fill":91,"style":943},"84","font-size:12px;font-weight:700","Rehearsed",[87,946,948],{"x":97,"y":947,"fill":114,"style":217},"100","runbook + build stamp",[75,950],{"x":938,"y":951,"width":90,"height":952,"rx":953,"fill":154,"opacity":102,"stroke":156,"style":104},"68","30","5",[87,955,909],{"x":79,"y":956,"fill":156,"style":943},"88",[87,958,960],{"x":97,"y":959,"fill":91,"style":943},"150","No runbook",[87,962,964],{"x":97,"y":963,"fill":114,"style":217},"166","same tooling available",[75,966],{"x":938,"y":678,"width":967,"height":952,"rx":953,"fill":667,"opacity":968,"stroke":668,"style":104},"440","0.16",[87,970,914],{"x":971,"y":972,"fill":668,"style":109},"470","154",[87,974,976],{"x":97,"y":975,"fill":114,"style":217},"228","Most of the gap is not the rollback command — it is establishing what is live and locating credentials",[87,978,979],{"x":97,"y":938,"fill":114,"style":217},"Both figures exclude detection time, which was around four minutes in every case",[220,981,982],{},"The tooling is identical in both rows. The difference is a stamped build, a written command and someone who has run it before.",[27,984,986],{"id":985},"pitfalls-rollback","Pitfalls & Rollback",[32,988,989,995,1001,1007,1013,1019],{},[35,990,991,994],{},[627,992,993],{},"Rolling back before checking the symptom's start time."," If the fault predates the current deployment, you have restored a build that also has it.",[35,996,997,1000],{},[627,998,999],{},"Forgetting to stop the pipeline."," A retried job or a colleague's push re-promotes the broken build mid-incident.",[35,1002,1003,1006],{},[627,1004,1005],{},"Purging the entire cache."," It converts a recovered site into an origin traffic spike. Purge specific paths only.",[35,1008,1009,1012],{},[627,1010,1011],{},"Rolling back configuration you deploy separately."," Redirect rules or headers managed outside the artifact need their own revert.",[35,1014,1015,1018],{},[627,1016,1017],{},"No credentials off CI."," If only the pipeline can deploy, only the pipeline can roll back — and the pipeline is often the thing you just paused.",[35,1020,1021,1024],{},[627,1022,1023],{},"Rollback of the rollback:"," if the restored build is also wrong, go back one more deployment. This is why retention of thirty days matters more than retention of one.",[27,1026,1028],{"id":1027},"conclusion","Conclusion",[14,1030,1031,1032,792],{},"A static rollback is a pointer change, so the recovery time is decided entirely by preparation: a build stamp so you know what is live, credentials in human hands, a written command per host, and the discipline to pause the pipeline first. Rehearse it once a quarter and the real incident becomes unremarkable. The surrounding practices — atomic deploys, artifact retention, smoke tests — are in ",[21,1033,24],{"href":23},[27,1035,1037],{"id":1036},"faq","FAQ",[224,1039,1041],{"id":1040},"should-i-roll-back-or-fix-forward","Should I roll back or fix forward?",[14,1043,1044],{},"Roll back first if readers are seeing something broken, then diagnose without time pressure. Fix forward only when the fault is trivially understood and the fix is a one-line change you can ship faster than a rollback, which is rare once you have measured both.",[224,1046,1048],{"id":1047},"how-do-i-know-which-deployment-was-the-last-good-one","How do I know which deployment was the last good one?",[14,1050,1051],{},"Every host lists deployments with a timestamp and commit. The last good one is the deployment that was live before the current one, unless the problem predates it — which is why a build stamp in the HTML and a quick check of when the symptom started are the first two steps.",[224,1053,1055],{"id":1054},"does-rolling-back-require-purging-the-cdn-cache","Does rolling back require purging the CDN cache?",[14,1057,1058],{},"Usually not, and purging everything is often harmful. HTML is typically short-cached or revalidated, and hashed assets are immutable so the old build's assets are still valid. Purge only the specific HTML paths if your cache policy holds them long.",[224,1060,1062],{"id":1061},"what-if-the-bad-deploy-also-changed-my-redirect-rules-or-headers","What if the bad deploy also changed my redirect rules or headers?",[14,1064,1065],{},"On hosts where those files are part of the deployment artifact, rolling back the deployment restores them too. Where they are configured outside the build, revert them separately, and note that in the runbook so nobody assumes one action covered both.",[224,1067,1069],{"id":1068},"how-do-i-stop-the-pipeline-from-immediately-redeploying-the-bad-build","How do I stop the pipeline from immediately redeploying the bad build?",[14,1071,1072],{},"Revert the offending commit on the default branch or pause the deployment integration before rolling back. Otherwise the next push, or a retried workflow, promotes the broken build again while you are still investigating.",[27,1074,1076],{"id":1075},"related","Related",[32,1078,1079,1088,1095,1102,1107],{},[35,1080,1081,1084,1085,1087],{},[627,1082,1083],{},"Parent:"," ",[21,1086,24],{"href":23}," — the practices that make this fast.",[35,1089,1090,1094],{},[21,1091,1093],{"href":1092},"\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 check that detects the need to roll back.",[35,1096,1097,1101],{},[21,1098,1100],{"href":1099},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads\u002F","Atomic Deploys vs Incremental Uploads"," — why the previous build is still intact.",[35,1103,1104,1106],{},[21,1105,791],{"href":790}," — what to purge, and what to leave.",[35,1108,1109,1113],{},[21,1110,1112],{"href":1111},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002F","Cloudflare Pages Edge Caching Setup"," — where deployments and cache rules live on one host.",[1115,1116,1117],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":234,"searchDepth":269,"depth":269,"links":1119},[1120,1121,1128,1129,1130,1131,1132,1133,1134,1141],{"id":29,"depth":269,"text":30},{"id":51,"depth":269,"text":52,"children":1122},[1123,1124,1125,1126,1127],{"id":226,"depth":313,"text":227},{"id":279,"depth":313,"text":280},{"id":345,"depth":313,"text":346},{"id":455,"depth":313,"text":456},{"id":569,"depth":313,"text":570},{"id":614,"depth":269,"text":615},{"id":698,"depth":269,"text":699},{"id":795,"depth":269,"text":796},{"id":823,"depth":269,"text":824},{"id":985,"depth":269,"text":986},{"id":1027,"depth":269,"text":1028},{"id":1036,"depth":269,"text":1037,"children":1135},[1136,1137,1138,1139,1140],{"id":1040,"depth":313,"text":1041},{"id":1047,"depth":313,"text":1048},{"id":1054,"depth":313,"text":1055},{"id":1061,"depth":313,"text":1062},{"id":1068,"depth":313,"text":1069},{"id":1075,"depth":269,"text":1076},[1143,1146,1149,1150],{"name":1144,"item":1145},"Home","\u002F",{"name":1147,"item":1148},"Production-Ready Deployment & CI\u002FCD Workflows","\u002Fproduction-ready-deployment-cicd-workflows\u002F",{"name":24,"item":23},{"name":5,"item":1151},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute\u002F","2026-08-01","A per-host runbook for reverting a broken static deploy: find the last good deployment ID, promote it, verify, and communicate — with no rebuild in the critical path.","md",[1156,1157,1158,1159,1160],{"q":1041,"a":1044},{"q":1048,"a":1051},{"q":1055,"a":1058},{"q":1062,"a":1065},{"q":1069,"a":1072},{},true,"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute",{"title":5,"description":1153},"production-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute\u002Findex","article","Ty08vksSaesf2LsSFaIftxShIMujdvS8vxjbqCpqyZE",[1169,1172,1175,1178,1181,1184,1187,1190,1193,1196,1199,1202,1205,1208,1211,1214,1217,1220,1223,1226,1229,1232,1235,1238,1241,1244,1247,1249,1251,1254,1257,1260,1263,1266,1269,1272,1275,1278,1281,1284,1287,1290,1293,1296,1299,1302,1305,1308,1311,1314,1317,1320,1323,1326,1329,1332,1335,1338,1340,1343,1346,1349,1352,1355,1358,1361,1364,1367,1370,1373,1376,1379,1382,1385,1388,1391,1394,1397,1400,1403,1405,1407,1408],{"path":1170,"title":1171},"\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":1173,"title":1174},"\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":1176,"title":1177},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":1179,"title":1180},"\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":1182,"title":1183},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":1185,"title":1186},"\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":1188,"title":1189},"\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":1191,"title":1192},"\u002Fchoosing-the-right-static-site-generator-for-production","Choosing the Right Static Site Generator for Production",{"path":1194,"title":1195},"\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":1197,"title":1198},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":1200,"title":1201},"\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":1203,"title":1204},"\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":1206,"title":1207},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators","Migrating Between Static Site Generators",{"path":1209,"title":1210},"\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":1212,"title":1213},"\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":1215,"title":1216},"\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":1218,"title":1219},"\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":1221,"title":1222},"\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":1224,"title":1225},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":1227,"title":1228},"\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":1230,"title":1231},"\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":1233,"title":1234},"\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":1236,"title":1237},"\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":1239,"title":1240},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":1242,"title":1243},"\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":1245,"title":1246},"\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":1248,"title":786},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs",{"path":1250,"title":791},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fpurging-the-cdn-cache-after-a-static-deploy",{"path":1252,"title":1253},"\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":1255,"title":1256},"\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":1258,"title":1259},"\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":1261,"title":1262},"\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":1264,"title":1265},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":1267,"title":1268},"\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":1270,"title":1271},"\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":1273,"title":1274},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":1276,"title":1277},"\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":1279,"title":1280},"\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":1282,"title":1283},"\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":1285,"title":1286},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":1288,"title":1289},"\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":1291,"title":1292},"\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":1294,"title":1295},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":1297,"title":1298},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":1300,"title":1301},"\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":1303,"title":1304},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":1306,"title":1307},"\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":1309,"title":1310},"\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":1312,"title":1313},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":1315,"title":1316},"\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":1318,"title":1319},"\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":1321,"title":1322},"\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":1324,"title":1325},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites","Third-Party Script Performance on Static Sites",{"path":1327,"title":1328},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Flazy-loading-youtube-embeds-on-static-sites","Lazy-Loading YouTube Embeds on Static Sites",{"path":1330,"title":1331},"\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":1333,"title":1334},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":1336,"title":1337},"\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":1339,"title":1112},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup",{"path":1341,"title":1342},"\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":1344,"title":1345},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams","Content Workflows for Documentation Teams",{"path":1347,"title":1348},"\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":1350,"title":1351},"\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":1353,"title":1354},"\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":1356,"title":1357},"\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":1359,"title":1360},"\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":1362,"title":1363},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":1365,"title":1366},"\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":1368,"title":1369},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":1371,"title":1372},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":1374,"title":1375},"\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":1377,"title":1378},"\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":1380,"title":1381},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":1383,"title":1384},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":1386,"title":1387},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":1389,"title":1390},"\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":1392,"title":1393},"\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":1395,"title":1396},"\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":1398,"title":1399},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":1401,"title":1402},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests","Preview Environments for Pull Requests",{"path":1404,"title":1100},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads",{"path":1406,"title":24},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites",{"path":1163,"title":5},{"path":1409,"title":1093},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url",1785611671104]