[{"data":1,"prerenderedAt":2093},["ShallowReactive",2],{"page:\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight":3,"all-docs-nav":1554},{"id":4,"title":5,"body":6,"breadcrumb":1531,"dateModified":1540,"datePublished":1540,"description":1541,"extension":1542,"faq":1543,"meta":1548,"navigation":498,"path":1549,"seo":1550,"slug":12,"stem":1551,"type":1552,"__hash__":1553},"content\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight\u002Findex.md","Migrating from MkDocs to Starlight",{"type":7,"value":8,"toc":1513},"minimark",[9,13,17,31,36,68,72,75,258,269,407,411,418,817,852,866,869,873,899,906,910,937,1048,1059,1184,1188,1195,1199,1206,1295,1366,1370,1426,1430,1433,1437,1442,1445,1449,1452,1456,1459,1463,1466,1470,1509],[10,11,5],"h1",{"id":12},"migrating-from-mkdocs-to-starlight",[14,15,16],"p",{},"Material for MkDocs is one of the best documentation themes ever built, and most teams that leave it do so reluctantly. The usual triggers are specific: builds that pass two or three minutes as the site grows, content that wants real components rather than Markdown extensions, or a platform team consolidating every site onto one JavaScript toolchain. When those apply, Starlight is the smoothest landing — it shares Material's information architecture (tabs, sidebar, admonitions, search), and its content is still Markdown.",[14,18,19,20,25,26,30],{},"This guide walks through a migration of a 900-page Material for MkDocs site: the conversion script, navigation, URL parity, search and the numbers afterwards. It extends ",[21,22,24],"a",{"href":23},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002F","Docs Frameworks: Docusaurus, Starlight and VitePress"," and applies the general playbook from ",[21,27,29],{"href":28},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002F","Migrating Between Static Site Generators",".",[32,33,35],"h2",{"id":34},"prerequisites","Prerequisites",[37,38,39,56,62,65],"ul",{},[40,41,42,43,47,48,51,52,55],"li",{},"The MkDocs site's ",[44,45,46],"code",{},"mkdocs.yml",", ",[44,49,50],{},"docs\u002F"," folder and a list of enabled Markdown extensions (",[44,53,54],{},"markdown_extensions:"," in the config).",[40,57,58,59,30],{},"The current production URL list — a crawl or the generated ",[44,60,61],{},"sitemap.xml",[40,63,64],{},"Node.js 20 or later, and a fresh Starlight project.",[40,66,67],{},"A preview host so the migrated site can be compared page by page against production before cutover.",[32,69,71],{"id":70},"inventory-the-markdown-extensions","Inventory the Markdown Extensions",[14,73,74],{},"MkDocs content is Markdown plus whichever Python-Markdown and PyMdown extensions the site enables. Every one of those is syntax that Starlight will render literally unless you convert it. Count usage before writing any code:",[76,77,82],"pre",{"className":78,"code":79,"language":80,"meta":81,"style":81},"language-bash shiki shiki-themes github-light github-dark","cd docs\ngrep -rhoE '^!!!\\s*\\w+|^\\?\\?\\?\\+?\\s*\\w+' . | awk '{print $1, $2}' | sort | uniq -c   # admonitions\ngrep -rc '^=== \"' . | awk -F: '$2>0' | wc -l                                             # files with tabs\ngrep -rhoE '\\{\\s*\\.[a-z-]+\\s*\\}' . | sort | uniq -c                                      # attr_list classes\ngrep -rhoE ':[a-z-]+:' . | sort | uniq -c | sort -rn | head                              # emoji \u002F icons\ngrep -rl '--8\u003C--' . | wc -l                                                              # snippets includes\n","bash","",[44,83,84,97,140,174,199,236],{"__ignoreMap":81},[85,86,89,93],"span",{"class":87,"line":88},"line",1,[85,90,92],{"class":91},"sj4cs","cd",[85,94,96],{"class":95},"sZZnC"," docs\n",[85,98,100,104,107,110,113,117,120,123,125,128,130,133,136],{"class":87,"line":99},2,[85,101,103],{"class":102},"sScJk","grep",[85,105,106],{"class":91}," -rhoE",[85,108,109],{"class":95}," '^!!!\\s*\\w+|^\\?\\?\\?\\+?\\s*\\w+'",[85,111,112],{"class":95}," .",[85,114,116],{"class":115},"szBVR"," |",[85,118,119],{"class":102}," awk",[85,121,122],{"class":95}," '{print $1, $2}'",[85,124,116],{"class":115},[85,126,127],{"class":102}," sort",[85,129,116],{"class":115},[85,131,132],{"class":102}," uniq",[85,134,135],{"class":91}," -c",[85,137,139],{"class":138},"sJ8bj","   # admonitions\n",[85,141,143,145,148,151,153,155,157,160,163,165,168,171],{"class":87,"line":142},3,[85,144,103],{"class":102},[85,146,147],{"class":91}," -rc",[85,149,150],{"class":95}," '^=== \"'",[85,152,112],{"class":95},[85,154,116],{"class":115},[85,156,119],{"class":102},[85,158,159],{"class":91}," -F:",[85,161,162],{"class":95}," '$2>0'",[85,164,116],{"class":115},[85,166,167],{"class":102}," wc",[85,169,170],{"class":91}," -l",[85,172,173],{"class":138},"                                             # files with tabs\n",[85,175,177,179,181,184,186,188,190,192,194,196],{"class":87,"line":176},4,[85,178,103],{"class":102},[85,180,106],{"class":91},[85,182,183],{"class":95}," '\\{\\s*\\.[a-z-]+\\s*\\}'",[85,185,112],{"class":95},[85,187,116],{"class":115},[85,189,127],{"class":102},[85,191,116],{"class":115},[85,193,132],{"class":102},[85,195,135],{"class":91},[85,197,198],{"class":138},"                                      # attr_list classes\n",[85,200,202,204,206,209,211,213,215,217,219,221,223,225,228,230,233],{"class":87,"line":201},5,[85,203,103],{"class":102},[85,205,106],{"class":91},[85,207,208],{"class":95}," ':[a-z-]+:'",[85,210,112],{"class":95},[85,212,116],{"class":115},[85,214,127],{"class":102},[85,216,116],{"class":115},[85,218,132],{"class":102},[85,220,135],{"class":91},[85,222,116],{"class":115},[85,224,127],{"class":102},[85,226,227],{"class":91}," -rn",[85,229,116],{"class":115},[85,231,232],{"class":102}," head",[85,234,235],{"class":138},"                              # emoji \u002F icons\n",[85,237,239,241,244,247,249,251,253,255],{"class":87,"line":238},6,[85,240,103],{"class":102},[85,242,243],{"class":91}," -rl",[85,245,246],{"class":95}," '--8\u003C--'",[85,248,112],{"class":95},[85,250,116],{"class":115},[85,252,167],{"class":102},[85,254,170],{"class":91},[85,256,257],{"class":138},"                                                              # snippets includes\n",[14,259,260,261,264,265,268],{},"On the 900-page site the inventory found 2,140 admonitions (of seven types), 186 files with content tabs, 37 files using ",[44,262,263],{},"--8\u003C--"," snippet includes, 412 Material icon shortcodes and 64 ",[44,266,267],{},"attr_list"," class annotations. Those five constructs were the whole conversion job; everything else was already standard Markdown.",[270,271,272,403],"figure",{},[273,274,281,282,281,286,281,290,281,297],"svg",{"viewBox":275,"role":276,"ariaLabelledBy":277,"xmlns":280},"0 0 760 290","img",[278,279],"mks-inv-title","mks-inv-desc","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","\n  ",[283,284,285],"title",{"id":278},"Extension constructs found in a 900-page MkDocs site",[287,288,289],"desc",{"id":279},"Bars of construct counts: 2,140 admonitions, 412 icon shortcodes, 186 files with content tabs, 64 attribute-list annotations and 37 snippet includes. Each bar is labelled with its Starlight equivalent: aside, inline SVG or text, Tabs component, removed or class, and a Markdown import.",[291,292],"rect",{"x":293,"y":293,"width":294,"height":295,"fill":296},"0","760","290","#ffffff",[298,299,301,302,301,310,301,317,301,322,301,331,301,337,301,341,301,346,301,351,301,355,301,362,301,367,301,371,301,377,301,382,301,386,301,392,301,397,281],"g",{"style":300},"font-family:system-ui, sans-serif;font-size:12px","\n    ",[303,304,309],"text",{"x":305,"y":306,"fill":307,"style":308},"380","28","#1f2937","font-size:16px;font-weight:700;text-anchor:middle","Five constructs account for all conversion work",[87,311],{"x1":312,"y1":313,"x2":312,"y2":314,"stroke":315,"style":316},"170","46","256","#d9e2ef","stroke-width:1.5px",[303,318,321],{"x":319,"y":320,"fill":307},"30","74","!!! admonitions",[291,323],{"x":312,"y":324,"width":325,"height":326,"rx":327,"fill":328,"opacity":329,"stroke":328,"style":330},"58","400","24","4","#6a4c93","0.25","stroke-width:1px",[303,332,336],{"x":333,"y":334,"fill":307,"style":335},"580","75","font-weight:700","2,140 → :::aside",[303,338,340],{"x":319,"y":339,"fill":307},"116",":icon: shortcodes",[291,342],{"x":312,"y":343,"width":344,"height":326,"rx":327,"fill":345,"opacity":329,"stroke":345,"style":330},"100","77","#1982c4",[303,347,350],{"x":348,"y":349,"fill":307,"style":335},"257","117","412 → Icon \u002F text",[303,352,354],{"x":319,"y":353,"fill":307},"158","=== tabs (files)",[291,356],{"x":312,"y":357,"width":358,"height":326,"rx":327,"fill":359,"opacity":360,"stroke":361,"style":330},"142","35","#ffca3a","0.35","#a97b00",[303,363,366],{"x":364,"y":365,"fill":307,"style":335},"215","159","186 → \u003CTabs> (MDX)",[303,368,370],{"x":319,"y":369,"fill":307},"200","{ .class } attrs",[291,372],{"x":312,"y":373,"width":374,"height":326,"rx":327,"fill":375,"opacity":329,"stroke":376,"style":330},"184","12","#ff595e","#d83b41",[303,378,381],{"x":379,"y":380,"fill":307,"style":335},"192","201","64 → removed or reviewed by hand",[303,383,385],{"x":319,"y":384,"fill":307},"242","--8\u003C-- snippets",[291,387],{"x":312,"y":388,"width":389,"height":326,"rx":327,"fill":390,"opacity":360,"stroke":391,"style":330},"226","7","#8ac926","#5a8a16",[303,393,396],{"x":394,"y":395,"fill":307,"style":335},"187","243","37 → MDX import",[303,398,402],{"x":305,"y":399,"fill":400,"style":401},"280","#556071","font-size:11px;text-anchor:middle","grep counts across docs\u002F; bar length proportional to occurrences",[404,405,406],"figcaption",{},"Run the inventory first: it turns \"migrate the docs\" into five bounded conversion rules and a short list of files that need a human.",[32,408,410],{"id":409},"convert-with-a-script-not-by-hand","Convert With a Script, Not by Hand",[14,412,413,414,417],{},"A Node script over the files handles the mechanical constructs. Admonitions are the largest group and the easiest: Material's indented body under ",[44,415,416],{},"!!! type \"Title\""," becomes a fenced aside.",[76,419,423],{"className":420,"code":421,"language":422,"meta":81,"style":81},"language-js shiki shiki-themes github-light github-dark","\u002F\u002F scripts\u002Fconvert-mkdocs.mjs (excerpt)\nconst TYPE = { note: 'note', info: 'note', tip: 'tip', success: 'tip',\n  warning: 'caution', danger: 'danger', bug: 'danger', example: 'note' };\n\nexport function convertAdmonitions(src) {\n  return src.replace(\n    \u002F^(!!!|\\?\\?\\?\\+?)\\s+(\\w+)(?:\\s+\"([^\"]*)\")?\\n((?:(?: {4}|\\t).*\\n|\\n)+)\u002Fgm,\n    (_, _kind, type, title, body) => {\n      const t = TYPE[type] ?? 'note';\n      const text = body.replace(\u002F^( {4}|\\t)\u002Fgm, '').trimEnd();\n      return `:::${t}${title ? `[${title}]` : ''}\\n${text}\\n:::\\n\\n`;\n    });\n}\n","js",[44,424,425,430,467,494,500,521,535,638,675,700,748,805,811],{"__ignoreMap":81},[85,426,427],{"class":87,"line":88},[85,428,429],{"class":138},"\u002F\u002F scripts\u002Fconvert-mkdocs.mjs (excerpt)\n",[85,431,432,435,438,441,445,448,451,453,456,459,462,464],{"class":87,"line":99},[85,433,434],{"class":115},"const",[85,436,437],{"class":91}," TYPE",[85,439,440],{"class":115}," =",[85,442,444],{"class":443},"sVt8B"," { note: ",[85,446,447],{"class":95},"'note'",[85,449,450],{"class":443},", info: ",[85,452,447],{"class":95},[85,454,455],{"class":443},", tip: ",[85,457,458],{"class":95},"'tip'",[85,460,461],{"class":443},", success: ",[85,463,458],{"class":95},[85,465,466],{"class":443},",\n",[85,468,469,472,475,478,481,484,486,489,491],{"class":87,"line":142},[85,470,471],{"class":443},"  warning: ",[85,473,474],{"class":95},"'caution'",[85,476,477],{"class":443},", danger: ",[85,479,480],{"class":95},"'danger'",[85,482,483],{"class":443},", bug: ",[85,485,480],{"class":95},[85,487,488],{"class":443},", example: ",[85,490,447],{"class":95},[85,492,493],{"class":443}," };\n",[85,495,496],{"class":87,"line":176},[85,497,499],{"emptyLinePlaceholder":498},true,"\n",[85,501,502,505,508,511,514,518],{"class":87,"line":201},[85,503,504],{"class":115},"export",[85,506,507],{"class":115}," function",[85,509,510],{"class":102}," convertAdmonitions",[85,512,513],{"class":443},"(",[85,515,517],{"class":516},"s4XuR","src",[85,519,520],{"class":443},") {\n",[85,522,523,526,529,532],{"class":87,"line":238},[85,524,525],{"class":115},"  return",[85,527,528],{"class":443}," src.",[85,530,531],{"class":102},"replace",[85,533,534],{"class":443},"(\n",[85,536,538,541,544,548,551,555,558,561,564,567,569,572,574,577,579,581,584,587,589,592,595,598,600,603,606,609,612,614,616,618,620,622,624,626,628,630,633,636],{"class":87,"line":537},7,[85,539,540],{"class":95},"    \u002F",[85,542,543],{"class":115},"^",[85,545,547],{"class":546},"sA_wV","(!!!",[85,549,550],{"class":115},"|",[85,552,554],{"class":553},"snhLl","\\?\\?\\?\\+",[85,556,557],{"class":115},"?",[85,559,560],{"class":546},")",[85,562,563],{"class":91},"\\s",[85,565,566],{"class":115},"+",[85,568,513],{"class":546},[85,570,571],{"class":91},"\\w",[85,573,566],{"class":115},[85,575,576],{"class":546},")(?:",[85,578,563],{"class":91},[85,580,566],{"class":115},[85,582,583],{"class":546},"\"(",[85,585,586],{"class":91},"[",[85,588,543],{"class":115},[85,590,591],{"class":91},"\"]",[85,593,594],{"class":115},"*",[85,596,597],{"class":546},")\")",[85,599,557],{"class":115},[85,601,602],{"class":91},"\\n",[85,604,605],{"class":546},"((?:(?: ",[85,607,608],{"class":115},"{4}|",[85,610,611],{"class":91},"\\t",[85,613,560],{"class":546},[85,615,30],{"class":91},[85,617,594],{"class":115},[85,619,602],{"class":91},[85,621,550],{"class":115},[85,623,602],{"class":91},[85,625,560],{"class":546},[85,627,566],{"class":115},[85,629,560],{"class":546},[85,631,632],{"class":95},"\u002F",[85,634,635],{"class":115},"gm",[85,637,466],{"class":443},[85,639,641,644,647,649,652,654,657,659,661,663,666,669,672],{"class":87,"line":640},8,[85,642,643],{"class":443},"    (",[85,645,646],{"class":516},"_",[85,648,47],{"class":443},[85,650,651],{"class":516},"_kind",[85,653,47],{"class":443},[85,655,656],{"class":516},"type",[85,658,47],{"class":443},[85,660,283],{"class":516},[85,662,47],{"class":443},[85,664,665],{"class":516},"body",[85,667,668],{"class":443},") ",[85,670,671],{"class":115},"=>",[85,673,674],{"class":443}," {\n",[85,676,678,681,684,686,688,691,694,697],{"class":87,"line":677},9,[85,679,680],{"class":115},"      const",[85,682,683],{"class":91}," t",[85,685,440],{"class":115},[85,687,437],{"class":91},[85,689,690],{"class":443},"[type] ",[85,692,693],{"class":115},"??",[85,695,696],{"class":95}," 'note'",[85,698,699],{"class":443},";\n",[85,701,703,705,708,710,713,715,717,719,721,724,726,728,730,732,734,736,739,742,745],{"class":87,"line":702},10,[85,704,680],{"class":115},[85,706,707],{"class":91}," text",[85,709,440],{"class":115},[85,711,712],{"class":443}," body.",[85,714,531],{"class":102},[85,716,513],{"class":443},[85,718,632],{"class":95},[85,720,543],{"class":115},[85,722,723],{"class":546},"( ",[85,725,608],{"class":115},[85,727,611],{"class":91},[85,729,560],{"class":546},[85,731,632],{"class":95},[85,733,635],{"class":115},[85,735,47],{"class":443},[85,737,738],{"class":95},"''",[85,740,741],{"class":443},").",[85,743,744],{"class":102},"trimEnd",[85,746,747],{"class":443},"();\n",[85,749,751,754,757,760,763,765,768,771,773,776,779,782,784,787,789,792,794,797,800,803],{"class":87,"line":750},11,[85,752,753],{"class":115},"      return",[85,755,756],{"class":95}," `:::${",[85,758,759],{"class":443},"t",[85,761,762],{"class":95},"}${",[85,764,283],{"class":443},[85,766,767],{"class":115}," ?",[85,769,770],{"class":95}," `[${",[85,772,283],{"class":443},[85,774,775],{"class":95},"}]`",[85,777,778],{"class":115}," :",[85,780,781],{"class":95}," ''}",[85,783,602],{"class":91},[85,785,786],{"class":95},"${",[85,788,303],{"class":443},[85,790,791],{"class":95},"}",[85,793,602],{"class":91},[85,795,796],{"class":95},":::",[85,798,799],{"class":91},"\\n\\n",[85,801,802],{"class":95},"`",[85,804,699],{"class":443},[85,806,808],{"class":87,"line":807},12,[85,809,810],{"class":443},"    });\n",[85,812,814],{"class":87,"line":813},13,[85,815,816],{"class":443},"}\n",[14,818,819,820,823,824,827,828,831,832,835,836,839,840,843,844,847,848,851],{},"Content tabs need MDX. Files containing ",[44,821,822],{},"=== \"Tab\""," blocks are renamed to ",[44,825,826],{},".mdx",", get ",[44,829,830],{},"import { Tabs, TabItem } from '@astrojs\u002Fstarlight\u002Fcomponents';"," at the top, and each tab group becomes a ",[44,833,834],{},"\u003CTabs>"," element with ",[44,837,838],{},"\u003CTabItem label=\"...\">"," children. Snippet includes (",[44,841,842],{},"--8\u003C-- \"path\"",") become MDX imports of the referenced file rendered as a component, or — for code samples — Starlight's ",[44,845,846],{},"\u003CCode code={...} lang=\"...\" \u002F>"," fed from a ",[44,849,850],{},"?raw"," import.",[14,853,854,855,858,859,861,862,865],{},"Icon shortcodes such as ",[44,856,857],{},":material-check:"," were replaced with plain text in tables (\"Yes\") and removed in headings, where they had been decorative. The 64 ",[44,860,267],{}," annotations were reviewed by hand: 51 were button styles on links, which became a small ",[44,863,864],{},"\u003CLinkButton>"," component, and 13 were obsolete.",[14,867,868],{},"Run the script, build, and commit the output in one pull request per top-level section so reviewers see bounded diffs.",[32,870,872],{"id":871},"rebuild-navigation-from-mkdocsyml","Rebuild Navigation From mkdocs.yml",[14,874,875,876,879,880,883,884,887,888,890,891,894,895,30],{},"MkDocs defines navigation explicitly in ",[44,877,878],{},"nav:","; Starlight takes a ",[44,881,882],{},"sidebar"," array. Translating is a thirty-line script that walks the YAML tree and emits Starlight entries, with one rule: where a MkDocs section lists every file in a folder in alphabetical order, emit ",[44,885,886],{},"autogenerate: { directory }"," instead of an explicit list, so new pages appear without config changes. Ordering that was explicit in ",[44,889,46],{}," becomes ",[44,892,893],{},"sidebar: { order: n }"," in each page's front matter, a conversion covered in general in ",[21,896,898],{"href":897},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fconverting-front-matter-at-scale-during-migration\u002F","Converting Front Matter at Scale During Migration",[14,900,901,902,905],{},"Material's top-level navigation tabs (",[44,903,904],{},"navigation.tabs",") have no direct Starlight equivalent. The site used five tabs; they became five top-level sidebar groups, with the most-used group expanded by default and the others collapsed, which usability sessions showed readers found as quickly as the tabs.",[32,907,909],{"id":908},"keep-every-url","Keep Every URL",[14,911,912,913,916,917,920,921,924,925,928,929,932,933,936],{},"MkDocs publishes ",[44,914,915],{},"docs\u002Fguides\u002Finstall.md"," at ",[44,918,919],{},"\u002Fguides\u002Finstall\u002F","; Starlight with ",[44,922,923],{},"trailingSlash: 'always'"," publishes ",[44,926,927],{},"src\u002Fcontent\u002Fdocs\u002Fguides\u002Finstall.md"," at the same path. The two differences to handle are case (MkDocs keeps filename case; Starlight lowercases slugs) and ",[44,930,931],{},"index.md"," versus ",[44,934,935],{},"README.md"," handling. Generate the old URL list from the production sitemap, the new list from the Starlight build, and diff them in CI:",[76,938,940],{"className":78,"code":939,"language":80,"meta":81,"style":81},"curl -s https:\u002F\u002Fdocs.example.com\u002Fsitemap.xml | grep -oP '(?\u003C=\u003Cloc>)[^\u003C]+' \\\n  | sed 's#https:\u002F\u002Fdocs.example.com##' | sort > old.txt\nfind dist -name index.html | sed 's#^dist##; s#index.html$##' | sort > new.txt\ncomm -23 old.txt new.txt > missing.txt && wc -l missing.txt\n",[44,941,942,967,988,1018],{"__ignoreMap":81},[85,943,944,947,950,953,955,958,961,964],{"class":87,"line":88},[85,945,946],{"class":102},"curl",[85,948,949],{"class":91}," -s",[85,951,952],{"class":95}," https:\u002F\u002Fdocs.example.com\u002Fsitemap.xml",[85,954,116],{"class":115},[85,956,957],{"class":102}," grep",[85,959,960],{"class":91}," -oP",[85,962,963],{"class":95}," '(?\u003C=\u003Cloc>)[^\u003C]+'",[85,965,966],{"class":91}," \\\n",[85,968,969,972,975,978,980,982,985],{"class":87,"line":99},[85,970,971],{"class":115},"  |",[85,973,974],{"class":102}," sed",[85,976,977],{"class":95}," 's#https:\u002F\u002Fdocs.example.com##'",[85,979,116],{"class":115},[85,981,127],{"class":102},[85,983,984],{"class":115}," >",[85,986,987],{"class":95}," old.txt\n",[85,989,990,993,996,999,1002,1004,1006,1009,1011,1013,1015],{"class":87,"line":142},[85,991,992],{"class":102},"find",[85,994,995],{"class":95}," dist",[85,997,998],{"class":91}," -name",[85,1000,1001],{"class":95}," index.html",[85,1003,116],{"class":115},[85,1005,974],{"class":102},[85,1007,1008],{"class":95}," 's#^dist##; s#index.html$##'",[85,1010,116],{"class":115},[85,1012,127],{"class":102},[85,1014,984],{"class":115},[85,1016,1017],{"class":95}," new.txt\n",[85,1019,1020,1023,1026,1029,1032,1034,1037,1040,1043,1045],{"class":87,"line":176},[85,1021,1022],{"class":102},"comm",[85,1024,1025],{"class":91}," -23",[85,1027,1028],{"class":95}," old.txt",[85,1030,1031],{"class":95}," new.txt",[85,1033,984],{"class":115},[85,1035,1036],{"class":95}," missing.txt",[85,1038,1039],{"class":443}," && ",[85,1041,1042],{"class":102},"wc",[85,1044,170],{"class":91},[85,1046,1047],{"class":95}," missing.txt\n",[14,1049,1050,1051,1054,1055,30],{},"The first run reported 23 missing URLs, all from mixed-case filenames. Each got a redirect in the host's ",[44,1052,1053],{},"_redirects"," file, and the diff became a required CI check — the technique from ",[21,1056,1058],{"href":1057},"\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",[270,1060,1061,1181],{},[273,1062,281,1067,281,1070,281,1073,281,1076,281,1167],{"viewBox":1063,"role":276,"ariaLabelledBy":1064,"xmlns":280},"0 0 760 270",[1065,1066],"mks-url-title","mks-url-desc",[283,1068,1069],{"id":1065},"URL parity check between the old and new site",[287,1071,1072],{"id":1066},"The production sitemap yields 912 old URLs and the Starlight build yields 889 new ones. A comm diff finds 23 URLs missing from the new build, all caused by mixed-case filenames. Each gets a redirect rule, bringing unresolved URLs to zero, and the check runs on every pull request.",[291,1074],{"x":293,"y":293,"width":294,"height":1075,"fill":296},"270",[298,1077,301,1078,301,1081,301,1086,301,1092,301,1096,301,1100,301,1104,301,1108,301,1113,301,1118,301,1122,301,1127,301,1130,301,1133,301,1137,301,1141,301,1144,301,1163,281],{"style":300},[303,1079,1080],{"x":305,"y":306,"fill":307,"style":308},"A URL diff in CI makes \"no broken links\" a checked fact",[291,1082],{"x":319,"y":1083,"width":312,"height":1083,"rx":1084,"fill":1085,"stroke":315,"style":316},"60","10","#f8fafc",[303,1087,1091],{"x":1088,"y":1089,"fill":307,"style":1090},"115","86","font-weight:700;text-anchor:middle","old sitemap",[303,1093,1095],{"x":1088,"y":1094,"fill":400,"style":401},"106","912 URLs",[291,1097],{"x":319,"y":1098,"width":312,"height":1083,"rx":1084,"fill":328,"opacity":1099,"stroke":328,"style":316},"150","0.12",[303,1101,1103],{"x":1088,"y":1102,"fill":307,"style":1090},"176","Starlight build",[303,1105,1107],{"x":1088,"y":1106,"fill":400,"style":401},"196","889 URLs",[291,1109],{"x":1075,"y":1110,"width":1111,"height":1083,"rx":1084,"fill":359,"opacity":1112,"stroke":361,"style":316},"105","140","0.26",[303,1114,1117],{"x":1115,"y":1116,"fill":307,"style":1090},"340","131","comm -23",[303,1119,1121],{"x":1115,"y":1120,"fill":400,"style":401},"151","23 missing",[291,1123],{"x":1124,"y":1110,"width":1125,"height":1083,"rx":1084,"fill":375,"opacity":1126,"stroke":376,"style":316},"470","120","0.14",[303,1128,1053],{"x":1129,"y":1116,"fill":307,"style":1090},"530",[303,1131,1132],{"x":1129,"y":1120,"fill":400,"style":401},"23 × 301",[291,1134],{"x":1135,"y":1110,"width":343,"height":1083,"rx":1084,"fill":390,"opacity":1136,"stroke":391,"style":316},"640","0.18",[303,1138,1140],{"x":1139,"y":1116,"fill":307,"style":1090},"690","0 broken",[303,1142,1143],{"x":1139,"y":1120,"fill":400,"style":401},"required check",[298,1145,1148,1149,1148,1154,1148,1157,1148,1160,301],{"stroke":400,"fill":1146,"style":1147},"none","stroke-width:2px","\n      ",[1150,1151],"path",{"d":1152,"style":1153},"M202 90 L266 124","marker-end:url(#mks-url-arrow)",[1150,1155],{"d":1156,"style":1153},"M202 180 L266 146",[1150,1158],{"d":1159,"style":1153},"M412 135 L466 135",[1150,1161],{"d":1162,"style":1153},"M592 135 L636 135",[303,1164,1166],{"x":305,"y":1165,"fill":400,"style":401},"244","All 23 misses came from mixed-case filenames that Starlight lowercases",[1168,1169,301,1170,281],"defs",{},[1171,1172,1148,1178,301],"marker",{"id":1173,"viewBox":1174,"refX":1175,"refY":1176,"markerWidth":389,"markerHeight":389,"orient":1177},"mks-url-arrow","0 0 10 10","8","5","auto-start-reverse",[1150,1179],{"d":1180,"fill":400},"M0 0 L10 5 L0 10 z",[404,1182,1183],{},"The check is cheap enough to keep forever, and it is what lets the cutover be reversible rather than hopeful.",[32,1185,1187],{"id":1186},"search","Search",[14,1189,1190,1191,30],{},"Material's built-in search builds a lunr index at build time and ships it as one JSON file — 3.8 MB uncompressed on this site, downloaded in full on the first search. Starlight's Pagefind indexes the built HTML into fragments and downloads only what a query needs: the first query fetched 96 KB. Search quality was comparable in spot checks of the fifty most common queries from the old analytics; Pagefind ranked the expected page first in 44 of 50 against 41 for lunr. The trade-offs are covered in ",[21,1192,1194],{"href":1193},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002F","Search for Static Sites",[32,1196,1198],{"id":1197},"measured-impact","Measured Impact",[14,1200,1201,1202,1205],{},"Both sites were built on the same GitHub Actions runner and timed with ",[44,1203,1204],{},"hyperfine"," over five runs; page metrics are Lighthouse 12 mobile medians over five templates.",[1207,1208,1209,1225],"table",{},[1210,1211,1212],"thead",{},[1213,1214,1215,1219,1222],"tr",{},[1216,1217,1218],"th",{},"Measure",[1216,1220,1221],{},"Material for MkDocs 9.5",[1216,1223,1224],{},"Starlight 0.34",[1226,1227,1228,1240,1251,1262,1273,1284],"tbody",{},[1213,1229,1230,1234,1237],{},[1231,1232,1233],"td",{},"Cold build",[1231,1235,1236],{},"142 s",[1231,1238,1239],{},"47 s",[1213,1241,1242,1245,1248],{},[1231,1243,1244],{},"Warm build (one page changed)",[1231,1246,1247],{},"139 s (no incremental mode used)",[1231,1249,1250],{},"16 s",[1213,1252,1253,1256,1259],{},[1231,1254,1255],{},"Compressed JS per page",[1231,1257,1258],{},"38 KB",[1231,1260,1261],{},"11 KB",[1213,1263,1264,1267,1270],{},[1231,1265,1266],{},"First search download",[1231,1268,1269],{},"3.8 MB index (610 KB compressed)",[1231,1271,1272],{},"96 KB",[1213,1274,1275,1278,1281],{},[1231,1276,1277],{},"Lab LCP, simulated 4G",[1231,1279,1280],{},"1.5 s",[1231,1282,1283],{},"1.1 s",[1213,1285,1286,1289,1292],{},[1231,1287,1288],{},"Engineer time to migrate",[1231,1290,1291],{},"—",[1231,1293,1294],{},"4 days",[270,1296,1297,1363],{},[273,1298,281,1303,281,1306,281,1309,281,1312],{"viewBox":1299,"role":276,"ariaLabelledBy":1300,"xmlns":280},"0 0 760 260",[1301,1302],"mks-build-title","mks-build-desc",[283,1304,1305],{"id":1301},"Build time before and after migration",[287,1307,1308],{"id":1302},"Paired bars for cold and warm builds. MkDocs took 142 seconds cold and 139 warm. Starlight took 47 seconds cold and 16 warm, because Astro's content layer skips unchanged entries.",[291,1310],{"x":293,"y":293,"width":294,"height":1311,"fill":296},"260",[298,1313,301,1314,301,1317,301,1321,301,1327,301,1331,301,1334,301,1339,301,1343,301,1346,301,1351,301,1355,301,1359,281],{"style":300},[303,1315,1316],{"x":305,"y":306,"fill":307,"style":308},"Seconds per build, 900 pages",[303,1318,1320],{"x":319,"y":1319,"fill":307,"style":335},"80","Cold",[291,1322],{"x":1323,"y":1324,"width":1325,"height":1326,"rx":327,"fill":375,"opacity":329,"stroke":376,"style":330},"130","62","497","20",[303,1328,1330],{"x":1329,"y":344,"fill":307},"637","MkDocs 142 s",[291,1332],{"x":1323,"y":1089,"width":1333,"height":1326,"rx":327,"fill":328,"opacity":329,"stroke":328,"style":330},"165",[303,1335,1338],{"x":1336,"y":1337,"fill":307},"305","101","Starlight 47 s",[303,1340,1342],{"x":319,"y":1341,"fill":307,"style":335},"160","One page edited",[291,1344],{"x":1323,"y":357,"width":1345,"height":1326,"rx":327,"fill":375,"opacity":329,"stroke":376,"style":330},"487",[303,1347,1350],{"x":1348,"y":1349,"fill":307},"627","157","MkDocs 139 s",[291,1352],{"x":1323,"y":1353,"width":1354,"height":1326,"rx":327,"fill":328,"opacity":329,"stroke":328,"style":330},"166","56",[303,1356,1358],{"x":1106,"y":1357,"fill":307},"181","Starlight 16 s",[303,1360,1362],{"x":305,"y":1361,"fill":400,"style":401},"236","hyperfine, 5 runs, GitHub Actions ubuntu-latest; content-layer cache persisted between runs",[404,1364,1365],{},"The cold build improved threefold; the edit-one-page case, which is what writers actually wait on, improved almost ninefold.",[32,1367,1369],{"id":1368},"pitfalls-rollback","Pitfalls & Rollback",[37,1371,1372,1387,1393,1410,1420],{},[40,1373,1374,1382,1383,1386],{},[1375,1376,1377,1378,1381],"strong",{},"Leaving ",[44,1379,1380],{},"!!!"," in plain text."," Any admonition the regex misses renders as literal exclamation marks. After conversion, ",[44,1384,1385],{},"grep -rn '^!!!' src\u002Fcontent\u002Fdocs"," must return nothing; make it a CI check.",[40,1388,1389,1392],{},[1375,1390,1391],{},"Indented code inside admonitions."," Material bodies are indented four spaces; a code fence inside a body is indented eight. Dedent by exactly one level, or code blocks lose their fences.",[40,1394,1395,1398,1399,1401,1402,1405,1406,1409],{},[1375,1396,1397],{},"MDX surprises in converted files."," Only files with tabs or imports should become ",[44,1400,826],{},". Plain Markdown stays ",[44,1403,1404],{},".md"," so a stray ",[44,1407,1408],{},"{"," in prose does not break the build.",[40,1411,1412,1419],{},[1375,1413,1414,1415,1418],{},"Lost ",[44,1416,1417],{},"mkdocs-macros"," output."," If the site used the macros plugin, its Jinja expressions render literally. Replace them with Astro components or build-time data before cutover.",[40,1421,1422,1425],{},[1375,1423,1424],{},"Rollback:"," keep the MkDocs build deployable until the Starlight site has run two weeks without a missing-URL report. Cutover is a DNS or routing change; so is reverting it.",[32,1427,1429],{"id":1428},"conclusion","Conclusion",[14,1431,1432],{},"A Material for MkDocs to Starlight migration is a bounded job once the extension inventory exists: five conversion rules, a navigation script, a URL diff in CI and a search swap. On this 900-page site it took four engineer-days, cut cold builds from 142 to 47 seconds and single-page rebuilds from 139 to 16, and removed a 3.8 MB search index from the first query. If your MkDocs site is small, fast and loved, stay — but if build time or component needs are pushing you out, this is the lowest-friction exit.",[32,1434,1436],{"id":1435},"faq","FAQ",[1438,1439,1441],"h3",{"id":1440},"why-would-a-team-leave-mkdocs-at-all","Why would a team leave MkDocs at all?",[14,1443,1444],{},"Usually for build speed on large sites, component-based content, or to consolidate onto a JavaScript toolchain the rest of the team already uses. Material for MkDocs remains an excellent choice for small to medium Python-centric projects.",[1438,1446,1448],{"id":1447},"how-do-mkdocs-admonitions-map-to-starlight","How do MkDocs admonitions map to Starlight?",[14,1450,1451],{},"Material's !!! note blocks become Starlight asides written with :::note and a closing :::. The four Starlight types are note, tip, caution and danger, so warning and similar Material types need mapping to the closest one.",[1438,1453,1455],{"id":1454},"will-my-urls-change","Will my URLs change?",[14,1457,1458],{},"They can keep the same form. MkDocs serves directory-style URLs with trailing slashes by default, and Starlight does the same when trailingSlash is set to always. Files named index.md map identically; renamed or moved files need redirects.",[1438,1460,1462],{"id":1461},"how-long-does-a-migration-take","How long does a migration take?",[14,1464,1465],{},"For a 900-page site with a conversion script, about four engineer-days including navigation, redirects and review. The conversion itself runs in seconds; the time goes on edge cases such as nested tabs and custom Markdown extensions.",[32,1467,1469],{"id":1468},"related","Related",[37,1471,1472,1481,1488,1495,1502],{},[40,1473,1474,1477,1478,1480],{},[1375,1475,1476],{},"Parent:"," ",[21,1479,24],{"href":23}," — why Starlight is the landing spot.",[40,1482,1483,1487],{},[21,1484,1486],{"href":1485},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-a-docs-site-from-jekyll-to-hugo\u002F","Migrating a Docs Site from Jekyll to Hugo"," — the same playbook between two other generators.",[40,1489,1490,1494],{},[21,1491,1493],{"href":1492},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fporting-shortcodes-and-includes-between-generators\u002F","Porting Shortcodes and Includes Between Generators"," — converting extension syntax in general.",[40,1496,1497,1501],{},[21,1498,1500],{"href":1499},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fcustomizing-starlight-without-forking-the-theme\u002F","Customizing Starlight Without Forking the Theme"," — matching Material's look afterwards.",[40,1503,1504,1508],{},[21,1505,1507],{"href":1506},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fadding-pagefind-to-an-astro-site\u002F","Adding Pagefind to an Astro Site"," — how the new search works under the hood.",[1510,1511,1512],"style",{},"html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}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}",{"title":81,"searchDepth":99,"depth":99,"links":1514},[1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,1530],{"id":34,"depth":99,"text":35},{"id":70,"depth":99,"text":71},{"id":409,"depth":99,"text":410},{"id":871,"depth":99,"text":872},{"id":908,"depth":99,"text":909},{"id":1186,"depth":99,"text":1187},{"id":1197,"depth":99,"text":1198},{"id":1368,"depth":99,"text":1369},{"id":1428,"depth":99,"text":1429},{"id":1435,"depth":99,"text":1436,"children":1525},[1526,1527,1528,1529],{"id":1440,"depth":142,"text":1441},{"id":1447,"depth":142,"text":1448},{"id":1454,"depth":142,"text":1455},{"id":1461,"depth":142,"text":1462},{"id":1468,"depth":99,"text":1469},[1532,1534,1537,1538],{"name":1533,"item":632},"Home",{"name":1535,"item":1536},"Choosing the Right Static Site Generator for Production","\u002Fchoosing-the-right-static-site-generator-for-production\u002F",{"name":24,"item":23},{"name":5,"item":1539},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight\u002F","2026-09-18","Move a Material for MkDocs site to Starlight: convert admonitions and tabs, rebuild navigation from mkdocs.yml, keep every URL and cut build time by two thirds.","md",[1544,1545,1546,1547],{"q":1441,"a":1444},{"q":1448,"a":1451},{"q":1455,"a":1458},{"q":1462,"a":1465},{},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight",{"title":5,"description":1541},"choosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmigrating-from-mkdocs-to-starlight\u002Findex","article","IkrHvy8yXtQnFpwVbEWNFXU66Bu3b3jsMKrQxiQNPhQ",[1555,1558,1561,1564,1567,1570,1573,1575,1578,1580,1583,1584,1587,1590,1593,1596,1599,1602,1605,1608,1610,1613,1616,1619,1622,1625,1628,1630,1632,1634,1637,1640,1643,1646,1648,1651,1654,1657,1660,1663,1666,1668,1671,1673,1676,1679,1682,1685,1688,1691,1694,1697,1700,1703,1706,1709,1712,1715,1718,1721,1724,1727,1730,1733,1736,1739,1742,1745,1748,1751,1754,1757,1760,1763,1766,1769,1772,1775,1778,1781,1784,1787,1790,1793,1796,1799,1802,1805,1808,1811,1814,1817,1820,1823,1826,1829,1832,1835,1838,1841,1844,1847,1850,1853,1856,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,1937,1940,1943,1946,1949,1952,1955,1958,1961,1964,1967,1970,1973,1976,1979,1982,1985,1988,1991,1994,1997,2000,2003,2006,2009,2012,2015,2018,2021,2024,2027,2030,2033,2036,2039,2042,2045,2048,2051,2054,2057,2060,2063,2066,2069,2072,2075,2078,2081,2084,2087,2090],{"path":1556,"title":1557},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fastro-vs-eleventy-build-times-at-10000-pages","Astro vs Eleventy Build Times at 10,000 Pages",{"path":1559,"title":1560},"\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":1562,"title":1563},"\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":1565,"title":1566},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites","Astro vs Eleventy for Documentation Sites",{"path":1568,"title":1569},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fshortcodes-vs-components-for-docs-authors","Shortcodes vs Components for Docs Authors",{"path":1571,"title":1572},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fastro-vs-eleventy-for-documentation-sites\u002Fsidebar-navigation-in-astro-and-eleventy","Sidebar Navigation in Astro and Eleventy",{"path":1574,"title":1500},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fcustomizing-starlight-without-forking-the-theme",{"path":1576,"title":1577},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fdocusaurus-vs-starlight-for-product-documentation","Docusaurus vs Starlight for Product Documentation",{"path":1579,"title":24},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress",{"path":1581,"title":1582},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fmdx-vs-markdoc-for-docs-content","MDX vs Markdoc for Docs Content",{"path":1549,"title":5},{"path":1585,"title":1586},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fversioned-documentation-with-docusaurus","Versioned Documentation with Docusaurus",{"path":1588,"title":1589},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fdocs-frameworks-docusaurus-starlight-vitepress\u002Fvitepress-for-library-documentation","VitePress for Library Documentation",{"path":1591,"title":1592},"\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":1594,"title":1595},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Fhugo-partialcached-for-faster-builds","Hugo partialCached for Faster Builds",{"path":1597,"title":1598},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories","Hugo Build Times for Large Repositories",{"path":1600,"title":1601},"\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":1603,"title":1604},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fhugo-build-times-for-large-repositories\u002Freducing-hugo-memory-usage-on-ci-runners","Reducing Hugo Memory Usage on CI Runners",{"path":1606,"title":1607},"\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":1609,"title":1535},"\u002Fchoosing-the-right-static-site-generator-for-production",{"path":1611,"title":1612},"\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":1614,"title":1615},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem","Jekyll Plugin Ecosystem",{"path":1617,"title":1618},"\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":1620,"title":1621},"\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":1623,"title":1624},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fspeeding-up-slow-jekyll-builds","Speeding Up Slow Jekyll Builds",{"path":1626,"title":1627},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fjekyll-plugin-ecosystem\u002Fupgrading-jekyll-and-ruby-versions-safely","Upgrading Jekyll and Ruby Versions Safely",{"path":1629,"title":898},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fconverting-front-matter-at-scale-during-migration",{"path":1631,"title":29},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators",{"path":1633,"title":1058},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fkeeping-redirects-working-after-an-ssg-migration",{"path":1635,"title":1636},"\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":1638,"title":1639},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-from-gatsby-to-astro","Migrating from Gatsby to Astro",{"path":1641,"title":1642},"\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":1644,"title":1645},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fmigrating-wordpress-to-a-static-site-generator","Migrating WordPress to a Static Site Generator",{"path":1647,"title":1493},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fmigrating-between-static-site-generators\u002Fporting-shortcodes-and-includes-between-generators",{"path":1649,"title":1650},"\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":1652,"title":1653},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites","Next.js Static Export for Content Sites",{"path":1655,"title":1656},"\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":1658,"title":1659},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Fnextjs-app-router-static-export-limitations","Next.js App Router Static Export Limitations",{"path":1661,"title":1662},"\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":1664,"title":1665},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fnextjs-static-export-for-content-sites\u002Foptimizing-images-in-nextjs-static-export","Optimizing Images in Next.js Static Export",{"path":1667,"title":1507},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fadding-pagefind-to-an-astro-site",{"path":1669,"title":1670},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fbuilding-a-lunr-index-at-build-time-in-eleventy","Building a Lunr Index at Build Time in Eleventy",{"path":1672,"title":1194},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites",{"path":1674,"title":1675},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Findexing-hugo-sites-with-pagefind","Indexing Hugo Sites with Pagefind",{"path":1677,"title":1678},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fmultilingual-search-on-static-sites","Multilingual Search on Static Sites",{"path":1680,"title":1681},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fpagefind-vs-algolia-docsearch","Pagefind vs Algolia DocSearch",{"path":1683,"title":1684},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fsearch-for-static-sites\u002Fsearch-index-size-budgets-for-large-docs","Search Index Size Budgets for Large Docs",{"path":1686,"title":1687},"\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":1689,"title":1690},"\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":1692,"title":1693},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Fevaluating-ssg-accessibility-defaults","Evaluating SSG Accessibility Defaults",{"path":1695,"title":1696},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix","SSG Framework Selection Matrix",{"path":1698,"title":1699},"\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":1701,"title":1702},"\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":1704,"title":1705},"\u002Fchoosing-the-right-static-site-generator-for-production\u002Fssg-framework-selection-matrix\u002Ftotal-cost-of-ownership-for-static-site-generators","Total Cost of Ownership for Static Site Generators",{"path":1707,"title":1708},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fcache-busting-with-content-hashed-filenames","Cache Busting with Content-Hashed Filenames",{"path":1710,"title":1711},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs","CDN Caching Rules for SSGs",{"path":1713,"title":1714},"\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":1716,"title":1717},"\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":1719,"title":1720},"\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":1722,"title":1723},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcdn-caching-rules-for-ssgs\u002Fstale-while-revalidate-for-static-html","Stale-While-Revalidate for Static HTML",{"path":1725,"title":1726},"\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":1728,"title":1729},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-cookie-banners","Fixing CLS from Cookie Banners",{"path":1731,"title":1732},"\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":1734,"title":1735},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites\u002Ffixing-cls-from-sticky-headers-and-anchor-links","Fixing CLS from Sticky Headers and Anchor Links",{"path":1737,"title":1738},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fcumulative-layout-shift-fixes-for-static-sites","Cumulative Layout Shift Fixes for Static Sites",{"path":1740,"title":1741},"\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":1743,"title":1744},"\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":1746,"title":1747},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Ffont-display-optional-vs-swap","font-display: optional vs swap",{"path":1749,"title":1750},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites","Font Loading Strategies for Static Sites",{"path":1752,"title":1753},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fmetric-matched-fallback-fonts-with-size-adjust","Metric-Matched Fallback Fonts with size-adjust",{"path":1755,"title":1756},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Ffont-loading-strategies-for-static-sites\u002Fpreloading-fonts-without-double-downloads","Preloading Fonts Without Double Downloads",{"path":1758,"title":1759},"\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":1761,"title":1762},"\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":1764,"title":1765},"\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":1767,"title":1768},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fgenerating-open-graph-images-at-build-time","Generating Open Graph Images at Build Time",{"path":1770,"title":1771},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro","Image Optimization Pipelines in Astro",{"path":1773,"title":1774},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Flazy-loading-images-without-hurting-lcp","Lazy-Loading Images Without Hurting LCP",{"path":1776,"title":1777},"\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":1779,"title":1780},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fimage-optimization-pipelines-in-astro\u002Fresponsive-images-with-srcset-in-eleventy","Responsive Images with srcset in Eleventy",{"path":1782,"title":1783},"\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":1785,"title":1786},"\u002Fperformance-optimization-core-web-vitals-for-ssgs","Core Web Vitals Optimization for SSGs",{"path":1788,"title":1789},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fastro-islands-vs-full-hydration-performance","Astro Islands vs Full Hydration Performance",{"path":1791,"title":1792},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Fdeferring-hydration-with-client-visible-in-astro","Deferring Hydration with client:visible in Astro",{"path":1794,"title":1795},"\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":1797,"title":1798},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering","JavaScript Hydration & Partial Rendering",{"path":1800,"title":1801},"\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":1803,"title":1804},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fjavascript-hydration-partial-rendering\u002Freplacing-react-islands-with-web-components","Replacing React Islands with Web Components",{"path":1806,"title":1807},"\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":1809,"title":1810},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Ffixing-lcp-on-text-heavy-documentation-pages","Fixing LCP on Text-Heavy Documentation Pages",{"path":1812,"title":1813},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites","Largest Contentful Paint Optimization for Static Sites",{"path":1815,"title":1816},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Flargest-contentful-paint-optimization-for-static-sites\u002Fmeasuring-lcp-subparts-with-devtools","Measuring LCP Subparts with DevTools",{"path":1818,"title":1819},"\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":1821,"title":1822},"\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":1824,"title":1825},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fcomparing-lab-and-field-data-with-crux","Comparing Lab and Field Data with CrUX",{"path":1827,"title":1828},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci","Performance Budgets and Lighthouse CI",{"path":1830,"title":1831},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Freducing-lighthouse-score-variance-in-ci","Reducing Lighthouse Score Variance in CI",{"path":1833,"title":1834},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Frunning-webpagetest-scripts-against-preview-deploys","Running WebPageTest Scripts Against Preview Deploys",{"path":1836,"title":1837},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fsetting-up-lighthouse-ci-for-a-static-site","Setting Up Lighthouse CI for a Static Site",{"path":1839,"title":1840},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Ftracking-bundle-size-per-pull-request","Tracking Bundle Size per Pull Request",{"path":1842,"title":1843},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fperformance-budgets-and-lighthouse-ci\u002Fwriting-a-performance-budget-that-fails-builds","Writing a Performance Budget That Fails Builds",{"path":1845,"title":1846},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fauditing-unused-preloads","Auditing Unused Preloads",{"path":1848,"title":1849},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed","Resource Hints and Navigation Speed",{"path":1851,"title":1852},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Finstant-navigation-with-speculation-rules","Instant Navigation with Speculation Rules",{"path":1854,"title":1855},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fpreconnect-vs-dns-prefetch-on-static-sites","Preconnect vs DNS-Prefetch on Static Sites",{"path":1857,"title":1858},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fprefetching-links-in-astro","Prefetching Links in Astro",{"path":1860,"title":1861},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fresource-hints-and-navigation-speed\u002Fview-transitions-on-multi-page-static-sites","View Transitions on Multi-Page Static Sites",{"path":1863,"title":1864},"\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":1866,"title":1867},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites","Third-Party Script Performance on Static Sites",{"path":1869,"title":1870},"\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":1872,"title":1873},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Floading-google-tag-manager-without-hurting-inp","Loading Google Tag Manager Without Hurting INP",{"path":1875,"title":1876},"\u002Fperformance-optimization-core-web-vitals-for-ssgs\u002Fthird-party-script-performance-on-static-sites\u002Frunning-third-party-scripts-in-a-web-worker-with-partytown","Running Third-Party Scripts in a Web Worker with Partytown",{"path":1878,"title":1879},"\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":1881,"title":1882},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fautomating-eleventy-deployments-with-cloudflare-pages","Automating Eleventy Deployments on Cloudflare Pages",{"path":1884,"title":1885},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fconfiguring-redirects-on-cloudflare-pages","Configuring Redirects on Cloudflare Pages",{"path":1887,"title":1888},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fcustom-domains-and-tls-on-cloudflare-pages","Custom Domains and TLS on Cloudflare Pages",{"path":1890,"title":1891},"\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":1893,"title":1894},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup","Cloudflare Pages Edge Caching Setup",{"path":1896,"title":1897},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcloudflare-pages-edge-caching-setup\u002Fmigrating-from-cloudflare-pages-to-workers-static-assets","Migrating from Cloudflare Pages to Workers Static Assets",{"path":1899,"title":1900},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Fchecking-links-in-pull-requests","Checking Links in Pull Requests",{"path":1902,"title":1903},"\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":1905,"title":1906},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams\u002Feditorial-checks-with-vale-in-ci","Editorial Checks with Vale in CI",{"path":1908,"title":1909},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fcontent-workflows-for-documentation-teams","Content Workflows for Documentation Teams",{"path":1911,"title":1912},"\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":1914,"title":1915},"\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":1917,"title":1918},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fbuilding-astro-sites-with-github-actions","Building Astro Sites with GitHub Actions",{"path":1920,"title":1921},"\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":1923,"title":1924},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fdeploying-to-github-pages-with-actions","Deploying to GitHub Pages with Actions",{"path":1926,"title":1927},"\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":1929,"title":1930},"\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":1932,"title":1933},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds","GitHub Actions for Automated SSG Builds",{"path":1935,"title":1936},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fgithub-actions-for-automated-ssg-builds\u002Fmatrix-builds-for-multi-site-monorepos","Matrix Builds for Multi-Site Monorepos",{"path":1938,"title":1939},"\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":1941,"title":1942},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fenabling-incremental-builds-in-eleventy","Enabling Incremental Builds in Eleventy",{"path":1944,"title":1945},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fincremental-builds-in-astro-with-the-content-layer","Incremental Builds in Astro with the Content Layer",{"path":1947,"title":1948},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs","Incremental Builds and Build Caching for SSGs",{"path":1950,"title":1951},"\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":1953,"title":1954},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fincremental-builds-and-build-caching-for-ssgs\u002Fremote-caching-with-turborepo-for-ssg-monorepos","Remote Caching with Turborepo for SSG Monorepos",{"path":1956,"title":1957},"\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":1959,"title":1960},"\u002Fproduction-ready-deployment-cicd-workflows","Production-Ready Deployment & CI\u002FCD for SSGs",{"path":1962,"title":1963},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Falerting-on-cache-hit-ratio-drops","Alerting on Cache Hit Ratio Drops",{"path":1965,"title":1966},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fbuilding-a-core-web-vitals-dashboard-from-rum-data","Building a Core Web Vitals Dashboard from RUM Data",{"path":1968,"title":1969},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fcrawling-for-broken-links-on-a-schedule","Crawling for Broken Links on a Schedule",{"path":1971,"title":1972},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production","Monitoring Static Sites in Production",{"path":1974,"title":1975},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Flogging-404s-at-the-edge","Logging 404s at the Edge",{"path":1977,"title":1978},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fmonitoring-static-sites-in-production\u002Fuptime-and-synthetic-checks-for-static-sites","Uptime and Synthetic Checks for Static Sites",{"path":1980,"title":1981},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fconfiguring-vercel-for-hugo-and-eleventy","Configuring Vercel for Hugo and Eleventy",{"path":1983,"title":1984},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies","Netlify vs Vercel Deployment Strategies",{"path":1986,"title":1987},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-build-hooks-for-content-updates","Netlify Build Hooks for Content Updates",{"path":1989,"title":1990},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fnetlify-vs-vercel-deployment-strategies\u002Fnetlify-redirects-and-rewrites-for-static-sites","Netlify Redirects and Rewrites for Static Sites",{"path":1992,"title":1993},"\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":1995,"title":1996},"\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":1998,"title":1999},"\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":2001,"title":2002},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fcleaning-up-stale-preview-deployments","Cleaning Up Stale Preview Deployments",{"path":2004,"title":2005},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests","Preview Environments for Pull Requests",{"path":2007,"title":2008},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpassword-protecting-preview-deployments","Password-Protecting Preview Deployments",{"path":2010,"title":2011},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fpreviewing-headless-cms-drafts","Previewing Headless CMS Drafts",{"path":2013,"title":2014},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fpreview-environments-for-pull-requests\u002Fvisual-regression-testing-on-preview-deploys","Visual Regression Testing on Preview Deploys",{"path":2016,"title":2017},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fatomic-deploys-vs-incremental-uploads","Atomic Deploys vs Incremental Uploads",{"path":2019,"title":2020},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Fcanary-releases-for-static-sites","Canary Releases for Static Sites",{"path":2022,"title":2023},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Ffeature-flags-on-static-sites","Feature Flags on Static Sites",{"path":2025,"title":2026},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites","Rollbacks and Deploy Safety for Static Sites",{"path":2028,"title":2029},"\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":2031,"title":2032},"\u002Fproduction-ready-deployment-cicd-workflows\u002Frollbacks-and-deploy-safety-for-static-sites\u002Frunning-smoke-tests-against-a-preview-url","Running Smoke Tests Against a Preview URL",{"path":2034,"title":2035},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fauditing-npm-dependencies-in-ssg-pipelines","Auditing npm Dependencies in SSG Pipelines",{"path":2037,"title":2038},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fenabling-hsts-and-preload-safely","Enabling HSTS and Preload Safely",{"path":2040,"title":2041},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fhash-based-csp-for-inline-scripts-in-astro","Hash-Based CSP for Inline Scripts in Astro",{"path":2043,"title":2044},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites","Security Headers and Hardening for Static Sites",{"path":2046,"title":2047},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsecuring-deploy-credentials-with-github-oidc","Securing Deploy Credentials with GitHub OIDC",{"path":2049,"title":2050},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fsubresource-integrity-for-third-party-assets","Subresource Integrity for Third-Party Assets",{"path":2052,"title":2053},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fsecurity-headers-for-static-sites\u002Fwriting-a-content-security-policy-for-a-static-site","Writing a Content Security Policy for a Static Site",{"path":2055,"title":2056},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fclean-urls-and-trailing-slashes-on-s3","Clean URLs and Trailing Slashes on S3",{"path":2058,"title":2059},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fcloudfront-functions-for-redirects","CloudFront Functions for Redirects",{"path":2061,"title":2062},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fdeploying-a-static-site-to-s3-and-cloudfront","Deploying a Static Site to S3 and CloudFront",{"path":2064,"title":2065},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites","Self-Hosting Static Sites on S3, Nginx and Caddy",{"path":2067,"title":2068},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-caddy","Serving a Static Site with Caddy",{"path":2070,"title":2071},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fserving-a-static-site-with-nginx","Serving a Static Site with Nginx",{"path":2073,"title":2074},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fself-hosting-static-sites\u002Fzero-downtime-deploys-with-symlink-swaps","Zero-Downtime Deploys with Symlink Swaps",{"path":2076,"title":2077},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fadding-a-contact-form-with-cloudflare-workers","Adding a Contact Form with Cloudflare Workers",{"path":2079,"title":2080},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fhandling-form-submissions-on-a-static-site","Handling Form Submissions on a Static Site",{"path":2082,"title":2083},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites","Serverless Functions for Static Sites",{"path":2085,"title":2086},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fnetlify-functions-vs-cloudflare-workers","Netlify Functions vs Cloudflare Workers",{"path":2088,"title":2089},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fprotecting-a-static-site-behind-authentication","Protecting a Static Site Behind Authentication",{"path":2091,"title":2092},"\u002Fproduction-ready-deployment-cicd-workflows\u002Fserverless-functions-for-static-sites\u002Fproxying-third-party-apis-from-an-edge-function","Proxying Third-Party APIs from an Edge Function",1789722847271]