[{"data":1,"prerenderedAt":455},["ShallowReactive",2],{"docs:\u002Fdocs\u002Fincremental-adoption":3,"i-lucide:moon":446,"i-lucide:github":451,"i-lucide:menu":453},{"id":4,"title":5,"body":6,"description":439,"extension":440,"meta":441,"navigation":189,"path":442,"seo":443,"stem":444,"__hash__":445},"docs\u002Fdocs\u002Fincremental-adoption.md","Incremental Adoption",{"type":7,"value":8,"toc":432},"minimark",[9,18,23,26,50,53,57,60,159,162,333,344,348,359,363,390,394,428],[10,11,12,13,17],"p",{},"Nuxt Endpoints is opt-in per route. A server route joins the endpoint system only when it exports an endpoint definition. Everything else in ",[14,15,16],"code",{},"server\u002F"," keeps running as a plain Nitro route, untouched by this module.",[19,20,22],"h2",{"id":21},"how-discovery-works","How discovery works",[10,24,25],{},"During build, the module inspects each scanned server route:",[27,28,29,47],"ul",{},[30,31,32,33,36,37,42,43,46],"li",{},"If the route uses an endpoint definition (created with ",[14,34,35],{},"defineEndpoint",", co-located or imported from a ",[38,39,41],"a",{"href":40},"\u002Fdocs\u002Fendpoints#separate-contract-files","contract file","), the route joins the generated client, the ",[14,44,45],{},"#endpoints"," types, and the OpenAPI document.",[30,48,49],{},"If it does not, the route is skipped entirely — it is not even imported during discovery. No validation is added, no types are generated for it, and its runtime behavior does not change.",[10,51,52],{},"There is no global middleware and no route allowlist to maintain. The export itself is the opt-in switch.",[19,54,56],{"id":55},"convert-a-single-route","Convert a single route",[10,58,59],{},"Start from an ordinary Nitro route:",[61,62,67],"pre",{"className":63,"code":64,"language":65,"meta":66,"style":66},"language-ts shiki shiki-themes github-light-default github-dark-default","\u002F\u002F server\u002Fapi\u002Fusers\u002F[id].get.ts\nexport default defineEventHandler((event) => {\n  const id = Number(getRouterParam(event, 'id'))\n  return { id, name: 'Tom' }\n})\n","ts","",[14,68,69,78,103,135,150],{"__ignoreMap":66},[70,71,74],"span",{"class":72,"line":73},"line",1,[70,75,77],{"class":76},"sA0OV","\u002F\u002F server\u002Fapi\u002Fusers\u002F[id].get.ts\n",[70,79,81,85,88,92,96,99],{"class":72,"line":80},2,[70,82,84],{"class":83},"swxxe","export",[70,86,87],{"class":83}," default",[70,89,91],{"class":90},"s9HWX"," defineEventHandler",[70,93,95],{"class":94},"sVS1I","((event) ",[70,97,98],{"class":83},"=>",[70,100,102],{"class":101},"saQ_J"," {\n",[70,104,106,109,113,116,119,122,125,128,132],{"class":72,"line":105},3,[70,107,108],{"class":83},"  const",[70,110,112],{"class":111},"sOOdx"," id",[70,114,115],{"class":83}," =",[70,117,118],{"class":90}," Number",[70,120,121],{"class":101},"(",[70,123,124],{"class":90},"getRouterParam",[70,126,127],{"class":101},"(event, ",[70,129,131],{"class":130},"sZItA","'id'",[70,133,134],{"class":101},"))\n",[70,136,138,141,144,147],{"class":72,"line":137},4,[70,139,140],{"class":83},"  return",[70,142,143],{"class":101}," { id, name: ",[70,145,146],{"class":130},"'Tom'",[70,148,149],{"class":101}," }\n",[70,151,153,156],{"class":72,"line":152},5,[70,154,155],{"class":101},"}",[70,157,158],{"class":94},")\n",[10,160,161],{},"Add the contract and handler in one call, replacing the plain event handler:",[61,163,165],{"className":63,"code":164,"language":65,"meta":66,"style":66},"\u002F\u002F server\u002Fapi\u002Fusers\u002F[id].get.ts\nimport { z } from 'zod'\n\nexport default defineEndpoint({\n  params: z.object({\n    id: z.coerce.number(),\n  }),\n  responses: {\n    200: z.object({\n      id: z.number(),\n      name: z.string(),\n    }),\n  },\n  handler: ({ params }) => {\n    return { id: params.id, name: 'Tom' }\n  },\n})\n",[14,166,167,171,185,191,203,213,225,234,240,253,263,274,280,288,307,320,327],{"__ignoreMap":66},[70,168,169],{"class":72,"line":73},[70,170,77],{"class":76},[70,172,173,176,179,182],{"class":72,"line":80},[70,174,175],{"class":83},"import",[70,177,178],{"class":101}," { z } ",[70,180,181],{"class":83},"from",[70,183,184],{"class":130}," 'zod'\n",[70,186,187],{"class":72,"line":105},[70,188,190],{"emptyLinePlaceholder":189},true,"\n",[70,192,193,195,197,200],{"class":72,"line":137},[70,194,84],{"class":83},[70,196,87],{"class":83},[70,198,199],{"class":90}," defineEndpoint",[70,201,202],{"class":94},"({\n",[70,204,205,208,211],{"class":72,"line":152},[70,206,207],{"class":101},"  params: z.",[70,209,210],{"class":90},"object",[70,212,202],{"class":101},[70,214,216,219,222],{"class":72,"line":215},6,[70,217,218],{"class":101},"    id: z.coerce.",[70,220,221],{"class":90},"number",[70,223,224],{"class":101},"(),\n",[70,226,228,231],{"class":72,"line":227},7,[70,229,230],{"class":101},"  })",[70,232,233],{"class":94},",\n",[70,235,237],{"class":72,"line":236},8,[70,238,239],{"class":101},"  responses: {\n",[70,241,243,246,249,251],{"class":72,"line":242},9,[70,244,245],{"class":111},"    200",[70,247,248],{"class":101},": z.",[70,250,210],{"class":90},[70,252,202],{"class":101},[70,254,256,259,261],{"class":72,"line":255},10,[70,257,258],{"class":101},"      id: z.",[70,260,221],{"class":90},[70,262,224],{"class":101},[70,264,266,269,272],{"class":72,"line":265},11,[70,267,268],{"class":101},"      name: z.",[70,270,271],{"class":90},"string",[70,273,224],{"class":101},[70,275,277],{"class":72,"line":276},12,[70,278,279],{"class":101},"    }),\n",[70,281,283,286],{"class":72,"line":282},13,[70,284,285],{"class":101},"  }",[70,287,233],{"class":94},[70,289,291,294,297,300,303,305],{"class":72,"line":290},14,[70,292,293],{"class":90},"  handler",[70,295,296],{"class":101},": ({ ",[70,298,299],{"class":94},"params",[70,301,302],{"class":101}," }) ",[70,304,98],{"class":83},[70,306,102],{"class":101},[70,308,310,313,316,318],{"class":72,"line":309},15,[70,311,312],{"class":83},"    return",[70,314,315],{"class":101}," { id: params.id, name: ",[70,317,146],{"class":130},[70,319,149],{"class":101},[70,321,323,325],{"class":72,"line":322},16,[70,324,285],{"class":101},[70,326,233],{"class":94},[70,328,330],{"class":72,"line":329},17,[70,331,332],{"class":94},"})\n",[10,334,335,336,339,340,343],{},"The route path, method, and callers do not change. Existing ",[14,337,338],{},"$fetch('\u002Fapi\u002Fusers\u002F1')"," calls keep working; the route now also validates its request and appears on ",[14,341,342],{},"$endpoint"," and in the OpenAPI document.",[19,345,347],{"id":346},"roll-back-a-route","Roll back a route",[10,349,350,351,354,355,358],{},"Remove the ",[14,352,353],{},"endpoint"," export and return to ",[14,356,357],{},"defineEventHandler",". The route leaves the generated client and OpenAPI document, and nothing else needs to be updated.",[19,360,362],{"id":361},"coexistence-rules","Coexistence rules",[27,364,365,372,380,383],{},[30,366,367,368,371],{},"Plain routes and endpoint routes live side by side in the same ",[14,369,370],{},"server\u002Fapi"," directory.",[30,373,374,376,377,379],{},[14,375,342],{}," and ",[14,378,45],{}," types cover only converted routes, so autocomplete reflects exactly what has a contract.",[30,381,382],{},"The OpenAPI document lists only converted routes. It grows as the migration proceeds.",[30,384,385,386,389],{},"Plain routes are still called with ",[14,387,388],{},"$fetch"," as before. There is no requirement to finish the migration.",[19,391,393],{"id":392},"suggested-migration-order","Suggested migration order",[395,396,397,408,417,420],"ol",{},[30,398,399,400,403,404,407],{},"Start with routes whose input validation you already hand-wrote — the contract usually replaces existing ",[14,401,402],{},"getQuery","\u002F",[14,405,406],{},"readBody"," checks directly.",[30,409,410,411,376,413,416],{},"Convert routes consumed by typed client code next, where ",[14,412,342],{},[14,414,415],{},"useEndpoint"," remove manual type assertions.",[30,418,419],{},"Convert externally consumed routes when you want them in the OpenAPI document.",[30,421,422,423,427],{},"Leave file streams, redirects, and other low-level handlers as plain routes, or see ",[38,424,426],{"href":425},"\u002Fdocs\u002Flow-level-http","Low-level HTTP"," for the escape hatches.",[429,430,431],"style",{},"html pre.shiki code .sA0OV, html code.shiki .sA0OV{--shiki-light:#6E7781;--shiki-dark:#8B949E}html pre.shiki code .swxxe, html code.shiki .swxxe{--shiki-light:#CF222E;--shiki-dark:#FF7B72}html pre.shiki code .s9HWX, html code.shiki .s9HWX{--shiki-light:#8250DF;--shiki-dark:#D2A8FF}html pre.shiki code .sVS1I, html code.shiki .sVS1I{--shiki-light:#953800;--shiki-dark:#FFA657}html pre.shiki code .saQ_J, html code.shiki .saQ_J{--shiki-light:#1F2328;--shiki-dark:#E6EDF3}html pre.shiki code .sOOdx, html code.shiki .sOOdx{--shiki-light:#0550AE;--shiki-dark:#79C0FF}html pre.shiki code .sZItA, html code.shiki .sZItA{--shiki-light:#0A3069;--shiki-dark:#A5D6FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-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":66,"searchDepth":80,"depth":80,"links":433},[434,435,436,437,438],{"id":21,"depth":80,"text":22},{"id":55,"depth":80,"text":56},{"id":346,"depth":80,"text":347},{"id":361,"depth":80,"text":362},{"id":392,"depth":80,"text":393},"Convert one route at a time. Every other route keeps working unchanged.","md",{},"\u002Fdocs\u002Fincremental-adoption",{"title":5,"description":439},"docs\u002Fincremental-adoption","z99PrayIWge6cTPQv5rGqWgyVC6uKDJ5CBBm1ooBKf0",{"left":447,"top":447,"width":448,"height":448,"rotate":447,"vFlip":449,"hFlip":449,"body":450},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":447,"top":447,"width":448,"height":448,"rotate":447,"vFlip":449,"hFlip":449,"body":452,"hidden":189},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5c.08-1.25-.27-2.48-1-3.5c.28-1.15.28-2.35 0-3.5c0 0-1 0-3 1.5c-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.4 5.4 0 0 0 4 9c0 3.5 3 5.5 6 5.5c-.39.49-.68 1.05-.85 1.65S8.93 17.38 9 18v4\"\u002F>\u003Cpath d=\"M9 18c-4.51 2-5-2-7-2\"\u002F>\u003C\u002Fg>",{"left":447,"top":447,"width":448,"height":448,"rotate":447,"vFlip":449,"hFlip":449,"body":454},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",1787723882376]