[{"data":1,"prerenderedAt":2058},["ShallowReactive",2],{"page:\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams":3,"all-docs-nav":1817},{"id":4,"title":5,"body":6,"breadcrumb":1793,"dateModified":1799,"datePublished":1799,"description":1800,"extension":1801,"faq":1802,"meta":1811,"navigation":1149,"path":1812,"seo":1813,"slug":12,"stem":1814,"type":1815,"__hash__":1816},"content\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Findex.md","Content Workflows for Documentation Teams",{"type":7,"value":8,"toc":1772},"minimark",[9,13,17,26,199,204,207,214,220,230,309,313,316,329,332,351,354,357,360,364,367,646,649,794,887,891,894,965,1070,1077,1081,1084,1090,1439,1445,1452,1456,1459,1462,1469,1477,1480,1484,1487,1490,1493,1496,1500,1503,1509,1515,1521,1611,1614,1618,1656,1660,1677,1681,1686,1689,1693,1696,1700,1703,1707,1710,1714,1717,1721,1724,1728,1768],[10,11,5],"h1",{"id":12},"content-workflows-for-documentation-teams",[14,15,16],"p",{},"A static site is a joy for engineers and, without deliberate work, an obstacle course for everyone else. The generator that makes builds fast and hosting cheap also puts the content behind a toolchain: a repository, a branch, a pull request, a local build. Documentation teams include technical writers, support engineers, product managers and occasional contributors, and most of them should not have to install anything to fix a sentence.",[14,18,19,20,25],{},"This guide covers the workflow around the build: how content moves from an idea to production, what a review actually needs, where a CMS earns its place, how to schedule publication without runtime logic, and which checks belong in the build so reviewers can focus on meaning. It sits under ",[21,22,24],"a",{"href":23},"\u002Fproduction-ready-deployment-cicd-workflows\u002F","Production-Ready Deployment & CI\u002FCD Workflows",".",[27,28,29,195],"figure",{},[30,31,38,39,38,43,38,47,38,54,38,181],"svg",{"viewBox":32,"role":33,"ariaLabelledBy":34,"xmlns":37},"0 0 760 320","img",[35,36],"cw-flow-title","cw-flow-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[40,41,42],"title",{"id":35},"The path from draft to published page",[44,45,46],"desc",{"id":36},"A pipeline with three entry points feeding one path. Writers can start in a Git-backed CMS, a web editor, or a local checkout. All three produce a branch, which triggers build gates and a preview deploy, then review, then merge and publish. Scheduled content re-enters the pipeline on a cron rebuild.",[48,49],"rect",{"x":50,"y":50,"width":51,"height":52,"fill":53},"0","760","320","#ffffff",[55,56,58,59,58,67,58,77,58,83,58,87,58,91,58,95,58,99,58,104,58,108,58,114,58,118,58,123,58,126,58,129,58,133,58,142,58,148,58,153,38],"g",{"style":57},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[60,61,66],"text",{"x":62,"y":63,"fill":64,"style":65},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","Three ways in, one way through",[48,68],{"x":69,"y":70,"width":71,"height":72,"rx":73,"fill":74,"opacity":75,"stroke":74,"style":76},"30","56","150","42","8","#6a4c93","0.14","stroke-width:1.5px",[60,78,82],{"x":79,"y":80,"fill":64,"style":81},"105","82","font-size:12px;text-anchor:middle","Git-backed CMS",[48,84],{"x":69,"y":85,"width":71,"height":72,"rx":73,"fill":74,"opacity":86,"stroke":74,"style":76},"108","0.12",[60,88,90],{"x":79,"y":89,"fill":64,"style":81},"134","Web editor",[48,92],{"x":69,"y":93,"width":71,"height":72,"rx":73,"fill":74,"opacity":94,"stroke":74,"style":76},"160","0.1",[60,96,98],{"x":79,"y":97,"fill":64,"style":81},"186","Local checkout",[48,100],{"x":101,"y":85,"width":102,"height":72,"rx":73,"fill":103,"opacity":75,"stroke":103,"style":76},"220","130","#1982c4",[60,105,107],{"x":106,"y":89,"fill":64,"style":81},"285","Branch + PR",[48,109],{"x":110,"y":70,"width":71,"height":72,"rx":73,"fill":111,"opacity":112,"stroke":113,"style":76},"390","#8ac926","0.18","#5a8a16",[60,115,117],{"x":116,"y":80,"fill":64,"style":81},"465","Build gates",[48,119],{"x":110,"y":93,"width":71,"height":72,"rx":73,"fill":120,"opacity":121,"stroke":122,"style":76},"#ffca3a","0.3","#a97b00",[60,124,125],{"x":116,"y":97,"fill":64,"style":81},"Preview deploy",[48,127],{"x":128,"y":85,"width":71,"height":72,"rx":73,"fill":103,"opacity":75,"stroke":103,"style":76},"580",[60,130,132],{"x":131,"y":89,"fill":64,"style":81},"655","Review → merge",[48,134],{"x":110,"y":135,"width":136,"height":137,"rx":138,"fill":139,"opacity":140,"stroke":141,"style":76},"238","340","46","10","#d9e2ef","0.5","#556071",[60,143,147],{"x":144,"y":145,"fill":64,"style":146},"560","258","font-size:12px;font-weight:700;text-anchor:middle","Scheduled rebuild publishes future-dated pages",[60,149,152],{"x":144,"y":150,"fill":141,"style":151},"276","font-size:11px;text-anchor:middle","no runtime logic, no CMS involvement",[55,154,157,158,157,163,157,166,157,169,157,172,157,175,157,178,58],{"stroke":141,"fill":155,"style":156},"none","stroke-width:2px","\n      ",[159,160],"path",{"d":161,"style":162},"M182 77 L218 122","marker-end:url(#cw-arrow)",[159,164],{"d":165,"style":162},"M182 129 L218 129",[159,167],{"d":168,"style":162},"M182 181 L218 138",[159,170],{"d":171,"style":162},"M352 122 L388 88",[159,173],{"d":174,"style":162},"M352 138 L388 174",[159,176],{"d":177,"style":162},"M542 88 L578 122",[159,179],{"d":180,"style":162},"M542 174 L578 138",[182,183,58,184,38],"defs",{},[185,186,157,192,58],"marker",{"id":187,"viewBox":188,"refX":73,"refY":189,"markerWidth":190,"markerHeight":190,"orient":191},"cw-arrow","0 0 10 10","5","7","auto-start-reverse",[159,193],{"d":194,"fill":141},"M0 0 L10 5 L0 10 z",[196,197,198],"figcaption",{},"The entry point is a preference; everything after the branch is identical. Keeping it that way is what lets an occasional contributor and a full-time writer share one review process.",[200,201,203],"h2",{"id":202},"decide-the-entry-points","Decide the Entry Points",[14,205,206],{},"Three interfaces cover a documentation team, and a healthy setup offers at least two.",[14,208,209,213],{},[210,211,212],"strong",{},"Local checkout."," Full-time writers with a technical background usually prefer this: a fast dev server, their own editor, and the ability to run the build gates before pushing. Its cost is onboarding — a toolchain install, a Node version, a first successful build.",[14,215,216,219],{},[210,217,218],{},"Web editor."," The repository host's own editor handles a typo, a broken link or a version number without anyone leaving the browser. It produces a normal branch and pull request, so the rest of the process is unchanged. This is the cheapest possible fix path and it costs nothing to enable.",[14,221,222,225,226,25],{},[210,223,224],{},"Git-backed CMS."," Decap, Sveltia, Tina, Keystatic and similar tools present a normal editing UI — fields, previews, media uploads — and commit Markdown behind the scenes. They earn their place when the front matter is structured enough that hand-editing YAML is error-prone, or when contributors genuinely will not use a code host. The setup is covered in ",[21,227,229],{"href":228},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fwiring-a-headless-cms-to-a-static-build\u002F","Wiring a Headless CMS to a Static Build",[231,232,233,252],"table",{},[234,235,236],"thead",{},[237,238,239,243,246,249],"tr",{},[240,241,242],"th",{},"Interface",[240,244,245],{},"Best for",[240,247,248],{},"Onboarding cost",[240,250,251],{},"Weakness",[253,254,255,269,282,295],"tbody",{},[237,256,257,260,263,266],{},[258,259,98],"td",{},[258,261,262],{},"Daily writers, engineers",[258,264,265],{},"Hours",[258,267,268],{},"Toolchain problems block writing",[237,270,271,273,276,279],{},[258,272,90],{},[258,274,275],{},"Occasional fixes",[258,277,278],{},"Minutes",[258,280,281],{},"No preview until CI runs",[237,283,284,286,289,292],{},[258,285,82],{},[258,287,288],{},"Structured content, non-technical authors",[258,290,291],{},"Days to set up",[258,293,294],{},"Another system to maintain",[237,296,297,300,303,306],{},[258,298,299],{},"Headless CMS + API",[258,301,302],{},"Content reused across products",[258,304,305],{},"Weeks",[258,307,308],{},"Build must fetch; loses Git history for content",[200,310,312],{"id":311},"make-the-preview-the-review","Make the Preview the Review",[14,314,315],{},"A documentation diff tells you what changed; a preview tells you whether it is right. Since previews are cheap on static hosting, make the rendered page the primary review artifact and the diff secondary.",[14,317,318,319,323,324,328],{},"That means the preview URL must appear on the pull request automatically, within a couple of minutes, on every push — the mechanics are in ",[21,320,322],{"href":321},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002F","Preview Environments for Pull Requests"," and, host-specifically, ",[21,325,327],{"href":326},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fsetting-up-deploy-previews-on-netlify-for-every-pull-request\u002F","Setting Up Deploy Previews on Netlify for Every Pull Request",". A preview that takes ten minutes is a preview nobody waits for.",[14,330,331],{},"Keep the review checklist short enough that reviewers use it every time:",[333,334,335,339,342,345,348],"ul",{},[336,337,338],"li",{},"Does the page answer the question its title asks?",[336,340,341],{},"Are the code samples runnable, and do they match the version in use?",[336,343,344],{},"Does every new claim carry a number or a source?",[336,346,347],{},"Do the links resolve, and do they point at the most specific page available?",[336,349,350],{},"Would a reader landing here from search understand it without the surrounding section?",[14,352,353],{},"Everything mechanical — link resolution, front matter validity, spelling, word counts — belongs in the build, not on this list.",[14,355,356],{},"Who reviews matters as much as what they check. Documentation benefits from two different reviewers doing two different jobs, and conflating them slows both: a subject-matter reviewer confirms the content is true, and an editorial reviewer confirms it is clear and consistent with the rest of the site. On a small team one person does both, and it helps to do them as two passes rather than one — read for accuracy, then read for clarity — because the two kinds of attention do not mix well.",[14,358,359],{},"Set an explicit expectation for review latency, and make it short. A day is workable; a week means authors context-switch away and return to a stale branch. If reviews routinely take longer, the problem is usually queueing rather than effort: nobody owns the queue, so every pull request waits for a volunteer. Assigning a rotating reviewer of the week fixes more review latency than any tooling change.",[200,361,363],{"id":362},"gate-the-build-so-reviewers-read-meaning","Gate the Build So Reviewers Read Meaning",[14,365,366],{},"Every check you automate is a class of comment reviewers never have to write again. For documentation, five gates cover most of it:",[368,369,374],"pre",{"className":370,"code":371,"language":372,"meta":373,"style":373},"language-yaml shiki shiki-themes github-light github-dark","# .github\u002Fworkflows\u002Fcontent.yml\nname: Content checks\non: [pull_request]\njobs:\n  check:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: actions\u002Fsetup-node@v4\n        with: { node-version: 20, cache: npm }\n      - run: npm ci\n      - run: npm run build\n      - name: Front matter schema\n        run: node scripts\u002Fcheck-frontmatter.mjs\n      - name: Internal links + anchors\n        run: npx linkinator .\u002Fdist --recurse --silent\n      - name: Spelling (project dictionary)\n        run: npx cspell \"content\u002F**\u002F*.md\" --no-progress\n      - name: Terminology\n        run: node scripts\u002Fcheck-terms.mjs\n      - name: Reading level and length\n        run: node scripts\u002Fcheck-readability.mjs\n","yaml","",[375,376,377,386,401,417,426,434,445,453,467,479,510,523,535,547,558,570,580,592,602,614,624,636],"code",{"__ignoreMap":373},[378,379,382],"span",{"class":380,"line":381},"line",1,[378,383,385],{"class":384},"sJ8bj","# .github\u002Fworkflows\u002Fcontent.yml\n",[378,387,389,393,397],{"class":380,"line":388},2,[378,390,392],{"class":391},"s9eBZ","name",[378,394,396],{"class":395},"sVt8B",": ",[378,398,400],{"class":399},"sZZnC","Content checks\n",[378,402,404,408,411,414],{"class":380,"line":403},3,[378,405,407],{"class":406},"sj4cs","on",[378,409,410],{"class":395},": [",[378,412,413],{"class":399},"pull_request",[378,415,416],{"class":395},"]\n",[378,418,420,423],{"class":380,"line":419},4,[378,421,422],{"class":391},"jobs",[378,424,425],{"class":395},":\n",[378,427,429,432],{"class":380,"line":428},5,[378,430,431],{"class":391},"  check",[378,433,425],{"class":395},[378,435,437,440,442],{"class":380,"line":436},6,[378,438,439],{"class":391},"    runs-on",[378,441,396],{"class":395},[378,443,444],{"class":399},"ubuntu-latest\n",[378,446,448,451],{"class":380,"line":447},7,[378,449,450],{"class":391},"    steps",[378,452,425],{"class":395},[378,454,456,459,462,464],{"class":380,"line":455},8,[378,457,458],{"class":395},"      - ",[378,460,461],{"class":391},"uses",[378,463,396],{"class":395},[378,465,466],{"class":399},"actions\u002Fcheckout@v4\n",[378,468,470,472,474,476],{"class":380,"line":469},9,[378,471,458],{"class":395},[378,473,461],{"class":391},[378,475,396],{"class":395},[378,477,478],{"class":399},"actions\u002Fsetup-node@v4\n",[378,480,482,485,488,491,493,496,499,502,504,507],{"class":380,"line":481},10,[378,483,484],{"class":391},"        with",[378,486,487],{"class":395},": { ",[378,489,490],{"class":391},"node-version",[378,492,396],{"class":395},[378,494,495],{"class":406},"20",[378,497,498],{"class":395},", ",[378,500,501],{"class":391},"cache",[378,503,396],{"class":395},[378,505,506],{"class":399},"npm",[378,508,509],{"class":395}," }\n",[378,511,513,515,518,520],{"class":380,"line":512},11,[378,514,458],{"class":395},[378,516,517],{"class":391},"run",[378,519,396],{"class":395},[378,521,522],{"class":399},"npm ci\n",[378,524,526,528,530,532],{"class":380,"line":525},12,[378,527,458],{"class":395},[378,529,517],{"class":391},[378,531,396],{"class":395},[378,533,534],{"class":399},"npm run build\n",[378,536,538,540,542,544],{"class":380,"line":537},13,[378,539,458],{"class":395},[378,541,392],{"class":391},[378,543,396],{"class":395},[378,545,546],{"class":399},"Front matter schema\n",[378,548,550,553,555],{"class":380,"line":549},14,[378,551,552],{"class":391},"        run",[378,554,396],{"class":395},[378,556,557],{"class":399},"node scripts\u002Fcheck-frontmatter.mjs\n",[378,559,561,563,565,567],{"class":380,"line":560},15,[378,562,458],{"class":395},[378,564,392],{"class":391},[378,566,396],{"class":395},[378,568,569],{"class":399},"Internal links + anchors\n",[378,571,573,575,577],{"class":380,"line":572},16,[378,574,552],{"class":391},[378,576,396],{"class":395},[378,578,579],{"class":399},"npx linkinator .\u002Fdist --recurse --silent\n",[378,581,583,585,587,589],{"class":380,"line":582},17,[378,584,458],{"class":395},[378,586,392],{"class":391},[378,588,396],{"class":395},[378,590,591],{"class":399},"Spelling (project dictionary)\n",[378,593,595,597,599],{"class":380,"line":594},18,[378,596,552],{"class":391},[378,598,396],{"class":395},[378,600,601],{"class":399},"npx cspell \"content\u002F**\u002F*.md\" --no-progress\n",[378,603,605,607,609,611],{"class":380,"line":604},19,[378,606,458],{"class":395},[378,608,392],{"class":391},[378,610,396],{"class":395},[378,612,613],{"class":399},"Terminology\n",[378,615,617,619,621],{"class":380,"line":616},20,[378,618,552],{"class":391},[378,620,396],{"class":395},[378,622,623],{"class":399},"node scripts\u002Fcheck-terms.mjs\n",[378,625,627,629,631,633],{"class":380,"line":626},21,[378,628,458],{"class":395},[378,630,392],{"class":391},[378,632,396],{"class":395},[378,634,635],{"class":399},"Reading level and length\n",[378,637,639,641,643],{"class":380,"line":638},22,[378,640,552],{"class":391},[378,642,396],{"class":395},[378,644,645],{"class":399},"node scripts\u002Fcheck-readability.mjs\n",[14,647,648],{},"The terminology check is the one most teams underrate. A short list of \"say this, not that\" — product names, capitalisation, deprecated feature names — catches the inconsistencies that otherwise consume review attention:",[368,650,654],{"className":651,"code":652,"language":653,"meta":373,"style":373},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F scripts\u002Fcheck-terms.mjs\nconst RULES = [\n  [\u002F\\bwebsite generator\\b\u002Fgi, 'static site generator'],\n  [\u002F\\bJamstack\\b\u002Fg, 'Jamstack'],          \u002F\u002F capitalisation\n  [\u002F\\bnode\\.js\\b\u002Fg, 'Node.js'],\n  [\u002F\\bcloudflare workers\\b\u002Fgi, 'Cloudflare Workers'],\n];\n","javascript",[375,655,656,661,676,706,734,765,789],{"__ignoreMap":373},[378,657,658],{"class":380,"line":381},[378,659,660],{"class":384},"\u002F\u002F scripts\u002Fcheck-terms.mjs\n",[378,662,663,667,670,673],{"class":380,"line":388},[378,664,666],{"class":665},"szBVR","const",[378,668,669],{"class":406}," RULES",[378,671,672],{"class":665}," =",[378,674,675],{"class":395}," [\n",[378,677,678,681,684,687,691,693,695,698,700,703],{"class":380,"line":403},[378,679,680],{"class":395},"  [",[378,682,683],{"class":399},"\u002F",[378,685,686],{"class":665},"\\b",[378,688,690],{"class":689},"sA_wV","website generator",[378,692,686],{"class":665},[378,694,683],{"class":399},[378,696,697],{"class":665},"gi",[378,699,498],{"class":395},[378,701,702],{"class":399},"'static site generator'",[378,704,705],{"class":395},"],\n",[378,707,708,710,712,714,717,719,721,723,725,728,731],{"class":380,"line":419},[378,709,680],{"class":395},[378,711,683],{"class":399},[378,713,686],{"class":665},[378,715,716],{"class":689},"Jamstack",[378,718,686],{"class":665},[378,720,683],{"class":399},[378,722,55],{"class":665},[378,724,498],{"class":395},[378,726,727],{"class":399},"'Jamstack'",[378,729,730],{"class":395},"],          ",[378,732,733],{"class":384},"\u002F\u002F capitalisation\n",[378,735,736,738,740,742,745,749,752,754,756,758,760,763],{"class":380,"line":428},[378,737,680],{"class":395},[378,739,683],{"class":399},[378,741,686],{"class":665},[378,743,744],{"class":689},"node",[378,746,748],{"class":747},"snhLl","\\.",[378,750,751],{"class":689},"js",[378,753,686],{"class":665},[378,755,683],{"class":399},[378,757,55],{"class":665},[378,759,498],{"class":395},[378,761,762],{"class":399},"'Node.js'",[378,764,705],{"class":395},[378,766,767,769,771,773,776,778,780,782,784,787],{"class":380,"line":436},[378,768,680],{"class":395},[378,770,683],{"class":399},[378,772,686],{"class":665},[378,774,775],{"class":689},"cloudflare workers",[378,777,686],{"class":665},[378,779,683],{"class":399},[378,781,697],{"class":665},[378,783,498],{"class":395},[378,785,786],{"class":399},"'Cloudflare Workers'",[378,788,705],{"class":395},[378,790,791],{"class":380,"line":447},[378,792,793],{"class":395},"];\n",[27,795,796,884],{},[30,797,38,802,38,805,38,808,38,811],{"viewBox":798,"role":33,"ariaLabelledBy":799,"xmlns":37},"0 0 760 300",[800,801],"cw-gates-title","cw-gates-desc",[40,803,804],{"id":800},"Review comments before and after adding content gates",[44,806,807],{"id":801},"A comparison of review comments per pull request. Before gates, an average of 11.4 comments per pull request, of which 7.9 were mechanical issues such as broken links, typos and inconsistent terms. After gates, 4.2 comments per pull request, almost all about accuracy and structure, and review turnaround fell from 2 days to 4 hours.",[48,809],{"x":50,"y":50,"width":51,"height":810,"fill":53},"300",[55,812,58,813,58,816,58,822,58,827,58,834,58,839,58,843,58,847,58,851,58,855,58,859,58,864,58,866,58,869,58,873,58,876,58,880,38],{"style":57},[60,814,815],{"x":62,"y":63,"fill":64,"style":65},"Automate the mechanical, review the meaning",[60,817,821],{"x":818,"y":819,"fill":64,"style":820},"60","76","font-size:12px;font-weight:700","Before gates",[60,823,826],{"x":818,"y":824,"fill":141,"style":825},"94","font-size:11px","11.4 comments \u002F PR",[48,828],{"x":829,"y":818,"width":830,"height":69,"rx":189,"fill":831,"opacity":832,"stroke":833,"style":76},"250","310","#ff595e","0.16","#d83b41",[60,835,838],{"x":836,"y":837,"fill":64,"style":81},"405","80","7.9 mechanical",[48,840],{"x":841,"y":818,"width":89,"height":69,"rx":189,"fill":111,"opacity":842,"stroke":113,"style":76},"566","0.2",[60,844,846],{"x":845,"y":837,"fill":64,"style":81},"633","3.5 substantive",[60,848,850],{"x":818,"y":849,"fill":64,"style":820},"152","After gates",[60,852,854],{"x":818,"y":853,"fill":141,"style":825},"170","4.2 comments \u002F PR",[48,856],{"x":829,"y":857,"width":858,"height":69,"rx":189,"fill":831,"opacity":75,"stroke":833,"style":76},"136","27",[60,860,863],{"x":861,"y":862,"fill":141,"style":825},"290","156","0.7",[48,865],{"x":52,"y":857,"width":89,"height":69,"rx":189,"fill":111,"opacity":842,"stroke":113,"style":76},[60,867,846],{"x":868,"y":862,"fill":64,"style":81},"387",[60,870,872],{"x":818,"y":101,"fill":64,"style":871},"font-size:13px;font-weight:700","Review turnaround",[48,874],{"x":829,"y":875,"width":830,"height":69,"rx":189,"fill":120,"opacity":121,"stroke":122,"style":76},"204",[60,877,879],{"x":836,"y":878,"fill":64,"style":81},"224","2 days → 4 hours",[60,881,883],{"x":818,"y":882,"fill":141,"style":825},"272","The substantive count is unchanged — gates removed work, not scrutiny",[196,885,886],{},"Note that the substantive comment count is identical before and after. The gates did not make reviews shallower; they removed the mechanical noise that was delaying them.",[200,888,890],{"id":889},"publish-on-a-schedule-without-runtime-logic","Publish on a Schedule Without Runtime Logic",[14,892,893],{},"Documentation teams frequently need a page to appear at a particular moment: a release announcement, an embargoed feature, a deprecation notice. On a static site there is no runtime to check a date, so the pattern is to filter at build time and rebuild on a schedule.",[368,895,897],{"className":651,"code":896,"language":653,"meta":373,"style":373},"\u002F\u002F Astro content collection filter — future-dated pages never build\nconst posts = await getCollection('blog', ({ data }) =>\n  !data.draft && data.date \u003C= new Date());\n",[375,898,899,904,939],{"__ignoreMap":373},[378,900,901],{"class":380,"line":381},[378,902,903],{"class":384},"\u002F\u002F Astro content collection filter — future-dated pages never build\n",[378,905,906,908,911,913,916,920,923,926,929,933,936],{"class":380,"line":388},[378,907,666],{"class":665},[378,909,910],{"class":406}," posts",[378,912,672],{"class":665},[378,914,915],{"class":665}," await",[378,917,919],{"class":918},"sScJk"," getCollection",[378,921,922],{"class":395},"(",[378,924,925],{"class":399},"'blog'",[378,927,928],{"class":395},", ({ ",[378,930,932],{"class":931},"s4XuR","data",[378,934,935],{"class":395}," }) ",[378,937,938],{"class":665},"=>\n",[378,940,941,944,947,950,953,956,959,962],{"class":380,"line":403},[378,942,943],{"class":665},"  !",[378,945,946],{"class":395},"data.draft ",[378,948,949],{"class":665},"&&",[378,951,952],{"class":395}," data.date ",[378,954,955],{"class":665},"\u003C=",[378,957,958],{"class":665}," new",[378,960,961],{"class":918}," Date",[378,963,964],{"class":395},"());\n",[368,966,968],{"className":370,"code":967,"language":372,"meta":373,"style":373},"# .github\u002Fworkflows\u002Fscheduled-publish.yml\non:\n  schedule:\n    - cron: '5 * * * *'      # hourly, five past\n  workflow_dispatch:\njobs:\n  publish:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - run: npm ci && npm run build\n      - run: npx wrangler deploy\n",[375,969,970,975,981,988,1004,1011,1017,1024,1032,1038,1048,1059],{"__ignoreMap":373},[378,971,972],{"class":380,"line":381},[378,973,974],{"class":384},"# .github\u002Fworkflows\u002Fscheduled-publish.yml\n",[378,976,977,979],{"class":380,"line":388},[378,978,407],{"class":406},[378,980,425],{"class":395},[378,982,983,986],{"class":380,"line":403},[378,984,985],{"class":391},"  schedule",[378,987,425],{"class":395},[378,989,990,993,996,998,1001],{"class":380,"line":419},[378,991,992],{"class":395},"    - ",[378,994,995],{"class":391},"cron",[378,997,396],{"class":395},[378,999,1000],{"class":399},"'5 * * * *'",[378,1002,1003],{"class":384},"      # hourly, five past\n",[378,1005,1006,1009],{"class":380,"line":428},[378,1007,1008],{"class":391},"  workflow_dispatch",[378,1010,425],{"class":395},[378,1012,1013,1015],{"class":380,"line":436},[378,1014,422],{"class":391},[378,1016,425],{"class":395},[378,1018,1019,1022],{"class":380,"line":447},[378,1020,1021],{"class":391},"  publish",[378,1023,425],{"class":395},[378,1025,1026,1028,1030],{"class":380,"line":455},[378,1027,439],{"class":391},[378,1029,396],{"class":395},[378,1031,444],{"class":399},[378,1033,1034,1036],{"class":380,"line":469},[378,1035,450],{"class":391},[378,1037,425],{"class":395},[378,1039,1040,1042,1044,1046],{"class":380,"line":481},[378,1041,458],{"class":395},[378,1043,461],{"class":391},[378,1045,396],{"class":395},[378,1047,466],{"class":399},[378,1049,1050,1052,1054,1056],{"class":380,"line":512},[378,1051,458],{"class":395},[378,1053,517],{"class":391},[378,1055,396],{"class":395},[378,1057,1058],{"class":399},"npm ci && npm run build\n",[378,1060,1061,1063,1065,1067],{"class":380,"line":525},[378,1062,458],{"class":395},[378,1064,517],{"class":391},[378,1066,396],{"class":395},[378,1068,1069],{"class":399},"npx wrangler deploy\n",[14,1071,1072,1073,25],{},"An hourly rebuild gives publication accurate to the hour with no infrastructure; a cron every fifteen minutes gets you closer at four times the build minutes. The trade-offs, including how to avoid a wasted deploy when nothing changed, are in ",[21,1074,1076],{"href":1075},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fscheduling-content-publication-with-cron-triggered-builds\u002F","Scheduling Content Publication With Cron-Triggered Builds",[200,1078,1080],{"id":1079},"structure-the-content-so-the-build-can-help","Structure the Content So the Build Can Help",[14,1082,1083],{},"A workflow is only as good as the shape of the content it moves. Two structural decisions do most of the work.",[14,1085,1086,1089],{},[210,1087,1088],{},"Put required metadata in a schema."," Every page needs a title, a description, a date and whatever your templates depend on. Declaring that as a schema means an author gets a build error naming the file and the field, rather than a reviewer noticing three days later that a search snippet is empty. In Astro this is a content collection schema; in Eleventy it is a computed-data validation step; in Hugo it is a template that fails loudly on a missing field.",[368,1091,1093],{"className":651,"code":1092,"language":653,"meta":373,"style":373},"\u002F\u002F scripts\u002Fcheck-frontmatter.mjs — generator-agnostic guard\nimport { readFile } from 'node:fs\u002Fpromises';\nimport { globSync } from 'node:fs';\nimport matter from 'gray-matter';\n\nconst REQUIRED = ['title', 'description', 'date'];\nlet bad = 0;\n\nfor (const file of globSync('content\u002F**\u002F*.md')) {\n  const { data } = matter(await readFile(file, 'utf8'));\n  for (const key of REQUIRED) {\n    if (!data[key]) { console.error(`${file}: missing ${key}`); bad++; }\n  }\n  if (data.description && (data.description.length \u003C 80 || data.description.length > 158)) {\n    console.error(`${file}: description is ${data.description.length} chars (want 80–158)`);\n    bad++;\n  }\n}\nprocess.exit(bad ? 1 : 0);\n",[375,1094,1095,1100,1117,1131,1145,1151,1178,1194,1198,1225,1260,1279,1321,1326,1364,1397,1406,1410,1415],{"__ignoreMap":373},[378,1096,1097],{"class":380,"line":381},[378,1098,1099],{"class":384},"\u002F\u002F scripts\u002Fcheck-frontmatter.mjs — generator-agnostic guard\n",[378,1101,1102,1105,1108,1111,1114],{"class":380,"line":388},[378,1103,1104],{"class":665},"import",[378,1106,1107],{"class":395}," { readFile } ",[378,1109,1110],{"class":665},"from",[378,1112,1113],{"class":399}," 'node:fs\u002Fpromises'",[378,1115,1116],{"class":395},";\n",[378,1118,1119,1121,1124,1126,1129],{"class":380,"line":403},[378,1120,1104],{"class":665},[378,1122,1123],{"class":395}," { globSync } ",[378,1125,1110],{"class":665},[378,1127,1128],{"class":399}," 'node:fs'",[378,1130,1116],{"class":395},[378,1132,1133,1135,1138,1140,1143],{"class":380,"line":419},[378,1134,1104],{"class":665},[378,1136,1137],{"class":395}," matter ",[378,1139,1110],{"class":665},[378,1141,1142],{"class":399}," 'gray-matter'",[378,1144,1116],{"class":395},[378,1146,1147],{"class":380,"line":428},[378,1148,1150],{"emptyLinePlaceholder":1149},true,"\n",[378,1152,1153,1155,1158,1160,1163,1166,1168,1171,1173,1176],{"class":380,"line":436},[378,1154,666],{"class":665},[378,1156,1157],{"class":406}," REQUIRED",[378,1159,672],{"class":665},[378,1161,1162],{"class":395}," [",[378,1164,1165],{"class":399},"'title'",[378,1167,498],{"class":395},[378,1169,1170],{"class":399},"'description'",[378,1172,498],{"class":395},[378,1174,1175],{"class":399},"'date'",[378,1177,793],{"class":395},[378,1179,1180,1183,1186,1189,1192],{"class":380,"line":447},[378,1181,1182],{"class":665},"let",[378,1184,1185],{"class":395}," bad ",[378,1187,1188],{"class":665},"=",[378,1190,1191],{"class":406}," 0",[378,1193,1116],{"class":395},[378,1195,1196],{"class":380,"line":455},[378,1197,1150],{"emptyLinePlaceholder":1149},[378,1199,1200,1203,1206,1208,1211,1214,1217,1219,1222],{"class":380,"line":469},[378,1201,1202],{"class":665},"for",[378,1204,1205],{"class":395}," (",[378,1207,666],{"class":665},[378,1209,1210],{"class":406}," file",[378,1212,1213],{"class":665}," of",[378,1215,1216],{"class":918}," globSync",[378,1218,922],{"class":395},[378,1220,1221],{"class":399},"'content\u002F**\u002F*.md'",[378,1223,1224],{"class":395},")) {\n",[378,1226,1227,1230,1233,1235,1238,1240,1243,1245,1248,1251,1254,1257],{"class":380,"line":481},[378,1228,1229],{"class":665},"  const",[378,1231,1232],{"class":395}," { ",[378,1234,932],{"class":406},[378,1236,1237],{"class":395}," } ",[378,1239,1188],{"class":665},[378,1241,1242],{"class":918}," matter",[378,1244,922],{"class":395},[378,1246,1247],{"class":665},"await",[378,1249,1250],{"class":918}," readFile",[378,1252,1253],{"class":395},"(file, ",[378,1255,1256],{"class":399},"'utf8'",[378,1258,1259],{"class":395},"));\n",[378,1261,1262,1265,1267,1269,1272,1274,1276],{"class":380,"line":512},[378,1263,1264],{"class":665},"  for",[378,1266,1205],{"class":395},[378,1268,666],{"class":665},[378,1270,1271],{"class":406}," key",[378,1273,1213],{"class":665},[378,1275,1157],{"class":406},[378,1277,1278],{"class":395},") {\n",[378,1280,1281,1284,1286,1289,1292,1295,1297,1300,1303,1306,1309,1312,1315,1318],{"class":380,"line":525},[378,1282,1283],{"class":665},"    if",[378,1285,1205],{"class":395},[378,1287,1288],{"class":665},"!",[378,1290,1291],{"class":395},"data[key]) { console.",[378,1293,1294],{"class":918},"error",[378,1296,922],{"class":395},[378,1298,1299],{"class":399},"`${",[378,1301,1302],{"class":395},"file",[378,1304,1305],{"class":399},"}: missing ${",[378,1307,1308],{"class":395},"key",[378,1310,1311],{"class":399},"}`",[378,1313,1314],{"class":395},"); bad",[378,1316,1317],{"class":665},"++",[378,1319,1320],{"class":395},"; }\n",[378,1322,1323],{"class":380,"line":537},[378,1324,1325],{"class":395},"  }\n",[378,1327,1328,1331,1334,1336,1339,1342,1345,1348,1351,1354,1356,1359,1362],{"class":380,"line":549},[378,1329,1330],{"class":665},"  if",[378,1332,1333],{"class":395}," (data.description ",[378,1335,949],{"class":665},[378,1337,1338],{"class":395}," (data.description.",[378,1340,1341],{"class":406},"length",[378,1343,1344],{"class":665}," \u003C",[378,1346,1347],{"class":406}," 80",[378,1349,1350],{"class":665}," ||",[378,1352,1353],{"class":395}," data.description.",[378,1355,1341],{"class":406},[378,1357,1358],{"class":665}," >",[378,1360,1361],{"class":406}," 158",[378,1363,1224],{"class":395},[378,1365,1366,1369,1371,1373,1375,1377,1380,1382,1384,1387,1389,1391,1394],{"class":380,"line":560},[378,1367,1368],{"class":395},"    console.",[378,1370,1294],{"class":918},[378,1372,922],{"class":395},[378,1374,1299],{"class":399},[378,1376,1302],{"class":395},[378,1378,1379],{"class":399},"}: description is ${",[378,1381,932],{"class":395},[378,1383,25],{"class":399},[378,1385,1386],{"class":395},"description",[378,1388,25],{"class":399},[378,1390,1341],{"class":406},[378,1392,1393],{"class":399},"} chars (want 80–158)`",[378,1395,1396],{"class":395},");\n",[378,1398,1399,1402,1404],{"class":380,"line":572},[378,1400,1401],{"class":395},"    bad",[378,1403,1317],{"class":665},[378,1405,1116],{"class":395},[378,1407,1408],{"class":380,"line":582},[378,1409,1325],{"class":395},[378,1411,1412],{"class":380,"line":594},[378,1413,1414],{"class":395},"}\n",[378,1416,1417,1420,1423,1426,1429,1432,1435,1437],{"class":380,"line":604},[378,1418,1419],{"class":395},"process.",[378,1421,1422],{"class":918},"exit",[378,1424,1425],{"class":395},"(bad ",[378,1427,1428],{"class":665},"?",[378,1430,1431],{"class":406}," 1",[378,1433,1434],{"class":665}," :",[378,1436,1191],{"class":406},[378,1438,1396],{"class":395},[14,1440,1441,1444],{},[210,1442,1443],{},"Keep one page per file and one file per URL."," Documentation teams sometimes reach for a single large file per section because it is easier to write. It is much harder to review, to link to, and to move. One file per URL means a pull request touching one page has a one-file diff, which is the single biggest factor in how quickly a review happens.",[14,1446,1447,1448,25],{},"The corollary is that reorganising sections must be cheap. If moving a page changes its URL, the workflow needs a redirect step, and a workflow with a manual redirect step will eventually skip it. Either derive URLs from a permalink field that survives file moves, or make the redirect generation automatic — the approaches are covered in ",[21,1449,1451],{"href":1450},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fkeeping-redirects-working-after-an-ssg-migration\u002F","Keeping Redirects Working After an SSG Migration",[200,1453,1455],{"id":1454},"handle-images-and-assets-without-blocking-writers","Handle Images and Assets Without Blocking Writers",[14,1457,1458],{},"The most common practical complaint from documentation authors is not Git — it is images. Where does a screenshot go, what size should it be, and why did the build fail because it was 4 MB?",[14,1460,1461],{},"Give the answer a shape that requires no decisions. Put images in a page bundle next to the Markdown, reference them relatively, and let the build resize and convert. Every major generator supports this, and it removes the two failure modes: an image in the wrong directory, and a 4 MB PNG in the repository.",[368,1463,1467],{"className":1464,"code":1466,"language":60,"meta":373},[1465],"language-text","content\u002Fguides\u002Fdeploying\u002F\n  index.md\n  deploy-dashboard.png      ← referenced as ![Dashboard](.\u002Fdeploy-dashboard.png)\n  rollback-panel.png\n",[375,1468,1466],{"__ignoreMap":373},[14,1470,1471,1472,1476],{},"Add a size guard so an oversized source is caught at the pull request rather than in a performance audit three months later, and let the pipeline generate the responsive variants automatically — the build-time work in ",[21,1473,1475],{"href":1474},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002F","Image Optimization Pipelines in Astro"," and its Hugo equivalent is what makes this safe to leave to non-engineers.",[14,1478,1479],{},"The same principle applies to diagrams. If a diagram requires a design tool, only the person with the tool can update it. If it is text — an inline SVG, a diagram-as-code block rendered at build time — anyone who can edit the page can fix the label that is now wrong.",[200,1481,1483],{"id":1482},"keep-content-and-code-together-usually","Keep Content and Code Together — Usually",[14,1485,1486],{},"For a documentation site, one repository is normally right. A single pull request can change a page and the component it renders with, the preview covers both, and the content's history sits alongside the code that presents it.",[14,1488,1489],{},"Split them when one of two things is true: the content is consumed by more than one site, or the contributor set is genuinely different and the code repository's permissions cannot accommodate them. In both cases the cost is real — two review processes, two histories, and a build that must fetch content from somewhere — so make the split deliberately rather than by default.",[14,1491,1492],{},"If you do split, keep the build reproducible: pin the content version the build uses rather than always fetching the tip, so a build can be repeated exactly. That single decision is the difference between a content repository and a moving target.",[14,1494,1495],{},"There is a middle path worth knowing about: keep content in the site repository but let a second team contribute through a fork or a limited-permission branch. This gives you a single build, a single history and one review process, while still allowing contributors who should not have write access to the code. Most repository hosts support this with no configuration beyond a branch protection rule, and it avoids the split entirely for the case that usually motivates it.",[200,1497,1499],{"id":1498},"measure-the-workflow-not-just-the-site","Measure the Workflow, Not Just the Site",[14,1501,1502],{},"Content workflows fail quietly: nobody announces that they have stopped writing because the toolchain is annoying. Three numbers make the health visible.",[14,1504,1505,1508],{},[210,1506,1507],{},"Time from first commit to publish."," Measured per pull request, this is the workflow's latency. A documentation team that publishes in hours behaves differently from one that publishes in weeks — the second batches changes, and batching is what makes review hard.",[14,1510,1511,1514],{},[210,1512,1513],{},"Share of contributions from outside the core team."," If support engineers and product managers never contribute, the entry points are too narrow, no matter how elegant the pipeline is.",[14,1516,1517,1520],{},[210,1518,1519],{},"Rework rate."," How often a page is corrected within a week of publishing. A high rate points at review happening too late or previews arriving too slowly, not at careless writers.",[27,1522,1523,1608],{},[30,1524,38,1529,38,1532,38,1535,38,1541],{"viewBox":1525,"role":33,"ariaLabelledBy":1526,"xmlns":37},"38 -11 584 297",[1527,1528],"cw-metrics-title","cw-metrics-desc",[40,1530,1531],{"id":1527},"Workflow health before and after the changes in this guide",[44,1533,1534],{"id":1528},"Three paired measures over two quarters. Median time from first commit to publish fell from 6.2 days to 0.4 days. Contributions from outside the core writing team rose from 9 percent to 34 percent. Rework within a week fell from 22 percent to 7 percent.",[48,1536],{"x":1537,"y":1538,"width":1539,"height":1540,"fill":53},"38","-11","584","297",[55,1542,58,1543,58,1546,58,1549,58,1553,58,1558,58,1562,58,1566,58,1570,58,1574,58,1578,58,1582,58,1587,58,1591,58,1595,58,1600,58,1604,38],{"style":57},[60,1544,1545],{"x":62,"y":63,"fill":64,"style":65},"Two quarters, one documentation team",[60,1547,1548],{"x":818,"y":819,"fill":64,"style":820},"Commit → publish",[48,1550],{"x":1551,"y":818,"width":1552,"height":63,"rx":189,"fill":831,"opacity":832,"stroke":833,"style":76},"270","330",[60,1554,1557],{"x":1555,"y":1556,"fill":833,"style":146},"435","79","6.2 days",[48,1559],{"x":1551,"y":824,"width":1560,"height":63,"rx":189,"fill":111,"opacity":1561,"stroke":113,"style":76},"22","0.26",[60,1563,1565],{"x":1552,"y":1564,"fill":113,"style":820},"113","0.4 days",[60,1567,1569],{"x":818,"y":1568,"fill":64,"style":820},"164","Outside contributors",[48,1571],{"x":1551,"y":1572,"width":137,"height":63,"rx":189,"fill":120,"opacity":1573,"stroke":122,"style":76},"148","0.34",[60,1575,1577],{"x":1552,"y":1576,"fill":122,"style":820},"167","9%",[48,1579],{"x":1551,"y":1580,"width":1581,"height":63,"rx":189,"fill":111,"opacity":1561,"stroke":113,"style":76},"182","174",[60,1583,1586],{"x":1584,"y":1585,"fill":113,"style":820},"470","201","34%",[60,1588,1590],{"x":818,"y":1589,"fill":64,"style":820},"252","Rework within a week",[48,1592],{"x":1551,"y":1593,"width":1594,"height":63,"rx":189,"fill":831,"opacity":75,"stroke":833,"style":76},"236","112",[60,1596,1599],{"x":1597,"y":1598,"fill":64,"style":146},"326","255","22%",[48,1601],{"x":1602,"y":1593,"width":1603,"height":63,"rx":189,"fill":111,"opacity":1561,"stroke":113,"style":76},"400","36",[60,1605,1607],{"x":1606,"y":1598,"fill":113,"style":820},"460","7%",[196,1609,1610],{},"The middle row is the one worth arguing for internally: opening a browser-based path tripled the share of contributions from people who talk to readers every day.",[14,1612,1613],{},"None of these needs a dashboard to start. A monthly query against the repository host's API, written down in the same place as the review checklist, is enough to notice a trend — and noticing is the whole point, since a workflow that has quietly stopped working looks identical to one nobody needed this month.",[200,1615,1617],{"id":1616},"common-pitfalls","Common Pitfalls",[333,1619,1620,1626,1632,1638,1644,1650],{},[336,1621,1622,1625],{},[210,1623,1624],{},"One interface only."," Requiring a local toolchain for a typo fix filters out exactly the contributors closest to the reader.",[336,1627,1628,1631],{},[210,1629,1630],{},"Reviewing diffs instead of previews."," Structure and rendering problems are invisible in a diff and obvious on the page.",[336,1633,1634,1637],{},[210,1635,1636],{},"Mechanical review comments."," Anything a reviewer says twice should become a build gate.",[336,1639,1640,1643],{},[210,1641,1642],{},"Slow previews."," A preview that arrives after the reviewer has moved on is not part of the workflow.",[336,1645,1646,1649],{},[210,1647,1648],{},"CMS as the source of truth."," A Git-backed CMS should commit Markdown you can read and edit by hand; if the repository is not authoritative, you have coupled publishing to a vendor.",[336,1651,1652,1655],{},[210,1653,1654],{},"Scheduling with client-side logic."," Hiding future content with JavaScript ships it to anyone who reads the source. Filter at build time.",[200,1657,1659],{"id":1658},"key-takeaways","Key Takeaways",[333,1661,1662,1665,1668,1671,1674],{},[336,1663,1664],{},"Offer at least two entry points: a local checkout for daily writers and a browser path for everyone else.",[336,1666,1667],{},"Make the preview URL the review artifact, and keep the human checklist to meaning and accuracy.",[336,1669,1670],{},"Move every mechanical check into the build — links, schema, spelling, terminology — so reviews get faster without getting shallower.",[336,1672,1673],{},"Publish future-dated content by filtering at build time and rebuilding on a cron.",[336,1675,1676],{},"Keep content in the site repository unless it is genuinely shared, and pin the version if you split.",[200,1678,1680],{"id":1679},"faq","FAQ",[1682,1683,1685],"h3",{"id":1684},"do-writers-need-to-learn-git-to-work-on-a-static-site","Do writers need to learn Git to work on a static site?",[14,1687,1688],{},"Not necessarily. A Git-backed CMS gives them a normal editing interface that commits behind the scenes, and a web-based editor covers small corrections. Teams that publish daily usually end up learning a handful of Git operations anyway, because the review flow is where the value is — but it should be a choice, not a barrier to the first contribution.",[1682,1690,1692],{"id":1691},"what-is-the-right-review-process-for-documentation","What is the right review process for documentation?",[14,1694,1695],{},"One reviewer, a preview URL, and a checklist short enough to actually use. Documentation review is mostly about accuracy and structure, both of which are easier to judge on a rendered preview than in a diff, so the preview link matters more than the review ceremony.",[1682,1697,1699],{"id":1698},"how-do-i-schedule-a-post-for-a-future-date","How do I schedule a post for a future date?",[14,1701,1702],{},"Filter future-dated content out of the build and trigger a rebuild on a schedule. A nightly or hourly cron that rebuilds and redeploys publishes anything whose date has arrived, with no runtime logic and no CMS involvement.",[1682,1704,1706],{"id":1705},"should-content-live-in-the-same-repository-as-the-site-code","Should content live in the same repository as the site code?",[14,1708,1709],{},"For a documentation site, usually yes: one repository means one pull request can change a page and the component it uses, and previews cover both. Split them only when the content is shared across several sites or the contributor set is genuinely different.",[1682,1711,1713],{"id":1712},"how-do-we-stop-broken-content-reaching-production","How do we stop broken content reaching production?",[14,1715,1716],{},"Gate the build. A link check, a front-matter schema and a spell check catch most content defects before review, and they give the author the feedback instead of the reviewer. The rule of thumb is that anything a reviewer says twice should become a check.",[1682,1718,1720],{"id":1719},"what-about-non-technical-contributors-who-only-edit-occasionally","What about non-technical contributors who only edit occasionally?",[14,1722,1723],{},"Give them the CMS or the web editor and a one-page guide. Occasional contributors should never have to install anything; the cost of onboarding them to a local toolchain exceeds the value of the change they came to make.",[200,1725,1727],{"id":1726},"related","Related",[333,1729,1730,1739,1744,1749,1756,1761],{},[336,1731,1732,1735,1736,1738],{},[210,1733,1734],{},"Parent:"," ",[21,1737,24],{"href":23}," — the pipeline this workflow rides on.",[336,1740,1741,1743],{},[21,1742,229],{"href":228}," — the editing layer, Git-backed or API-backed.",[336,1745,1746,1748],{},[21,1747,1076],{"href":1075}," — publishing at a time without a runtime.",[336,1750,1751,1755],{},[21,1752,1754],{"href":1753},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fdocs-as-code-review-workflow-for-writers\u002F","Docs-as-Code Review Workflow for Writers"," — branches, reviews and checklists in practice.",[336,1757,1758,1760],{},[21,1759,322],{"href":321}," — the preview that makes review work.",[336,1762,1763,1767],{},[21,1764,1766],{"href":1765},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002F","Rollbacks and Deploy Safety for Static Sites"," — what happens when something gets through anyway.",[1769,1770,1771],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}html pre.shiki code .snhLl, html code.shiki .snhLl{--shiki-default:#22863A;--shiki-default-font-weight:bold;--shiki-dark:#85E89D;--shiki-dark-font-weight:bold}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":373,"searchDepth":388,"depth":388,"links":1773},[1774,1775,1776,1777,1778,1779,1780,1781,1782,1783,1784,1792],{"id":202,"depth":388,"text":203},{"id":311,"depth":388,"text":312},{"id":362,"depth":388,"text":363},{"id":889,"depth":388,"text":890},{"id":1079,"depth":388,"text":1080},{"id":1454,"depth":388,"text":1455},{"id":1482,"depth":388,"text":1483},{"id":1498,"depth":388,"text":1499},{"id":1616,"depth":388,"text":1617},{"id":1658,"depth":388,"text":1659},{"id":1679,"depth":388,"text":1680,"children":1785},[1786,1787,1788,1789,1790,1791],{"id":1684,"depth":403,"text":1685},{"id":1691,"depth":403,"text":1692},{"id":1698,"depth":403,"text":1699},{"id":1705,"depth":403,"text":1706},{"id":1712,"depth":403,"text":1713},{"id":1719,"depth":403,"text":1720},{"id":1726,"depth":388,"text":1727},[1794,1796,1797],{"name":1795,"item":683},"Home",{"name":24,"item":23},{"name":5,"item":1798},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002F","2026-08-01","Make a static site publishable by non-engineers: branch and review conventions, a CMS or editor layer, scheduled publishing, and build gates that catch content errors early.","md",[1803,1804,1805,1806,1809,1810],{"q":1685,"a":1688},{"q":1692,"a":1695},{"q":1699,"a":1702},{"q":1706,"a":1807},{"For a documentation site, usually yes":1808},"one repository means one pull request can change a page and the component it uses, and previews cover both. Split them only when the content is shared across several sites or the contributor set is genuinely different.",{"q":1713,"a":1716},{"q":1720,"a":1723},{},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams",{"title":5,"description":1800},"production-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Findex","guide","AHWSOXXYfIIa_hUv9wpxoAtDrZn3CLHHY-1FINgJ64s",[1818,1821,1824,1827,1830,1833,1836,1839,1842,1845,1848,1851,1854,1857,1859,1862,1865,1868,1871,1874,1877,1880,1883,1886,1889,1892,1895,1898,1901,1904,1907,1910,1913,1916,1919,1922,1925,1928,1931,1934,1936,1939,1942,1945,1948,1951,1954,1957,1960,1963,1966,1969,1972,1975,1978,1981,1984,1987,1990,1992,1993,1995,1997,2000,2003,2006,2009,2012,2015,2018,2021,2024,2027,2030,2033,2036,2039,2042,2045,2047,2050,2052,2055],{"path":1819,"title":1820},"\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":1822,"title":1823},"\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":1825,"title":1826},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":1828,"title":1829},"\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":1831,"title":1832},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":1834,"title":1835},"\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":1837,"title":1838},"\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":1840,"title":1841},"\u002Fchoosing-the-right-static-site-generator-for-production","Choosing the Right Static Site Generator for Production",{"path":1843,"title":1844},"\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":1846,"title":1847},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":1849,"title":1850},"\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":1852,"title":1853},"\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":1855,"title":1856},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators","Migrating Between Static Site Generators",{"path":1858,"title":1451},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fkeeping-redirects-working-after-an-ssg-migration",{"path":1860,"title":1861},"\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":1863,"title":1864},"\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":1866,"title":1867},"\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":1869,"title":1870},"\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":1872,"title":1873},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":1875,"title":1876},"\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":1878,"title":1879},"\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":1881,"title":1882},"\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":1884,"title":1885},"\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":1887,"title":1888},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":1890,"title":1891},"\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":1893,"title":1894},"\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":1896,"title":1897},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs","CDN Caching Rules for SSGs",{"path":1899,"title":1900},"\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":1902,"title":1903},"\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":1905,"title":1906},"\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":1908,"title":1909},"\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":1911,"title":1912},"\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":1914,"title":1915},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":1917,"title":1918},"\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":1920,"title":1921},"\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":1923,"title":1924},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":1926,"title":1927},"\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":1929,"title":1930},"\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":1932,"title":1933},"\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":1935,"title":1475},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro",{"path":1937,"title":1938},"\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":1940,"title":1941},"\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":1943,"title":1944},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":1946,"title":1947},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":1949,"title":1950},"\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":1952,"title":1953},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":1955,"title":1956},"\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":1958,"title":1959},"\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":1961,"title":1962},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":1964,"title":1965},"\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":1967,"title":1968},"\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":1970,"title":1971},"\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":1973,"title":1974},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites","Third-Party Script Performance on Static Sites",{"path":1976,"title":1977},"\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":1979,"title":1980},"\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":1982,"title":1983},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":1985,"title":1986},"\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":1988,"title":1989},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup","Cloudflare Pages Edge Caching Setup",{"path":1991,"title":1754},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fdocs-as-code-review-workflow-for-writers",{"path":1812,"title":5},{"path":1994,"title":1076},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fscheduling-content-publication-with-cron-triggered-builds",{"path":1996,"title":229},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fwiring-a-headless-cms-to-a-static-build",{"path":1998,"title":1999},"\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":2001,"title":2002},"\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":2004,"title":2005},"\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":2007,"title":2008},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":2010,"title":2011},"\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":2013,"title":2014},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":2016,"title":2017},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":2019,"title":2020},"\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":2022,"title":2023},"\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":2025,"title":2026},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":2028,"title":2029},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":2031,"title":2032},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":2034,"title":2035},"\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":2037,"title":2038},"\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":2040,"title":2041},"\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":2043,"title":2044},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":2046,"title":322},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests",{"path":2048,"title":2049},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":2051,"title":1766},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites",{"path":2053,"title":2054},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frolling-back-a-bad-static-deploy-in-under-a-minute","Rolling Back a Bad Static Deploy in Under a Minute",{"path":2056,"title":2057},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url","Running Smoke Tests Against a Preview URL",1785611670808]