[{"data":1,"prerenderedAt":2262},["ShallowReactive",2],{"page:\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade":3,"all-docs-nav":2019},{"id":4,"title":5,"body":6,"breadcrumb":1989,"dateModified":1999,"datePublished":1999,"description":2000,"extension":2001,"faq":2002,"meta":2012,"navigation":311,"path":2013,"seo":2014,"slug":2015,"stem":2016,"type":2017,"__hash__":2018},"content\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade\u002Findex.md","Content Collections vs the Eleventy Data Cascade",{"type":7,"value":8,"toc":1969},"minimark",[9,13,17,26,31,41,45,262,266,506,643,653,738,742,745,812,815,821,825,828,831,917,1025,1029,1032,1507,1515,1519,1522,1742,1745,1749,1752,1825,1835,1839,1875,1879,1882,1886,1891,1898,1902,1905,1909,1912,1916,1919,1923,1926,1930,1965],[10,11,5],"h1",{"id":12},"content-collections-vs-the-eleventy-data-cascade",[14,15,16],"p",{},"Astro and Eleventy solve the same problem — get values from content files into templates — with opposite instincts. Astro asks you to declare a schema and fails the build when content does not match. Eleventy composes values from layers and lets a missing one be undefined. Both are defensible; they produce very different experiences once a documentation site has a hundred pages and several contributors.",[14,18,19,20,25],{},"This guide compares them concretely, shows what each catches and misses, and gives the patterns for getting the best of both. It sits under ",[21,22,24],"a",{"href":23},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002F","Astro vs Eleventy for Documentation Sites",".",[27,28,30],"h2",{"id":29},"prerequisites","Prerequisites",[32,33,34,38],"ul",{},[35,36,37],"li",{},"Familiarity with front matter and templates in at least one of the two generators.",[35,39,40],{},"A documentation site with more than one content type, since both models are trivial with a single type.",[27,42,44],{"id":43},"the-two-models","The Two Models",[46,47,48,258],"figure",{},[49,50,57,58,57,62,57,66,57,73,57,244],"svg",{"viewBox":51,"role":52,"ariaLabelledBy":53,"xmlns":56},"0 0 760 320","img",[54,55],"cc-models-title","cc-models-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[59,60,61],"title",{"id":54},"Schema validation versus layered cascade",[63,64,65],"desc",{"id":55},"Astro content collections take front matter through a declared schema, which either produces typed data or fails the build naming the file and field. The Eleventy data cascade merges global data, directory data, front matter and computed data in priority order, producing a value that may be undefined without any error.",[67,68],"rect",{"x":69,"y":69,"width":70,"height":71,"fill":72},"0","760","320","#ffffff",[74,75,77,78,77,86,77,93,77,104,77,110,77,115,77,119,77,126,77,132,77,136,77,140,77,144,77,149,77,155,77,159,77,162,77,166,77,169,77,172,77,174,77,178,77,183,77,188,77,192,77,195,77,199,77,203,77,208,77,239,57],"g",{"style":76},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[79,80,85],"text",{"x":81,"y":82,"fill":83,"style":84},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","Declare and verify, or layer and merge",[79,87,92],{"x":88,"y":89,"fill":90,"style":91},"40","62","#5a8a16","font-size:12px;font-weight:700","Astro content collections",[67,94],{"x":95,"y":96,"width":97,"height":98,"rx":99,"fill":100,"opacity":101,"stroke":102,"style":103},"240","50","130","42","8","#d9e2ef","0.55","#556071","stroke-width:1.5px",[79,105,109],{"x":106,"y":107,"fill":83,"style":108},"305","76","font-size:12px;text-anchor:middle","front matter",[67,111],{"x":112,"y":96,"width":97,"height":98,"rx":99,"fill":113,"opacity":114,"stroke":113,"style":103},"400","#6a4c93","0.14",[79,116,118],{"x":117,"y":107,"fill":83,"style":108},"465","schema",[67,120],{"x":121,"y":82,"width":122,"height":123,"rx":99,"fill":124,"opacity":125,"stroke":90,"style":103},"560","160","38","#8ac926","0.18",[79,127,131],{"x":128,"y":129,"fill":83,"style":130},"640","52","font-size:11px;text-anchor:middle","typed data → templates",[67,133],{"x":121,"y":107,"width":122,"height":123,"rx":99,"fill":134,"opacity":114,"stroke":135,"style":103},"#ff595e","#d83b41",[79,137,139],{"x":128,"y":138,"fill":83,"style":130},"94","build fails, names",[79,141,143],{"x":128,"y":142,"fill":83,"style":130},"108","the file and field",[79,145,148],{"x":88,"y":146,"fill":147,"style":91},"176","#a97b00","Eleventy data cascade",[67,150],{"x":95,"y":151,"width":97,"height":152,"rx":153,"fill":100,"opacity":154,"stroke":102,"style":103},"132","32","6","0.5",[79,156,158],{"x":106,"y":157,"fill":83,"style":130},"153","global _data",[67,160],{"x":95,"y":161,"width":97,"height":152,"rx":153,"fill":100,"opacity":154,"stroke":102,"style":103},"168",[79,163,165],{"x":106,"y":164,"fill":83,"style":130},"189","directory data",[67,167],{"x":95,"y":168,"width":97,"height":152,"rx":153,"fill":100,"opacity":154,"stroke":102,"style":103},"204",[79,170,109],{"x":106,"y":171,"fill":83,"style":130},"225",[67,173],{"x":95,"y":95,"width":97,"height":152,"rx":153,"fill":100,"opacity":154,"stroke":102,"style":103},[79,175,177],{"x":106,"y":176,"fill":83,"style":130},"261","computed data",[67,179],{"x":112,"y":161,"width":97,"height":180,"rx":99,"fill":181,"opacity":182,"stroke":147,"style":103},"68","#ffca3a","0.3",[79,184,187],{"x":117,"y":185,"fill":83,"style":186},"196","font-size:12px;font-weight:700;text-anchor:middle","merge by",[79,189,191],{"x":117,"y":190,"fill":83,"style":186},"214","priority",[67,193],{"x":121,"y":161,"width":122,"height":180,"rx":99,"fill":194,"opacity":114,"stroke":194,"style":103},"#1982c4",[79,196,198],{"x":128,"y":197,"fill":83,"style":130},"192","value or undefined",[79,200,202],{"x":128,"y":201,"fill":102,"style":130},"210","no error either way",[79,204,207],{"x":128,"y":205,"fill":147,"style":206},"228","font-size:11px;font-weight:700;text-anchor:middle","template renders anyway",[74,209,212,213,212,218,212,221,212,224,212,227,212,230,212,233,212,236,77],{"stroke":102,"fill":210,"style":211},"none","stroke-width:2px","\n      ",[214,215],"path",{"d":216,"style":217},"M372 71 L398 71","marker-end:url(#cc-arrow)",[214,219],{"d":220,"style":217},"M532 62 L558 52",[214,222],{"d":223,"style":217},"M532 80 L558 90",[214,225],{"d":226,"style":217},"M372 148 L398 180",[214,228],{"d":229,"style":217},"M372 184 L398 192",[214,231],{"d":232,"style":217},"M372 220 L398 210",[214,234],{"d":235,"style":217},"M372 256 L398 222",[214,237],{"d":238,"style":217},"M532 202 L558 202",[79,240,243],{"x":88,"y":241,"fill":102,"style":242},"300","font-size:11px","The difference that matters in practice is the red box: one model has it, the other does not",[245,246,77,247,57],"defs",{},[248,249,212,255,77],"marker",{"id":250,"viewBox":251,"refX":99,"refY":252,"markerWidth":253,"markerHeight":253,"orient":254},"cc-arrow","0 0 10 10","5","7","auto-start-reverse",[214,256],{"d":257,"fill":102},"M0 0 L10 5 L0 10 z",[259,260,261],"figcaption",{},"Both models get data into templates. Only one of them tells you, at build time and by filename, that a page is missing something a template depends on.",[27,263,265],{"id":264},"what-each-looks-like","What Each Looks Like",[267,268,273],"pre",{"className":269,"code":270,"language":271,"meta":272,"style":272},"language-typescript shiki shiki-themes github-light github-dark","\u002F\u002F Astro — src\u002Fcontent\u002Fconfig.ts\nimport { defineCollection, z } from 'astro:content';\n\nconst guides = defineCollection({\n  type: 'content',\n  schema: z.object({\n    title: z.string().max(70),\n    description: z.string().min(80).max(158),\n    section: z.enum(['deploy', 'perform', 'author']),\n    weight: z.number().default(100),\n    updated: z.date(),\n  }),\n});\n\nexport const collections = { guides };\n","typescript","",[274,275,276,285,306,313,333,345,356,380,410,439,460,472,478,484,489],"code",{"__ignoreMap":272},[277,278,281],"span",{"class":279,"line":280},"line",1,[277,282,284],{"class":283},"sJ8bj","\u002F\u002F Astro — src\u002Fcontent\u002Fconfig.ts\n",[277,286,288,292,296,299,303],{"class":279,"line":287},2,[277,289,291],{"class":290},"szBVR","import",[277,293,295],{"class":294},"sVt8B"," { defineCollection, z } ",[277,297,298],{"class":290},"from",[277,300,302],{"class":301},"sZZnC"," 'astro:content'",[277,304,305],{"class":294},";\n",[277,307,309],{"class":279,"line":308},3,[277,310,312],{"emptyLinePlaceholder":311},true,"\n",[277,314,316,319,323,326,330],{"class":279,"line":315},4,[277,317,318],{"class":290},"const",[277,320,322],{"class":321},"sj4cs"," guides",[277,324,325],{"class":290}," =",[277,327,329],{"class":328},"sScJk"," defineCollection",[277,331,332],{"class":294},"({\n",[277,334,336,339,342],{"class":279,"line":335},5,[277,337,338],{"class":294},"  type: ",[277,340,341],{"class":301},"'content'",[277,343,344],{"class":294},",\n",[277,346,348,351,354],{"class":279,"line":347},6,[277,349,350],{"class":294},"  schema: z.",[277,352,353],{"class":328},"object",[277,355,332],{"class":294},[277,357,359,362,365,368,371,374,377],{"class":279,"line":358},7,[277,360,361],{"class":294},"    title: z.",[277,363,364],{"class":328},"string",[277,366,367],{"class":294},"().",[277,369,370],{"class":328},"max",[277,372,373],{"class":294},"(",[277,375,376],{"class":321},"70",[277,378,379],{"class":294},"),\n",[277,381,383,386,388,390,393,395,398,401,403,405,408],{"class":279,"line":382},8,[277,384,385],{"class":294},"    description: z.",[277,387,364],{"class":328},[277,389,367],{"class":294},[277,391,392],{"class":328},"min",[277,394,373],{"class":294},[277,396,397],{"class":321},"80",[277,399,400],{"class":294},").",[277,402,370],{"class":328},[277,404,373],{"class":294},[277,406,407],{"class":321},"158",[277,409,379],{"class":294},[277,411,413,416,419,422,425,428,431,433,436],{"class":279,"line":412},9,[277,414,415],{"class":294},"    section: z.",[277,417,418],{"class":328},"enum",[277,420,421],{"class":294},"([",[277,423,424],{"class":301},"'deploy'",[277,426,427],{"class":294},", ",[277,429,430],{"class":301},"'perform'",[277,432,427],{"class":294},[277,434,435],{"class":301},"'author'",[277,437,438],{"class":294},"]),\n",[277,440,442,445,448,450,453,455,458],{"class":279,"line":441},10,[277,443,444],{"class":294},"    weight: z.",[277,446,447],{"class":328},"number",[277,449,367],{"class":294},[277,451,452],{"class":328},"default",[277,454,373],{"class":294},[277,456,457],{"class":321},"100",[277,459,379],{"class":294},[277,461,463,466,469],{"class":279,"line":462},11,[277,464,465],{"class":294},"    updated: z.",[277,467,468],{"class":328},"date",[277,470,471],{"class":294},"(),\n",[277,473,475],{"class":279,"line":474},12,[277,476,477],{"class":294},"  }),\n",[277,479,481],{"class":279,"line":480},13,[277,482,483],{"class":294},"});\n",[277,485,487],{"class":279,"line":486},14,[277,488,312],{"emptyLinePlaceholder":311},[277,490,492,495,498,501,503],{"class":279,"line":491},15,[277,493,494],{"class":290},"export",[277,496,497],{"class":290}," const",[277,499,500],{"class":321}," collections",[277,502,325],{"class":290},[277,504,505],{"class":294}," { guides };\n",[267,507,511],{"className":508,"code":509,"language":510,"meta":272,"style":272},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Eleventy — content\u002Fguides\u002Fguides.11tydata.js (directory data)\nmodule.exports = {\n  layout: 'guide.njk',\n  section: 'deploy',          \u002F\u002F default for everything in this directory\n  eleventyComputed: {\n    \u002F\u002F Derived at render, after front matter is merged\n    permalink: (data) => `\u002Fguides\u002F${data.page.fileSlug}\u002F`,\n    description: (data) => data.description || data.summary || '',\n  },\n};\n","javascript",[274,512,513,518,533,543,556,561,566,604,633,638],{"__ignoreMap":272},[277,514,515],{"class":279,"line":280},[277,516,517],{"class":283},"\u002F\u002F Eleventy — content\u002Fguides\u002Fguides.11tydata.js (directory data)\n",[277,519,520,523,525,528,530],{"class":279,"line":287},[277,521,522],{"class":321},"module",[277,524,25],{"class":294},[277,526,527],{"class":321},"exports",[277,529,325],{"class":290},[277,531,532],{"class":294}," {\n",[277,534,535,538,541],{"class":279,"line":308},[277,536,537],{"class":294},"  layout: ",[277,539,540],{"class":301},"'guide.njk'",[277,542,344],{"class":294},[277,544,545,548,550,553],{"class":279,"line":315},[277,546,547],{"class":294},"  section: ",[277,549,424],{"class":301},[277,551,552],{"class":294},",          ",[277,554,555],{"class":283},"\u002F\u002F default for everything in this directory\n",[277,557,558],{"class":279,"line":335},[277,559,560],{"class":294},"  eleventyComputed: {\n",[277,562,563],{"class":279,"line":347},[277,564,565],{"class":283},"    \u002F\u002F Derived at render, after front matter is merged\n",[277,567,568,571,574,578,581,584,587,589,591,594,596,599,602],{"class":279,"line":358},[277,569,570],{"class":328},"    permalink",[277,572,573],{"class":294},": (",[277,575,577],{"class":576},"s4XuR","data",[277,579,580],{"class":294},") ",[277,582,583],{"class":290},"=>",[277,585,586],{"class":301}," `\u002Fguides\u002F${",[277,588,577],{"class":294},[277,590,25],{"class":301},[277,592,593],{"class":294},"page",[277,595,25],{"class":301},[277,597,598],{"class":294},"fileSlug",[277,600,601],{"class":301},"}\u002F`",[277,603,344],{"class":294},[277,605,606,609,611,613,615,617,620,623,626,628,631],{"class":279,"line":382},[277,607,608],{"class":328},"    description",[277,610,573],{"class":294},[277,612,577],{"class":576},[277,614,580],{"class":294},[277,616,583],{"class":290},[277,618,619],{"class":294}," data.description ",[277,621,622],{"class":290},"||",[277,624,625],{"class":294}," data.summary ",[277,627,622],{"class":290},[277,629,630],{"class":301}," ''",[277,632,344],{"class":294},[277,634,635],{"class":279,"line":412},[277,636,637],{"class":294},"  },\n",[277,639,640],{"class":279,"line":441},[277,641,642],{"class":294},"};\n",[14,644,645,646,649,650,652],{},"The Astro version is a contract: a page missing ",[274,647,648],{},"description",", or with one of 40 characters, fails the build with the filename. The Eleventy version is a set of defaults and derivations: a page missing ",[274,651,648],{}," gets an empty string, and the meta tag renders empty.",[654,655,656,672],"table",{},[657,658,659],"thead",{},[660,661,662,666,669],"tr",{},[663,664,665],"th",{},"Concern",[663,667,668],{},"Astro collections",[663,670,671],{},"Eleventy cascade",[673,674,675,687,702,716,727],"tbody",{},[660,676,677,681,684],{},[678,679,680],"td",{},"Missing required field",[678,682,683],{},"Build error, names file and field",[678,685,686],{},"Undefined, renders empty",[660,688,689,692,699],{},[678,690,691],{},"Section-wide defaults",[678,693,694,695,698],{},"Explicit in schema ",[274,696,697],{},".default()"," or a helper",[678,700,701],{},"Native — one directory data file",[660,703,704,707,710],{},[678,705,706],{},"Derived values",[678,708,709],{},"Computed in the page or a helper",[678,711,712,713],{},"Native — ",[274,714,715],{},"eleventyComputed",[660,717,718,721,724],{},[678,719,720],{},"Editor support",[678,722,723],{},"Types flow into templates",[678,725,726],{},"None by default",[660,728,729,732,735],{},[678,730,731],{},"Cost of adding a field",[678,733,734],{},"Edit schema + backfill or default",[678,736,737],{},"Add a default in one file",[27,739,741],{"id":740},"where-the-cascade-wins","Where the Cascade Wins",[14,743,744],{},"Directory data is genuinely elegant for a documentation site with sections that differ. Setting a layout, a section label, a sidebar order and a set of related links for an entire directory, without touching any page, is one small file:",[267,746,748],{"className":508,"code":747,"language":510,"meta":272,"style":272},"\u002F\u002F content\u002Freference\u002Freference.11tydata.js\nmodule.exports = {\n  layout: 'reference.njk',\n  eleventyNavigation: { parent: 'Reference' },\n  showApiVersionBanner: true,\n  tags: ['reference'],\n};\n",[274,749,750,755,767,776,787,797,808],{"__ignoreMap":272},[277,751,752],{"class":279,"line":280},[277,753,754],{"class":283},"\u002F\u002F content\u002Freference\u002Freference.11tydata.js\n",[277,756,757,759,761,763,765],{"class":279,"line":287},[277,758,522],{"class":321},[277,760,25],{"class":294},[277,762,527],{"class":321},[277,764,325],{"class":290},[277,766,532],{"class":294},[277,768,769,771,774],{"class":279,"line":308},[277,770,537],{"class":294},[277,772,773],{"class":301},"'reference.njk'",[277,775,344],{"class":294},[277,777,778,781,784],{"class":279,"line":315},[277,779,780],{"class":294},"  eleventyNavigation: { parent: ",[277,782,783],{"class":301},"'Reference'",[277,785,786],{"class":294}," },\n",[277,788,789,792,795],{"class":279,"line":335},[277,790,791],{"class":294},"  showApiVersionBanner: ",[277,793,794],{"class":321},"true",[277,796,344],{"class":294},[277,798,799,802,805],{"class":279,"line":347},[277,800,801],{"class":294},"  tags: [",[277,803,804],{"class":301},"'reference'",[277,806,807],{"class":294},"],\n",[277,809,810],{"class":279,"line":358},[277,811,642],{"class":294},[14,813,814],{},"The equivalent in a schema-first model means either repeating the values in every page's front matter or writing a helper that merges defaults by path prefix. Both work; neither is as direct.",[14,816,817,818,820],{},"The cascade also handles derivation gracefully. ",[274,819,715],{}," runs after merging, so a value can depend on other values — a canonical URL built from a slug and a section, a description falling back to a summary, a title assembled from a product name and a page name. Doing the same in Astro means a function called from the layout, which is fine but less discoverable.",[27,822,824],{"id":823},"where-the-schema-wins","Where the Schema Wins",[14,826,827],{},"Everything about contributors. On a site with several authors, the schema is the difference between an author learning about a required field immediately and a reviewer catching it three days later — or nobody catching it and a search snippet shipping empty.",[14,829,830],{},"Turning on a schema for an existing corpus is a useful audit in itself. On one 900-page site, the first schema run produced 63 failures: missing descriptions, descriptions over the length that renders in a search result, dates as strings rather than dates, and one section value that had been misspelled consistently for two years.",[46,832,833,914],{},[49,834,57,839,57,842,57,845,57,848],{"viewBox":835,"role":52,"ariaLabelledBy":836,"xmlns":56},"0 0 760 280",[837,838],"cc-audit-title","cc-audit-desc",[59,840,841],{"id":837},"Defects found by turning on a schema",[63,843,844],{"id":838},"A breakdown of 63 content defects found on first running a schema over a 900-page site: 28 missing or empty descriptions, 19 descriptions outside the useful length range, 9 dates stored as strings, 5 pages with an invalid section value and 2 titles over 70 characters.",[67,846],{"x":69,"y":69,"width":70,"height":847,"fill":72},"280",[74,849,77,850,77,854,77,858,77,862,77,867,77,871,77,875,77,880,77,885,77,889,77,893,77,898,77,902,77,906,77,910,57],{"style":76},[79,851,853],{"x":81,"y":852,"fill":83,"style":84},"26","63 defects, found in one build, on a site nobody thought was broken",[279,855],{"x1":241,"y1":856,"x2":241,"y2":857,"stroke":100,"style":103},"44","222",[79,859,861],{"x":860,"y":107,"fill":83,"style":91},"60","Missing description",[67,863],{"x":241,"y":864,"width":865,"height":82,"rx":252,"fill":134,"opacity":866,"stroke":135,"style":103},"58","340","0.16",[79,868,82],{"x":869,"y":870,"fill":135,"style":186},"470","77",[79,872,874],{"x":860,"y":873,"fill":83,"style":91},"124","Wrong length",[67,876],{"x":241,"y":877,"width":878,"height":82,"rx":252,"fill":181,"opacity":879,"stroke":147,"style":103},"106","231","0.34",[79,881,884],{"x":882,"y":883,"fill":83,"style":186},"415","125","19",[79,886,888],{"x":860,"y":887,"fill":83,"style":91},"172","Date as string",[67,890],{"x":241,"y":891,"width":892,"height":82,"rx":252,"fill":194,"opacity":125,"stroke":194,"style":103},"154","109",[79,894,897],{"x":895,"y":896,"fill":83,"style":186},"354","173","9",[79,899,901],{"x":860,"y":900,"fill":83,"style":91},"220","Invalid section \u002F title",[67,903],{"x":241,"y":904,"width":905,"height":82,"rx":252,"fill":113,"opacity":125,"stroke":113,"style":103},"202","85",[79,907,253],{"x":908,"y":909,"fill":83,"style":186},"342","221",[79,911,913],{"x":164,"y":912,"fill":102,"style":242},"260","Shared linear scale · every one of these rendered without an error before the schema existed",[259,915,916],{},"None of these produced a broken page. They produced empty meta tags, truncated snippets and one section that had quietly never appeared in its own index.",[46,918,919,1022],{},[49,920,57,925,57,928,57,931,57,934,57,1015],{"viewBox":921,"role":52,"ariaLabelledBy":922,"xmlns":56},"0 0 760 290",[923,924],"cc-close-title","cc-close-desc",[59,926,927],{"id":923},"Closing the gap in each direction",[63,929,930],{"id":924},"Two rows. Eleventy starts with native directory defaults and no validation, and adding a validation hook gives it both. Astro starts with native schema validation and no directory defaults, and adding a path-prefix helper gives it both. Each gap is a small amount of code.",[67,932],{"x":69,"y":69,"width":70,"height":933,"fill":72},"290",[74,935,77,936,77,939,77,942,77,948,77,951,77,955,77,958,77,962,77,965,77,968,77,971,77,974,77,978,77,981,77,985,77,988,77,990,77,992,77,994,77,996,77,999,77,1002,77,1011,57],{"style":76},[79,937,938],{"x":81,"y":82,"fill":83,"style":84},"Each generator is one small file away from the other's strength",[79,940,941],{"x":88,"y":397,"fill":147,"style":91},"Eleventy",[67,943],{"x":944,"y":945,"width":946,"height":947,"rx":99,"fill":124,"opacity":125,"stroke":90,"style":103},"150","56","180","46",[79,949,950],{"x":95,"y":107,"fill":83,"style":108},"directory defaults",[79,952,954],{"x":95,"y":953,"fill":90,"style":130},"93","native",[67,956],{"x":957,"y":945,"width":946,"height":947,"rx":99,"fill":134,"opacity":114,"stroke":135,"style":103},"350",[79,959,961],{"x":960,"y":107,"fill":83,"style":108},"440","validation",[79,963,964],{"x":960,"y":953,"fill":135,"style":130},"missing",[67,966],{"x":967,"y":945,"width":946,"height":947,"rx":99,"fill":194,"opacity":114,"stroke":194,"style":103},"550",[79,969,970],{"x":128,"y":107,"fill":83,"style":108},"add an after hook",[79,972,973],{"x":128,"y":953,"fill":102,"style":130},"~25 lines",[79,975,977],{"x":88,"y":976,"fill":90,"style":91},"186","Astro",[67,979],{"x":944,"y":980,"width":946,"height":947,"rx":99,"fill":124,"opacity":125,"stroke":90,"style":103},"162",[79,982,984],{"x":95,"y":983,"fill":83,"style":108},"182","schema validation",[79,986,954],{"x":95,"y":987,"fill":90,"style":130},"199",[67,989],{"x":957,"y":980,"width":946,"height":947,"rx":99,"fill":134,"opacity":114,"stroke":135,"style":103},[79,991,950],{"x":960,"y":983,"fill":83,"style":108},[79,993,964],{"x":960,"y":987,"fill":135,"style":130},[67,995],{"x":967,"y":980,"width":946,"height":947,"rx":99,"fill":194,"opacity":114,"stroke":194,"style":103},[79,997,998],{"x":128,"y":983,"fill":83,"style":108},"path-prefix helper",[79,1000,1001],{"x":128,"y":987,"fill":102,"style":130},"~12 lines",[74,1003,212,1004,212,1008,77],{"stroke":102,"fill":210,"style":211},[214,1005],{"d":1006,"style":1007},"M532 79 L548 79","marker-end:url(#cc-close-arrow)",[214,1009],{"d":1010,"style":1007},"M532 185 L548 185",[79,1012,1014],{"x":88,"y":1013,"fill":102,"style":242},"256","Choose on which behaviour you want by default, not on which is possible — both are possible in both",[245,1016,77,1017,57],{},[248,1018,212,1020,77],{"id":1019,"viewBox":251,"refX":99,"refY":252,"markerWidth":253,"markerHeight":253,"orient":254},"cc-close-arrow",[214,1021],{"d":257,"fill":102},[259,1023,1024],{},"The defaults matter more than the ceiling: on a long-lived site, the behaviour nobody has to remember to configure is the one you actually get.",[27,1026,1028],{"id":1027},"getting-validation-in-eleventy","Getting Validation in Eleventy",[14,1030,1031],{},"The cascade's flexibility is worth keeping; the silence is not. A short hook restores the failure mode:",[267,1033,1035],{"className":508,"code":1034,"language":510,"meta":272,"style":272},"\u002F\u002F eleventy.config.js\nconst { z } = require('zod');\n\nconst guideSchema = z.object({\n  title: z.string().max(70),\n  description: z.string().min(80).max(158),\n  section: z.enum(['deploy', 'perform', 'author']),\n});\n\nmodule.exports = (eleventyConfig) => {\n  eleventyConfig.on('eleventy.after', ({ results }) => {\n    const errors = [];\n    for (const r of results) {\n      if (!r.inputPath.startsWith('.\u002Fcontent\u002Fguides\u002F')) continue;\n      const parsed = guideSchema.safeParse(r.data ?? {});\n      if (!parsed.success) {\n        errors.push(`${r.inputPath}: ${parsed.error.issues.map((i) => i.path.join('.') + ' ' + i.message).join('; ')}`);\n      }\n    }\n    if (errors.length) {\n      console.error(errors.join('\\n'));\n      throw new Error(`${errors.length} content validation error(s)`);\n    }\n  });\n};\n",[274,1036,1037,1042,1069,1073,1089,1106,1131,1152,1156,1160,1182,1208,1221,1239,1268,1293,1305,1410,1416,1422,1437,1463,1491,1496,1502],{"__ignoreMap":272},[277,1038,1039],{"class":279,"line":280},[277,1040,1041],{"class":283},"\u002F\u002F eleventy.config.js\n",[277,1043,1044,1046,1049,1052,1055,1058,1061,1063,1066],{"class":279,"line":287},[277,1045,318],{"class":290},[277,1047,1048],{"class":294}," { ",[277,1050,1051],{"class":321},"z",[277,1053,1054],{"class":294}," } ",[277,1056,1057],{"class":290},"=",[277,1059,1060],{"class":328}," require",[277,1062,373],{"class":294},[277,1064,1065],{"class":301},"'zod'",[277,1067,1068],{"class":294},");\n",[277,1070,1071],{"class":279,"line":308},[277,1072,312],{"emptyLinePlaceholder":311},[277,1074,1075,1077,1080,1082,1085,1087],{"class":279,"line":315},[277,1076,318],{"class":290},[277,1078,1079],{"class":321}," guideSchema",[277,1081,325],{"class":290},[277,1083,1084],{"class":294}," z.",[277,1086,353],{"class":328},[277,1088,332],{"class":294},[277,1090,1091,1094,1096,1098,1100,1102,1104],{"class":279,"line":335},[277,1092,1093],{"class":294},"  title: z.",[277,1095,364],{"class":328},[277,1097,367],{"class":294},[277,1099,370],{"class":328},[277,1101,373],{"class":294},[277,1103,376],{"class":321},[277,1105,379],{"class":294},[277,1107,1108,1111,1113,1115,1117,1119,1121,1123,1125,1127,1129],{"class":279,"line":347},[277,1109,1110],{"class":294},"  description: z.",[277,1112,364],{"class":328},[277,1114,367],{"class":294},[277,1116,392],{"class":328},[277,1118,373],{"class":294},[277,1120,397],{"class":321},[277,1122,400],{"class":294},[277,1124,370],{"class":328},[277,1126,373],{"class":294},[277,1128,407],{"class":321},[277,1130,379],{"class":294},[277,1132,1133,1136,1138,1140,1142,1144,1146,1148,1150],{"class":279,"line":358},[277,1134,1135],{"class":294},"  section: z.",[277,1137,418],{"class":328},[277,1139,421],{"class":294},[277,1141,424],{"class":301},[277,1143,427],{"class":294},[277,1145,430],{"class":301},[277,1147,427],{"class":294},[277,1149,435],{"class":301},[277,1151,438],{"class":294},[277,1153,1154],{"class":279,"line":382},[277,1155,483],{"class":294},[277,1157,1158],{"class":279,"line":412},[277,1159,312],{"emptyLinePlaceholder":311},[277,1161,1162,1164,1166,1168,1170,1173,1176,1178,1180],{"class":279,"line":441},[277,1163,522],{"class":321},[277,1165,25],{"class":294},[277,1167,527],{"class":321},[277,1169,325],{"class":290},[277,1171,1172],{"class":294}," (",[277,1174,1175],{"class":576},"eleventyConfig",[277,1177,580],{"class":294},[277,1179,583],{"class":290},[277,1181,532],{"class":294},[277,1183,1184,1187,1190,1192,1195,1198,1201,1204,1206],{"class":279,"line":462},[277,1185,1186],{"class":294},"  eleventyConfig.",[277,1188,1189],{"class":328},"on",[277,1191,373],{"class":294},[277,1193,1194],{"class":301},"'eleventy.after'",[277,1196,1197],{"class":294},", ({ ",[277,1199,1200],{"class":576},"results",[277,1202,1203],{"class":294}," }) ",[277,1205,583],{"class":290},[277,1207,532],{"class":294},[277,1209,1210,1213,1216,1218],{"class":279,"line":474},[277,1211,1212],{"class":290},"    const",[277,1214,1215],{"class":321}," errors",[277,1217,325],{"class":290},[277,1219,1220],{"class":294}," [];\n",[277,1222,1223,1226,1228,1230,1233,1236],{"class":279,"line":480},[277,1224,1225],{"class":290},"    for",[277,1227,1172],{"class":294},[277,1229,318],{"class":290},[277,1231,1232],{"class":321}," r",[277,1234,1235],{"class":290}," of",[277,1237,1238],{"class":294}," results) {\n",[277,1240,1241,1244,1246,1249,1252,1255,1257,1260,1263,1266],{"class":279,"line":486},[277,1242,1243],{"class":290},"      if",[277,1245,1172],{"class":294},[277,1247,1248],{"class":290},"!",[277,1250,1251],{"class":294},"r.inputPath.",[277,1253,1254],{"class":328},"startsWith",[277,1256,373],{"class":294},[277,1258,1259],{"class":301},"'.\u002Fcontent\u002Fguides\u002F'",[277,1261,1262],{"class":294},")) ",[277,1264,1265],{"class":290},"continue",[277,1267,305],{"class":294},[277,1269,1270,1273,1276,1278,1281,1284,1287,1290],{"class":279,"line":491},[277,1271,1272],{"class":290},"      const",[277,1274,1275],{"class":321}," parsed",[277,1277,325],{"class":290},[277,1279,1280],{"class":294}," guideSchema.",[277,1282,1283],{"class":328},"safeParse",[277,1285,1286],{"class":294},"(r.data ",[277,1288,1289],{"class":290},"??",[277,1291,1292],{"class":294}," {});\n",[277,1294,1296,1298,1300,1302],{"class":279,"line":1295},16,[277,1297,1243],{"class":290},[277,1299,1172],{"class":294},[277,1301,1248],{"class":290},[277,1303,1304],{"class":294},"parsed.success) {\n",[277,1306,1308,1311,1314,1316,1319,1322,1324,1327,1330,1333,1335,1338,1340,1343,1345,1348,1351,1354,1356,1358,1361,1363,1365,1367,1370,1372,1375,1377,1380,1383,1386,1388,1390,1393,1395,1397,1399,1402,1405,1408],{"class":279,"line":1307},17,[277,1309,1310],{"class":294},"        errors.",[277,1312,1313],{"class":328},"push",[277,1315,373],{"class":294},[277,1317,1318],{"class":301},"`${",[277,1320,1321],{"class":294},"r",[277,1323,25],{"class":301},[277,1325,1326],{"class":294},"inputPath",[277,1328,1329],{"class":301},"}: ${",[277,1331,1332],{"class":294},"parsed",[277,1334,25],{"class":301},[277,1336,1337],{"class":294},"error",[277,1339,25],{"class":301},[277,1341,1342],{"class":294},"issues",[277,1344,25],{"class":301},[277,1346,1347],{"class":328},"map",[277,1349,1350],{"class":301},"((",[277,1352,1353],{"class":321},"i",[277,1355,580],{"class":301},[277,1357,583],{"class":290},[277,1359,1360],{"class":294}," i",[277,1362,25],{"class":301},[277,1364,214],{"class":294},[277,1366,25],{"class":301},[277,1368,1369],{"class":328},"join",[277,1371,373],{"class":301},[277,1373,1374],{"class":301},"'.'",[277,1376,580],{"class":301},[277,1378,1379],{"class":290},"+",[277,1381,1382],{"class":301}," ' '",[277,1384,1385],{"class":290}," +",[277,1387,1360],{"class":294},[277,1389,25],{"class":301},[277,1391,1392],{"class":294},"message",[277,1394,400],{"class":301},[277,1396,1369],{"class":328},[277,1398,373],{"class":301},[277,1400,1401],{"class":301},"'; '",[277,1403,1404],{"class":301},")",[277,1406,1407],{"class":301},"}`",[277,1409,1068],{"class":294},[277,1411,1413],{"class":279,"line":1412},18,[277,1414,1415],{"class":294},"      }\n",[277,1417,1419],{"class":279,"line":1418},19,[277,1420,1421],{"class":294},"    }\n",[277,1423,1425,1428,1431,1434],{"class":279,"line":1424},20,[277,1426,1427],{"class":290},"    if",[277,1429,1430],{"class":294}," (errors.",[277,1432,1433],{"class":321},"length",[277,1435,1436],{"class":294},") {\n",[277,1438,1440,1443,1445,1448,1450,1452,1455,1458,1460],{"class":279,"line":1439},21,[277,1441,1442],{"class":294},"      console.",[277,1444,1337],{"class":328},[277,1446,1447],{"class":294},"(errors.",[277,1449,1369],{"class":328},[277,1451,373],{"class":294},[277,1453,1454],{"class":301},"'",[277,1456,1457],{"class":321},"\\n",[277,1459,1454],{"class":301},[277,1461,1462],{"class":294},"));\n",[277,1464,1466,1469,1472,1475,1477,1479,1482,1484,1486,1489],{"class":279,"line":1465},22,[277,1467,1468],{"class":290},"      throw",[277,1470,1471],{"class":290}," new",[277,1473,1474],{"class":328}," Error",[277,1476,373],{"class":294},[277,1478,1318],{"class":301},[277,1480,1481],{"class":294},"errors",[277,1483,25],{"class":301},[277,1485,1433],{"class":321},[277,1487,1488],{"class":301},"} content validation error(s)`",[277,1490,1068],{"class":294},[277,1492,1494],{"class":279,"line":1493},23,[277,1495,1421],{"class":294},[277,1497,1499],{"class":279,"line":1498},24,[277,1500,1501],{"class":294},"  });\n",[277,1503,1505],{"class":279,"line":1504},25,[277,1506,642],{"class":294},[14,1508,1509,1510,1514],{},"Run it in CI as a content gate — the same slot the other checks occupy in ",[21,1511,1513],{"href":1512},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002F","Content Workflows for Documentation Teams",". It runs after the build rather than before, so it is a check rather than a compiler, but the effect on contributors is identical: the failure names their file.",[27,1516,1518],{"id":1517},"getting-section-defaults-in-astro","Getting Section Defaults in Astro",[14,1520,1521],{},"The reverse gap is easy to close too. A path-prefix defaults helper gives you directory-data ergonomics:",[267,1523,1525],{"className":269,"code":1524,"language":271,"meta":272,"style":272},"\u002F\u002F src\u002Flib\u002Fsection-defaults.ts\nconst DEFAULTS: Record\u003Cstring, Record\u003Cstring, unknown>> = {\n  'reference\u002F': { layout: 'reference', showApiVersionBanner: true },\n  'guides\u002F':    { layout: 'guide', showApiVersionBanner: false },\n};\n\nexport function withDefaults\u003CT extends Record\u003Cstring, unknown>>(id: string, data: T) {\n  const prefix = Object.keys(DEFAULTS).find((p) => id.startsWith(p));\n  return { ...(prefix ? DEFAULTS[prefix] : {}), ...data };\n}\n",[274,1526,1527,1532,1571,1588,1606,1610,1614,1664,1706,1737],{"__ignoreMap":272},[277,1528,1529],{"class":279,"line":280},[277,1530,1531],{"class":283},"\u002F\u002F src\u002Flib\u002Fsection-defaults.ts\n",[277,1533,1534,1536,1539,1542,1545,1548,1550,1552,1555,1557,1559,1561,1564,1567,1569],{"class":279,"line":287},[277,1535,318],{"class":290},[277,1537,1538],{"class":321}," DEFAULTS",[277,1540,1541],{"class":290},":",[277,1543,1544],{"class":328}," Record",[277,1546,1547],{"class":294},"\u003C",[277,1549,364],{"class":321},[277,1551,427],{"class":294},[277,1553,1554],{"class":328},"Record",[277,1556,1547],{"class":294},[277,1558,364],{"class":321},[277,1560,427],{"class":294},[277,1562,1563],{"class":321},"unknown",[277,1565,1566],{"class":294},">> ",[277,1568,1057],{"class":290},[277,1570,532],{"class":294},[277,1572,1573,1576,1579,1581,1584,1586],{"class":279,"line":308},[277,1574,1575],{"class":301},"  'reference\u002F'",[277,1577,1578],{"class":294},": { layout: ",[277,1580,804],{"class":301},[277,1582,1583],{"class":294},", showApiVersionBanner: ",[277,1585,794],{"class":321},[277,1587,786],{"class":294},[277,1589,1590,1593,1596,1599,1601,1604],{"class":279,"line":315},[277,1591,1592],{"class":301},"  'guides\u002F'",[277,1594,1595],{"class":294},":    { layout: ",[277,1597,1598],{"class":301},"'guide'",[277,1600,1583],{"class":294},[277,1602,1603],{"class":321},"false",[277,1605,786],{"class":294},[277,1607,1608],{"class":279,"line":335},[277,1609,642],{"class":294},[277,1611,1612],{"class":279,"line":347},[277,1613,312],{"emptyLinePlaceholder":311},[277,1615,1616,1618,1621,1624,1626,1629,1632,1634,1636,1638,1640,1642,1645,1648,1650,1653,1655,1657,1659,1662],{"class":279,"line":358},[277,1617,494],{"class":290},[277,1619,1620],{"class":290}," function",[277,1622,1623],{"class":328}," withDefaults",[277,1625,1547],{"class":294},[277,1627,1628],{"class":328},"T",[277,1630,1631],{"class":290}," extends",[277,1633,1544],{"class":328},[277,1635,1547],{"class":294},[277,1637,364],{"class":321},[277,1639,427],{"class":294},[277,1641,1563],{"class":321},[277,1643,1644],{"class":294},">>(",[277,1646,1647],{"class":576},"id",[277,1649,1541],{"class":290},[277,1651,1652],{"class":321}," string",[277,1654,427],{"class":294},[277,1656,577],{"class":576},[277,1658,1541],{"class":290},[277,1660,1661],{"class":328}," T",[277,1663,1436],{"class":294},[277,1665,1666,1669,1672,1674,1677,1680,1682,1685,1687,1690,1692,1694,1696,1698,1701,1703],{"class":279,"line":382},[277,1667,1668],{"class":290},"  const",[277,1670,1671],{"class":321}," prefix",[277,1673,325],{"class":290},[277,1675,1676],{"class":294}," Object.",[277,1678,1679],{"class":328},"keys",[277,1681,373],{"class":294},[277,1683,1684],{"class":321},"DEFAULTS",[277,1686,400],{"class":294},[277,1688,1689],{"class":328},"find",[277,1691,1350],{"class":294},[277,1693,14],{"class":576},[277,1695,580],{"class":294},[277,1697,583],{"class":290},[277,1699,1700],{"class":294}," id.",[277,1702,1254],{"class":328},[277,1704,1705],{"class":294},"(p));\n",[277,1707,1708,1711,1713,1716,1719,1722,1724,1727,1729,1732,1734],{"class":279,"line":412},[277,1709,1710],{"class":290},"  return",[277,1712,1048],{"class":294},[277,1714,1715],{"class":290},"...",[277,1717,1718],{"class":294},"(prefix ",[277,1720,1721],{"class":290},"?",[277,1723,1538],{"class":321},[277,1725,1726],{"class":294},"[prefix] ",[277,1728,1541],{"class":290},[277,1730,1731],{"class":294}," {}), ",[277,1733,1715],{"class":290},[277,1735,1736],{"class":294},"data };\n",[277,1738,1739],{"class":279,"line":441},[277,1740,1741],{"class":294},"}\n",[14,1743,1744],{},"Call it once where entries are loaded, and the schema still validates whatever the page itself declares. Structural defaults live in one file; per-page requirements stay enforced.",[27,1746,1748],{"id":1747},"measured-impact","Measured Impact",[14,1750,1751],{},"Two documentation sites of comparable size (roughly 900 pages, six contributors), tracked over one quarter:",[654,1753,1754,1769],{},[657,1755,1756],{},[660,1757,1758,1761,1764,1767],{},[663,1759,1760],{},"Measure",[663,1762,1763],{},"Eleventy, no validation",[663,1765,1766],{},"Eleventy + validation hook",[663,1768,668],{},[673,1770,1771,1785,1798,1811],{},[660,1772,1773,1776,1779,1782],{},[678,1774,1775],{},"Content defects reaching production",[678,1777,1778],{},"31",[678,1780,1781],{},"3",[678,1783,1784],{},"2",[660,1786,1787,1790,1793,1796],{},[678,1788,1789],{},"Median time to notice a defect",[678,1791,1792],{},"26 days",[678,1794,1795],{},"Same build",[678,1797,1795],{},[660,1799,1800,1803,1806,1808],{},[678,1801,1802],{},"Time to add a section-wide default",[678,1804,1805],{},"2 minutes",[678,1807,1805],{},[678,1809,1810],{},"10 minutes (helper)",[660,1812,1813,1816,1819,1822],{},[678,1814,1815],{},"Contributor errors on first PR",[678,1817,1818],{},"4.1 per person",[678,1820,1821],{},"1.2",[678,1823,1824],{},"0.9",[14,1826,1827,1828,1830,1831,25],{},"The pattern is clear enough to state simply: validation is what removes content defects, and it is available in both generators. Astro gives it to you by default; Eleventy gives you a better story for structural defaults and asks you to add the validation yourself. Choose on which default you would rather have to remember, which is a real consideration on a site that will outlive the person configuring it — a theme that runs through ",[21,1829,24],{"href":23}," and the trade-off table in the ",[21,1832,1834],{"href":1833},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002F","SSG Framework Selection Matrix",[27,1836,1838],{"id":1837},"pitfalls-rollback","Pitfalls & Rollback",[32,1840,1841,1848,1854,1863,1869],{},[35,1842,1843,1847],{},[1844,1845,1846],"strong",{},"Schema without defaults."," A required field with no default and 900 existing pages is a migration, not a check. Add the field optional, backfill, then make it required.",[35,1849,1850,1853],{},[1844,1851,1852],{},"Over-modelling."," A schema listing every field a template might use makes adding a page a chore. Require what templates genuinely depend on.",[35,1855,1856,1859,1860,1862],{},[1844,1857,1858],{},"Computed values that hide errors."," An ",[274,1861,715],{}," description falling back to an empty string is exactly the silence validation is meant to remove; fall back to a failure instead.",[35,1864,1865,1868],{},[1844,1866,1867],{},"Directory data as global state."," A default four levels up that nobody remembers is as confusing as a magic constant. Keep defaults shallow and documented.",[35,1870,1871,1874],{},[1844,1872,1873],{},"Rollback:"," the Eleventy hook is one file and one config line — delete it and the build behaves as before. An Astro schema can be relaxed field by field without touching content.",[27,1876,1878],{"id":1877},"conclusion","Conclusion",[14,1880,1881],{},"The models differ less in capability than in default behaviour. Astro's schema makes content defects loud and immediate at the cost of some ceremony for section-wide defaults; Eleventy's cascade makes defaults effortless and content defects silent. Both gaps are a few lines of code to close, so the real question is which default you want on a site that a future contributor will inherit — and for a growing documentation site with multiple authors, loud is usually right.",[27,1883,1885],{"id":1884},"faq","FAQ",[1887,1888,1890],"h3",{"id":1889},"can-eleventy-validate-front-matter-like-astros-schema-does","Can Eleventy validate front matter like Astro's schema does?",[14,1892,1893,1894,1897],{},"Not natively, but a short build step or an ",[274,1895,1896],{},"eleventy.after"," hook running a schema validator gets you the same failure mode. The difference is that in Astro validation is the default and in Eleventy it is something you choose to add, which decides whether it exists on a site nobody has tended for a year.",[1887,1899,1901],{"id":1900},"is-the-data-cascade-harder-to-reason-about","Is the data cascade harder to reason about?",[14,1903,1904],{},"It is more flexible and less explicit. A value can come from front matter, a directory data file, a global data file or a computed function, and tracing which one won takes a moment. That flexibility is genuinely useful for shared defaults; it costs clarity when a value is unexpected.",[1887,1906,1908],{"id":1907},"which-model-is-better-for-a-large-documentation-site","Which model is better for a large documentation site?",[14,1910,1911],{},"A typed schema scales better with contributors, because it tells an author what is required at the moment they get it wrong. The cascade scales better with structural variety, because a directory data file can set defaults for a whole section without touching any page.",[1887,1913,1915],{"id":1914},"do-i-have-to-choose-one","Do I have to choose one?",[14,1917,1918],{},"Within a project, effectively yes — they come with their generators. But the underlying practices port: you can add schema validation to Eleventy, and you can emulate directory-level defaults in Astro with a small helper that merges defaults by path prefix.",[1887,1920,1922],{"id":1921},"what-happens-when-a-page-is-missing-a-required-field","What happens when a page is missing a required field?",[14,1924,1925],{},"In Astro the build fails and names the file and field. In Eleventy the value is simply undefined and the template renders without it, which usually means an empty meta description rather than an error — silent, and only noticed weeks later.",[27,1927,1929],{"id":1928},"related","Related",[32,1931,1932,1941,1948,1955,1960],{},[35,1933,1934,1937,1938,1940],{},[1844,1935,1936],{},"Parent:"," ",[21,1939,24],{"href":23}," — the wider comparison.",[35,1942,1943,1947],{},[21,1944,1946],{"href":1945},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fchoosing-between-astro-and-eleventy-for-large-docs\u002F","Choosing Between Astro and Eleventy for Large Docs"," — the decision at scale.",[35,1949,1950,1954],{},[21,1951,1953],{"href":1952},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002F","Migrating Between Static Site Generators"," — what changing content model costs.",[35,1956,1957,1959],{},[21,1958,1513],{"href":1512}," — where validation runs in the pipeline.",[35,1961,1962,1964],{},[21,1963,1834],{"href":1833}," — the trade-off in context.",[1966,1967,1968],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":272,"searchDepth":287,"depth":287,"links":1970},[1971,1972,1973,1974,1975,1976,1977,1978,1979,1980,1981,1988],{"id":29,"depth":287,"text":30},{"id":43,"depth":287,"text":44},{"id":264,"depth":287,"text":265},{"id":740,"depth":287,"text":741},{"id":823,"depth":287,"text":824},{"id":1027,"depth":287,"text":1028},{"id":1517,"depth":287,"text":1518},{"id":1747,"depth":287,"text":1748},{"id":1837,"depth":287,"text":1838},{"id":1877,"depth":287,"text":1878},{"id":1884,"depth":287,"text":1885,"children":1982},[1983,1984,1985,1986,1987],{"id":1889,"depth":308,"text":1890},{"id":1900,"depth":308,"text":1901},{"id":1907,"depth":308,"text":1908},{"id":1914,"depth":308,"text":1915},{"id":1921,"depth":308,"text":1922},{"id":1928,"depth":287,"text":1929},[1990,1993,1996,1997],{"name":1991,"item":1992},"Home","\u002F",{"name":1994,"item":1995},"Choosing the Right Static Site Generator for Production","\u002Fchoosing-the-right-static-site-generator-for-production\u002F",{"name":24,"item":23},{"name":5,"item":1998},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade\u002F","2026-08-01","Two ways to model documentation content: a typed schema that fails the build, or a layered cascade that resolves at render. What each buys, and how to get validation in both.","md",[2003,2005,2006,2007,2011],{"q":1890,"a":2004},"Not natively, but a short build step or an eleventy.before hook running a schema validator gets you the same failure mode. The difference is that in Astro validation is the default and in Eleventy it is something you choose to add, which decides whether it exists on a site nobody has tended for a year.",{"q":1901,"a":1904},{"q":1908,"a":1911},{"q":1915,"a":2008},{"Within a project, effectively yes — they come with their generators":2009},{" But the underlying practices port":2010},"you can add schema validation to Eleventy, and you can emulate directory-level defaults in Astro with a small helper that merges defaults by path prefix.",{"q":1922,"a":1925},{},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade",{"title":5,"description":2000},"content-collections-vs-eleventy-data-cascade","choosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fcontent-collections-vs-eleventy-data-cascade\u002Findex","article","9w3QW2XIQJarQi6OGKUauNNfGbfo8qIpRJOMadKw1b8",[2020,2023,2024,2026,2029,2032,2035,2038,2040,2043,2046,2049,2052,2054,2057,2060,2063,2066,2069,2072,2075,2078,2081,2084,2086,2089,2092,2095,2098,2101,2104,2107,2110,2113,2116,2119,2122,2125,2128,2131,2134,2137,2140,2143,2146,2149,2152,2155,2158,2161,2164,2167,2170,2173,2176,2179,2182,2185,2188,2191,2193,2196,2199,2202,2205,2208,2211,2214,2217,2220,2223,2226,2229,2232,2235,2238,2241,2244,2247,2250,2253,2256,2259],{"path":2021,"title":2022},"\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":2013,"title":5},{"path":2025,"title":24},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites",{"path":2027,"title":2028},"\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":2030,"title":2031},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":2033,"title":2034},"\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":2036,"title":2037},"\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":2039,"title":1994},"\u002Fchoosing-the-right-static-site-generator-for-production",{"path":2041,"title":2042},"\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":2044,"title":2045},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":2047,"title":2048},"\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":2050,"title":2051},"\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":2053,"title":1953},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators",{"path":2055,"title":2056},"\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":2058,"title":2059},"\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":2061,"title":2062},"\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":2064,"title":2065},"\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":2067,"title":2068},"\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":2070,"title":2071},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":2073,"title":2074},"\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":2076,"title":2077},"\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":2079,"title":2080},"\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":2082,"title":2083},"\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":2085,"title":1834},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix",{"path":2087,"title":2088},"\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":2090,"title":2091},"\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":2093,"title":2094},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs","CDN Caching Rules for SSGs",{"path":2096,"title":2097},"\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":2099,"title":2100},"\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":2102,"title":2103},"\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":2105,"title":2106},"\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":2108,"title":2109},"\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":2111,"title":2112},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":2114,"title":2115},"\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":2117,"title":2118},"\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":2120,"title":2121},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":2123,"title":2124},"\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":2126,"title":2127},"\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":2129,"title":2130},"\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":2132,"title":2133},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":2135,"title":2136},"\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":2138,"title":2139},"\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":2141,"title":2142},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":2144,"title":2145},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":2147,"title":2148},"\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":2150,"title":2151},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":2153,"title":2154},"\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":2156,"title":2157},"\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":2159,"title":2160},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":2162,"title":2163},"\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":2165,"title":2166},"\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":2168,"title":2169},"\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":2171,"title":2172},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites","Third-Party Script Performance on Static Sites",{"path":2174,"title":2175},"\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":2177,"title":2178},"\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":2180,"title":2181},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":2183,"title":2184},"\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":2186,"title":2187},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup","Cloudflare Pages Edge Caching Setup",{"path":2189,"title":2190},"\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":2192,"title":1513},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams",{"path":2194,"title":2195},"\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":2197,"title":2198},"\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":2200,"title":2201},"\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":2203,"title":2204},"\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":2206,"title":2207},"\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":2209,"title":2210},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":2212,"title":2213},"\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":2215,"title":2216},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":2218,"title":2219},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":2221,"title":2222},"\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":2224,"title":2225},"\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":2227,"title":2228},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":2230,"title":2231},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":2233,"title":2234},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":2236,"title":2237},"\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":2239,"title":2240},"\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":2242,"title":2243},"\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":2245,"title":2246},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":2248,"title":2249},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests","Preview Environments for Pull Requests",{"path":2251,"title":2252},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":2254,"title":2255},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites","Rollbacks and Deploy Safety for Static Sites",{"path":2257,"title":2258},"\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":2260,"title":2261},"\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",1785611671048]