---
title: "Nuxt 3 reaches end of life on 31 July: a checklist · vuejs.school"
description: "Nuxt 3 stops getting fixes on Friday. Patch to 3.21.10 today, check your modules and Node version, then plan the move to Nuxt 4 in order."
canonical_url: "https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist"
meta:
  "og:description": "Nuxt 3 stops getting fixes on Friday. Patch to 3.21.10 today, check your modules and Node version, then plan the move to Nuxt 4 in order."
  "og:image": "https://vuejs.school/_og/d/a_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3QgwrcgdnVlanMuc2Nob29s%2Cc_OgCard.takumi%2Ctitle_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3Q%2Cdescription_~TnV4dCAzIHN0b3BzIGdldHRpbmcgZml4ZXMgb24gRnJpZGF5LiBQYXRjaCB0byAzLjIxLjEwIHRvZGF5LCBjaGVjayB5b3VyIG1vZHVsZXMgYW5kIE5vZGUgdmVyc2lvbiwgdGhlbiBwbGFuIHRoZSBtb3ZlIHRvIE51eHQgNCBpbiBvcmRlci4%2Ceyebrow_~UmVsZWFzZSBub3RlcyDCtyA3IG1pbiByZWFk%2Ctint_sky%2Cp_Ii9jb21tdW5pdHkvYmxvZy9udXh0LTMtZW5kLW9mLWxpZmUtYS1jaGVja2xpc3Qi%2Cs_xSvRyGk5viysuQw5.png"
  "og:image:alt": "Nuxt 3 reaches end of life on 31 July: a checklist · vuejs.school"
  "og:image:height": "600"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "Nuxt 3 reaches end of life on 31 July: a checklist · vuejs.school"
  "twitter:image": "https://vuejs.school/_og/d/a_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3QgwrcgdnVlanMuc2Nob29s%2Cc_OgCard.takumi%2Ctitle_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3Q%2Cdescription_~TnV4dCAzIHN0b3BzIGdldHRpbmcgZml4ZXMgb24gRnJpZGF5LiBQYXRjaCB0byAzLjIxLjEwIHRvZGF5LCBjaGVjayB5b3VyIG1vZHVsZXMgYW5kIE5vZGUgdmVyc2lvbiwgdGhlbiBwbGFuIHRoZSBtb3ZlIHRvIE51eHQgNCBpbiBvcmRlci4%2Ceyebrow_~UmVsZWFzZSBub3RlcyDCtyA3IG1pbiByZWFk%2Ctint_sky%2Cp_Ii9jb21tdW5pdHkvYmxvZy9udXh0LTMtZW5kLW9mLWxpZmUtYS1jaGVja2xpc3Qi%2Cs_xSvRyGk5viysuQw5.png"
  "twitter:image:alt": "Nuxt 3 reaches end of life on 31 July: a checklist · vuejs.school"
---

> Index of every page on this site: [llms.txt](https://vuejs.school/llms.txt)

## What end of life means for a 3.x app

End of life means the 3.x line is no longer maintained. Your app keeps running on 1 August. What stops is the flow of fixes: a vulnerability reported after Friday gets a patch for Nuxt 4, and no 3.x release is promised for it.

The date has moved once. When Nuxt 4.0 shipped on 15 July 2025, its announcement promised Nuxt 3 maintenance (bug fixes and backports from 4) until the end of January 2026. The [Nuxt 4.3 post](https://nuxt.com/blog/v4-3) of 22 January extended that: security updates and critical bug fixes would continue, and Nuxt 3 would meet its end of life on 31 July 2026. The [Nuxt 4.5 release](https://nuxt.com/blog/v4-5) on 18 July repeated the date and called its companion, 3.21.9, one of the last few 3.x releases.

## What the 27 July patches fix

The security post groups its advisories under seven headings, six for Nuxt and one for Nuxt DevTools. Each entry below says who is affected:

- **Remote code execution through server island props (High).** Only if `vue.runtimeCompiler` is switched on (it is off by default) and island props can reach dynamic component resolution such as `<component :is>`.
- **Unauthorised component instantiation through island props (Medium).** No runtime compiler needed. An island that forwards an undeclared prop onto a polymorphic `as` root could be made to render an arbitrary element or component. It does not allow code execution.
- **Route rule authorisation bypass (High).** Apps that use `routeRules` with `appMiddleware` as an access check, where a rule key contains an uppercase letter, for example one derived from `pages/Admin.vue`. This is a regression introduced by the fix for CVE-2026-53721, so being on 4.4.7 or 3.21.7 does not protect you.
- **Server component denial of service (High).** Any app with server components or islands. An unauthenticated request could crash the server.
- **Cross-user payload disclosure on cached pages (High).** 4.x only, from 4.4.0. With `cache`, `swr` or `isr` route rules on pages that show per-user data, the cached `_payload.json` could reach another visitor.
- **Dev server path disclosure (Low).** Only when running `nuxi dev --host` on an untrusted network.
- **DevTools remote code execution (Critical, development only).** Anyone who runs `nuxt dev` with DevTools enabled. Fixed in `@nuxt/devtools` 3.3.1, which a refreshed lockfile pulls in.

Two follow-ups after upgrading:

- **Route rules now match case-insensitively**, like Vue Router. If you relied on case-sensitive matching, set `router.options.sensitive: true` in your config.
- **On 4.x, purge your CDN if you cache authenticated pages.** A leaked `_payload.json` may already sit in an edge cache, and upgrading does not evict it.

If you are pinned to an older release and cannot upgrade yet, the post points to Socket's Certified Patches as a stopgap, while saying that upgrading remains the recommended fix.

## Step 1: patch to 3.21.10 today

On a 3.x project, keep the upgrade on the 3.x line with the `--channel=v3` flag (the command the Nuxt 4.5 post gives), then confirm what you got:

```
npx nuxt@latest upgrade --dedupe --channel=v3
npm ls nuxt @nuxt/devtools
```

`--dedupe` rewrites the lockfile, which is how `@nuxt/devtools` 3.3.1 arrives. The second command should print `nuxt@3.21.10` and a DevTools version of 3.3.1 or later. Run your tests, deploy, and commit this change on its own.

## Step 2: audit your modules

Modules are where an upgrade stalls. Open `nuxt.config.ts`, copy the `modules` array into a list, and check each one's latest release for Nuxt 4 support. Sort them into three groups: already works on 4, has a newer major that does, and unmaintained.

Nuxt helps with this. A module can declare which Nuxt versions it supports in its `meta.compatibility`. When the running Nuxt falls outside that range, Nuxt skips the module and logs `Module <name> is disabled due to incompatibility issues`. A skipped module is easy to miss in a busy dev log, and the app may still boot without it. During the migration, make that warning an error:

*nuxt.config.ts*

```
export default defineNuxtConfig({
  modules: ['@nuxt/image', '@nuxtjs/i18n'],
  experimental: {
    enforceModuleCompatibility: true,
  },
})
```

With the flag on, an incompatible module stops the build with a `ModuleCompatibilityError` instead of disappearing quietly. Upgrade the modules that have a release supporting both 3 and 4 now, while you are still on 3, so each change is tested on its own. For an unmaintained module, look for a replacement before you touch Nuxt.

## Step 3: move to Node 24 before Nuxt 4

Nuxt 4.5.1 accepts fewer Node versions than Nuxt 3.21.10:

Run `node --version` on your machine, in CI and on your hosting platform. Node 20 reached its own end of life on 30 April, so a project still on it has two unsupported pieces, not one. Move to Node 24.11 or a later 24.x release (Node 24 is the active long-term support line), and do it as a separate change on Nuxt 3.21.10, which runs on both Node 20 and Node 24.

## Step 4: turn on Nuxt 4 behaviour while still on 3

Since Nuxt 3.12, a 3.x project can opt in to many of Nuxt 4's breaking changes with one setting. This is the bridge: you fix what breaks with the old version still installed, and the final upgrade becomes small.

*nuxt.config.ts*

```
export default defineNuxtConfig({
  future: {
    compatibilityVersion: 4,
  },
})
```

If your project uses layers, the 3.x upgrade guide says each layer that opts in needs this setting too. Then run the codemods the [upgrade guide](https://nuxt.com/docs/4.x/getting-started/upgrade) recommends. The guide pins the version because of a bug in later releases:

```
npx codemod@0.18.7 nuxt/4/migration-recipe
```

The recipe runs its codemods one after another and lets you deselect any of them. It moves `pages/`, `components/`, `composables/` and the other app folders into `app/` (with `server/` staying at the root) and rewrites code for several of the data-fetching changes.

One of those changes needs a decision. With Nuxt 4 behaviour on, `data` from `useFetch` and `useAsyncData` is a shallow ref: fetching new data still updates the page, but changing a property inside it no longer re-renders anything. The recipe's `shallow-function-reactivity` step adds `{ deep: true }` to the calls it finds, which brings back Nuxt 3's deep reactivity and gives up the performance gain for deeply nested data.

That step is worth deselecting. The guide says most code needs no change, so fix by hand only the code that changes `data` in place, like this page:

*app/pages/todos.vue**Breaks***

```
<script setup lang="ts">
interface Todo { id: number, title: string, done: boolean }

const { data: todos } = await useFetch<Todo[]>('/api/todos')

function markDone(todo: Todo) {
  todo.done = true
}
</script>

<template>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      <button type="button" @click="markDone(todo)">
        {{ todo.done ? 'Done' : todo.title }}
      </button>
    </li>
  </ul>
</template>
```

The click changes the object, but nothing updates on screen. Opt that one call back in to deep reactivity:

*app/pages/todos.vue**Works***

```
const { data: todos } = await useFetch<Todo[]>('/api/todos', { deep: true })
```

Also search for `=== null` checks on `data` and `error`: both now start as `undefined`.

## Step 5: upgrade to Nuxt 4.5.1

When the app is green with `compatibilityVersion: 4`, install Nuxt 4, refresh the lockfile, and remove the `future` block:

```
npm install nuxt@^4.5.1
npx nuxt upgrade --dedupe
```

The second command is the one the Nuxt 4.5 post recommends: it deduplicates the lockfile so the libraries Nuxt depends on move with it. Three major versions change underneath you at once:

- **Vite 7 to 8.** The Nuxt 4.5 post asks you to check custom Vite plugins and config against the Vite migration guide.
- **Vue Router 4.6 to 5**, which Nuxt switched to in 4.4.
- **unhead 2 to 3**, the library behind `useHead`. The Nuxt 4.5 post warns that its stricter `useHead` types can surface type errors.

Run `nuxt typecheck` and your test suite, and read what fails before reaching for workarounds.

Our step-by-step walkthrough of upgrading a small Nuxt 3 app, written a week after Nuxt 4.0 shipped, shows each of these stages with the diff to expect. It still holds; add the Node and Vite notes from this post.

## A timeline for teams starting this week

Friday is not a migration deadline. It is the day the safety net goes. A sensible order:

1. Today: patch to 3.21.10 and deploy.
2. This week: the module list, the Node upgrade, and `enforceModuleCompatibility`.
3. Next week: a branch with `compatibilityVersion: 4` and the codemods, merged when tests pass.
4. The week after: the upgrade to 4.5.1, deployed to a preview environment first.

A team of one with a small app can get through items 2 to 4 in a couple of days. A large app with many modules should still finish within the month, because every week on 3.x after Friday is a week without security fixes.

**Check it stuck**3 questions from the Modules, plugins and layers quiz.

[**Practice now**](https://vuejs.school/learn/nuxt/modules-and-the-nuxt-ecosystem?tab=quiz)

**Was this helpful?**

## **Keep reading**

[Release notes · 7 min read**What's new in Nuxt 4.6: nuxt/server, typed $fetch, cookie sessions and Vapor**](https://vuejs.school/community/blog/whats-new-in-nuxt-4-6) [Tutorial · 6 min read**useFetch or $fetch? Picking the right one in Nuxt**](https://vuejs.school/community/blog/usefetch-or-fetch-picking-the-right-one-in-nuxt)

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://vuejs.school/#website","@type":"WebSite","description":"A free AI-instructed school for Vue.js. Short tutorials, runnable code and quizzes that adapt to you.","name":"vuejs.school","url":"https://vuejs.school/","publisher":{"@id":"https://vuejs.school/#identity"}},{"@id":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist#webpage","@type":"WebPage","dateModified":"2026-10-27T19:31:40.253Z","datePublished":"2026-07-28","description":"Nuxt 3 stops getting fixes on Friday. Patch to 3.21.10 today, check your modules and Node version, then plan the move to Nuxt 4 in order.","name":"Nuxt 3 reaches end of life on 31 July: a checklist","url":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist","breadcrumb":{"@id":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist#breadcrumb"},"isPartOf":{"@id":"https://vuejs.school/#website"},"potentialAction":[{"@type":"ReadAction","target":["https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist"]}],"primaryImageOfPage":{"@id":"https://vuejs.school/#logo"}},{"@id":"https://vuejs.school/#identity","@type":"Organization","description":"A free AI-instructed school for Vue.js. Short tutorials, runnable code and quizzes that adapt to you.","name":"vuejs.school","url":"https://vuejs.school","logo":{"@id":"https://vuejs.school/#logo"}},{"@id":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist#article","dateModified":"2026-10-27T19:31:40.253Z","datePublished":"2026-07-28","description":"Nuxt 3 stops getting fixes on Friday. Patch to 3.21.10 today, check your modules and Node version, then plan the move to Nuxt 4 in order.","headline":"Nuxt 3 reaches end of life on 31 July: a checklist","inLanguage":"en","isAccessibleForFree":true,"thumbnailUrl":"https://vuejs.school/_og/d/a_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3QgwrcgdnVlanMuc2Nob29s%2Cc_OgCard.takumi%2Ctitle_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3Q%2Cdescription_~TnV4dCAzIHN0b3BzIGdldHRpbmcgZml4ZXMgb24gRnJpZGF5LiBQYXRjaCB0byAzLjIxLjEwIHRvZGF5LCBjaGVjayB5b3VyIG1vZHVsZXMgYW5kIE5vZGUgdmVyc2lvbiwgdGhlbiBwbGFuIHRoZSBtb3ZlIHRvIE51eHQgNCBpbiBvcmRlci4%2Ceyebrow_~UmVsZWFzZSBub3RlcyDCtyA3IG1pbiByZWFk%2Ctint_sky%2Cp_Ii9jb21tdW5pdHkvYmxvZy9udXh0LTMtZW5kLW9mLWxpZmUtYS1jaGVja2xpc3Qi%2Cs_xSvRyGk5viysuQw5.png","@type":["Article","BlogPosting"],"articleSection":["Release notes"],"author":{"@id":"https://vuejs.school/#identity"},"image":{"@id":"https://vuejs.school/#/schema/image/1"},"isPartOf":{"@id":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist#webpage"},"mainEntityOfPage":{"@id":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist#webpage"},"publisher":{"@id":"https://vuejs.school/#identity"}},{"@id":"https://vuejs.school/community/blog/nuxt-3-end-of-life-a-checklist#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"Blog","item":"https://vuejs.school/community/blog","position":1},{"@type":"ListItem","name":"Nuxt 3 reaches end of life on 31 July: a checklist","position":2}]},{"@id":"https://vuejs.school/#logo","@type":"ImageObject","caption":"vuejs.school","contentUrl":"https://vuejs.school/apple-touch-icon.png","inLanguage":"en","url":"https://vuejs.school/apple-touch-icon.png"},{"@id":"https://vuejs.school/#/schema/image/1","@type":"ImageObject","contentUrl":"https://vuejs.school/_og/d/a_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3QgwrcgdnVlanMuc2Nob29s%2Cc_OgCard.takumi%2Ctitle_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3Q%2Cdescription_~TnV4dCAzIHN0b3BzIGdldHRpbmcgZml4ZXMgb24gRnJpZGF5LiBQYXRjaCB0byAzLjIxLjEwIHRvZGF5LCBjaGVjayB5b3VyIG1vZHVsZXMgYW5kIE5vZGUgdmVyc2lvbiwgdGhlbiBwbGFuIHRoZSBtb3ZlIHRvIE51eHQgNCBpbiBvcmRlci4%2Ceyebrow_~UmVsZWFzZSBub3RlcyDCtyA3IG1pbiByZWFk%2Ctint_sky%2Cp_Ii9jb21tdW5pdHkvYmxvZy9udXh0LTMtZW5kLW9mLWxpZmUtYS1jaGVja2xpc3Qi%2Cs_xSvRyGk5viysuQw5.png","inLanguage":"en","url":"https://vuejs.school/_og/d/a_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3QgwrcgdnVlanMuc2Nob29s%2Cc_OgCard.takumi%2Ctitle_~TnV4dCAzIHJlYWNoZXMgZW5kIG9mIGxpZmUgb24gMzEgSnVseTogYSBjaGVja2xpc3Q%2Cdescription_~TnV4dCAzIHN0b3BzIGdldHRpbmcgZml4ZXMgb24gRnJpZGF5LiBQYXRjaCB0byAzLjIxLjEwIHRvZGF5LCBjaGVjayB5b3VyIG1vZHVsZXMgYW5kIE5vZGUgdmVyc2lvbiwgdGhlbiBwbGFuIHRoZSBtb3ZlIHRvIE51eHQgNCBpbiBvcmRlci4%2Ceyebrow_~UmVsZWFzZSBub3RlcyDCtyA3IG1pbiByZWFk%2Ctint_sky%2Cp_Ii9jb21tdW5pdHkvYmxvZy9udXh0LTMtZW5kLW9mLWxpZmUtYS1jaGVja2xpc3Qi%2Cs_xSvRyGk5viysuQw5.png"}]}
```