[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"tools-page-nuxt-upgrade-checker":3},{"page":4,"related":531,"variants":550},{"path":5,"name":6,"title":7,"description":8,"checkedAt":9,"sources":10,"faq":32,"related":51,"nuxter":55,"body":58,"tool":529,"preset":530},"\u002Ftools\u002Fnuxt-upgrade-checker","Nuxt upgrade checker","Nuxt 3 to 4 Migration Checker for Modules and Config","Plan a Nuxt 3 to 4 migration. Paste package.json to see which modules declare Nuxt 4 or 5, which nuxt.config options break, and the official checklist.","2026-10-06",[11,14,17,20,23,26,29],{"label":12,"url":13},"Nuxt docs, Upgrade Guide","https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fgetting-started\u002Fupgrade",{"label":15,"url":16},"Nuxt docs, Roadmap","https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fcommunity\u002Froadmap",{"label":18,"url":19},"Nuxt Kit docs, Modules (compatibility)","https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fapi\u002Fkit\u002Fmodules",{"label":21,"url":22},"Nuxt docs, Nuxt 5 Upgrade Guide (in development)","https:\u002F\u002Fnuxt.com\u002Fdocs\u002F5.x\u002Fgetting-started\u002Fupgrade",{"label":24,"url":25},"Nuxt module list API","https:\u002F\u002Fapi.nuxt.com\u002Fmodules",{"label":27,"url":28},"jsDelivr, @nuxt\u002Fcontent module.json","https:\u002F\u002Fcdn.jsdelivr.net\u002Fnpm\u002F@nuxt\u002Fcontent@latest\u002Fdist\u002Fmodule.json",{"label":30,"url":31},"npm registry, @sentry\u002Fnuxt latest manifest","https:\u002F\u002Fregistry.npmjs.org\u002F@sentry\u002Fnuxt\u002Flatest",[33,36,39,42,45,48],{"question":34,"answer":35},"When did Nuxt 3 reach end of life?","On 31 July 2026. Since then it gets no bug fixes or security patches, and the roadmap on nuxt.com lists it as unsupported. Nuxt 4 is the active major, and the official upgrade guide covers the move.",{"question":37,"answer":38},"When is Nuxt 5 coming out?","The roadmap on nuxt.com estimates the fourth quarter of 2026 and gives no firmer date. Nuxt 5 brings Nitro v3, and Nuxt 4 stays supported for at least six months after it ships. You can test much of its behaviour on Nuxt 4.2 or later today.",{"question":40,"answer":41},"How do I upgrade from Nuxt 3 to Nuxt 4?","Check your modules first, then install nuxt@^4.0.0, run the codemod recipe and work through the changes in the upgrade guide. Nuxt disables a module whose compatibility range leaves out the running version and only warns in the console, so a blocked module shows up as missing features rather than a failed build.",{"question":43,"answer":44},"How do I know if a Nuxt module supports Nuxt 4?","Read what it declares. Modules built with Nuxt's module builder ship a dist\u002Fmodule.json whose compatibility.nuxt is the range Nuxt checks when it loads them, and some state a nuxt peer dependency on npm instead. A range that names 4, such as ^4.0.0 or >=4.1.0, is a stronger claim than an open one like >=3.0.0. Either way it is the author's claim, so the module's changelog and issues are the real test.",{"question":46,"answer":47},"Can I test Nuxt 5 changes on Nuxt 4?","Yes, from Nuxt 4.2. Set future.compatibilityVersion to 5 in nuxt.config and the defaults switch to Nuxt 5 behaviour, such as case-sensitive routing, typed pages and the Vite Environment API. The move to Nitro v3 is not part of the flag. From Nuxt 4.6 you can also import server handlers from nuxt\u002Fserver, so the same files run on both.",{"question":49,"answer":50},"Is there a codemod for Nuxt 4?","Yes. npx codemod@0.18.7 nuxt\u002F4\u002Fmigration-recipe runs every Nuxt 4 codemod in sequence, and the guide pins that version because of an issue in the codemod CLI. You can deselect any codemod as it runs, and each one is also listed beside its change in the guide.",[52,53,54],"nuxt-environment-variables","secret-key-generator","cloudflare-cron-generator",{"body":56,"to":57},"Nuxter is built on Nuxt 4, so a project that starts from it begins on the far side of this migration, with sign-in, payments, email and background jobs already working on Cloudflare Workers.","\u002Ffeatures",{"type":59,"value":60,"toc":521},"minimark",[61,66,70,78,82,85,138,141,160,164,171,178,181,185,188,212,235,244,293,312,327,334,338,341,389,392,399,507,510,514,517],[62,63,65],"h2",{"id":64},"nuxt-3-is-past-its-end-of-life","Nuxt 3 is past its end of life",[67,68,69],"p",{},"Nuxt 3 no longer receives bug fixes or security patches. Nuxt 4 is the active major, and the roadmap commits to supporting it for at least six months after Nuxt 5 ships. The table further down lists the dates and the versions the checklists depend on.",[67,71,72,73,77],{},"The Nuxt team split the breaking changes on purpose. Nuxt 4 is a stability release that turns on by default what ",[74,75,76],"code",{},"compatibilityVersion: 4"," used to opt in to. Nuxt 5 follows with the move to Nitro v3 and further changes. A Nuxt 3 app goes through 4 first, so the checker shows the Nuxt 4 checklist before the Nuxt 5 preview.",[62,79,81],{"id":80},"what-the-checker-reads","What the checker reads",[67,83,84],{},"The checker parses your package.json in the browser and picks out every dependency named like a Nuxt module, plus any other dependency the module list on nuxt.com names. For each one it looks for a declared Nuxt range in three places, in this order:",[86,87,88,103,120],"ol",{},[89,90,91,98,99,102],"li",{},[92,93,94,97],"strong",{},[74,95,96],{},"dist\u002Fmodule.json"," on jsDelivr."," A module built with Nuxt's module builder copies its ",[74,100,101],{},"meta.compatibility"," there. Nuxt checks that range when it loads the module and, when the running version falls outside it, disables the module with a warning in the console.",[89,104,105,111,112,115,116,119],{},[92,106,107,110],{},[74,108,109],{},"peerDependencies"," on npm",", under ",[74,113,114],{},"nuxt"," or ",[74,117,118],{},"@nuxt\u002Fkit",". Some modules declare their range only here.",[89,121,122,125,126,129,130,133,134,137],{},[92,123,124],{},"The module's listing on nuxt.com",", used only when the package itself says nothing, and labelled as possibly stale. When this page was checked, nuxt.com listed ",[74,127,128],{},"@nuxt\u002Fcontent"," as ",[74,131,132],{},">=3.0.0-rc.3",", while the module's own module.json declared ",[74,135,136],{},">=4.1.0 || ^3.19.0",".",[67,139,140],{},"It reads two versions of each module: the newest one your range allows, and the latest release. When your range leaves Nuxt 4 out but the latest release declares it, the fix is a module upgrade, and the checker says which version.",[67,142,143,144,147,148,151,152,155,156,159],{},"Your nuxt.config goes through a TypeScript-aware parser, and keys inside ",[74,145,146],{},"$production",", ",[74,149,150],{},"$development"," and ",[74,153,154],{},"$env"," overrides count as if set at the top level. Only literal values are read, so a value built from a variable shows as ",[74,157,158],{},"…"," rather than a guess.",[62,161,163],{"id":162},"a-declared-range-is-a-claim-not-a-test","A declared range is a claim, not a test",[67,165,166,167,170],{},"A range such as ",[74,168,169],{},">=3.0.0"," has no upper bound, so it allows Nuxt 4 and Nuxt 5 without naming either. The checker calls that an open range and counts it apart from a range that names the version. Open ranges are common in modules that predate Nuxt 4, and many of them work fine.",[67,172,173,174,177],{},"The reverse happens too. The roadmap lists Auth Utils, a planned core module, with Nuxt support for 4.x and 5.x, yet the ",[74,175,176],{},"nuxt-auth-utils"," package declares no range in its module.json or on npm. A module that declares nothing is not a module that fails; it is one you check by hand, in its changelog and its issues.",[67,179,180],{},"A range that leaves your target out is the one to act on first, because Nuxt disables a module whose compatibility range does not match the running version. That shows up as missing features and a console warning, not as a failed build.",[62,182,184],{"id":183},"the-nuxt-4-changes-most-likely-to-bite","The Nuxt 4 changes most likely to bite",[67,186,187],{},"The guide labels each change with an impact level, and the checklist keeps that order. Most of the data fetching changes sit near the bottom of it, yet they fail quietly at runtime rather than in the build, so check them first.",[67,189,190,151,193,196,197,151,200,203,204,207,208,211],{},[74,191,192],{},"data",[74,194,195],{},"error"," from ",[74,198,199],{},"useAsyncData",[74,201,202],{},"useFetch"," now start as ",[74,205,206],{},"undefined"," rather than ",[74,209,210],{},"null",":",[213,214,219],"pre",{"className":215,"code":216,"language":217,"meta":218,"style":218},"language-diff shiki shiki-themes github-light github-light github-dark","- if (data.value === null) {\n+ if (data.value === undefined) {\n","diff","",[74,220,221,229],{"__ignoreMap":218},[222,223,226],"span",{"class":224,"line":225},"line",1,[222,227,228],{},"- if (data.value === null) {\n",[222,230,232],{"class":224,"line":231},2,[222,233,234],{},"+ if (data.value === undefined) {\n",[67,236,237,239,240,243],{},[74,238,192],{}," is now a ",[74,241,242],{},"shallowRef",", so mutating a nested property no longer updates the page. Replace the whole value, or opt back in where you need it:",[213,245,249],{"className":246,"code":247,"language":248,"meta":218,"style":218},"language-ts shiki shiki-themes github-light github-light github-dark","const { data } = await useFetch('\u002Fapi\u002Ftodos', { deep: true })\n","ts",[74,250,251],{"__ignoreMap":218},[222,252,253,257,261,264,267,270,273,277,280,284,287,290],{"class":224,"line":225},[222,254,256],{"class":255},"s8jYJ","const",[222,258,260],{"class":259},"sxrX7"," { ",[222,262,192],{"class":263},"sBjJW",[222,265,266],{"class":259}," } ",[222,268,269],{"class":255},"=",[222,271,272],{"class":255}," await",[222,274,276],{"class":275},"snPdu"," useFetch",[222,278,279],{"class":259},"(",[222,281,283],{"class":282},"sIIMD","'\u002Fapi\u002Ftodos'",[222,285,286],{"class":259},", { deep: ",[222,288,289],{"class":263},"true",[222,291,292],{"class":259}," })\n",[67,294,295,296,147,298,151,300,303,304,307,308,311],{},"Calls that share a key now share one ",[74,297,192],{},[74,299,195],{},[74,301,302],{},"status",", so their options have to agree. The boolean ",[74,305,306],{},"dedupe"," values on ",[74,309,310],{},"refresh"," are gone as well:",[213,313,315],{"className":215,"code":314,"language":217,"meta":218,"style":218},"- await refresh({ dedupe: true })\n+ await refresh({ dedupe: 'cancel' })\n",[74,316,317,322],{"__ignoreMap":218},[222,318,319],{"class":224,"line":225},[222,320,321],{},"- await refresh({ dedupe: true })\n",[222,323,324],{"class":224,"line":231},[222,325,326],{},"+ await refresh({ dedupe: 'cancel' })\n",[67,328,329,330,333],{},"The new ",[74,331,332],{},"app\u002F"," directory is the most visible change, but it is optional: Nuxt detects the old layout and keeps working with it.",[62,335,337],{"id":336},"testing-nuxt-5-today","Testing Nuxt 5 today",[67,339,340],{},"From Nuxt 4.2 you can switch most defaults to Nuxt 5 behaviour with one flag:",[213,342,344],{"className":246,"code":343,"language":248,"meta":218,"style":218},"export default defineNuxtConfig({\n  future: {\n    compatibilityVersion: 5,\n  },\n})\n",[74,345,346,360,365,377,383],{"__ignoreMap":218},[222,347,348,351,354,357],{"class":224,"line":225},[222,349,350],{"class":255},"export",[222,352,353],{"class":255}," default",[222,355,356],{"class":275}," defineNuxtConfig",[222,358,359],{"class":259},"({\n",[222,361,362],{"class":224,"line":231},[222,363,364],{"class":259},"  future: {\n",[222,366,368,371,374],{"class":224,"line":367},3,[222,369,370],{"class":259},"    compatibilityVersion: ",[222,372,373],{"class":263},"5",[222,375,376],{"class":259},",\n",[222,378,380],{"class":224,"line":379},4,[222,381,382],{"class":259},"  },\n",[222,384,386],{"class":224,"line":385},5,[222,387,388],{"class":259},"})\n",[67,390,391],{},"The flag covers changes such as case-sensitive routing, typed pages, the Vite Environment API and the Options API compiled out of the client bundle. It changes defaults, so an experimental option you set explicitly can hold on to today's behaviour; the checker flags each one that Nuxt 5 behaviour would change.",[67,393,394,395,398],{},"From Nuxt 4.6, server code can import its handler and helpers from ",[74,396,397],{},"nuxt\u002Fserver",", so the same file runs on Nitro v2 today and Nitro v3 under Nuxt 5:",[213,400,402],{"className":246,"code":401,"language":248,"meta":218,"style":218},"import { defineEventHandler, getQuery } from 'nuxt\u002Fserver'\n\nexport default defineEventHandler((event) => {\n  const { name } = getQuery\u003C{ name?: string }>(event)\n  return { message: `Hello, ${name ?? 'world'}!` }\n})\n",[74,403,404,418,424,449,480,502],{"__ignoreMap":218},[222,405,406,409,412,415],{"class":224,"line":225},[222,407,408],{"class":255},"import",[222,410,411],{"class":259}," { defineEventHandler, getQuery } ",[222,413,414],{"class":255},"from",[222,416,417],{"class":282}," 'nuxt\u002Fserver'\n",[222,419,420],{"class":224,"line":231},[222,421,423],{"emptyLinePlaceholder":422},true,"\n",[222,425,426,428,430,433,436,440,443,446],{"class":224,"line":367},[222,427,350],{"class":255},[222,429,353],{"class":255},[222,431,432],{"class":275}," defineEventHandler",[222,434,435],{"class":259},"((",[222,437,439],{"class":438},"sP4rz","event",[222,441,442],{"class":259},") ",[222,444,445],{"class":255},"=>",[222,447,448],{"class":259}," {\n",[222,450,451,454,456,459,461,463,466,469,471,474,477],{"class":224,"line":379},[222,452,453],{"class":255},"  const",[222,455,260],{"class":259},[222,457,458],{"class":263},"name",[222,460,266],{"class":259},[222,462,269],{"class":255},[222,464,465],{"class":275}," getQuery",[222,467,468],{"class":259},"\u003C{ ",[222,470,458],{"class":438},[222,472,473],{"class":255},"?:",[222,475,476],{"class":263}," string",[222,478,479],{"class":259}," }>(event)\n",[222,481,482,485,488,491,493,496,499],{"class":224,"line":385},[222,483,484],{"class":255},"  return",[222,486,487],{"class":259}," { message: ",[222,489,490],{"class":282},"`Hello, ${",[222,492,458],{"class":259},[222,494,495],{"class":255}," ??",[222,497,498],{"class":282}," 'world'}!`",[222,500,501],{"class":259}," }\n",[222,503,505],{"class":224,"line":504},6,[222,506,388],{"class":259},[67,508,509],{},"The Nuxt 5 upgrade guide on nuxt.com is still being written as the work lands, so treat the preview checklist as a moving target.",[62,511,513],{"id":512},"when-starting-fresh-beats-migrating","When starting fresh beats migrating",[67,515,516],{},"Migrating keeps your history and is usually the right call. Starting again from a Nuxt 4 base makes more sense when the app is small, when several of its modules declare nothing or leave Nuxt 4 out, or when you were going to replace its auth, payments or deployment anyway. Either way, sort out the modules first: one that blocks Nuxt 4 blocks both paths.",[518,519,520],"style",{},"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 .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 .s8jYJ, html code.shiki .s8jYJ{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sxrX7, html code.shiki .sxrX7{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sBjJW, html code.shiki .sBjJW{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .snPdu, html code.shiki .snPdu{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sIIMD, html code.shiki .sIIMD{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sP4rz, html code.shiki .sP4rz{--shiki-light:#E36209;--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":218,"searchDepth":231,"depth":231,"links":522},[523,524,525,526,527,528],{"id":64,"depth":231,"text":65},{"id":80,"depth":231,"text":81},{"id":162,"depth":231,"text":163},{"id":183,"depth":231,"text":184},{"id":336,"depth":231,"text":337},{"id":512,"depth":231,"text":513},"nuxt-upgrade-checker",null,[532,538,544],{"path":533,"tool":52,"name":534,"title":535,"description":536,"summary":537,"checkedAt":9},"\u002Ftools\u002Fnuxt-environment-variables","Nuxt environment variables","Nuxt Environment Variables: runtimeConfig to NUXT_","Paste a nuxt.config to get the Nuxt environment variables that override each runtimeConfig key, the type each value arrives as and the names that collide.","Paste a nuxt.config and get the NUXT_ variable for every runtimeConfig key, the type it arrives as and the names that collide.",{"path":539,"tool":53,"name":540,"title":541,"description":542,"summary":543,"checkedAt":9},"\u002Ftools\u002Fsecret-key-generator","Secret key generator","Secret Key Generator for .env, JWT and Webhooks","Generate random secret keys in your browser for NUXT_SESSION_PASSWORD, Better Auth, JWT and webhook signing, as hex, base64, base64url or letters and digits.","Secrets for NUXT_SESSION_PASSWORD, Better Auth, JWT and webhooks, as hex, base64 or base64url, with the .env and Wrangler lines.",{"path":545,"tool":54,"name":546,"title":547,"description":548,"summary":549,"checkedAt":9},"\u002Ftools\u002Fcloudflare-cron-generator","Cloudflare cron trigger generator","Cloudflare Cron Triggers Generator and Tester","Build and test Cloudflare Cron Triggers: plain-English meaning, the next runs in UTC and your time zone, and the Wrangler and Nitro scheduledTasks config.","Build a cron trigger, read it in plain English, see its next runs and copy the Wrangler and Nitro config.",[]]