Experimental Features
Nuxt includes experimental features that you can enable in your configuration file.
Internally, Nuxt uses @nuxt/schema
to define these experimental features. You can refer to the API documentation or the source code for more information.
alwaysRunFetchOnKeyChange
Whether to run useFetch
when the key changes, even if it is set to immediate: false
and it has not been triggered yet.
useFetch
and useAsyncData
will always run when the key changes if immediate: true
or if it has been already triggered.
This flag is disabled by default, but you can enable this feature:
export default defineNuxtConfig({
experimental: {
alwaysRunFetchOnKeyChange: true,
},
})
appManifest
Use app manifests to respect route rules on client-side.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
appManifest: false,
},
})
asyncContext
Enable native async context to be accessible for nested composables in Nuxt and in Nitro. This opens the possibility to use composables inside async composables and reduce the chance to get the Nuxt instance is unavailable
error.
export default defineNuxtConfig({
experimental: {
asyncContext: true,
},
})
asyncEntry
Enables generation of an async entry point for the Vue bundle, aiding module federation support.
export default defineNuxtConfig({
experimental: {
asyncEntry: true,
},
})
externalVue
Externalizes vue
, @vue/*
and vue-router
when building.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
externalVue: false,
},
})
extractAsyncDataHandlers
Extracts handler functions from useAsyncData
and useLazyAsyncData
calls into separate chunks for improved code splitting and caching efficiency.
export default defineNuxtConfig({
experimental: {
extractAsyncDataHandlers: true,
},
})
This feature transforms inline handler functions into dynamically imported chunks:
<!-- Before -->
<script setup>
const { data } = await useAsyncData('user', async () => {
return await $fetch('/api/user')
})
</script>
<!-- After transformation -->
<script setup>
const { data } = await useAsyncData('user', () =>
import('/generated-chunk.js').then(r => r.default()),
)
</script>
The benefit of this transformation is that we can split out data fetching logic — while still allowing the code to be loaded if required.
emitRouteChunkError
Emits app:chunkError
hook when there is an error loading vite/webpack chunks. Default behavior is to perform a reload of the new route on navigation to a new route when a chunk fails to load.
By default, Nuxt will also perform a reload of the new route when a chunk fails to load when navigating to a new route (automatic
).
Setting automatic-immediate
will lead Nuxt to perform a reload of the current route right when a chunk fails to load (instead of waiting for navigation). This is useful for chunk errors that are not triggered by navigation, e.g., when your Nuxt app fails to load a lazy component. A potential downside of this behavior is undesired reloads, e.g., when your app does not need the chunk that caused the error.
You can disable automatic handling by setting this to false
, or handle chunk errors manually by setting it to manual
.
export default defineNuxtConfig({
experimental: {
emitRouteChunkError: 'automatic', // or 'automatic-immediate', 'manual' or false
},
})
enforceModuleCompatibility
Whether Nuxt should throw an error (and fail to load) if a Nuxt module is incompatible.
This feature is disabled by default.
export default defineNuxtConfig({
experimental: {
enforceModuleCompatibility: true,
},
})
restoreState
Allows Nuxt app state to be restored from sessionStorage
when reloading the page after a chunk error or manual reloadNuxtApp()
call.
To avoid hydration errors, it will be applied only after the Vue app has been mounted, meaning there may be a flicker on initial load.
useState
as auto-generated keys may not match across builds.export default defineNuxtConfig({
experimental: {
restoreState: true,
},
})
inlineRouteRules
Define route rules at the page level using defineRouteRules
.
export default defineNuxtConfig({
experimental: {
inlineRouteRules: true,
},
})
Matching route rules will be created, based on the page's path
.
renderJsonPayloads
Allows rendering of JSON payloads with support for revivifying complex types.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
renderJsonPayloads: false,
},
})
noVueServer
Disables Vue server renderer endpoint within Nitro.
export default defineNuxtConfig({
experimental: {
noVueServer: true,
},
})
parseErrorData
Whether to parse error.data
when rendering a server error page.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
parseErrorData: false,
},
})
payloadExtraction
Enables extraction of payloads of pages generated with nuxt generate
.
export default defineNuxtConfig({
experimental: {
payloadExtraction: true,
},
})
clientFallback
Enables the experimental <NuxtClientFallback>
component for rendering content on the client if there's an error in SSR.
export default defineNuxtConfig({
experimental: {
clientFallback: true,
},
})
crossOriginPrefetch
Enables cross-origin prefetch using the Speculation Rules API.
export default defineNuxtConfig({
experimental: {
crossOriginPrefetch: true,
},
})
viewTransition
Enables View Transition API integration with client-side router.
export default defineNuxtConfig({
experimental: {
viewTransition: true,
},
})
writeEarlyHints
Enables writing of early hints when using node server.
export default defineNuxtConfig({
experimental: {
writeEarlyHints: true,
},
})
componentIslands
Enables experimental component islands support with <NuxtIsland>
and .island.vue
files.
export default defineNuxtConfig({
experimental: {
componentIslands: true, // false or 'local+remote'
},
})
localLayerAliases
Resolve ~
, ~~
, @
and @@
aliases located within layers with respect to their layer source and root directories.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
localLayerAliases: false,
},
})
typedPages
Enable the new experimental typed router using unplugin-vue-router
.
export default defineNuxtConfig({
experimental: {
typedPages: true,
},
})
Out of the box, this will enable typed usage of navigateTo
, <NuxtLink>
, router.push()
and more.
You can even get typed params within a page by using const route = useRoute('route-name')
.
pnpm
without shamefully-hoist=true
, you will need to have unplugin-vue-router
installed as a devDependency in order for this feature to work.watcher
Set an alternative watcher that will be used as the watching service for Nuxt.
Nuxt uses chokidar-granular
by default, which will ignore top-level directories
(like node_modules
and .git
) that are excluded from watching.
You can set this instead to parcel
to use @parcel/watcher
, which may improve
performance in large projects or on Windows platforms.
You can also set this to chokidar
to watch all files in your source directory.
export default defineNuxtConfig({
experimental: {
watcher: 'chokidar-granular', // 'chokidar' or 'parcel' are also options
},
})
sharedPrerenderData
Nuxt automatically shares payload data between pages that are prerendered. This can result in a significant performance improvement when prerendering sites that use useAsyncData
or useFetch
and fetch the same data in different pages.
You can disable this feature if needed.
export default defineNuxtConfig({
experimental: {
sharedPrerenderData: false,
},
})
It is particularly important when enabling this feature to make sure that any unique key of your data
is always resolvable to the same data. For example, if you are using useAsyncData
to fetch
data related to a particular page, you should provide a key that uniquely matches that data. (useFetch
should do this automatically for you.)
// This would be unsafe in a dynamic page (e.g. `[slug].vue`) because the route slug makes a difference
// to the data fetched, but Nuxt can't know that because it's not reflected in the key.
const route = useRoute()
const { data } = await useAsyncData(async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
// Instead, you should use a key that uniquely identifies the data fetched.
const { data } = await useAsyncData(route.params.slug, async () => {
return await $fetch(`/api/my-page/${route.params.slug}`)
})
clientNodeCompat
With this feature, Nuxt will automatically polyfill Node.js imports in the client build using unenv
.
Buffer
work in the browser, you need to manually inject them.import { Buffer } from 'node:buffer'
globalThis.Buffer ||= Buffer
scanPageMeta
Nuxt exposing some route metadata defined in definePageMeta
at build-time to modules (specifically alias
, name
, path
, redirect
, props
and middleware
).
This only works with static or strings/arrays rather than variables or conditional assignment. See original issue for more information and context.
By default page metadata is only scanned after all routes have been registered in pages:extend
. Then another hook, pages:resolved
will be called.
You can disable this feature if it causes issues in your project.
export default defineNuxtConfig({
experimental: {
scanPageMeta: false,
},
})
cookieStore
Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh useCookie
ref values.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
cookieStore: false,
},
})
buildCache
Caches Nuxt build artifacts based on a hash of the configuration and source files.
This only works for source files within srcDir
and serverDir
for the Vue/Nitro parts of your app.
This flag is disabled by default, but you can enable it:
export default defineNuxtConfig({
experimental: {
buildCache: true,
},
})
When enabled, changes to the following files will trigger a full rebuild:
.nuxtrc
.npmrc
package.json
package-lock.json
yarn.lock
pnpm-lock.yaml
tsconfig.json
bun.lock
bun.lockb
In addition, any changes to files within srcDir
will trigger a rebuild of the Vue client/server bundle. Nitro will always be rebuilt (though work is in progress to allow Nitro to announce its cacheable artifacts and their hashes).
checkOutdatedBuildInterval
Set the time interval (in ms) to check for new builds. Disabled when experimental.appManifest
is false
.
Set to false
to disable.
export default defineNuxtConfig({
experimental: {
checkOutdatedBuildInterval: 3600000, // 1 hour, or false to disable
},
})
extraPageMetaExtractionKeys
The definePageMeta()
macro is a useful way to collect build-time meta about pages. Nuxt itself provides a set list of supported keys which is used to power some of the internal features such as redirects, page aliases and custom paths.
This option allows passing additional keys to extract from the page metadata when using scanPageMeta
.
<script lang="ts" setup>
definePageMeta({
foo: 'bar',
})
</script>
export default defineNuxtConfig({
experimental: {
extraPageMetaExtractionKeys: ['foo'],
},
hooks: {
'pages:resolved' (ctx) {
// ✅ foo is available
},
},
})
This allows modules to access additional metadata from the page metadata in the build context. If you are using this within a module, it's recommended also to augment the NuxtPage
types with your keys.
navigationRepaint
Wait for a single animation frame before navigation, which gives an opportunity for the browser to repaint, acknowledging user interaction.
It can reduce INP when navigating on prerendered routes.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
navigationRepaint: false,
},
})
normalizeComponentNames
Nuxt updates auto-generated Vue component names to match the full component name you would use to auto-import the component.
If you encounter issues, you can disable this feature.
export default defineNuxtConfig({
experimental: {
normalizeComponentNames: false,
},
})
By default, if you haven't set it manually, Vue will assign a component name that matches the filename of the component.
├─ components/
├─── SomeFolder/
├───── MyComponent.vue
In this case, the component name would be MyComponent
, as far as Vue is concerned. If you wanted to use <KeepAlive>
with it, or identify it in the Vue DevTools, you would need to use this component.
But in order to auto-import it, you would need to use SomeFolderMyComponent
.
By setting experimental.normalizeComponentNames
, these two values match, and Vue will generate a component name that matches the Nuxt pattern for component naming.
spaLoadingTemplateLocation
When rendering a client-only page (with ssr: false
), we optionally render a loading screen (from ~/spa-loading-template.html
).
It can be set to within
, which will render it like this:
<div id="__nuxt">
<!-- spa loading template -->
</div>
Alternatively, you can render the template alongside the Nuxt app root by setting it to body
:
<div id="__nuxt"></div>
<!-- spa loading template -->
This avoids a white flash when hydrating a client-only page.
browserDevtoolsTiming
Enables performance markers for Nuxt hooks in browser devtools. This adds performance markers that you can track in the Performance tab of Chromium-based browsers, which is useful for debugging and optimizing performance.
This is enabled by default in development mode. If you need to disable this feature, it is possible to do so:
export default defineNuxtConfig({
experimental: {
browserDevtoolsTiming: false,
},
})
debugModuleMutation
Records mutations to nuxt.options
in module context, helping to debug configuration changes made by modules during the Nuxt initialization phase.
This is enabled by default when debug
mode is enabled. If you need to disable this feature, it is possible to do so:
To enable it explicitly:
export default defineNuxtConfig({
experimental: {
debugModuleMutation: true,
},
})
lazyHydration
This enables hydration strategies for <Lazy>
components, which improves performance by deferring hydration of components until they're needed.
Lazy hydration is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
lazyHydration: false,
},
})
templateImportResolution
Disable resolving imports into Nuxt templates from the path of the module that added the template.
By default, Nuxt attempts to resolve imports in templates relative to the module that added them. Setting this to false
disables this behavior, which may be useful if you're experiencing resolution conflicts in certain environments.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
templateImportResolution: false,
},
})
templateRouteInjection
By default the route object returned by the auto-imported useRoute()
composable is kept in sync with the current page in view in <NuxtPage>
. This is not true for vue-router
's exported useRoute
or for the default $route
object available in your Vue templates.
By enabling this option a mixin will be injected to keep the $route
template object in sync with Nuxt's managed useRoute()
.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
templateRouteInjection: false,
},
})
decorators
This option enables enabling decorator syntax across your entire Nuxt/Nitro app, powered by esbuild.
For a long time, TypeScript has had support for decorators via compilerOptions.experimentalDecorators
. This implementation predated the TC39 standardization process. Now, decorators are a Stage 3 Proposal, and supported without special configuration in TS 5.0+ (see https://github.com/microsoft/TypeScript/pull/52582 and https://devblogs.microsoft.com/typescript/announcing-typescript-5-0-beta/#decorators).
Enabling experimental.decorators
enables support for the TC39 proposal, NOT for TypeScript's previous compilerOptions.experimentalDecorators
implementation.
Usage
export default defineNuxtConfig({
experimental: {
decorators: true,
},
})
function something (_method: () => unknown) {
return () => 'decorated'
}
class SomeClass {
@something
public someMethod () {
return 'initial'
}
}
const value = new SomeClass().someMethod()
// this will return 'decorated'
defaults
This allows specifying the default options for core Nuxt components and composables.
These options will likely be moved elsewhere in the future, such as into app.config
or into the app/
directory.
export default defineNuxtConfig({
experimental: {
defaults: {
nuxtLink: {
componentName: 'NuxtLink',
prefetch: true,
prefetchOn: {
visibility: true,
},
},
useAsyncData: {
deep: true,
},
},
},
})
purgeCachedData
Whether to clean up Nuxt static and asyncData caches on route navigation.
Nuxt will automatically purge cached data from useAsyncData
and nuxtApp.static.data
. This helps prevent memory leaks and ensures fresh data is loaded when needed, but it is possible to disable it.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
purgeCachedData: false,
},
})
granularCachedData
Whether to call and use the result from getCachedData
when refreshing data for useAsyncData
and useFetch
(whether by watch
, refreshNuxtData()
, or a manual refresh()
call.
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
granularCachedData: false,
},
})
headNext
Use head optimisations:
- Add the capo.js head plugin in order to render tags in of the head in a more performant way.
- Uses the hash hydration plugin to reduce initial hydration
This flag is enabled by default, but you can disable this feature:
export default defineNuxtConfig({
experimental: {
headNext: false,
},
})
pendingWhenIdle
For useAsyncData
and useFetch
, whether pending
should be true
when data has not yet started to be fetched.
This flag is disabled by default, but you can enable this feature:
export default defineNuxtConfig({
experimental: {
pendingWhenIdle: true,
},
})
entryImportMap
By default, Nuxt improves chunk stability by using an import map to resolve the entry chunk of the bundle.
This injects an import map at the top of your <head>
tag:
<script type="importmap">{"imports":{"#entry":"/_nuxt/DC5HVSK5.js"}}</script>
Within the script chunks emitted by Vite, imports will be from #entry
. This means that changes to the entry will not invalidate chunks which are otherwise unchanged.
vite.build.target
to include a browser that doesn't support import maps, or if you have configured vite.build.rollupOptions.output.entryFileNames
to a value that does not include [hash]
.If you need to disable this feature you can do so:
export default defineNuxtConfig({
experimental: {
entryImportMap: false,
},
// or, better, simply tell vite your desired target
// which nuxt will respect
vite: {
build: {
target: 'safari13',
},
},
})
typescriptPlugin
Enable enhanced TypeScript developer experience with the @dxup/nuxt
module.
This experimental plugin provides improved TypeScript integration and development tooling for better DX when working with TypeScript in Nuxt applications.
This flag is disabled by default, but you can enable this feature:
export default defineNuxtConfig({
experimental: {
typescriptPlugin: true,
},
})
- Have
typescript
installed as a dependency - Configure VS Code to use your workspace TypeScript version (see VS Code documentation)