π Highlights
There's a lot in this one!
β‘οΈ A New New Nuxt
Say hello to create-nuxt
, a new tool for starting Nuxt projects (big thanks to @devgar for donating the package name)!
It's a streamlined version of nuxi init
- just a sixth of the size and bundled as a single file with all dependencies inlined, to get you going as fast as possible.
Starting a new project is as simple as:
npm create nuxt
Special thanks to @cmang for the beautiful ASCII-art. β€οΈ
Want to learn more about where we're headed with the Nuxt CLI? Check out our roadmap here, including our plans for an interactive modules selector.
π Unhead v2
We've upgraded to unhead
v2, the engine behind Nuxt's <head>
management. This major version removes deprecations and improves how context works:
- For Nuxt 3 users, we're shipping a legacy compatibility build so nothing breaks
- The context implementation is now more direct via Nuxt itself
// Nuxt now re-exports composables while properly resolving the context
export function useHead(input, options = {}) {
const unhead = injectHead(options.nuxt)
return head(input, { head: unhead, ...options })
}
If you're using Unhead directly in your app, keep in mind:
- Import from Nuxt's auto-imports or
#app/composables/head
instead of@unhead/vue
- Importing directly from
@unhead/vue
might lose async context
Don't worry though - we've maintained backward compatibility in Nuxt 3, so most users won't need to change anything!
If you've opted into compatibilityVersion: 4
, check out our upgrade guide for additional changes.
π§ Devtools v2 Upgrade
Nuxt Devtools has leveled up to v2 (#30889)!
You'll love the new features like custom editor selection, Discovery.js for inspecting resolved configs (perfect for debugging), the return of the schema generator, and slimmer dependencies.
One of our favorite improvements is the ability to track how modules modify your Nuxt configuration - giving you X-ray vision into what's happening under the hood.
π Discover all the details in the Nuxt DevTools release notes.
β‘οΈ Performance Improvements
We're continuing to make Nuxt faster, and there are a number of improvements in v3.16:
- Using
exsolve
for module resolution (#31124) along with the rest of the unjs ecosystem (nitro, c12, pkg-types, and more) - which dramatically speeds up module resolution - Smarter module resolution paths (#31037) - prioritizes direct imports for better efficiency
- Eliminated duplicated Nitro alias resolution (#31088) - leaner file handling
- Streamlined
loadNuxt
by skipping unnecessary resolution steps (#31176) - faster startups - Adopt
oxc-parser
for parsing in Nuxt plugins (#30066)
All these speed boosts happen automatically - no configuration needed!
Shout out to CodSpeed with Vitest benchmarking to measure these improvements in CI - it has been really helpful.
To add some anecdotal evidence, my personal site at roe.dev loads 32% faster with v3.16, and nuxt.com is 28% faster. I hope you see similar results! β‘οΈ
π°οΈ Delayed Hydration Support
We're very pleased to bring you native delayed/lazy hydration support (#26468)! This lets you control exactly when components hydrate, which can improve initial load performance and time-to-interactive. We're leveraging Vue's built-in hydration strategies - check them out in the Vue docs.
<template>
<!-- Hydrate when component becomes visible in viewport -->
<LazyExpensiveComponent hydrate-on-visible />
<!-- Hydrate when browser is idle -->
<LazyHeavyComponent hydrate-on-idle />
<!-- Hydrate on interaction (mouseover in this case) -->
<LazyDropdown hydrate-on-interaction="mouseover" />
<!-- Hydrate when media query matches -->
<LazyMobileMenu hydrate-on-media-query="(max-width: 768px)" />
<!-- Hydrate after a specific delay in milliseconds -->
<LazyFooter :hydrate-after="2000" />
</template>
You can also listen for when hydration happens with the @hydrated
event:
<LazyComponent hydrate-on-visible @hydrated="onComponentHydrated" />
Learn more about lazy hydration in our components documentation.
𧩠Advanced Pages Configuration
You can now fine-tune which files Nuxt scans for pages (#31090), giving you more control over your project structure:
export default defineNuxtConfig({
pages: {
// Filter specific files or directories
pattern: ['**/*.vue'],
}
})
π Enhanced Debugging
We've made debugging with the debug
option more flexible! Now you can enable just the debug logs you need (#30578):
export default defineNuxtConfig({
debug: {
// Enable specific debugging features
templates: true,
modules: true,
watchers: true,
hooks: {
client: true,
server: true,
},
nitro: true,
router: true,
hydration: true,
}
})
Or keep it simple with debug: true
to enable all these debugging features.
π¨ Decorators Support
For the decorator fans out there (whoever you are!), we've added experimental support (#27672). As with all experimental features, feedback is much appreciated.
export default defineNuxtConfig({
experimental: {
decorators: true
}
})
function something (_method: () => unknown) {
return () => 'decorated'
}
class SomeClass {
@something
public someMethod () {
return 'initial'
}
}
const value = new SomeClass().someMethod()
// returns 'decorated'
π Named Layer Aliases
It's been much requested, and it's here! Auto-scanned local layers (from your ~~/layers
directory) now automatically create aliases. You can access your ~~/layers/test
layer via #layers/test
(#30948) - no configuration needed.
If you want named aliases for other layers, you can add a name to your layer configuration:
export default defineNuxtConfig({
$meta: {
name: 'example-layer',
},
})
This creates the alias #layers/example-layer
pointing to your layer - making imports cleaner and more intuitive.
π§ͺ Error Handling Improvements
We've greatly improved error messages and source tracking (#31144):
- Better warnings for undefined
useAsyncData
calls with precise file location information - Error pages now appear correctly on island page errors (#31081)
Plus, we're now using Nitro's beautiful error handling (powered by youch) to provide more helpful error messages in the terminal, complete with stacktrace support.
Nitro now also automatically applies source maps without requiring extra Node options, and we set appropriate security headers when rendering error pages.
π¦ Module Development Improvements
For module authors, we've added the ability to augment Nitro types with addTypeTemplate
(#31079):
// Inside your Nuxt module
export default defineNuxtModule({
setup(options, nuxt) {
addTypeTemplate({
filename: 'types/my-module.d.ts',
getContents: () => `
declare module 'nitropack' {
interface NitroRouteConfig {
myCustomOption?: boolean
}
}
`
}, { nitro: true })
}
})
βοΈ Nitro v2.11 Upgrade
We've upgraded to Nitro v2.11. There are so many improvements - more than I can cover in these brief release notes.
π Check out all the details in the Nitro v2.11.0 release notes.
π¦ New unjs
Major Versions
This release includes several major version upgrades from the unjs ecosystem, focused on performance and smaller bundle sizes through ESM-only distributions:
- unenv upgraded to v2 (full rewrite)
- db0 upgraded to v0.3 (ESM-only, native node:sql, improvements)
- ohash upgraded to v2 (ESM-only, native node:crypto support, much faster)
- untyped upgraded to v2 (ESM-only, smaller install size)
- unimport upgraded to v4 (improvements)
- c12 upgraded to v3 (ESM-only)
- pathe upgraded to v2 (ESM-only)
- cookie-es upgraded to v2 (ESM-only)
- esbuild upgraded to v0.25
- chokidar upgraded to v4
β Upgrading
As usual, our recommendation for upgrading is to run:
npx nuxi@latest upgrade --dedupe
This refreshes your lockfile and pulls in all the latest dependencies that Nuxt relies on, especially from the unjs ecosystem.
π Changelog
π Enhancements
- nuxt: Upgrade
@nuxt/devtools
to v2 (#30889) - nuxt: Granular debug options (#30578)
- nuxt: Add type hints for
NuxtPage
(#30704) - nuxt: Support tracking changes to nuxt options by modules (#30555)
- nuxt: Allow disabling auto-imported polyfills (#30332)
- schema: Add runtime + internal type validation (#30844)
- kit,nuxt,schema: Support experimental decorators syntax (#27672)
- kit,nuxt: Allow multiple nuxts to run in one process (#30510)
- kit: Add named layer aliases (#30948)
- kit,nuxt,vite:
directoryToURL
to normalise paths (#30986) - nuxt: Allow forcing
start
/set
in loading indicator (#30989) - nuxt: Allow specifying glob patterns for scanning
pages/
(#31090) - nuxt: Add types for default
NuxtLink
slot (#31104) - nuxt: Delayed/lazy hydration support (#26468)
- vite: Add vite's modulepreload polyfill (#31164)
- nuxt: Show source file when warning about undefined useAsyncData (#31144)
- kit,nuxt: Augment nitro types with
addTypeTemplate
(#31079) - kit,nuxt: Resolve template imports from originating module (#31175)
- nuxt: Use
oxc-parser
instead of esbuild + acorn (#30066) - nuxt: Upgrade to unhead v2 (#31169)
- nuxt: Align nuxt error handling with nitro (#31230)
π₯ Performance
- nuxt: Remove duplicated nitro alias resolution (#31088)
- kit: Try non-subpath routes first to resolve nuxt modules (#31037)
- nuxt: Migrate to use
exsolve
for module resolution (#31124) - kit: Skip extra module resolution step in
loadNuxt
(#31176)
π©Ή Fixes
- nuxt: Ensure
<NuxtLayout>
fallback
prop is typed (#30832) - nuxt: Assign slot to be rendered for client components (#30768)
- nuxt,vite: Do not override vite import conditions (#30887)
- nuxt: Prevent
keepalive
cache reset (#30807) - nuxt: Remove
div
wrapper in client-only pages (#30425) - schema: Update type import to
nitropack
(aba75bd5a) - vite: Use resolveId from vite-node to resolve deps (#30922)
- schema: Normalise additional experimental options (63e0c342c)
- nuxt: Delete existing properties in app config HMR (#30918)
- schema: Return
null
from resolve functions (d68e8ce57) - schema: Check if
app.head.meta
values are undefined (#30959) - nuxt: Make
shared/
directories available within layers (#30843) - kit: Ensure nuxt is loaded from cwd rather than parent dir (#30910)
- ui-templates: Remove extra
<pre>
when rendering dev errors (9aab69ec4) - nuxt: Use tsx loader for jsx blocks as well (#31014)
- Remove unimplemented
page:transition:start
type (#31040) - kit: Expose module dependency errors (#31035)
- nuxt: Deprioritise layer css imports (#31020)
- nuxt: Ensure
provide
/inject
work insetup
ofdefineNuxtComponent
(#30982) - nuxt: Decode URI components in cache driver methods (#30973)
- nuxt: Use
_
for NuxtIsland name on server pages (#31072) - nuxt: Use
ohash
to calculate legacy async data key without hash (#31087) - nuxt,schema: Resolve
shared
dir from config (#31091) - kit,schema: Set esbuild target for experimental decorators (#31089)
- nuxt: Set
nuxt.options.pages
to detected configuration (#31101) - nuxt: Warn when
definePageMeta
does not receive an object (#31156) - nuxt: Fix nitro import statements for v2 (151cf7d49)
- nuxt: Update path to
no-ssr
middleware handler (a99c59fbd) - nuxt: Align type of custom
navigate
withvue-router
(7a1934509) - nuxt: Show error page on island page error (#31081)
- nuxt: Do not render payloads if disabled, and correct regexp (#31167)
- nuxt: Add backwards-compatible serialisation for
nuxt.options.pages
(fa480e0a0) - ui-templates: Escape inline scripts correctly in ui templates (39c2b0a2c)
- nuxt: Add back fallback nuxtlink type signature (a8856de59)
- kit: Provide default extensions in
resolveModule
(6fb5c9c15) - nuxt: Provide default extensions in
resolveTypePath
(a0f9ddfe2) - nuxt: Strip query before generating payload url (34ddc2d2f)
- schema: Resolve workspaceDir to closest git config (7a2fbce01)
- kit: Include declaration files when resolving
compilerOptions.paths
(835e89404) - nuxt: Consolidate head component context (#31209)
- nuxt: Resolve shared externals to absolute paths (#31227)
- nuxt: Skip deep merge in dev mode for prototype keys (#31205)
- schema: Use
RawVueCompilerOptions
for unresolvedtsconfig
(#31202) - nuxt: Ensure externals are resolved first (#31235)
- nuxt: Ensure we strip all chars in payload url (4f067f601)
- nuxt: Exempt nitro from import protections (#31246)
- nuxt: Normalise error url to pathname (87b69c9ae)
- nuxt: Ensure head components are reactive (#31248)
- nuxt: Preserve query/hash when calling
navigateTo
with replace (#31244) - nuxt: Apply ignore rules to nitro
devStorage
(#31233) - nuxt: Fall back to wasm if oxc native bindings are missing (#31190)
- nuxt: Pass
useFetch
function name on server for warning (#31213) - vite: Prevent overriding server build chunks (89a29e760)
- nuxt: Strip query in
x-nitro-prerender
header (2476cab9a)
π Refactors
- nuxt: Prefer logical assignment operators (#31004)
- nuxt: Use
isEqual
fromohash/utils
(2e27cd30c) - nuxt: Update to
noScripts
route rule (#31083) - nuxt: Re-organize internal
runtime/nitro
files (#31131) - nuxt: Explicitly type internal request fetch (54cb80319)
- nuxt: Use relative imports (1bce3dc3b)
- nuxt: Early return island response (#31094)
π Documentation
- Tiny typo (#30799)
- Fix typo (#30817)
- Remove backslashes in
spaLoadingTemplate
example (#30830) - Update path to nuxt binary (8992c4ea0)
- Add nuxt lifecycle (#30726)
- Add additional information about
NuxtPage
(#30781) - Improve
navigateTo
docs with clearer structure and examples (#30876) - Add auto import info about shared utils (#30858)
- Fix typo and improve data fetching examples (#30935)
- Clarify that local layers are scanned from
rootDir
(27e356fe6) - Fix typo (#30963)
- Update links to unhead sources (6c520ef74)
- Fix typo (#30971)
- Add tips on how to override layers aliases (#30970)
- Add description for
vue:setup
andapp:data:refresh
hooks (#31001) - Mention requirement to wrap middleware in
defineNuxtRouteMiddleware
(#31005) - Add
port
option to preview command (#30999) - Remove link to deleted nuxt 2 section (#31077)
- Link to the scripts releases page (#31095)
- Add
.nuxtrc
documentation (#31093) - Fix typo in example command (#31112)
- Explain why headers not forwarded when using
$fetch
on the server (#31114) - Fix links to nitro directory structure (5a696176d)
- Update to use
create nuxt
command (fe82af4c9) - Update getCachedData types (#31208)
- Update code example for nightly release to default to
3x
(a243f8fcf) - Clarify lifecycle behavior of
<NuxtPage>
during page changes (#31116) - Mention workaround for
typedPages
in unhoisted pnpm setups (#31262)
π¦ Build
- nuxt: Add subpath imports for type support (8ef3fcc4d)
π‘ Chore
- Remove second version of vitest (bc9ac7349)
- Bump bundle size (c5e191165)
- Add basic copilot instructions (d47b830d3)
- Handle undefined author (0161985c0)
- Use logical or assignment (#30992)
- Reorder options object (11e6b8398)
- Lint (86c960c6f)
- Fix broken lockfile (05501d2c8)
- Add
errx
dependency (566418177) - Add additional dummy url to ignore (bc101e4ae)
- Ignore internal resolution errors in nuxt types (0d54dc3f4)
- Bump octokit patch versions (a477065b4)
- Bump
@nuxtjs/mdc
typechecking dep (f23683b26) - Ignore
nitro/renderer
templates (b29c0e86b)
β Tests
- Add benchmarks for dev server initial build (#30742)
- Exclude urls from lychee crawler used in test suite (8e2d9a640)
- Prepare environment to ensure more reproducible dev tests (bc89ef867)
- Update unit test (5a71ef8ac)
- Add major version to unit test (676447239)
- Slightly improve coverage (d992c0da9)
- Bump timeout for route hmr (cbe38cf52)
- Update unit test snapshot for jsx (4910959b9)
- Disable codspeed outside of ci (71de708a0)
- Add some more stability in hmr tests (9a9fcdab5)
- Skip testing spa-preloader in dev (6cf97bfe5)
- Fix time-based hydration test (da3b39d67)
- Simplify further (ad306f472)
- Filter out dev server logs π (ee040eea3)
- Update unit test snapshot (97ec3143a)
- Provide nuxt extensions in unit test (358729e96)
- Add benchmark for vite client build (#31118)
- Update build benchmark (82ca08f93)
- Ensure dev tests have separate buildDirs (d7623f884)
- Update nitro type import (8f61d0090)
- Update import to
#internal/nitro/app
(a1b855cc5) - Try to improve dev test stability (#31218)
- Migrate hmr test to use playwright runner (#31241)
β€οΈ Contributors
- Anoesj Sadraee (@Anoesj)
- Daniel Roe (@danielroe)
- John Tanzer (@moshetanzer)
- Connor Pearson (@cjpearson)
- Connor Roberts (@murshex)
- Harlan Wilton (@harlan-zw)
- Alex Liu (@Mini-ghost)
- Kevin Deng δΈε²ζΊε (@sxzz)
- xjccc (@xjccc)
- Julien Huang (@huang-julien)
- Michael Brevard (@GalacticHypernova)
- Maik Kowol (@94726)
- Anthony Fu (@antfu)
- Bobbie Goede (@BobbieGoede)
- Clayton Chew (@claytonchew)
- awfulness (@awfulness)
- SΓ©bastien Chopin (@atinux)
- Saeid Zareie (@Saeid-Za)
- Vahagn Zaqaryan (@Vahagn-Zaqaryan)
- Idorenyin Udoh (@idorenyinudoh)
- Jonas Thelemann (@dargmuesli)
- Ryota Watanabe (@wattanx)
- Horu (@HigherOrderLogic)
- Nolhan (@Nonolanlan1007)
- Typed SIGTERM (@typed-sigterm)
- Hans Tu (@ChiaHanTu)
- Damian GΕowala (@DamianGlowala)
- David Marr (@marr)
- Camille Coutens (@Kamsou)
- Charlie β¨ (@CharleeWa)
- Hussain Panahy (@HP8585)
- @beer (@iiio2)