Skip to content

Update devDependency nuxt to v3.21.6 [SECURITY]#174

Open
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-nuxt-vulnerability
Open

Update devDependency nuxt to v3.21.6 [SECURITY]#174
renovate[bot] wants to merge 1 commit into
mainfrom
renovate/npm-nuxt-vulnerability

Conversation

@renovate

@renovate renovate Bot commented Mar 19, 2025

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
nuxt (source) 3.14.1593.21.6 age confidence

Nuxt allows DOS via cache poisoning with payload rendering response

CVE-2025-27415 / GHSA-jvhm-gjrh-3h93

More information

Details

Summary

By sending a crafted HTTP request to a server behind an CDN, it is possible in some circumstances to poison the CDN cache and highly impacts the availability of a site.

It is possible to craft a request, such as https://mysite.com/?/_payload.json which will be rendered as JSON. If the CDN in front of a Nuxt site ignores the query string when determining whether to cache a route, then this JSON response could be served to future visitors to the site.

Impact

An attacker can perform this attack to a vulnerable site in order to make a site unavailable indefinitely. It is also possible in the case where the cache will be reset to make a small script to send a request each X seconds (=caching duration) so that the cache is permanently poisoned making the site completely unavailable.

Conclusion :

This is similar to a vulnerability in Next.js that resulted in CVE-2024-46982 (and see this article, in particular the "Internal URL parameter and pageProps" part, the latter being very similar to the one concerning us here.)

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt has Client-Side Path Traversal in Nuxt Island Payload Revival

CVE-2025-59414 / GHSA-p6jq-8vc4-79f6

More information

Details

Summary

A client-side path traversal vulnerability in Nuxt's Island payload revival mechanism allowed attackers to manipulate client-side requests to different endpoints within the same application domain when specific prerendering conditions are met.

Technical Details

The vulnerability occurs in the client-side payload revival process (revive-payload.client.ts) where Nuxt Islands are automatically fetched when encountering serialized __nuxt_island objects. The issue affects the following flow:

  1. During prerendering, if an API endpoint returns user-controlled data containing a crafted __nuxt_island object
  2. This data gets serialized with devalue.stringify and stored in the prerendered page
  3. When a client navigates to the prerendered page, devalue.parse deserializes the payload
  4. The Island reviver attempts to fetch /__nuxt_island/${key}.json where key could contain path traversal sequences
Prerequisites for Exploitation

This vulnerability requires all of the following conditions:

  1. Prerendered pages: The application must use Nuxt's prerendering feature (nitro.prerender)
  2. Attacker-controlled API responses: The attacker must be able to control the response content of an API endpoint that is called during prerendering via useFetch, useAsyncData, or similar composables
  3. Client-side navigation: A user must navigate to the prerendered page (not during initial SSR hydration)
Attack Scenario
// Malicious API response during prerendering
{
  "__nuxt_island": {
    "key": "../../../../internal/service",
    "params": { "action": "probe" }
  }
}

This could cause the client to make requests to /__nuxt_island/../../../../internal/service.json if path traversal is not properly handled by the server.

Impact Assessment
  • Limited Impact: The vulnerability has a low severity due to the highly specific prerequisites
  • No Direct Data Exfiltration: The vulnerability does not directly expose sensitive data
  • Client-Side Only: Requests originate from the client, not the server
Mitigation

Action Required:

  • Update to Nuxt 3.19.0+ or 4.1.0+ immediately
  • Review any prerendered pages that fetch external or user-controlled data

Temporary Workarounds (if immediate update is not possible):

  1. Disable prerendering for pages that fetch user-controlled data
  2. Implement strict input validation on API endpoints used during prerendering
  3. Use allowlists for API response structures during prerendering
Fix Details

The fix implemented validation for Island keys in revive-payload.server.ts:

  • Island keys must match the pattern /^[a-z][a-z\d-]*_[a-z\d]+$/i
  • Maximum length of 100 characters
  • Prevents path traversal and special characters

Severity

  • CVSS Score: 3.1 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: Reflected XSS in navigateTo() external redirect

CVE-2026-45669 / GHSA-fx6j-w5w5-h468

More information

Details

Summary

navigateTo() with external: true generates a server-side HTML redirect body containing a <meta http-equiv="refresh"> tag. The destination URL is only sanitized by replacing " with %22, leaving <, >, &, and ' unencoded. An attacker who can influence the URL passed to navigateTo(url, { external: true }) can break out of the content="…" attribute and inject arbitrary HTML/JavaScript that executes under the application's origin.

This is a different root cause from CVE-2024-34343 (GHSA-vf6r-87q4-2vjf), which addressed javascript: protocol bypass. The issue here is triggered by any valid URL containing >.

Impact

Applications that pass user-controlled input to navigateTo(url, { external: true }) — typically via a ?next= / ?redirect= query parameter used for post-login or "return to" flows — are vulnerable to reflected cross-site scripting. The injected script runs in the context of the application's origin during the server-rendered redirect response, before the meta-refresh fires.

Details

In packages/nuxt/src/app/composables/router.ts, the SSR redirect path builds an HTML response body with only " percent-encoded in the destination URL:

const encodedLoc = location.replace(/"/g, '%22')
nuxtApp.ssrContext!['~renderResponse'] = {
status: sanitizeStatusCode(options?.redirectCode || 302, 302),
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
headers: { location: encodeURL(location, isExternalHost) },
}

The Location header is normalised through encodeURL() (which uses the URL constructor and correctly percent-encodes attribute-significant characters). The HTML body uses a narrower sanitiser. That mismatch is the root cause.

Proof of concept

Global middleware that forwards a query parameter to navigateTo:

// middleware/redirect.global.ts
export default defineNuxtRouteMiddleware((to) => {
const next = to.query.next as string | undefined
if (next) {
 return navigateTo(next, { external: true })
}
})

Request:

GET /?next=https://evil.example/x><img src=x onerror=alert(document.domain)>

Response body:

<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=https://evil.example/x><img src=x onerror=alert(document.domain)>"></head></html>

The > after evil.example/x terminates the content="…" attribute, and the <img onerror> tag executes JavaScript in the application's origin before any redirect
occurs.

Patches

Fixed in nuxt@4.4.6 and nuxt@3.21.6 by #​35052. The fix percent-encodes the full set of HTML-attribute-significant characters (&, ", ', <, >) before interpolating the URL into the meta-refresh body

Workarounds

If you can't upgrade immediately, validate user-controlled URLs before passing them to navigateTo(url, { external: true }). At minimum, normalise through new URL(input).toString() and reject inputs containing < or > (a normalised URL with these characters is malformed and safe to refuse).

Severity

  • CVSS Score: 5.3 / 10 (Medium)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Nuxt: __nuxt_island endpoint does not bind responses to request props, enabling shared-cache poisoning

CVE-2026-46342 / GHSA-g8wj-3cr3-6w7v

More information

Details

Summary

The /__nuxt_island/* endpoint accepts attacker-controlled props query/body parameters and renders any island component without verifying that the URL-resident hash (<Name>_<hashId>.json) was actually issued for those inputs by <NuxtIsland>. The hash is computed and embedded client-side but never validated server-side, so the same path can return materially different responses depending on the query.

Island components are documented as rendering independently of route context - page middleware does not apply to them, and they are intentionally cacheable as a function of their props. This advisory does not treat that contract as a vulnerability. It treats the absence of a binding between the URL the cache keys on and the response served at that URL as one.

Impact

In applications where a CDN or reverse-proxy in front of the app caches /__nuxt_island/* keyed by path only (ignoring query) - a documented misconfiguration class, see GHSA-jvhm-gjrh-3h93 - an attacker can prime the cache for a path with their own choice of props, and subsequent users requesting the same path receive the attacker's rendered HTML rather than the response intended for them. The cache entry persists until normal expiry.

Where the affected island has any prop flowing into an unsafe HTML sink in application code (v-html, innerHTML, a third-party renderer treating a prop as HTML), this becomes stored XSS in the embedding page's origin until the cache entry expires. HttpOnly cookies remain out of reach but anything else in the origin (other cookies, in-origin requests, DOM state) is reachable by the injected script.

Preconditions:

  • experimental.componentIslands enabled (or the default 'auto' with at least one server / island component in the app).
  • A shared intermediary cache (CDN, reverse-proxy, edge cache) keyed on path only.
  • For the XSS pivot specifically: an application-authored island that puts a prop through an unsafe HTML sink.

Without the second precondition, the response shape is per-request and unaffected. Without the third, the worst case is content-swap / inert HTML injection rather than script execution.

Patches

Patched in nuxt@4.4.6 and nuxt@3.21.6 by #​35077. The island handler now recomputes the expected hashId from (name, props, context) using the same ohash function <NuxtIsland> already uses to embed the hash in the URL, and rejects requests (HTTP 400) whose URL-resident hash does not match. The response is now a pure function of the request path: a path-keyed shared cache returns the correct response to every requester for that path, and an attacker cannot synthesise a path whose hash matches arbitrary props.

Workarounds

For users unable to upgrade immediately:

  • Ensure any intermediary cache keys /__nuxt_island/* on the full query string, not on the path alone. This is the recommended configuration regardless.
  • Audit application-authored islands for props flowing into v-html / innerHTML / similar HTML sinks; treat island props as untrusted user input.
Note on island authentication

[!IMPORTANT]
It's important to remember that route middleware does not run when rendering island components, and islands cannot rely on routing-layer auth. Applications gating sensitive data behind page middleware should enforce that auth inside the island's own data layer (server-only routes, useRequestEvent + manual session checks, etc.) rather than relying on the embedding page's middleware - this was true before this advisory and remains true after it.

A separate advisory addresses *.server.vue pages registered as page_<routeName> islands, where the documented "middleware doesn't run for islands" contract collides with the page's own definePageMeta({ middleware }) declaration in a way that constitutes a genuine bug rather than documented behaviour.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N

References

This data is provided by the GitHub Advisory Database (CC-BY 4.0).


Release Notes

nuxt/nuxt (nuxt)

v3.21.6

Compare Source

3.21.6 is the next patch release.

👉 Changelog

compare changes

🩹 Fixes
  • nuxt: Prefer our own builder/server deps (#​35029)
  • nitro: Add json extension to payload cache items (#​35043)
  • nuxt: Handle errors fetching app manifest (#​35050)
  • nuxt: Preserve setPageLayout props on same-path navigation (#​35055)
  • vite: Don't strip buildAssetsDir from vite-node SSR ids (#​35040)
  • nuxt: Mark useLoadingIndicator properties as readonly (#​35062)
  • vite: Strip queries in css inline styles map (#​35067)
  • nuxt: Encode html-significant characters in external redirect body (#​35052)
  • nitro: Validate island request hash matches props (#​35077)
  • nitro: Use regexp to strip query (042b615e6)
  • nitro: Use statusCode for nitro v2 compatibility (82dcd6a31)
  • nuxt: Render component-less parent routes during client-side nav (#​35036)
  • nuxt: Run middleware for page islands (#​35092)
💅 Refactors
  • rspack,webpack: Extract same-origin check for dev middleware (#​35051)
📖 Documentation
  • Remove CSB, set node 22 and use steps for clarity (#​35066)
🏡 Chore
✅ Tests
  • Relax relative time assertion (256513eb0)
  • Move build assets dir fixture out of app/ (6d2ac69ff)
🤖 CI
❤️ Contributors

v3.21.5

Compare Source

3.21.5 is the next patch release.

👉 Changelog

compare changes

🔥 Performance
  • kit: Cache layer roots and short-circuit isIgnored relative (#​35015)
🩹 Fixes
  • nitro: Correct payload route rule for / + override ssr: true (#​34990)
  • nitro: Break recursive rendering deadlocks during prerender (#​34939)
  • vite: Drop redundant css link when entry styles are inlined (#​34950)
  • nuxt: Only force suspense remount after first resolve (#​34949)
  • kit: Read .env before resolving nuxt schema (#​34958)
  • nitro: Preserve serverHandlers array after nitro:config (#​34985)
  • vite: Only consider CSS inlined when styles are actually emitted (#​35006)
  • nuxt: Handle string presets in auto-imports (#​35013)
  • nuxt: Correct island transform for server pages and 'deep' mode (#​35005)
  • vite: Inline css for non-island children of server components (#​35001)
  • nuxt: Defer head DOM updates until page transition finishes (#​35016)
  • nuxt: Explicitly freeze head during island plugin phase (#​35010)
  • vite: Inline css imported from non-vue js modules (#​35020)
  • nitro: Remove unused middleware (fe857d36b)
📖 Documentation
  • Add warning about routing in server components (#​34994)
🏡 Chore
✅ Tests
  • Extract server components fixture + add some failing tests (#​34995)
  • Isolate buildDir per matrix project for shared fixtures (#​35007)
  • Split env testing into separate file (fd4019cf8)
  • Use 3.x style tsconfig (86625efad)
  • Use more 3.x style tsconfigs (4a9bde3f3)
  • Correct import path (133d5f6d7)
  • Update snapshots (9fc42f788)
❤️ Contributors

v3.21.4

Compare Source

v3.21.2

Compare Source

v3.21.1

Compare Source

3.21.1 is a regularly schedule patch release.

👉 Changelog

compare changes

🩹 Fixes
  • nuxt: Correct reference format of server builder (#​34177)
  • nuxt: Add status/statusText getters to NuxtError (#​34188)
  • schema: Add direnv and vendor to default ignore (#​34190)
  • nuxt: Focus hash links after navigation (#​34193)
  • nuxt: Exclude head runtime from unhead imports transform (#​34195)
  • kit: Include prereleases in semver satisfy check (#​34210)
  • nuxt: Watch server/ for builder:watch hook (#​34208)
  • nitro: Encode unicode paths in x-nitro-prerender header (#​34202)
  • nitro: Preserve error.message for fatal errors (#​34226)
  • Only enable dynamic imports when ts plugin (#​34205)
  • webpack: Use H3Error for 403 in dev server (#​34233)
  • nuxt: Ensure NuxtError extends Error type (#​34242)
  • vite: Use H3Error for 404 in dev server (#​34225)
  • nuxt: Add backwards compat for #app barrel export in keyed functions (#​34199)
  • nuxt: Track + re-add custom routes on hmr (#​32044)
  • nuxt: Keep vnode when leaving deeper nested route (#​33778)
  • vite: Prevent CSS flickering in dev mode after config changes (#​33856)
  • nuxt: Do not start view transition if there is no route (#​33723)
  • nuxt: Call deferHydration done on NuxtPage unmount (#​34152)
  • nuxt: Handle invalid datetime in ` (#​33992)
  • nuxt: Preserve middleware error status in 404 fallback (#​34148)
  • nitro: Do not augment nuxt/schema (#​34255)
  • nuxt: Cache manifest files to preserve buildId (#​34002)
  • nuxt: Don't decode query string in SSR context URL (#​34252)
  • nuxt: Allow specifying moduleDependencies by meta.name (#​34263)
  • nuxt: Resolve #components import mapping conflict for packages outside rootDir (#​34139)
  • vite,webpack: Use node.res to send 403/404 (#​34266)
  • nitro,nuxt: Align path encoding with vue-router (#​34265)
  • nitro: Augment nuxt/schema once more (9f5bb611d)
💅 Refactors
  • nuxt: Prefer genObjectKey to omit unnecessary quotes (#​34245)
  • nuxt: Use ComponentProps helper to extract layout props (#​34248)
📖 Documentation
  • Remove link to ai guide entirely (084b5d7f2)
  • Update roadmap dates (#​34166)
  • Clarify shared type context limitations for custom imports (#​34194)
  • Fix broken links (#​34223)
  • Document payload extraction for ISR/SWR routes (#​34222)
  • Update example of email validation (#​34247)
  • Add documentation for keyedComposables (#​34201)
🏡 Chore
✅ Tests
  • Vitest v4 compatibility (70e147b71)
  • Add runtime tests for deeply nested <NuxtPage> navigation (707a9dc44)
  • Resolve merge issues in tests (85abddc54)
❤️ Contributors

v3.21.0

Compare Source

3.21.0 is the next minor release.

Nuxt 4.3 and 3.21 bring powerful new features for layouts, caching, and developer experience – plus significant performance improvements under the hood.

📣 Some News

Extended v3 Support

Early this month, I opened a discussion to find out how the upgrade had gone from v3 to v4. I was really pleased to hear how well it had gone for most people.

Having said that, we're committed to making sure no one gets left behind. And so we will continue to provide security updates and critical bug fix releases beyond the previously announced end-of-life date of January 31, 2026, meaning Nuxt v3 will meet its end-of-life on July 31, 2026.

[!TIP]
As usual, today also brings a minor release for v3, with many of the same improvements backported from v4.3.

Preparing for Nuxt 5

We're closer than ever to the releases of Nuxt v5 and Nitro v3. In the coming weeks, the main branch of the Nuxt repository will begin receiving initial commits for Nuxt 5. However, it's still business as usual.

  • Continue making pull requests to the main branch
  • We'll backport changes to the 4.x and 3.x branches

Keep an eye out on the Upgrade Guide – we'll be adding details about how you can already start migrating your projects to prepare for Nuxt v4 with future.compatibilityVersion: 5.

🗂️ Route Rule Layouts

But that's enough about the future. We have a lot of good things for you today!

First, you can now set layouts directly in route rules using the new appLayout property (#​31092). This provides a centralized, declarative way to manage layouts across your application without scattering definePageMeta calls throughout your pages.

export default defineNuxtConfig({
  routeRules: {
    '/admin/**': { appLayout: 'admin' },
    '/dashboard/**': { appLayout: 'dashboard' },
    '/auth/**': { appLayout: 'minimal' }
  }
})

This might be useful for:

  • Admin panels with a shared layout across many routes
  • Marketing pages that need a different layout from the app

[!TIP]
Plus, you can pass props to layouts now! See the setPageLayout improvements below.

📦 ISR/SWR Payload Extraction

Payload extraction now works with ISR (incremental static regeneration), SWR (stale-while-revalidate) and cache routeRules (#​33467). Previously, only pre-rendered pages could generate _payload.json files.

This means:

  • Client-side navigation to ISR/SWR pages can use cached payloads
  • CDNs (Vercel, Netlify, Cloudflare) can cache payload files alongside HTML
  • Fewer API calls during navigation – data can be prefetched and served from the cached payload
export default defineNuxtConfig({
  routeRules: {
    '/products/**': { 
      isr: 3600, // Revalidate every hour
    }
  }
})

🧹 Dev Mode Payload Extraction

Related to the above, payload extraction now also works in development mode (#​30784). This makes it easier to test and debug payload behavior without needing to run a production build.

[!IMPORTANT]
Payload extraction works in dev mode with nitro.static set to true, or for individual pages which have isr, swr, prerender or cache route rules.

🚫 Disable Modules from Layers

When extending Nuxt layers, you can now disable specific modules that you don't need (#​33883). Just pass false to the module's options:

export default defineNuxtConfig({
  extends: ['../shared-layer'],
  // disable @&#8203;nuxt/image from layer
  image: false,
})

🏷️ Route Groups in Page Meta

Route groups (folders wrapped in parentheses like (protected)/) are now exposed in page meta (#​33460). This makes it easy to check which groups a route belongs to in middleware or anywhere you have access to the route.

<script setup lang="ts">
// This page's meta will include: { groups: ['protected'] }
useRoute().meta.groups
</script>
export default defineNuxtRouteMiddleware((to) => {
  if (to.meta.groups?.includes('protected') && !isAuthenticated()) {
    return navigateTo('/login')
  }
})

This provides a clean, convention-based approach to route-level authorization without needing to add definePageMeta to every protected page.

🎨 Layout Props with setPageLayout

The setPageLayout composable now accepts a second parameter to pass props to your layout (#​33805):

export default defineNuxtRouteMiddleware((to) => {
  setPageLayout('admin', {
    sidebar: true,
    theme: 'dark'
  })
})
<script setup lang="ts">
defineProps<{
  sidebar?: boolean
  theme?: 'light' | 'dark'
}>()
</script>

🔧 #server Alias

A new #server alias provides clean imports within your server directory (#​33870), similar to how #shared works:

// Before: relative path hell
import { helper } from '../../../../utils/helper'

// After: clean and predictable
import { helper } from '#server/utils/helper'

The alias includes import protection – you can't accidentally import #server code from client or shared contexts.

🪟 Draggable Error Overlay

The development error overlay introduced in Nuxt 4.2 is now draggable and can be minimized (#​33695). You can:

  • Drag it to any corner of the screen (it snaps to edges)
  • Minimize it to a small pill button when you want to keep working
  • Your position and minimized state persist across page reloads

This is a quality-of-life improvement when you're iterating on fixes and don't want the overlay blocking your view.

https://github.com/user-attachments/assets/nuxt_4-3_error_demo.mp4

⚙️ Async Plugin Constructors

Module authors can now use async functions when adding build plugins (#​33619):

export default defineNuxtModule({
  async setup() {
    // Lazy load only when actually needed
    addVitePlugin(() => import('my-cool-plugin').then(r => r.default()))
    
    // No need to load webpack plugin if using Vite
    addWebpackPlugin(() => import('my-cool-plugin/webpack').then(r => r.default()))
  }
})

This enables true lazy loading of build plugins, avoiding unnecessary code loading when plugins aren't needed.

🚀 Performance Improvements

This release includes several performance optimizations for faster builds:

  • Hook filters - Internal plugins now use filters to avoid running hooks unnecessarily (#​33898)
  • SSR styles optimization - The nuxt:ssr-styles plugin is now significantly faster (#​33862, #​33865)
  • Layer alias transform - Skipped when using Vite (it handles this natively) (#​33864)
  • Route rules compilation - Route rules are now compiled into a client chunk using rou3, removing the need for radix3 in the client bundle and eliminating app manifest fetches (#​33920)

🎨 Inline Styles for Webpack/Rspack

The inlineStyles feature now works with webpack and rspack builders (#​33966), not just Vite. This enables critical CSS inlining for better Core Web Vitals regardless of your bundler choice.

⚠️ Deprecations

statusCodestatus, statusMessagestatusText

In preparation for Nitro v3 and H3 v2, we're moving to use Web API naming conventions (#​33912). The old properties still work but are deprecated in advance of v5:

- throw createError({ statusCode: 404, statusMessage: 'Not Found' })
+ throw createError({ status: 404, statusText: 'Not Found' })

🐛 Bug Fixes

Notable fixes in this release:

  • Fixed head component deduplication using key attribute (#​33958, #​33963)
  • Fixed async data properties not being reactive in Options API (#​34119)
  • Fixed useCookie unsafe number parsing during decode (#​34007)
  • Fixed NuxtPage not re-rendering when nested NuxtLayout has layouts disabled (#​34078)
  • Fixed client-side pathname decoding for non-ASCII route aliases (#​34043)
  • Fixed suspense remounting when navigating after pending state (#​33991)
  • Fixed clipboard copy in error overlay (#​33873)
  • Enabled allowArbitraryExtensions by default in TypeScript config (#​34084)
  • Added noUncheckedIndexedAccess to server tsconfig for safer typing (#​33985)

[!IMPORTANT]
Enabling noUncheckedIndexedAccess in the Nitro server TypeScript config improves type safety but may surface new type errors in your server code. This change was necessary because Nuxt's app context performs type checks on server routes (learn more).

While we recommend keeping this enabled for better type safety, you can disable it if needed:

export default defineNuxtConfig({
  nitro: {
    typescript: {
      tsConfig: {
        compilerOptions: {
          noUncheckedIndexedAccess: false
        }
      }
    }
  }
})

Note that disabling this may allow type errors to slip through that could cause runtime issues with indexed access.

📚 Documentation

  • Improved module author guides with clearer structure (#​33803)
  • Added MCP setup instructions for Claude Desktop (#​33914)
  • Added layers directory documentation (#​33967)
  • Added Deno package manager examples (#​34070)
  • Clarified type-checking context limitations for server routes (#​33964)

🎉 Nuxt 3.21.0

Alongside v4.3.0, we're releasing Nuxt v3.21.0 with many of the same improvements backported to the 3.x branch. This release includes:

  • All the same features: Route rule layouts, ISR payload extraction, layout props with setPageLayout, #server alias, draggable error overlay, and more
  • All performance improvements: SSR styles optimization, hook filters, and route rules compilation
  • Module disabling: Disable layer modules by setting options to false
  • Critical bug fixes: Async data reactivity in Options API, useCookie number parsing, head component deduplication, and more

✅ Upgrading

Our recommendation for upgrading is to run:

npx nuxt@latest upgrade --dedupe --channel=v3

This will deduplicate your lockfile and help ensure you pull in updates from other dependencies that Nuxt relies on, particularly in the unjs ecosystem.

[!TIP]
Check out our upgrade guide if upgrading from an older version.

👉 Changelog

compare changes

🚀 Enhancements
  • kit: Support async constructor for adding plugins (#​33619)
  • kit: Export Nuxt major version type (#​33700)
  • schema: Add #server alias for server directory imports (#​33870)
  • schema: Hoist nitro crossws types (6ff79ea6c)
  • nitro,nuxt: Compile route rules into client chunk (#​33920)
  • nuxt: Allow disabling modules by setting module options to false (#​33883)
  • kit: Allow specifying moduleDependencies as an async function (#​33504)
  • nuxt: Support appLayout in route rules (#​31092)
  • nuxt: Add route groups to page meta (#​33460)
  • nuxt: Enable payload extraction for ISR/SWR routes (#​33467)
  • nuxt: Allow updating props with setPageLayout (#​33805)
  • nuxt: Enable dragging and minimizing for error overlay (#​33695)
  • nitro,nuxt: Add support for payload extraction in dev (#​30784)
  • rspack,webpack: Add inline styles (#​33966)
  • kit: Add forward-compatible nitro types (#​34036)
🔥 Performance
  • nuxt: Do not init layer alias transform when using vite (#​33864)
  • vite: Add hook filters for ssr styles plugin (#​33865)
  • vite: Optimize nuxt:ssr-styles plugin (#​33862)
  • nuxt: Use filter for vfs plugin load (5bd8e81ed)
  • nuxt,vite: Use filters to avoid running hooks unnecessarily (e762a1e20)
  • nuxt,vite: Add more filters to internal plugins (#​33898)
🩹 Fixes
  • kit: Normalize local layer paths with trailing slashes (#​33858)
  • nuxt: Avoid overwriting multiple head input in island handler (#​33849)
  • nuxt: Update meta instead of calling router.replace in page hmr (#​33897)
  • nuxt: Don't call page:loading:end in cache if already called (fbbe10133)
  • vite: Add error handling for parsing NUXT_VITE_NODE_OPTIONS (8abb7ef5b)
  • nuxt: Do not skip middleware when appMiddleware references invalid key (ed8bb68c5)
  • nitro: Clipboard copy in error overlay (#​33873)
  • webpack,rspack: Resolve deep imports in virtual files (#​33927)
  • webpack: Disable async chunks in dev mode (c4bfd0a49)
  • webpack: Correctly evaluate sourcemap name (93e3d92b9)
  • nuxt: Handle node10 resolution for nuxt/meta (b748840bc)
  • nuxt: Do not early return if component priorities conflict (#​33955)
  • nuxt: Use key for tag deduplication in <Head> component (#​33958)
  • schema,vite: Resolve build.transpile when initialising vite (#​33868)
  • nuxt,rspack,webpack: Inject module identifiers for webpack builders (#​33962)
  • nuxt: Add key to head components for proper deduplication (#​33963)
  • nitro: Check prettyResponse.body type before error overlay (#​33977)
  • nuxt: Don't URI-encode static route paths (#​33990)
  • nuxt: Skip internal stub routes from prerender (#​34001)
  • kit,schema: Align module onUpgrade arguments with types (#​33988)
  • nuxt: Handle unsafe number parsing in useCookie decode (#​34007)
  • nuxt: Do not externalise rou3 (7da94e8c3)
  • nitro: Add noUncheckedIndexedAccess to server tsconfig (#​33985)
  • nuxt: Update global reference to globalThis in useRequestFetch (#​33976)
  • vite: Configure hmr port for server build (#​33929)
  • kit: Add forward compatible nitro v3 types (#​34053)
  • nitro,nuxt: Do not import nitro deps in builders (#​34054)
  • nitro: Add h3 types to auto-imports (#​34035)
  • schema: Add some more directories to ignore (9cb9a19dd)
  • nitro: Also augment nuxt/schema (9b40196a6)
  • nuxt: Make asyncData properties reactive in Options API (#​34119)
  • nuxt: Rerender NuxtPage when nested NuxtLayout has explicitly disabled layouts (#​34078)
  • nuxt,schema: Clean up types (5ce351d0f)
  • nuxt: Allow user augmentation of runtime config (dd30410cb)
  • kit,nitro: Enable allowArbitraryExtensions by default (#​34084)
  • nuxt: Decode client-side pathname for non-ASCII route aliases (#​34043)
  • nuxt: Force remount suspense when navigating after pending (#​33991)
  • nuxt: Add documentation link to server builder error message (#​34122)
  • nuxt: Validate placeholder/fallback tags + warn about placeholder/fallback props (f7912d3f3)
  • nuxt: Force flush useAsyncData debounced execute post watcher flush (#​34125)
  • nitro: Process isr/swr/cache keys (7f2bf4d13)
  • nuxt: Add typeFrom support for imports.d.ts template exports (#​34135)
  • nuxt: Ensure we inline styles for hydrate-never components (#​34132)
💅 Refactors
  • kit: Add explicit return types for kit utilities (ec2239cb4)
  • nitro,nuxt,schema,vite: Provide explicit return types (2564002de)
  • kit,nuxt,schema: Use named imports from defu + consola (e31668f67)
  • Add explicit .ts file extensions to relative imports (458f3c9b6)
  • kit,nitro,nuxt,schema: Reduce barrels + move <> to as (08f72881e)
  • nitro,nuxt: Use ~ prefix for internal ssrContext properties (#​33896)
  • nitro: Add explicit return types for runtime utils (74bb6ddeb)
  • nitro: Move tree-shaken flags from replace plugin -> vfs (#​33907)
  • nitro,nuxt,vite,webpack: Use status/statusText + deprecate old props (#​33912)
  • webpack: Use RuntimeModule API for chunk preloads (#​33930)
  • nuxt: Use AST-aware function key injection (#​33446)
  • nitro,nuxt,schema: Use augments for nitro schema types (#​34039)
  • nitro,rspack,vite,webpack: Move cors handling -> nitro builder (#​34048)
  • nitro: Move to nitropack/runtime namespace (b06d53166)
  • nitro,nuxt: Move to nitropack/runtime namespace (897a2259f)
📖 Documentation
  • Fix useHead return type (#​33857)
  • Add correct instructions to upgrade to latest Nuxt 3.x (#​33866)
  • Improve grammar (#​34093)
  • Use h2 for nuxt add command page (a0a1763d5)
  • Update links to module guide (c9c1282f8)
  • Split and improve Module Author Guides (#​33803)
  • Split directory structure and re-order guides (v4) (#​33691)
  • Add mcp server and llms.txt (#​33371)
  • Add note that middleware doesn't run when rendering islands (d22cf7903)
  • Add note on default branch for layers (#​33919)
  • Add mcp setup instructions for claude desktop (#​33914)
  • Mention deno as package manager (#​33875)
  • Clarify purpose of statusText (#​32834)
  • Update lychee config and remove medium article link (36c19ce73)
  • Update module count and fix typo (#​33950)
  • Add DeepWiki badge (#​33508)
  • Give example of usage of defineWrappedResponseHandler (#​33952)
  • Provide cleaner example code for vitest projects (#​33960)
  • Update yarn create command (b30432979)
  • Update roadmap with a11y (7ea35137c)
  • Add a11y release (#​34041)
  • Remove Nuxtr from recommendations (#​34045)
  • Remove duplicate feature (#​34058)
  • Provide deno package manager examples (#​34070)
  • Make custom wrapper recipe link more prominent (#​34085)
  • nuxt: Mention custom serializers in useState docs (#​34105)
  • Clarify module setups in .nuxtrc example (#​34107)
  • Add layers directory documentation (#​33967)
  • Add a tip for appLayout (9b78698c3)
  • Add docs for disabling modules by passing false to its options (18500730c)
  • Add info about caching payloads with isr/swr (4b055548e)
  • Add example for async addVitePlugin (4407f6862)
  • Add example of passing props to layouts (401aa90ab)
  • Mark vite plugin as not typed (25eae7699)
  • Add warning about source from <NuxtIsland> ([08778

Note

PR body was truncated to here.


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • ""
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@changeset-bot

changeset-bot Bot commented Mar 19, 2025

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 213712a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify

netlify Bot commented Mar 19, 2025

Copy link
Copy Markdown

Deploy Preview for vintl-nuxt ready!

Name Link
🔨 Latest commit 213712a
🔍 Latest deploy log https://app.netlify.com/projects/vintl-nuxt/deploys/6a1df3a9fe6f89000813fb3b
😎 Deploy Preview https://deploy-preview-174--vintl-nuxt.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 01ada71 to 6d20236 Compare April 1, 2025 12:25
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 6d20236 to 3dd2d0c Compare July 2, 2025 18:47
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch 2 times, most recently from b4d48ef to 92d5bb2 Compare August 13, 2025 14:00
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 92d5bb2 to 6b67637 Compare August 19, 2025 14:46
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 6b67637 to 60a4906 Compare August 31, 2025 13:58
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 60a4906 to 2bc37f8 Compare September 17, 2025 22:15
@renovate renovate Bot changed the title Update devDependency nuxt to v3.16.0 [SECURITY] Update devDependency nuxt to v3.19.0 [SECURITY] Sep 17, 2025
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 2bc37f8 to 8ba5ab8 Compare September 25, 2025 20:07
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 8ba5ab8 to 3b97b1d Compare October 21, 2025 09:43
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 3b97b1d to fbe86f6 Compare November 11, 2025 02:28
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from fbe86f6 to 2552eb6 Compare November 18, 2025 12:06
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 2552eb6 to 2729a1e Compare December 3, 2025 18:56
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 2729a1e to b6b2c63 Compare December 31, 2025 13:52
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from b6b2c63 to 7edb258 Compare January 8, 2026 18:53
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch 2 times, most recently from 31467d5 to de93ccc Compare January 23, 2026 23:55
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from de93ccc to 874c777 Compare February 2, 2026 20:29
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch 2 times, most recently from 1b0121a to ee1a55d Compare February 17, 2026 16:41
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from ee1a55d to a1fbf53 Compare March 5, 2026 16:04
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from a1fbf53 to c3aa28a Compare March 13, 2026 11:03
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch 2 times, most recently from 7beb8c1 to c641aed Compare April 8, 2026 16:53
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from c641aed to dcb05fa Compare May 1, 2026 08:41
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch 3 times, most recently from 4fb3548 to 2e7e818 Compare May 19, 2026 18:59
@renovate renovate Bot changed the title Update devDependency nuxt to v3.19.0 [SECURITY] Update devDependency nuxt to v3.21.6 [SECURITY] May 19, 2026
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from 2e7e818 to f45a3c1 Compare May 28, 2026 20:49
@renovate renovate Bot force-pushed the renovate/npm-nuxt-vulnerability branch from f45a3c1 to 213712a Compare June 1, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants