[{"data":1,"prerenderedAt":397},["ShallowReactive",2],{"sanity-LevEgKvCUg3Ul3GKyhTsfZIfaGswLQ-qsmdjo9-lWe4":3,"sanity-ms_P8HfoJ-ggEtrvpTDlOHSi4ZPrROEU428LnmLpLTA":84,"shiki-block-v-0-0-0-0-0-1-0-0":395,"shiki-block-v-0-0-0-0-0-1-0-1":396},{"data":4},{"_createdAt":5,"_id":6,"_rev":7,"_system":8,"_type":6,"_updatedAt":11,"acceptAllLink":12,"acceptNecessaryLink":40,"bannerColorSource":50,"bannerDescription":51,"bannerTitle":52,"categories":53,"declineAllLink":54,"managePreferencesLink":63,"modalColorSource":50,"modalTitle":72,"preferencesIconColorSource":50,"provider":73,"savePreferencesLink":74,"thirdPartyEmbedCode":53,"title":83},"2026-07-28T12:06:44Z","cookieSettings","ci4zAxlS92c5lxcUZgKERY",{"base":9},{"id":6,"rev":10},"4areb77bueJ0iGsV9TVGmy","2026-09-03T17:08:03Z",{"_type":13,"newTab":14,"style":15,"title":38,"type":39},"link",false,{"_type":16,"design":17,"icon":30,"iconPosition":34,"stylePreset":35},"link.style",{"_type":18,"colorSource":19,"gradient":20,"hover":25,"shape":29,"style":29},"link.style.design","manual",{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},"gradient","to-r","linear","at-center",{"_type":26,"colorSource":27,"gradient":28},"link.style.hover","none",{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},"default",{"_type":31,"name":32,"type":33},"icon.config","pi-compass","noicon","start",{"_ref":36,"_type":37},"0a45d6ae-0177-47f2-ab3e-2dd19191fca6","reference","Accept all","button",{"_type":13,"newTab":14,"style":41,"title":49,"type":39},{"_type":16,"design":42,"icon":46,"iconPosition":34,"stylePreset":47},{"_type":18,"colorSource":19,"gradient":43,"hover":44,"shape":29,"style":29},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":26,"colorSource":27,"gradient":45},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":31,"name":32,"type":33},{"_ref":48,"_type":37},"1b28bc78-22fc-4f39-ab55-441e2a601f6e","Accept necessary","inherit","We use cookies to enhance your browsing experience and analyse our traffic. Please choose your cookie preferences below.","We use cookies",null,{"_type":13,"newTab":14,"style":55,"title":62,"type":39},{"_type":16,"design":56,"icon":60,"iconPosition":34,"stylePreset":61},{"_type":18,"colorSource":19,"gradient":57,"hover":58,"shape":29,"style":29},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":26,"colorSource":27,"gradient":59},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":31,"name":32,"type":33},{"_ref":48,"_type":37},"Decline all",{"_type":13,"newTab":14,"style":64,"title":71,"type":39},{"_type":16,"design":65,"icon":69,"iconPosition":34,"stylePreset":70},{"_type":18,"colorSource":19,"gradient":66,"hover":67,"shape":29,"style":29},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":26,"colorSource":27,"gradient":68},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":31,"name":32,"type":33},{"_ref":48,"_type":37},"Manage preferences","Cookie Preferences","custom",{"_type":13,"newTab":14,"style":75,"title":82,"type":39},{"_type":16,"design":76,"icon":80,"iconPosition":34,"stylePreset":81},{"_type":18,"colorSource":19,"gradient":77,"hover":78,"shape":29,"style":29},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":26,"colorSource":27,"gradient":79},{"_type":21,"colorSource":19,"direction":22,"gradientType":23,"radialPosition":24},{"_type":31,"name":32,"type":33},{"_ref":36,"_type":37},"Save preferences","Cookie Settings",{"data":85,"sourceMap":-1},[86],{"_createdAt":87,"_id":88,"_rev":89,"_system":90,"_type":93,"_updatedAt":94,"authorProfile":95,"authorRef":101,"body":103,"categories":351,"excerpt":360,"footer":53,"layout":361,"mainImage":370,"navigation":53,"publishedAt":375,"readTime":376,"relatedPosts":377,"routeOptions":378,"seo":384,"showOnWebsite":380,"slug":383,"tags":390,"title":394},"2026-07-29T22:40:35Z","937dc554-ba95-4228-926c-018e8c01c6eb","yP8kuGLgTlEjnh0hQ204as",{"base":91},{"id":88,"rev":92},"dbCQ1Un4N62Rg6Tb6MaUEu","post","2026-08-15T17:29:54Z",{"avatar":53,"bio":96,"name":97,"role":98,"sameAs":99},"Builds Nuxion. Ex-agency lead who got tired of rebuilding the same CMS plumbing on every project and decided to ship it once","Jason Reid","Founder \u002F Content Writer",[100],"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fjason-reid-150476116\u002F",{"_ref":102,"_type":37},"006a4499-f3d6-4fbc-8cb4-3ddf05f11242",[104,124,141,150,169,176,184,231,239,271,282,290,298,304,335,343],{"_key":105,"_type":106,"children":107,"markDefs":122,"style":123},"27bfc71052e9","block",[108,113,118],{"_key":109,"_type":110,"marks":111,"text":112},"24ea88536f77","span",[],"Most CMS integrations rot quietly. An editor renames a field, a developer refactors a query, and nothing complains — until a section renders blank in production three weeks later. Nuxion is built so that class of bug can't ship. The chain from a Sanity schema to a rendered Vue component is typed end-to-end and enforced at ",{"_key":114,"_type":110,"marks":115,"text":117},"1df3e3d32f79",[116],"strong","build time",{"_key":119,"_type":110,"marks":120,"text":121},"8749af88a132",[],".",[],"normal",{"_key":125,"_type":106,"children":126,"markDefs":140,"style":123},"0871d5b47468",[127,131,136],{"_key":128,"_type":110,"marks":129,"text":130},"7e17038bad12",[],"Here's the core idea: every block is three files that stay in lockstep — a schema, a component, and a single registry entry that ties the two together by ",{"_key":132,"_type":110,"marks":133,"text":135},"09df4a72bd5b",[134],"code","_type",{"_key":137,"_type":110,"marks":138,"text":139},"6b2a1c768805",[],". Break the contract, and the type check fails.",[],{"_key":142,"_type":106,"children":143,"markDefs":148,"style":149},"bcfbf0f619d1",[144],{"_key":145,"_type":110,"marks":146,"text":147},"44fda32e51c0",[],"The registry is the source of truth",[],"h2",{"_key":151,"_type":106,"children":152,"markDefs":168,"style":123},"09eec6e67264",[153,157,161,164],{"_key":154,"_type":110,"marks":155,"text":156},"6a1995ed356e",[134],"ComponentRenderer.vue",{"_key":158,"_type":110,"marks":159,"text":160},"e9ecb712d71f",[]," resolves each block's ",{"_key":162,"_type":110,"marks":163,"text":135},"b68ea14cc06e",[134],{"_key":165,"_type":110,"marks":166,"text":167},"7b077c4d6732",[]," against a merged registry of web and custom components, then binds the block's data onto the resolved component. The registry key must match the schema name exactly:",[],{"_key":170,"_type":171,"colorSource":50,"markDefs":53,"snippet":172},"c1d7112a8b7a","code.block",{"_type":134,"code":173,"filename":174,"language":175},"'custom.features-grid': {\n  element: defineAsyncComponent(() => import('.\u002FCustomFeaturesGrid.vue')),\n  props: { ...data },\n},","custom\u002Findex.ts","typescript",{"_key":177,"_type":106,"children":178,"markDefs":183,"style":123},"f56cd7229cd6",[179],{"_key":180,"_type":110,"marks":181,"text":182},"a5d71ffcffe5",[],"Because the key is a literal union derived from your schemas, a typo here is a red squiggle, not a silent miss.",[],{"_key":185,"_type":106,"children":186,"markDefs":227,"style":230},"46f479c48737",[187,192,196,200,204,208,212,216,220,223],{"_key":188,"_type":110,"marks":189,"text":191},"3e703ef48348",[116,190],"9ce143fe48ff","The rename test ",{"_key":193,"_type":110,"marks":194,"text":195},"298f0cb71bf8",[],"\ntestRename ",{"_key":197,"_type":110,"marks":198,"text":199},"a3d0c4c5496e",[134],"title",{"_key":201,"_type":110,"marks":202,"text":203},"00be32091022",[]," to ",{"_key":205,"_type":110,"marks":206,"text":207},"aecd198a814f",[134],"heading",{"_key":209,"_type":110,"marks":210,"text":211},"dabe4f328df5",[]," in a schema and run ",{"_key":213,"_type":110,"marks":214,"text":215},"bd60883be59b",[134],"npm run typecheck",{"_key":217,"_type":110,"marks":218,"text":219},"66b1a084f0bc",[],". Every query and component that still reads ",{"_key":221,"_type":110,"marks":222,"text":199},"bbd80df4d610",[134],{"_key":224,"_type":110,"marks":225,"text":226},"2dd24368b6f0",[]," lights up. Fix them, and only then does the build pass.",[228],{"_key":190,"_type":207,"level":229},"h4","blockquote",{"_key":232,"_type":106,"children":233,"markDefs":238,"style":149},"31d37123dacd",[234],{"_key":235,"_type":110,"marks":236,"text":237},"bcdeefe33fa9",[],"Projections keep GROQ typed",[],{"_key":240,"_type":106,"children":241,"markDefs":270,"style":123},"c8d1ea9e6967",[242,246,250,254,258,262,266],{"_key":243,"_type":110,"marks":244,"text":245},"a4a7c0edaf4e",[],"Typed queries live in ",{"_key":247,"_type":110,"marks":248,"text":249},"d33520ac0bdf",[134],"groq-queries.ts",{"_key":251,"_type":110,"marks":252,"text":253},"cdf9cf48b6e4",[]," and flow through ",{"_key":255,"_type":110,"marks":256,"text":257},"d005d0e0cc1d",[134],"useSanityQuery\u003CT>()",{"_key":259,"_type":110,"marks":260,"text":261},"2f87470e307f",[]," with TypeGen-generated types. The default spread covers colors and images; ",{"_key":263,"_type":110,"marks":264,"text":265},"efe36ba59c25",[134],"link.group",{"_key":267,"_type":110,"marks":268,"text":269},"12dc327281b1",[]," and portable-text fields usually need an explicit projection entry.",[],{"_key":272,"_type":106,"children":273,"markDefs":280,"style":230},"c654017b9e12",[274],{"_key":275,"_type":110,"marks":276,"text":279},"d07e6ab95a37",[116,277,278],"em","dee9be9fb1b5","\"If it compiles, the CMS wiring is correct. That's the whole promise — you stop testing the plumbing and go build.\"",[281],{"_key":278,"_type":207,"level":149},{"_key":283,"_type":106,"children":284,"markDefs":289,"style":149},"19ecd94fe8d4",[285],{"_key":286,"_type":110,"marks":287,"text":288},"e2431455a7d4",[],"Scaffold, don't hand-wire",[],{"_key":291,"_type":106,"children":292,"markDefs":297,"style":123},"6ca4f4eaa532",[293],{"_key":294,"_type":110,"marks":295,"text":296},"3e60895ac391",[],"You almost never write those three files by hand. The scaffolder generates the schema, a typed component, every registration, and regenerates types in one command — the block is immediately insertable in Studio:",[],{"_key":299,"_type":171,"colorSource":50,"markDefs":53,"snippet":300},"cb1b1fc4f833",{"_type":134,"code":301,"filename":302,"language":303},"npm run scaffold:component -- custom.testimonial","Shell","bash",{"_key":305,"_type":106,"children":306,"markDefs":334,"style":123},"f85976e82b39",[307,311,314,318,322,326,330],{"_key":308,"_type":110,"marks":309,"text":310},"ac5ed7a6827d",[],"From there it's ordinary Vue. Bind the typed data, reach for shared element types like ",{"_key":312,"_type":110,"marks":313,"text":265},"47db1da81a7b",[134],{"_key":315,"_type":110,"marks":316,"text":317},"d70e60838da9",[]," and ",{"_key":319,"_type":110,"marks":320,"text":321},"d70d319402a8",[134],"portable-text",{"_key":323,"_type":110,"marks":324,"text":325},"ca8b4f32d086",[]," instead of reinventing them, and let ",{"_key":327,"_type":110,"marks":328,"text":329},"36fbd84896e1",[134],"PageSection",{"_key":331,"_type":110,"marks":332,"text":333},"88c0932ea841",[]," own width and gutter so your block only handles vertical rhythm and content.",[],{"_key":336,"_type":106,"children":337,"markDefs":342,"style":123},"280ecccae05f",[338],{"_key":339,"_type":110,"marks":340,"text":341},"41152d0884fc",[],"The payoff compounds. Every block you add inherits the same guarantees, so a project with forty custom sections is exactly as safe to refactor as one with four.",[],{"_key":344,"_type":106,"children":345,"markDefs":350,"style":123},"df0a130b105b",[346],{"_key":347,"_type":110,"marks":348,"text":349},"69b1ae21e2ea",[],"",[],[352],{"_createdAt":353,"_id":354,"_rev":355,"_type":356,"_updatedAt":357,"slug":358,"title":359},"2026-07-29T23:00:06Z","32154214-62dd-4f13-bacf-7499f1eaec27","eOgq1Ovu5XNUv1qNFUGdR9","category","2026-07-29T23:00:17Z","engineering","Engineering","A tour of the compile-time registry, TypeGen projections, and the dynamic component system that make a renamed Sanity field fail your build instead of your production site.",{"_type":362,"colorOptions":363,"fontOptions":367,"layout":29,"pageDesign":369},"post.layout.options",{"_type":364,"theme":365},"page.color.options",{"_ref":366,"_type":37},"749e3441-68a7-4fd3-8340-7f6eb2263a11",{"_type":368,"bodyFont":349,"primaryFont":349},"font.options","design2",{"_type":371,"alt":372,"asset":373},"image","Coding background picture",{"_ref":374,"_type":37},"image-4793427bd370f43377ff076f3253890feed17c46-3399x5099-jpg","2026-07-29T22:30:37.617Z",2,[],{"_type":379,"includeInSitemap":380,"slug":381},"page.routing.options",true,{"_type":382,"current":383},"slug","type-safe-from-schema-to-render-how-nuxion-keeps-your-cms-honest",{"_type":385,"favicon":386,"image":53,"schema":387,"socialImages":389},"seo",{"mimeType":53,"url":53},{"organizationType":388},"Organization",{"facebook":53,"linkedin":53,"twitter":53},[391,392,393],"sanity","typegen","nuxt4","Type-safe from schema to render: how Nuxion keeps your CMS honest","\u003Cpre class=\"shiki shiki-themes github-light github-dark nuxion-code__pre\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">npm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> run\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> setup:project\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>","\u003Cpre class=\"shiki shiki-themes github-light github-dark nuxion-code__pre\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">npm\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> run\u003C\u002Fspan>\u003Cspan style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> dev:all\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>",1789667190738]