Nuxt v4.6.2 landed on 16 October, a week after 4.6.1. The release notes call it a patch release and list no upgrade notes, but the changelog has several items that change behaviour you may depend on. This post sorts them by what you should actually verify after upgrading.
The two changes worth a deliberate look
Server island head goes through useHeadSafe rules
The release applies useHeadSafe rules to the head produced by server islands. useHeadSafe is the restricted variant of useHead: it keeps only an allow-list of attributes per element and drops the rest, such as innerHTML on scripts or http-equiv on meta tags. The docs recommend it whenever head data can come from user-generated content.
The release notes give a one-line description, so I can't tell you exactly which head entries from an island will now be filtered. The practical reading is that an island can no longer emit arbitrary script content or dangerous meta attributes into the host page's head. If a server island currently relies on that, for example by injecting an inline script through useHead, check the rendered <head> after the upgrade.
<script setup lang="ts">
// Inside a .server.vue island component
useHead({
title: "Profile",
meta: [{ name: "description", content: "Public profile" }], // plain meta survives
// script: [{ innerHTML: "..." }] // the kind of entry that useHeadSafe rules drop
});
</script>
This follows the 4.5.1 security release, which, per the release list, fixed several server-island issues. Treat 4.6.2 as continued hardening of the same surface rather than a new feature.
Server route rules match case-insensitively
Server route rules are now matched case-insensitively unless routing is configured as case-sensitive. Route rules are how you attach redirect, proxy, headers, swr, isr, prerender and similar per-route behaviour:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
"/admin/**": { headers: { "cache-control": "no-store" } },
"/proxy/**": { proxy: "https://api.example.com/**" },
},
});
Why this matters: a rule written for /admin/** that only matches lowercase paths is easy to sidestep with /Admin/x if the router itself resolves that request. Making rule matching agree with routing closes that kind of gap. I did not find a Nuxt doc page describing the case-sensitivity option itself, so I won't name a config key; check how your app handles routing sensitivity and test a few mixed-case URLs against rules that set headers or caching.
If you use swr or isr rules, remember that 4.5.1 already told people to purge CDN or edge caches after its fixes. 4.6.2 does not repeat that instruction.
Fixes by area
Navigation and routing
- Error state is preserved when a navigation is aborted or cancelled (#36546).
- A page transition is no longer started when there is no page to leave (#36535).
- Scroll offsets now work for element IDs that begin with a digit (#36524).
- The middleware layout is kept when a deferred prerendered route is restored (#36560).
appMiddlewaregiven as a string or an array is normalised (#36565).- Router params are read from the path h3 matched.
If you have custom scroll behaviour or anchors like #2026-roadmap, the digit-leading ID fix is the one to retest.
Server and Nitro
- Response headers are passed to
render:responselisteners (#36583). - Server tsconfig is preserved when the build directory is relocated (#36494).
- Unused h3 imports are avoided in the
nuxt/serverruntime (#36609). - h3 and Nitro presets are disabled only when
nitroAutoImportsis off (#36548). AnyFetchPathis re-exported for emitted server route types (#36610).- Dependencies under absolute transpile directories are no longer inlined (#36540).
The render:response change is the most visible for module authors: hooks that inspect or log headers now get them. Combined with the typed $fetch rebuild in 4.6.0, the AnyFetchPath re-export fixes a case where generated declarations referenced a type that consumers could not import.
Vite and dev server
- Compile-error overlays are replayed only to newly loaded pages (#36611).
- The dev SSR entry is warmed up from a Nitro plugin (#36615).
- Inlined
vueresolves to its bundler build in dev (#36569). - Null-byte virtual CSS is linked through
/@id/in dev (#36549). - The SPA loading template location is respected in vite-server (#36536).
Kit and schema
- Module directories with a dot in their name are no longer excluded from the app tsconfig (#36331).
- Module dependencies are resolved from the declaring module (#36542).
- The filename-derived handler method is lowercased on Nitro v2 (#36567).
experimental.typescriptPlugingets a default value (#36561).
The handler-method fix matters if you name server files like users.GET.ts and run Nitro v2: the method derived from the filename is now lowercased. Module authors should note the dependency resolution change, since resolving from the declaring module avoids picking up a version from the consuming app.
Vapor
Nuxt now detects Vapor slots using rawVaporSlotKey from Vue (#36614). This pairs with the Vapor work covered in the Vue 3.6 release candidate posts; it only affects you if you are experimenting with Vapor components.
Upgrade checklist
- Run
npx nuxt upgradeand let the lockfile dedupe; the 4.5.1 notes recommended--dedupe. - Render a page that includes a server island and diff its
<head>against the previous version. - Request a few protected or cached paths with mixed-case URLs and confirm the headers and cache behaviour you expect.
- If you write modules, re-run your test fixtures: resolution from the declaring module and the tsconfig exclusion change both alter what a module sees.
- Check any custom
render:responsehook; it now receives response headers.
Trade-offs and caveats
- The release notes are terse. Several entries have no PR number on the page, only a commit hash, so the exact edge cases are in the commits. Read the diffs for the items you rely on rather than trusting a summary, including this one.
- Stricter head handling in islands can break legitimate but unusual setups. The upside is a smaller injection surface; the cost is that anything outside the allow-list silently disappears.
- Case-insensitive matching is the safer default for rules that guard behaviour, but it can surprise anyone who intentionally had distinct rules for different casings.
- There are no listed breaking changes, which is reasonable for a patch, but "no upgrade notes" is not the same as "no behavioural change", as the two items above show.