[{"data":1,"prerenderedAt":419},["ShallowReactive",2],{"blog-list-en":3},[4,267],{"id":5,"title":6,"body":7,"date":253,"description":254,"extension":255,"image":256,"meta":257,"navigation":258,"path":259,"seo":260,"stem":261,"tags":262,"__hash__":266},"blog_en\u002Fblog\u002Fnuxt-content-static-blog.md","Building a static blog with Nuxt Content v3",{"type":8,"value":9,"toc":247},"minimark",[10,19,24,32,129,136,140,143,218,222,225,233,236,240,243],[11,12,13,14,18],"p",{},"This site is a fully static Nuxt app. Every post is a Markdown file in the repo, and ",[15,16,17],"code",{},"nuxt generate"," turns the whole thing into plain HTML. Here's the interesting part of the setup.",[20,21,23],"h2",{"id":22},"collections-are-typed","Collections are typed",[11,25,26,27,31],{},"Nuxt Content v3 replaced the old file-based querying with ",[28,29,30],"strong",{},"collections"," — you declare a schema, and frontmatter gets validated at build time:",[33,34,39],"pre",{"className":35,"code":36,"language":37,"meta":38,"style":38},"language-ts shiki shiki-themes github-light github-dark","const blogSchema = z.object({\n  title: z.string(),\n  description: z.string(),\n  date: z.string(),\n  tags: z.array(z.string()).default([]),\n})\n","ts","",[15,40,41,68,80,90,100,123],{"__ignoreMap":38},[42,43,46,50,54,57,61,65],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"szBVR","const",[42,51,53],{"class":52},"sj4cs"," blogSchema",[42,55,56],{"class":48}," =",[42,58,60],{"class":59},"sVt8B"," z.",[42,62,64],{"class":63},"sScJk","object",[42,66,67],{"class":59},"({\n",[42,69,71,74,77],{"class":44,"line":70},2,[42,72,73],{"class":59},"  title: z.",[42,75,76],{"class":63},"string",[42,78,79],{"class":59},"(),\n",[42,81,83,86,88],{"class":44,"line":82},3,[42,84,85],{"class":59},"  description: z.",[42,87,76],{"class":63},[42,89,79],{"class":59},[42,91,93,96,98],{"class":44,"line":92},4,[42,94,95],{"class":59},"  date: z.",[42,97,76],{"class":63},[42,99,79],{"class":59},[42,101,103,106,109,112,114,117,120],{"class":44,"line":102},5,[42,104,105],{"class":59},"  tags: z.",[42,107,108],{"class":63},"array",[42,110,111],{"class":59},"(z.",[42,113,76],{"class":63},[42,115,116],{"class":59},"()).",[42,118,119],{"class":63},"default",[42,121,122],{"class":59},"([]),\n",[42,124,126],{"class":44,"line":125},6,[42,127,128],{"class":59},"})\n",[11,130,131,132,135],{},"Typos in frontmatter now fail the build instead of silently rendering ",[15,133,134],{},"undefined",". This is the single biggest quality-of-life win over v2.",[20,137,139],{"id":138},"queries-look-like-sql-because-they-are","Queries look like SQL because they are",[11,141,142],{},"Under the hood, content lives in SQLite. The query API compiles to SQL:",[33,144,146],{"className":35,"code":145,"language":37,"meta":38,"style":38},"const posts = await queryCollection('blog_en')\n  .order('date', 'DESC')\n  .limit(3)\n  .all()\n",[15,147,148,173,194,208],{"__ignoreMap":38},[42,149,150,152,155,157,160,163,166,170],{"class":44,"line":45},[42,151,49],{"class":48},[42,153,154],{"class":52}," posts",[42,156,56],{"class":48},[42,158,159],{"class":48}," await",[42,161,162],{"class":63}," queryCollection",[42,164,165],{"class":59},"(",[42,167,169],{"class":168},"sZZnC","'blog_en'",[42,171,172],{"class":59},")\n",[42,174,175,178,181,183,186,189,192],{"class":44,"line":70},[42,176,177],{"class":59},"  .",[42,179,180],{"class":63},"order",[42,182,165],{"class":59},[42,184,185],{"class":168},"'date'",[42,187,188],{"class":59},", ",[42,190,191],{"class":168},"'DESC'",[42,193,172],{"class":59},[42,195,196,198,201,203,206],{"class":44,"line":82},[42,197,177],{"class":59},[42,199,200],{"class":63},"limit",[42,202,165],{"class":59},[42,204,205],{"class":52},"3",[42,207,172],{"class":59},[42,209,210,212,215],{"class":44,"line":92},[42,211,177],{"class":59},[42,213,214],{"class":63},"all",[42,216,217],{"class":59},"()\n",[20,219,221],{"id":220},"two-languages-two-collections","Two languages, two collections",[11,223,224],{},"For a bilingual site, one collection per locale keeps things simple:",[33,226,231],{"className":227,"code":229,"language":230},[228],"language-text","content\u002F\n  en\u002Fblog\u002F    → collection blog_en, served at \u002Fblog\n  uz\u002Fblog\u002F    → collection blog_uz, served at \u002Fuz\u002Fblog\n","text",[15,232,229],{"__ignoreMap":38},[11,234,235],{},"A tiny composable picks the right collection from the active locale, and the rest of the code never thinks about i18n.",[20,237,239],{"id":238},"the-result","The result",[11,241,242],{},"No server, no database in production, no CMS subscription. Just Markdown files, a git history, and static HTML that any CDN can serve.",[244,245,246],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":38,"searchDepth":70,"depth":82,"links":248},[249,250,251,252],{"id":22,"depth":70,"text":23},{"id":138,"depth":70,"text":139},{"id":220,"depth":70,"text":221},{"id":238,"depth":70,"text":239},"2026-07-14","How this site works under the hood: Markdown collections, SQLite-backed queries, and full static generation with Nuxt.","md",null,{},true,"\u002Fblog\u002Fnuxt-content-static-blog",{"title":6,"description":254},"blog\u002Fnuxt-content-static-blog",[263,264,265],"nuxt","vue","tooling","Vjjtutnkn2zGY1coUA-L_dr9pk_zjeJYAjL0ciEyAk8",{"id":268,"title":269,"body":270,"date":409,"description":410,"extension":255,"image":256,"meta":411,"navigation":258,"path":412,"seo":413,"stem":414,"tags":415,"__hash__":418},"blog_en\u002Fblog\u002Fhello-world.md","Hello, world — why I'm starting this blog",{"type":8,"value":271,"toc":404},[272,280,284,287,309,313,316,391,395,398,401],[11,273,274,275,279],{},"Every engineer eventually hears the same advice: ",[276,277,278],"em",{},"write in public",". This is me finally taking it.",[20,281,283],{"id":282},"what-to-expect-here","What to expect here",[11,285,286],{},"I plan to write about three things:",[288,289,290,297,303],"ol",{},[291,292,293,296],"li",{},[28,294,295],{},"Engineering notes"," — problems I hit at work and how I solved them",[291,298,299,302],{},[28,300,301],{},"Tooling"," — editors, CLIs, and workflows that actually save time",[291,304,305,308],{},[28,306,307],{},"Career"," — what I learn about growing as a software engineer",[20,310,312],{"id":311},"why-write-at-all","Why write at all?",[11,314,315],{},"Writing forces clarity. If I can't explain a solution in a few paragraphs, I probably don't understand it yet. A blog is also a public notebook — six months from now, the person most likely to need these notes is me.",[33,317,319],{"className":35,"code":318,"language":37,"meta":38,"style":38},"\u002F\u002F The whole plan, as code:\nconst blog = {\n  cadence: 'when I have something worth saying',\n  language: ['en', 'uz'],\n  topics: ['engineering', 'tooling', 'career'],\n}\n",[15,320,321,327,339,350,366,386],{"__ignoreMap":38},[42,322,323],{"class":44,"line":45},[42,324,326],{"class":325},"sJ8bj","\u002F\u002F The whole plan, as code:\n",[42,328,329,331,334,336],{"class":44,"line":70},[42,330,49],{"class":48},[42,332,333],{"class":52}," blog",[42,335,56],{"class":48},[42,337,338],{"class":59}," {\n",[42,340,341,344,347],{"class":44,"line":82},[42,342,343],{"class":59},"  cadence: ",[42,345,346],{"class":168},"'when I have something worth saying'",[42,348,349],{"class":59},",\n",[42,351,352,355,358,360,363],{"class":44,"line":92},[42,353,354],{"class":59},"  language: [",[42,356,357],{"class":168},"'en'",[42,359,188],{"class":59},[42,361,362],{"class":168},"'uz'",[42,364,365],{"class":59},"],\n",[42,367,368,371,374,376,379,381,384],{"class":44,"line":102},[42,369,370],{"class":59},"  topics: [",[42,372,373],{"class":168},"'engineering'",[42,375,188],{"class":59},[42,377,378],{"class":168},"'tooling'",[42,380,188],{"class":59},[42,382,383],{"class":168},"'career'",[42,385,365],{"class":59},[42,387,388],{"class":44,"line":125},[42,389,390],{"class":59},"}\n",[20,392,394],{"id":393},"a-note-on-the-two-languages","A note on the two languages",[11,396,397],{},"I write in English and Uzbek. Not every post will be translated — each language gets the posts that make sense for its audience.",[11,399,400],{},"See you in the next post.",[244,402,403],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .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":38,"searchDepth":70,"depth":82,"links":405},[406,407,408],{"id":282,"depth":70,"text":283},{"id":311,"depth":70,"text":312},{"id":393,"depth":70,"text":394},"2026-07-10","The obligatory first post: what this blog is for, what I'll write about, and why writing in public matters for engineers.",{},"\u002Fblog\u002Fhello-world",{"title":269,"description":410},"blog\u002Fhello-world",[416,417],"meta","career","8gQyRdZxZAg6lljmYYzjiFlDvuVFTHEQ0j4LdjNcYyU",1784073506410]