# The Full-Stack Vue Framework > Build fast, production-ready web apps with Vue. File-based routing, auto-imports, and server-side rendering โ€” all configured out of the box. ## When to use this Use these docs when you are writing, reviewing or debugging code for a Nuxt application: scaffolding a project, configuring `nuxt.config.ts`, picking a rendering mode per route, writing pages, layouts, components, composables, server routes, middleware and plugins, fetching data with `useFetch` and `useAsyncData`, adding or authoring a module, upgrading between major versions, and deploying to a specific provider. They cover Nuxt itself. For Vue, Vite, Nitro or UnJS APIs, go to their own documentation, and for questions about a specific module, to the module's own docs, which the directory links. ## How to fetch these docs Every documentation, blog and deploy page is also Markdown. Append `.md` to a URL, or send `Accept: text/markdown` on the HTML one. is the whole documentation in a single file, and lists every page. For search and structured lookups, call the MCP server at (streamable HTTP), described by . The REST endpoints under `/api/v1` are public, read-only and need no credentials: the module directory, its health data, and the core and ecosystem teams. describes them. ## Features - **Zero Configuration**: Start coding with Vue or Typescript immediately โ€” Nuxt handles all the setup for you. - **Rendering Modes**: Server-side rendering, client-side rendering, static-site generation, you decide, up to the page level. - **Routing & Layouts**: Use our file-based routing system to build complex url-based views while reusing components for performance. - **Data Fetching**: Make your Vue component async and await your data. Nuxt provides powerful composables for universal data fetching. - **Error Handling**: Catch errors in your application with our built-in handlers and custom error pages. - **Transitions**: Implement smooth transitions between layouts, pages, and components. - **Assets & Style**: Benefit from automatic image, font, and script optimizations with built-in support. - **SEO & Meta Tags**: Create production-ready applications that are fully indexable by search engines. - **Modular**: Extend Nuxt features with 200+ modules to ship your application faster. - **Middleware**: Protect or add custom logic (localization, A/B testing) before rendering pages. - **Type-safe with TypeScript**: Write type-safe code with automatically generated types and tsconfig.json. ## Getting started ```bash npx nuxi@latest init cd npm install npm run dev ``` - Introduction: - Installation: - Configuration: ## Explore - Documentation: - Modules: - Templates: - Showcase: - Deploy: - Blog: - Changelog: - Team: ## Community - GitHub: - Discord: - X (Twitter): - Bluesky: ## Resources for Agents - [API catalog: every service document this site publishes](https://nuxt.com/.well-known/api-catalog) - [Sitemap (XML)](https://nuxt.com/sitemap.xml) - [Sitemap (Markdown): every page on the site](https://nuxt.com/sitemap.md) - [MCP server card: MCP endpoint at https://nuxt.com/mcp](https://nuxt.com/.well-known/mcp/server-card.json) - [MCP endpoint (streamable HTTP)](https://nuxt.com/mcp) - [llms.txt: index of the documentation for LLMs](https://nuxt.com/llms.txt) - [llms-full.txt: the full documentation as a single file](https://nuxt.com/llms-full.txt) - [OpenAPI specification: machine-readable API surface](https://nuxt.com/openapi.json) - [Design system](https://nuxt.com/design.md) - [Documentation](https://nuxt.com/docs) Every page on this site is available as raw markdown: append `.md` to its URL or send `Accept: text/markdown`. # Nuxt API Reference > Explore all Nuxt Internals: Components, Composables, Utils, Commands and more. Explore Nuxt built-in components for pages, layouts, head, and more. Discover Nuxt composable functions for data-fetching, head management and more. Learn about Nuxt utility functions for navigation, error handling and more. List of Nuxt CLI commands to init, analyze, build, and preview your application. Understand Nuxt Kit utilities to create modules and control Nuxt. Go deep in Nuxt internals with Nuxt lifecycle hooks. Explore all Nuxt configuration options to customize your application. # Lifecycle Hooks > Nuxt provides a powerful hooking system to expand almost every aspect using hooks. ## App Hooks (Runtime) Check the [app source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts#L37) for all available hooks.
Hook Arguments Environment Description
app:created vueApp Server & Client Called when initial vueApp instance is created.
app:error err Server & Client Called when a fatal error occurs.
app:error:cleared { redirect? } Server & Client Called when a fatal error occurs.
vue:setup - Server & Client Called when the setup of Nuxt root is initialized. This callback must be synchronous.
vue:error err, target, info Server & Client Called when a vue error propagates to the root component. Learn More .
app:rendered renderContext Server Called when SSR rendering is done.
app:redirected - Server Called before SSR redirection.
app:beforeMount vueApp Client Called before mounting the app, called only on client side.
app:mounted vueApp Client Called when Vue app is initialized and mounted in browser.
app:suspense:resolve appComponent Client On Suspense resolved event.
app:manifest:update { id, timestamp } Client Called when there is a newer version of your app detected.
app:data:refresh keys? Client Called when refreshNuxtData is called.
link:prefetch to Client Called when a is observed to be prefetched.
page:start pageComponent? Client Called on Suspense inside of NuxtPage pending event.
page:finish pageComponent? Client Called on Suspense inside of NuxtPage resolved event.
page:loading:start - Client Called when a route navigation begins (before resolution) or when the page key changes. May fire without the page component's setup() re-running if the page is reused (e.g. with a static key in definePageMeta ).
page:loading:end - Client Called after page:finish
page:transition:finish pageComponent? Client After page transition onAfterLeave event.
dev:ssr-logs logs Client Called with an array of server-side logs that have been passed to the client (if features.devLogs is enabled).
page:view-transition:start transition Client Called after document.startViewTransition is called when experimental viewTransition support is enabled . The transition argument is a ViewTransition object with a types property ( ViewTransitionTypeSet ) that can be read or modified.
## Nuxt Hooks (Build Time) Check the [schema source code](https://github.com/nuxt/nuxt/blob/main/packages/schema/src/types/hooks.ts#L83) for all available hooks.
Hook Arguments Description
kit:compatibility compatibility, issues Allows extending compatibility checks.
ready nuxt Called after Nuxt initialization, when the Nuxt instance is ready to work.
close nuxt Called when Nuxt instance is gracefully closing.
restart { hard?: boolean } To be called to restart the current Nuxt instance.
modules:before - Called during Nuxt initialization, before installing user modules.
modules:done - Called during Nuxt initialization, after installing user modules.
module:before module Called immediately before each individual module is set up.
module:done module Called immediately after each individual module has been set up, including how long it took.
app:resolve app Called after resolving the app instance.
app:templates app Called during NuxtApp generation, to allow customizing, modifying or adding new files to the build directory (either virtually or to written to .nuxt ).
app:templatesGenerated app Called after templates are compiled into the virtual file system (vfs).
server:routes routes, context Called when Nuxt needs the full set of route handlers the server will serve, so that it can type $fetch and useFetch against them. The configured server builder adds the handlers it discovered by scanning, alongside those registered through serverHandlers .
build:before - Called before Nuxt bundle builder.
build:done - Called after Nuxt bundle builder is complete.
build:manifest manifest Called during the manifest build by Vite and webpack. This allows customizing the manifest that Nitro will use to render ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-only.ts) # > Render components only during development with the component. Nuxt provides the `` component to render a component only during development. The content will not be included in production builds. ```vue [app/pages/example.vue] ``` ## Slots - `#fallback`: if you ever require to have a replacement during production. ```vue ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/dev-only.ts) # > The component adds a hidden element to announce dynamic content changes to assistive technologies. This component is available in Nuxt v4.4.2+. ## Usage Add `` in your [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app) or [`app/layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts) to enable announcing dynamic content changes to screen readers. This is useful for form validation, toast notifications, loading states, and other in-page updates. ```vue [app/app.vue] ``` Then use the [`useAnnouncer`](https://nuxt.com/docs/5.x/api/composables/use-announcer) composable anywhere in your app to announce messages: ```vue [app/pages/contact.vue] ``` ## Slots You can pass custom HTML or components through the announcer's default slot. ```vue ``` ## Props - `atomic`: Controls if screen readers announce only changes or the entire content. Set to true for full content readouts on updates, false for changes only. (default `true`) - `politeness`: Sets the default urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) ## Differences from ``
Aspect
Purpose Announces route/page changes Announces any dynamic content
Trigger Automatic on navigation Manual via polite() / assertive()
Message source Page </code> </td> <td> Developer-provided </td> </tr> <tr> <td> <strong> atomic default </strong> </td> <td> <code> false </code> </td> <td> <code> true </code> </td> </tr> </tbody> </table> <callout> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-announcer.ts). </callout> <callout> You can hook into the underlying announcer instance using [the `useAnnouncer` composable](https://nuxt.com/docs/5.x/api/composables/use-announcer), which allows you to set custom announcement messages. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-announcer.ts) # <NuxtClientFallback> > Nuxt provides the <NuxtClientFallback> component to render its content on the client if any of its children trigger an error in SSR Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR. <note to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#clientfallback"> This component is experimental and in order to use it you must enable the `experimental.clientFallback` option in your `nuxt.config`. </note> ```vue [app/pages/example.vue] <template> <div> <Sidebar /> <!-- this component will be rendered on client-side --> <NuxtClientFallback fallback-tag="span"> <Comments /> <BrokeInSSR /> </NuxtClientFallback> </div> </template> ``` ## Events - `@ssr-error`: Event emitted when a child triggers an error in SSR. Note that this will only be triggered on the server.```vue <template> <NuxtClientFallback @ssr-error="logSomeError"> <!-- ... --> </NuxtClientFallback> </template> ``` ## Props - `placeholderTag` | `fallbackTag`: Specify a fallback tag to be rendered if the slot fails to render on the server. - **type**: `string` - **default**: `div` - `placeholder` | `fallback`: Specify fallback content to be rendered if the slot fails to render. - **type**: `string` - `keepFallback`: Keep the fallback content if it failed to render server-side. - **type**: `boolean` - **default**: `false` <warning icon="i-ph-warning-duotone"> The `placeholder` and `fallback` props render content as raw HTML. Do not pass untrusted user input to these props as it may lead to XSS vulnerabilities. Use the `#fallback` or `#placeholder` slots instead for dynamic content that needs proper escaping. </warning> ```vue <template> <!-- render <span>Hello world</span> server-side if the default slot fails to render --> <NuxtClientFallback fallback-tag="span" fallback="Hello world" > <BrokeInSSR /> </NuxtClientFallback> </template> ``` ## Slots - `#fallback`: specify content to be displayed server-side if the slot fails to render. ```vue <template> <NuxtClientFallback> <!-- ... --> <template #fallback> <!-- this will be rendered on server side if the default slot fails to render in ssr --> <p>Hello world</p> </template> </NuxtClientFallback> </template> ``` --- - [Source (client)](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.client.ts) - [Source (server)](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.server.ts) # <NuxtErrorBoundary> > The <NuxtErrorBoundary> component handles client-side errors happening in its default slot. <tip> The `<NuxtErrorBoundary>` uses Vue's [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) hook under the hood. </tip> ## Events - `@error`: Event emitted when the default slot of the component throws an error.```vue [app/app.vue] <template> <NuxtErrorBoundary @error="logSomeError"> <!-- ... --> </NuxtErrorBoundary> </template> ``` ## Slots - `#error`: Specify a fallback content to display in case of error.```vue [app/app.vue] <template> <NuxtErrorBoundary> <!-- ... --> <template #error="{ error, clearError }"> <p>An error occurred: {{ error }}</p> <button @click="clearError"> Clear error </button> </template> </NuxtErrorBoundary> </template> ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> ## Example ### Accessing `error` and `clearError` in Script You can access `error` and `clearError` properties within the component's script as below: ```vue [app/app.vue] <template> <NuxtErrorBoundary ref="errorBoundary"> <!-- ... --> </NuxtErrorBoundary> </template> <script setup lang="ts"> const errorBoundary = useTemplateRef('errorBoundary') // errorBoundary.value?.error // errorBoundary.value?.clearError() </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-error-boundary.vue) # <NuxtImg> > Nuxt provides a <NuxtImg> component to handle automatic image optimization. `<NuxtImg>` is a drop-in replacement for the native `<img>` tag. - Uses built-in provider to optimize local and remote images - Converts `src` to provider-optimized URLs - Automatically resizes images based on `width` and `height` - Generates responsive sizes when providing `sizes` option - Supports native lazy loading as well as other `<img>` attributes ## Setup In order to use `<NuxtImg>` you should install and enable the Nuxt Image module: ```bash [Terminal] npx nuxt module add image ``` ## Usage `<NuxtImg>` outputs a native `img` tag directly (without any wrapper around it). Use it like you would use the `<img>` tag: ```html <NuxtImg src="/nuxt-icon.png" /> ``` Will result in: ```html <img src="/nuxt-icon.png" /> ``` <read-more target="_blank" to="https://image.nuxt.com/usage/nuxt-img"> Read more about the `<NuxtImg>` component. </read-more> --- - [Source](https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtImg.vue) # <NuxtIsland> > Nuxt provides the <NuxtIsland> component to render a non-interactive component without any client JS. When rendering an island component, the content of the island component is static, thus no JS is downloaded client-side. Changing the island component props triggers a refetch of the island component to re-render it again. <tip> Server only components use `<NuxtIsland>` under the hood </tip> <read-more to="https://nuxt.com/docs/5.x/guide/concepts/server-components"> Read the dedicated guide to server components and islands. </read-more> ## Props - `name` : Name of the component to render. - **type**: `string` - **required** - `lazy`: Make the component non-blocking. - **type**: `boolean` - **default**: `false` - `props`: Props to send to the component to render. - **type**: `Record<string, any>` - `source`: Remote source to call the island to render. - **type**: `string` - **dangerouslyLoadClientComponents**: Required to load client components from a remote source. - **type**: `boolean` - **default**: `false` <note> Remote islands need `experimental.componentIslands` to be `'local+remote'` in your `nuxt.config`. </note> <warning icon="i-ph-warning-duotone"> Using the `source` prop to render content from a remote server is inherently dangerous. When you specify a remote `source`, you are fully trusting that server to provide safe HTML content that will be rendered directly in your application. This is similar to using `v-html` with external content - the remote server can inject any HTML, including potentially malicious content. **Only use source with servers you fully trust and control.** The `dangerouslyLoadClientComponents` prop controls an additional layer of risk: whether to also download and execute client components from the remote source. Even with `dangerouslyLoadClientComponents` disabled (the default), you are still trusting the remote server's HTML output. </warning> <note> Component props and context are sent as GET query parameters to enable caching. Query parameters may be visible in server access logs, CDN caches, and HTTP `Referer` headers. </note> <note> By default, component islands are scanned from the `~/components/islands/` directory. So the `~/components/islands/MyIsland.vue` component could be rendered with `<NuxtIsland name="MyIsland" />`. </note> ## Known Limitations ### `useId` in island and server components Each island is rendered in its own Vue app on the server, so Vue's [`useId`](https://vuejs.org/api/composition-api-helpers#useid) counter restarts for every island. Ids generated inside an island can therefore collide with ids generated by other islands on the same page, or by the rest of your app. **Workaround**: set a distinct [`idPrefix`](https://vuejs.org/api/application#app-config-idprefix) on the island's Vue app from a server plugin, based on the island context id: ```ts [plugins/island-id-prefix.server.ts] export default defineNuxtPlugin((nuxtApp) => { const islandContext = nuxtApp.ssrContext?.islandContext if (islandContext) { nuxtApp.vueApp.config.idPrefix = `${islandContext.id}-v` } }) ``` - **Identical islands still share the same ids.** Two instances of the same island rendered with the same name, props and context share a single server render (and payload entry), so their HTML โ€” including any `useId`-generated ids โ€” is identical, and the island context id used as prefix is the same. This results in duplicated `id` attributes in the DOM, which can break `aria-*` references and `<label for>` associations between the two instances. There is currently no workaround for this case. - **useId does not work in interactive components inside islands.** A component loaded with the [`nuxt-client` attribute](https://nuxt.com/docs/5.x/guide/concepts/server-components#selective-hydration-with-nuxt-client) is server-rendered inside the island's app but hydrated by the main client app, so `useId` returns different values on the server and on the client, causing a hydration mismatch. ## Slots Slots can be passed to an island component if declared. Every slot is interactive since the parent component is the one providing it. Some slots are reserved to `NuxtIsland` for special cases. - `#fallback`: Specify the content to be rendered before the island loads (if the component is lazy) or if `NuxtIsland` fails to fetch the component. ## Ref - `refresh()` - **type**: `() => Promise<void>` - **description**: force refetch the server component by refetching it. ## Events - `error` - **parameters**: - **error**: - **type**: `unknown` - **description**: emitted when `NuxtIsland` fails to fetch the new island. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-island.ts) # <NuxtLayout> > Nuxt provides the <NuxtLayout> component to show layouts on pages and error pages. You can use `<NuxtLayout />` component to activate the `default` layout on `app.vue` or `error.vue`. ```vue [app/app.vue] <template> <NuxtLayout> some page content </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/layouts"> </read-more> ## Props - `name`: Specify a layout name to be rendered, can be a string, reactive reference or a computed property. It **must** match the name of the corresponding layout file in the [`app/layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts) directory, or `false` to disable the layout. - **type**: `string | false` - **default**: `default` ```vue [app/pages/index.vue] <script setup lang="ts"> // layouts/custom.vue const layout = 'custom' </script> <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> ``` <note> Please note the layout name is normalized to kebab-case, so if your layout file is named `errorLayout.vue`, it will become `error-layout` when passed as a `name` property to `<NuxtLayout />`. </note> ```vue [error.vue] <template> <NuxtLayout name="error-layout"> <NuxtPage /> </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/layouts"> Read more about dynamic layouts. </read-more> - `fallback`: If an invalid layout is passed to the `name` prop, no layout will be rendered. Specify a `fallback` layout to be rendered in this scenario. It **must** match the name of the corresponding layout file in the [`app/layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts) directory. - **type**: `string` - **default**: `null` ## Additional Props `NuxtLayout` also accepts any additional props that you may need to pass to the layout. These custom props are then made accessible as attributes. ```vue [app/pages/some-page.vue] <template> <div> <NuxtLayout name="custom" title="I am a custom layout" > <!-- ... --> </NuxtLayout> </div> </template> ``` In the above example, the value of `title` will be available using `$attrs.title` in the template or `useAttrs().title` in `<script setup>` at custom.vue. ```vue [app/layouts/custom.vue] <script setup lang="ts"> const layoutCustomProps = useAttrs() console.log(layoutCustomProps.title) // I am a custom layout </script> ``` ## Layout Props from Page Meta When using [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) with the object syntax for `layout`, props are automatically passed to the layout component. The layout can receive them with `defineProps`: ```vue [app/pages/dashboard.vue] <script setup lang="ts"> definePageMeta({ layout: { name: 'admin', props: { sidebar: true, }, }, }) </script> ``` ```vue [app/layouts/admin.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean }>() </script> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/layouts#passing-props-to-layouts"> Read more about passing props to layouts. </read-more> ## Transitions `<NuxtLayout />` renders incoming content via `<slot />`, which is then wrapped around Vueโ€™s `<Transition />` component to activate layout transition. For this to work as expected, it is recommended that `<NuxtLayout />` is **not** the root element of the page component. <code-group> ```vue [app/pages/index.vue] <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> </NuxtLayout> </div> </template> ``` ```vue [app/layouts/custom.vue] <template> <div> <!-- named slot --> <slot name="header" /> <slot /> </div> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/5.x/getting-started/transitions"> </read-more> ## Layout's Ref To get the ref of a layout component, access it through `ref.value.layoutRef`. <code-group> ```vue [app/app.vue] <script setup lang="ts"> const layout = ref() function logFoo () { layout.value.layoutRef.foo() } </script> <template> <NuxtLayout ref="layout"> default layout </NuxtLayout> </template> ``` ```vue [app/layouts/default.vue] <script setup lang="ts"> const foo = () => console.log('foo') defineExpose({ foo, }) </script> <template> <div> default layout <slot /> </div> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/layouts"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-layout.ts) # <NuxtLink> > Nuxt provides <NuxtLink> component to handle any kind of links within your application. <note> `<NuxtLink>` is a drop-in replacement for both Vue Router's `<RouterLink>` component and HTML's `<a>` tag. It intelligently determines whether the link is *internal* or *external* and renders it accordingly with available optimizations (prefetching, default attributes, etc.) </note> <read-more title="Nuxt accessibility" to="https://nuxt.com/docs/5.x/guide/best-practices/accessibility#links"> </read-more> ## Internal Routing In this example, we use `<NuxtLink>` component to link to another page of the application. <code-group> ```vue [app/pages/index.vue] <template> <NuxtLink to="/about">About page</NuxtLink> </template> ``` ```html [(Renders as) index.html] <!-- (Vue Router & Smart Prefetching) --> <a href="/about">About page</a> ``` </code-group> ### Passing Params to Dynamic Routes In this example, we pass the `id` param to link to the route `~/pages/posts/[id].vue`. <code-group> ```vue [app/pages/index.vue] <template> <NuxtLink :to="{ name: 'posts-id', params: { id: 123 } }"> Post 123 </NuxtLink> </template> ``` ```html [(Renders as) index.html] <a href="/posts/123">Post 123</a> ``` </code-group> <tip> Check out the Pages panel in Nuxt DevTools to see the route name and the params it might take. </tip> <tip> When you pass an object into the `to` prop, `<NuxtLink>` will inherit Vue Routerโ€™s handling of query parameters. Keys and values will be automatically encoded, so you donโ€™t need to call `encodeURI` or `encodeURIComponent` manually. </tip> ### Handling Static File and Cross-App Links By default, `<NuxtLink>` uses Vue Router's client side navigation for relative route. When linking to static files in the `/public` directory or to another application hosted on the same domain, it might result in unexpected 404 errors because they are not part of the client routes. In such cases, you can use the `external` prop with `<NuxtLink>` to bypass Vue Router's internal routing mechanism. The `external` prop explicitly indicates that the link is external. `<NuxtLink>` will render the link as a standard HTML `<a>` tag. This ensures the link behaves correctly, bypassing Vue Routerโ€™s logic and directly pointing to the resource. #### Linking to Static Files For static files in the `/public` directory, such as PDFs or images, use the `external` prop to ensure the link resolves correctly. ```vue [app/pages/index.vue] <template> <NuxtLink to="/example-report.pdf" external > Download Report </NuxtLink> </template> ``` #### Linking to a Cross-App URL When pointing to a different application on the same domain, using the `external` prop ensures the correct behavior. ```vue [app/pages/index.vue] <template> <NuxtLink to="/another-app" external > Go to Another App </NuxtLink> </template> ``` Using the `external` prop or relying on automatic handling ensures proper navigation, avoids unexpected routing issues, and improves compatibility with static resources or cross-application scenarios. ## External Routing In this example, we use `<NuxtLink>` component to link to a website. ```vue [app/app.vue] <template> <NuxtLink to="https://nuxtjs.org"> Nuxt website </NuxtLink> <!-- <a href="https://nuxtjs.org" rel="noopener noreferrer">...</a> --> </template> ``` ## `rel` and `noRel` Attributes A `rel` attribute of `noopener noreferrer` is applied by default to links with a `target` attribute or to absolute links (e.g., links starting with `http://`, `https://`, or `//`). - `noopener` solves a [security bug](https://mathiasbynens.github.io/rel-noopener/) in older browsers. - `noreferrer` improves privacy for your users by not sending the `Referer` header to the linked site. These defaults have no negative impact on SEO and are considered [best practice](https://developer.chrome.com/docs/lighthouse/best-practices/external-anchors-use-rel-noopener). When you need to overwrite this behavior you can use the `rel` or `noRel` props. ```vue [app/app.vue] <template> <NuxtLink to="https://twitter.com/nuxt_js"> Nuxt Twitter </NuxtLink> <!-- <a href="https://twitter.com/nuxt_js" rel="noopener noreferrer">...</a> --> <NuxtLink to="https://discord.nuxtjs.org" rel="noopener" > Nuxt Discord </NuxtLink> <!-- <a href="https://discord.nuxtjs.org" rel="noopener">...</a> --> <NuxtLink to="/about" target="_blank" >About page</NuxtLink> <!-- <a href="/about" target="_blank" rel="noopener noreferrer">...</a> --> </template> ``` A `noRel` prop can be used to prevent the default `rel` attribute from being added to the absolute links. ```vue [app/app.vue] <template> <NuxtLink to="https://github.com/nuxt" no-rel > Nuxt GitHub </NuxtLink> <!-- <a href="https://github.com/nuxt">...</a> --> </template> ``` <note> `noRel` and `rel` cannot be used together. `rel` will be ignored. </note> ## Prefetch Links Nuxt automatically includes smart prefetching. That means it detects when a link is visible (by default), either in the viewport or when scrolling and prefetches the JavaScript for those pages so that they are ready when the user clicks the link. Nuxt only loads the resources when the browser isn't busy and skips prefetching if your connection is offline or if you only have 2g connection. When using the `custom` prop, `<NuxtLink>` does not automatically attach prefetch handlers. You can call `prefetch` from the custom slot yourself. ```vue [app/pages/index.vue] <NuxtLink to="/about" no-prefetch> About page not pre-fetched </NuxtLink> <NuxtLink to="/about" :prefetch="false"> About page not pre-fetched </NuxtLink> ``` ### Custom Prefetch Triggers We now support custom prefetch triggers for `<NuxtLink>` after `v3.13.0`. You can use the `prefetchOn` prop to control when to prefetch links. ```vue <template> <NuxtLink prefetch-on="visibility"> This will prefetch when it becomes visible (default) </NuxtLink> <NuxtLink prefetch-on="interaction"> This will prefetch when hovered or when it gains focus </NuxtLink> </template> ``` - `visibility`: Prefetches when the link becomes visible in the viewport. Monitors the element's intersection with the viewport using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Prefetching is triggered when the element is scrolled into view. - `interaction`: Prefetches when the link is hovered or focused. This approach listens for `pointerenter` and `focus` events, proactively prefetching resources when the user indicates intent to interact. You can also use an object to configure `prefetchOn`: ```vue <template> <NuxtLink :prefetch-on="{ interaction: true }"> This will prefetch when hovered or when it gains focus </NuxtLink> </template> ``` That you probably don't want both enabled! ```vue <template> <NuxtLink :prefetch-on="{ visibility: true, interaction: true }"> This will prefetch when hovered/focus - or when it becomes visible </NuxtLink> </template> ``` This configuration will observe when the element enters the viewport and also listen for `pointerenter` and `focus` events. This may result in unnecessary resource usage or redundant prefetching, as both triggers can prefetch the same resource under different conditions. When using `custom`, prefetching is controlled by your slot implementation <badge className="align-middle" color="info" size="xs"> v4.5 </badge> : ```vue <template> <NuxtLink v-slot="{ href, navigate, prefetch, shouldPrefetch }" to="/about" custom > <a :href="href" @click="navigate" @pointerenter="shouldPrefetch('interaction') && prefetch()" @focus="shouldPrefetch('interaction') && prefetch()" > About page </a> </NuxtLink> </template> ``` ### Enable Cross-origin Prefetch To enable cross-origin prefetching, you can set the `crossOriginPrefetch` option in your `nuxt.config`. This will enable cross-origin prefetching using the [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API). ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { crossOriginPrefetch: true, }, }) ``` ### Disable prefetch globally It's also possible to enable/disable prefetching all links globally for your app. ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { prefetch: false, }, }, }, }) ``` ## Props ### RouterLink When not using `external`, `<NuxtLink>` supports all Vue Router's [`RouterLink` props](https://router.vuejs.org/api/interfaces/routerlinkprops) - `to`: Any URL or a [route location object](https://router.vuejs.org/api/type-aliases/routelocation) from Vue Router - `custom`: Whether `<NuxtLink>` should wrap its content in an `<a>` element. It allows taking full control of how a link is rendered and how navigation works when it is clicked. Works the same as [Vue Router's `custom` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#custom-) - `exactActiveClass`: A class to apply on exact active links. Works the same as [Vue Router's `exactActiveClass` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#exactActiveClass-) on internal links. Defaults to Vue Router's default (`"router-link-exact-active"`) - `activeClass`: A class to apply on active links. Works the same as [Vue Router's `activeClass` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#activeClass-) on internal links. Defaults to Vue Router's default (`"router-link-active"`) - `replace`: Works the same as [Vue Router's `replace` prop](https://router.vuejs.org/api/interfaces/routelocationoptions#replace-) on internal links - `ariaCurrentValue`: An `aria-current` attribute value to apply on exact active links. Works the same as [Vue Router's `ariaCurrentValue` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#ariaCurrentValue-) on internal links ### NuxtLink - `href`: An alias for `to`. If used with `to`, `href` will be ignored - `noRel`: If set to `true`, no `rel` attribute will be added to the external link - `external`: Forces the link to be rendered as an `<a>` tag instead of a Vue Router `RouterLink`. - `prefetch`: When enabled will prefetch middleware, layouts and payloads (when using [payloadExtraction](https://nuxt.com/docs/5.x/guide/going-further/experimental-features#payloadextraction)) of links in the viewport. Used by the experimental [crossOriginPrefetch](https://nuxt.com/docs/5.x/guide/going-further/experimental-features#crossoriginprefetch) config. - `prefetchOn`: Allows custom control of when to prefetch links. Possible options are `interaction` and `visibility` (default). You can also pass an object for full control, for example: `{ interaction: true, visibility: true }`. This prop is only used when `prefetch` is enabled (default) and `noPrefetch` is not set. - `noPrefetch`: Disables prefetching. - `prefetchedClass`: A class to apply to links that have been prefetched. <note> With the `custom` prop, `prefetch`, `prefetchOn` and `prefetchedClass` do not attach handlers or classes automatically. Use the custom slot's `prefetch`, `prefetched` and `shouldPrefetch` values to implement this behavior. </note> ### Anchor - `target`: A `target` attribute value to apply on the link - `rel`: A `rel` attribute value to apply on the link. Defaults to `"noopener noreferrer"` for external links. <tip> Defaults can be overwritten, see [overwriting defaults](https://nuxt.com/docs/5.x/api/components/nuxt-link#overwriting-defaults) if you want to change them. </tip> ## Overwriting Defaults ### In Nuxt Config You can overwrite some `<NuxtLink>` defaults in your [`nuxt.config`](https://nuxt.com/docs/5.x/guide/going-further/experimental-features#defaults) <important> These options will likely be moved elsewhere in the future, such as into `app.config` or into the `app/` directory. </important> ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { // default values componentName: 'NuxtLink', externalRelAttribute: 'noopener noreferrer', activeClass: 'router-link-active', exactActiveClass: 'router-link-exact-active', prefetchedClass: undefined, // can be any valid string class name trailingSlash: undefined, // can be 'append' or 'remove' prefetch: true, prefetchOn: { visibility: true }, }, }, }, }) ``` ### Custom Link Component You can overwrite `<NuxtLink>` defaults by creating your own link component using `defineNuxtLink`. ```ts [app/components/MyNuxtLink.ts] export default defineNuxtLink({ componentName: 'MyNuxtLink', /* see signature below for more */ }) ``` The component is auto-imported by its file name, so you can use `<MyNuxtLink />` as usual with your new defaults. `componentName` only sets the component's internal name (as shown in Vue DevTools); it does not change how the component is used in templates. ### `defineNuxtLink` Signature ```ts interface NuxtLinkOptions { componentName?: string externalRelAttribute?: string activeClass?: string exactActiveClass?: string trailingSlash?: 'append' | 'remove' prefetch?: boolean prefetchedClass?: string prefetchOn?: Partial<{ visibility: boolean interaction: boolean }> } function defineNuxtLink (options: NuxtLinkOptions): Component {} ``` - `componentName`: The component's internal name, as shown in Vue DevTools. It does not change the name used in templates (that comes from the component's file name). Default is `NuxtLink`. - `externalRelAttribute`: A default `rel` attribute value applied on external links. Defaults to `"noopener noreferrer"`. Set it to `""` to disable - `activeClass`: A default class to apply on active links. Works the same as [Vue Router's `linkActiveClass` option](https://router.vuejs.org/api/interfaces/routeroptions#linkActiveClass-). Defaults to Vue Router's default (`"router-link-active"`) - `exactActiveClass`: A default class to apply on exact active links. Works the same as [Vue Router's `linkExactActiveClass` option](https://router.vuejs.org/api/interfaces/routeroptions#linkExactActiveClass-). Defaults to Vue Router's default (`"router-link-exact-active"`) - `trailingSlash`: An option to either add or remove trailing slashes in the `href`. If unset or not matching the valid values `append` or `remove`, it will be ignored. - `prefetch`: Whether or not to prefetch links by default. - `prefetchOn`: Granular control of which prefetch strategies to apply by default. - `prefetchedClass`: A default class to apply to links that have been prefetched. <link-example to="https://nuxt.com/docs/5.x/examples/routing/pages"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-link.ts) # <NuxtLoadingIndicator> > Display a progress bar between page navigations. ## Usage Add `<NuxtLoadingIndicator/>` in your [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app) or [`app/layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts). ```vue [app/app.vue] <template> <NuxtLoadingIndicator /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` <link-example to="https://nuxt.com/docs/5.x/examples/routing/pages"> </link-example> ## Slots You can pass custom HTML or components through the loading indicator's default slot. ## Props - `color`: The color of the loading bar. It can be set to `false` to turn off explicit color styling. - `errorColor`: The color of the loading bar when `error` is set to `true`. - `height`: Height of the loading bar, in pixels (default `3`). - `duration`: Duration of the loading bar, in milliseconds (default `2000`). - `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`). - `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100. <note> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts). </note> <note> You can hook into the underlying indicator instance using [the `useLoadingIndicator` composable](https://nuxt.com/docs/5.x/api/composables/use-loading-indicator), which will allow you to trigger start/finish events yourself. </note> <tip> The loading indicator's speed gradually decreases after reaching a specific point controlled by `estimatedProgress`. This adjustment provides a more accurate reflection of longer page loading times and prevents the indicator from prematurely showing 100% completion. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts) # <NuxtPage> > The <NuxtPage> component is required to display pages located in the pages/ directory. `<NuxtPage>` is a built-in component that comes with Nuxt. It lets you display top-level or nested pages located in the [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) directory. <note> `<NuxtPage>` is a wrapper around [`<RouterView>`](https://router.vuejs.org/api/interfaces/routerviewprops) from Vue Router. It should be used instead of `<RouterView>` because the former takes additional care of internal states. Otherwise, `useRoute()` may return incorrect paths. </note> `<NuxtPage>` includes the following components: ```vue <template> <RouterView v-slot="{ Component }"> <!-- Optional, when using transitions --> <Transition> <!-- Optional, when using keep-alive --> <KeepAlive> <Suspense> <component :is="Component" /> </Suspense> </KeepAlive> </Transition> </RouterView> </template> ``` By default, Nuxt does not enable `<Transition>` and `<KeepAlive>`. You can enable them in the nuxt.config file or by setting the `transition` and `keepalive` properties on `<NuxtPage>`. If you want to define a specific page, you can set it in `definePageMeta` in the page component. <warning> If you enable `<Transition>` in your page component, ensure that the page has a single root element. </warning> Since `<NuxtPage>` uses `<Suspense>` under the hood, the component lifecycle behavior during page changes differs from that of a typical Vue application. In a typical Vue application, a new page component is mounted **only after** the previous one has been fully unmounted. However, in Nuxt, due to how Vue `<Suspense>` is implemented, the new page component is mounted **before** the previous one is unmounted. ## Props - `name`: tells `<RouterView>` to render the component with the corresponding name in the matched route record's components option. See [Named Views](https://nuxt.com/docs/5.x/directory-structure/app/pages#named-views) for the `name@view.vue` filename convention. - type: `string` - `route`: route location that has all of its components resolved. - type: `RouteLocationNormalized` - `pageKey`: control when the `NuxtPage` component is re-rendered. - type: `string` or `function` - `transition`: define global transitions for all pages rendered with the `NuxtPage` component. - type: `boolean` or [`TransitionProps`](https://vuejs.org/api/built-in-components#transition) - `keepalive`: control state preservation of pages rendered with the `NuxtPage` component. - type: `boolean` or [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive) <tip> Nuxt automatically resolves the `name` and `route` by scanning and rendering all Vue component files found in the `/pages` directory. </tip> ## Example For example, if you pass a key that never changes, the `<NuxtPage>` component will be rendered only once - when it is first mounted. ```vue [app/app.vue] <template> <NuxtPage page-key="static" /> </template> ``` You can also use a dynamic key based on the current route: ```html <NuxtPage :page-key="route => route.fullPath" /> ``` <warning> Don't use `$route` object here as it can cause problems with how `<NuxtPage>` renders pages with `<Suspense>`. </warning> Alternatively, `pageKey` can be passed as a `key` value via [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) from the `<script>` section of your Vue component in the `/pages` directory. ```vue [app/pages/my-page.vue] <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, }) </script> ``` <link-example to="https://nuxt.com/docs/5.x/examples/routing/pages"> </link-example> ## Page's Ref To get the `ref` of a page component, access it through `ref.value.pageRef` ```vue [app/app.vue] <script setup lang="ts"> const page = ref() function logFoo () { page.value.pageRef.foo() } </script> <template> <NuxtPage ref="page" /> </template> ``` ```vue [my-page.vue] <script setup lang="ts"> const foo = () => { console.log('foo method called') } defineExpose({ foo, }) </script> ``` ## Custom Props `<NuxtPage>` also accepts custom props that you may need to pass further down the hierarchy. For example, in the below example, the value of `foobar` will be passed to the `NuxtPage` component and then to the page components. ```vue [app/app.vue] <template> <NuxtPage :foobar="123" /> </template> ``` We can access the `foobar` prop in the page component: ```vue [app/pages/page.vue] <script setup lang="ts"> const props = defineProps<{ foobar: number }>() console.log(props.foobar) // Outputs: 123 ``` If you have not defined the prop with `defineProps`, any props passed down to `NuxtPage` can still be accessed directly from the page `attrs`: ```vue [app/pages/page.vue] <script setup lang="ts"> const attrs = useAttrs() console.log(attrs.foobar) // Outputs: 123 </script> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/pages"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/page.ts) # <NuxtPicture> > Nuxt provides a <NuxtPicture> component to handle automatic image optimization. `<NuxtPicture>` is a drop-in replacement for the native `<picture>` tag. Usage of `<NuxtPicture>` is almost identical to [`<NuxtImg>`](https://nuxt.com/docs/5.x/api/components/nuxt-img) but it also allows serving modern formats like `webp` when possible. Learn more about the [`<picture>` tag on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture). ## Setup In order to use `<NuxtPicture>` you should install and enable the Nuxt Image module: ```bash [Terminal] npx nuxt module add image ``` <read-more target="_blank" to="https://image.nuxt.com/usage/nuxt-picture"> Read more about the `<NuxtPicture>` component. </read-more> --- - [Source](https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtPicture.vue) # <NuxtRouteAnnouncer> > The <NuxtRouteAnnouncer> component adds a hidden element with the page title to announce route changes to assistive technologies. <important> This component is available in Nuxt v3.12+. </important> <read-more title="Nuxt accessibility" to="https://nuxt.com/docs/5.x/guide/best-practices/accessibility#route-announcements"> </read-more> ## Usage Add `<NuxtRouteAnnouncer/>` in your [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app) or [`app/layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts) to enhance accessibility by informing assistive technologies about page title changes. This ensures that navigational changes are announced to users relying on screen readers. ```vue [app/app.vue] <template> <NuxtRouteAnnouncer /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` ## Slots You can pass custom HTML or components through the route announcer's default slot. ```vue <template> <NuxtRouteAnnouncer> <template #default="{ message }"> <p>{{ message }} was loaded.</p> </template> </NuxtRouteAnnouncer> </template> ``` ## Props - `atomic`: Controls if screen readers only announce changes or the entire content. Set to true for full content readouts on updates, false for changes only. (default `false`) - `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) <callout> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts). </callout> <callout> You can hook into the underlying announcer instance using [the `useRouteAnnouncer` composable](https://nuxt.com/docs/5.x/api/composables/use-route-announcer), which allows you to set a custom announcement message. </callout> <callout> For announcing in-page content changes (form validation, toast notifications, loading states, etc.), use the [`<NuxtAnnouncer>`](https://nuxt.com/docs/5.x/api/components/nuxt-announcer) component with the [`useAnnouncer`](https://nuxt.com/docs/5.x/api/composables/use-announcer) composable instead. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts) # <NuxtTime> > The <NuxtTime> component displays time in a locale-friendly format with server-client consistency. <important> This component is available in Nuxt v3.17+. </important> The `<NuxtTime>` component lets you display dates and times in a locale-friendly format with proper `<time>` HTML semantics. It ensures consistent rendering between server and client without hydration mismatches. ## Usage You can use the `<NuxtTime>` component anywhere in your app: ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" /> </template> ``` ## Props ### `datetime` - Type: `Date | number | string` - Required: `true` The date and time value to display. You can provide: - A `Date` object - A timestamp (number) - An ISO-formatted date string ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" /> <NuxtTime :datetime="new Date()" /> <NuxtTime datetime="2023-06-15T09:30:00.000Z" /> </template> ``` ### `locale` - Type: `string` - Required: `false` - Default: Uses the browser or server's default locale The [BCP 47 language tag](https://datatracker.ietf.org/doc/html/rfc5646) for formatting (e.g., 'en-US', 'fr-FR', 'ja-JP'): ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" locale="fr-FR" /> </template> ``` ### Formatting Props The component accepts any property from the [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) options: ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" year="numeric" month="long" day="numeric" hour="2-digit" minute="2-digit" /> </template> ``` This would output something like: "April 22, 2025, 08:30 AM" ### `relative` - Type: `boolean` - Required: `false` - Default: `false` Enables relative time formatting using the Intl.RelativeTimeFormat API: ```vue [app/app.vue] <template> <!-- Shows something like "5 minutes ago" --> <NuxtTime :datetime="Date.now() - 5 * 60 * 1000" relative /> </template> ``` ### Relative Time Formatting Props When `relative` is set to `true`, the component also accepts properties from [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat): <warning> Due to `style` being a reserved prop, `relativeStyle` prop is used instead. </warning> ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now() - 3 * 24 * 60 * 60 * 1000" relative numeric="auto" relative-style="long" /> </template> ``` This would output something like: "3 days ago" or "last Friday" depending on the `numeric` setting. ## Example ### Basic Usage ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" /> </template> ``` ### Custom Formatting ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" weekday="long" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" time-zone-name="short" /> </template> ``` ### Relative Time ```vue [app/app.vue] <template> <div> <p> <NuxtTime :datetime="Date.now() - 30 * 1000" relative /> <!-- 30 seconds ago --> </p> <p> <NuxtTime :datetime="Date.now() - 45 * 60 * 1000" relative /> <!-- 45 minutes ago --> </p> <p> <NuxtTime :datetime="Date.now() + 2 * 24 * 60 * 60 * 1000" relative /> <!-- in 2 days --> </p> </div> </template> ``` ### With Custom Locale ```vue [app/app.vue] <template> <div> <NuxtTime :datetime="Date.now()" locale="en-US" weekday="long" /> <NuxtTime :datetime="Date.now()" locale="fr-FR" weekday="long" /> <NuxtTime :datetime="Date.now()" locale="ja-JP" weekday="long" /> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-time.vue) # <NuxtWelcome> > The <NuxtWelcome> component greets users in new projects made from the starter template. It includes links to the Nuxt documentation, source code, and social media accounts. ```vue [app/app.vue] <template> <NuxtWelcome /> </template> ``` <read-more target="_blank" to="https://templates.ui.nuxtjs.org/templates/welcome"> Preview the `<NuxtWelcome />` component. </read-more> <tip> This component is part of [`@nuxt/ui-templates`](https://github.com/nuxt/nuxt/tree/main/packages/ui-templates) package. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/ui-templates/templates/welcome/index.html) # <Teleport> > The <Teleport> component teleports a component to a different location in the DOM. <warning> The `to` target of [`<Teleport>`](https://vuejs.org/guide/built-ins/teleport) expects a CSS selector string or an actual DOM node. Nuxt currently has SSR support for teleports to `#teleports` only, with client-side support for other targets using a `<ClientOnly>` wrapper. </warning> ## Body Teleport ```vue <template> <button @click="open = true"> Open Modal </button> <Teleport to="#teleports"> <div v-if="open" class="modal" > <p>Hello from the modal!</p> <button @click="open = false"> Close </button> </div> </Teleport> </template> ``` ## Client-side Teleport ```vue <template> <ClientOnly> <Teleport to="#some-selector"> <!-- content --> </Teleport> </ClientOnly> </template> ``` <link-example to="https://nuxt.com/docs/5.x/examples/advanced/teleport"> </link-example> # createUseAsyncData > A factory function to create a custom useAsyncData composable with pre-defined default options. `createUseAsyncData` creates a custom [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) composable with pre-defined options. The resulting composable is fully typed and works exactly like `useAsyncData`, but with your defaults baked in. <note> `createUseAsyncData` is a compiler macro. It must be used as an **exported** declaration in the `composables/` directory (or any directory scanned by the Nuxt compiler). Nuxt automatically injects de-duplication keys at build time. </note> ## Usage ```ts [app/composables/useCachedData.ts] export const useCachedData = createUseAsyncData({ getCachedData (key, nuxtApp) { return nuxtApp.payload.data[key] ?? nuxtApp.static.data[key] }, }) ``` ```vue [app/pages/index.vue] <script setup lang="ts"> const { data: mountains } = await useCachedData( 'mountains', () => $fetch('https://api.nuxtjs.dev/mountains'), ) </script> ``` The resulting composable has the same signature and return type as [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data), with all options available for the caller to use or override. ## Type ```ts [Signature] function createUseAsyncData ( options?: Partial<AsyncDataOptions>, ): typeof useAsyncData function createUseAsyncData ( options: (callerOptions: AsyncDataOptions) => Partial<AsyncDataOptions>, ): typeof useAsyncData ``` ## Options `createUseAsyncData` accepts all the same options as [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data#parameters), including `server`, `lazy`, `immediate`, `default`, `transform`, `pick`, `getCachedData`, `deep`, `dedupe`, `timeout`, and `watch`. See the full list of options in the [`useAsyncData` documentation](https://nuxt.com/docs/5.x/api/composables/use-async-data#parameters). ## Default vs Override Mode ### Default Mode (plain object) When you pass a plain object, the factory options act as **defaults**. Callers can override any option: ```ts [app/composables/useLazyData.ts] export const useLazyData = createUseAsyncData({ lazy: true, server: false, }) ``` ```ts // Uses the defaults (lazy: true, server: false) const { data } = await useLazyData('key', () => fetchSomeData()) // Caller overrides server to true const { data } = await useLazyData('key', () => fetchSomeData(), { server: true }) ``` ### Override Mode (function) When you pass a function, the factory options **override** the caller's options. The function receives the caller's options as its argument: ```ts [app/composables/useStrictData.ts] // deep is always enforced as false export const useStrictData = createUseAsyncData(callerOptions => ({ deep: false, })) ``` <read-more to="https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch"> </read-more> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-async-data"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # createUseFetch > A factory function to create a custom useFetch composable with pre-defined default options. `createUseFetch` creates a custom [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) composable with pre-defined options. The resulting composable is fully typed and works exactly like `useFetch`, but with your defaults baked in. <note> `createUseFetch` is a compiler macro. It must be used as an **exported** declaration in the `composables/` directory (or any directory scanned by the Nuxt compiler). Nuxt automatically injects de-duplication keys at build time. </note> ## Usage ```ts [app/composables/useAPI.ts] export const useAPI = createUseFetch({ baseURL: 'https://api.nuxt.com', }) ``` ```vue [app/pages/modules.vue] <script setup lang="ts"> const { data: modules } = await useAPI('/modules') </script> ``` The resulting `useAPI` composable has the same signature and return type as [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch), with all options available for the caller to use or override. ## Type ```ts [Signature] function createUseFetch ( options?: Partial<UseFetchOptions>, ): typeof useFetch function createUseFetch ( options: (callerOptions: UseFetchOptions) => Partial<UseFetchOptions>, ): typeof useFetch // where the client declares the routes it serves function createUseFetch<Routes> ( options: Partial<UseFetchOptions> & { routes: Routes }, ): DeclaredUseFetch<Routes> ``` ## Options `createUseFetch` accepts all the same options as [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch#parameters), including `baseURL`, `headers`, `query`, `onRequest`, `onResponse`, `server`, `lazy`, `transform`, `getCachedData`, and more. See the full list of options in the [`useFetch` documentation](https://nuxt.com/docs/5.x/api/composables/use-fetch#parameters). ## Typing a Third-Party API By default a composable created with `createUseFetch` is typed from the routes your own server serves, so a request to another API resolves to `unknown`. Pass `routes` to say what that API serves, and every request the composable makes is resolved against it instead: ```ts [app/composables/usePetStore.ts] import type { DynamicParam, Endpoint } from 'nuxt/app' interface Pet { id: number, name: string } interface PetStoreRoutes { '/pets': { [Endpoint]: { GET: { response: Pet[], query: { limit?: number } } POST: { response: Pet, body: { name: string } } } // a path parameter, matched positionally [DynamicParam]: { [Endpoint]: { GET: { response: Pet } } } } } export const usePetStore = createUseFetch({ baseURL: 'https://api.example.com', routes: {} as PetStoreRoutes, }) ``` ```ts const { data: pets } = await usePetStore('/pets') // ^? Pet[] const { data: pet } = await usePetStore('/pets/42') // ^? Pet await usePetStore('/pets', { method: 'post', body: { name: 'Rex' } }) await usePetStore('/pats') // ^ no GET route matches '/pats' await usePetStore('/pets', { method: 'put' }) // ^ no PUT route matches '/pets' await usePetStore('/pets', { method: 'post' }) // ^ body is required ``` Only the type of `routes` is read, so pass `{} as Routes`; the value is dropped before the request is made. The declared paths are matched **as written**, since they are the paths the API documents. You should not prefix them with the `baseURL`. A path built at runtime resolves to `unknown`. <note> The routes a client declares are its own. They are not added to your app's route set, so plain `$fetch` and `useFetch` are unaffected, and this client will not accept your own server's paths. </note> <tip> The interface above is the shape [`fetchdts`](https://github.com/unjs/fetchdts) uses, which is what Nuxt generates for your own server routes. A module can therefore generate one from an API description - an OpenAPI document, for example - with `compileRoutes` from `fetchdts/compiler`, and hand the emitted interface to `routes`. </tip> ## Default vs Override Mode ### Default Mode (plain object) When you pass a plain object, the factory options act as **defaults**. Callers can override any option: ```ts [app/composables/useAPI.ts] export const useAPI = createUseFetch({ baseURL: 'https://api.nuxt.com', lazy: true, }) ``` ```ts // Uses the default baseURL const { data } = await useAPI('/modules') // Caller overrides the baseURL const { data } = await useAPI('/modules', { baseURL: 'https://other-api.com' }) ``` ### Override Mode (function) When you pass a function, the factory options **override** the caller's options. The function receives the caller's options as its argument, so you can read them to compute your overrides: ```ts [app/composables/useAPI.ts] // baseURL is always enforced, regardless of what the caller passes export const useAPI = createUseFetch(callerOptions => ({ baseURL: 'https://api.nuxt.com', })) ``` This is useful for enforcing settings like authentication headers or a specific base URL that should not be changed by the caller. ## Combining with a Custom `$fetch` You can pass a custom `$fetch` instance to `createUseFetch`: ```ts [app/composables/useAPI.ts] export const useAPI = createUseFetch(callerOptions => ({ $fetch: useNuxtApp().$api as typeof $fetch, ...callerOptions, })) ``` <important> The **function signature** (override mode) is required here so that [`useNuxtApp()`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) is called in the setup context (at the composable call site) rather than in the module scope, where no Nuxt instance is available. </important> <read-more to="https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch"> </read-more> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-fetch"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # onPrehydrate > Use onPrehydrate to run a callback on the client immediately before Nuxt hydrates the page. <important> This composable is available in Nuxt v3.12+. </important> `onPrehydrate` is a composable lifecycle hook that allows you to run a callback on the client immediately before Nuxt hydrates the page. <note> This is an advanced utility and should be used with care. For example, [`nuxt-time`](https://github.com/danielroe/nuxt-time/pull/251) and [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode/blob/main/src/script.js) manipulate the DOM to avoid hydration mismatches. </note> ## Usage Call `onPrehydrate` in the setup function of a Vue component (e.g., in `<script setup>`) or in a plugin. The call itself only has an effect when made on the server and is stripped from your client build. The callback you pass, however, is serialized and inlined into the HTML, so it runs in the **browser** immediately before Nuxt hydrates. This means it can access browser globals like `window` and the DOM. ## Type ```ts [Signature] export function onPrehydrate (callback: (el: HTMLElement) => void): void export function onPrehydrate (callback: string | ((el: HTMLElement) => void), key?: string): undefined | string ``` ## Parameters <table> <thead> <tr> <th> Parameter </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> callback </code> </td> <td> <code> ((el: HTMLElement) => void) | string </code> </td> <td> Yes </td> <td> A function (or stringified function) to run before Nuxt hydrates. It will be stringified and inlined in the HTML. Should not have external dependencies or reference variables outside the callback. Runs before Nuxt runtime initializes, so it should not rely on Nuxt or Vue context. </td> </tr> <tr> <td> <code> key </code> </td> <td> <code> string </code> </td> <td> No </td> <td> (Advanced) A unique key to identify the prehydrate script, useful for advanced scenarios like multiple root nodes. </td> </tr> </tbody> </table> ## Return Values - Returns `undefined` when called with only a callback function. - Returns a string (the prehydrate id) when called with a callback and a key, which can be used to set or access the `data-prehydrate-id` attribute for advanced use cases. ## Example ```vue [app/app.vue]twoslash <script setup lang="ts"> declare const window: Window // ---cut--- onPrehydrate(() => { // Runs in the browser, right before Nuxt hydrates console.log(window) }) // Access the root element onPrehydrate((el) => { console.log(el.outerHTML) // <div data-v-inspector="app.vue:15:3" data-prehydrate-id=":b3qlvSiBeH:"> Hi there </div> }) // Advanced: access/set `data-prehydrate-id` yourself const prehydrateId = onPrehydrate((el) => {}) </script> <template> <div> Hi there </div> </template> ``` Under the hood, the callback is stringified and minified at build time, then inlined as a `<script>` tag in the server-rendered HTML, just before the closing `</body>` tag. For the example above, the rendered HTML includes something like: ```html <div data-prehydrate-id=":b3qlvSiBeH:"> Hi there </div> <script>(()=>{console.log(window)})()</script> <script>document.querySelectorAll('[data-prehydrate-id*=":b3qlvSiBeH:"]').forEach(el=>{console.log(el.outerHTML)})</script> ``` When the callback accepts an `el` parameter, the component's root element is tagged with a `data-prehydrate-id` attribute so the inlined script can find it. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useAnnouncer > A composable for announcing messages to screen readers. <important> This composable is available in Nuxt v4.4.2+. </important> ## Description A composable for announcing dynamic content changes to screen readers. Unlike [`useRouteAnnouncer`](https://nuxt.com/docs/5.x/api/composables/use-route-announcer) which automatically announces route changes, `useAnnouncer` gives you manual control over what and when to announce. Use this for in-page updates like form validation, async operations, toast notifications, and live content changes. ## Parameters - `politeness`: Sets the default urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) ## Properties ### `message` - **type**: `Ref<string>` - **description**: The current message to announce ### `politeness` - **type**: `Ref<'polite' | 'assertive' | 'off'>` - **description**: Screen reader announcement urgency level ## Methods ### `set(message, politeness = "polite")` Sets the message to announce with its urgency level. ### `polite(message)` Sets the message with `politeness = "polite"`. Use for non-urgent updates that can wait for the screen reader to finish its current task. ### `assertive(message)` Sets the message with `politeness = "assertive"`. Use for urgent updates that should interrupt the screen reader immediately. ## Example ```vue [app/pages/contact.vue] <script setup lang="ts"> const { polite, assertive } = useAnnouncer() async function submitForm () { try { await $fetch('/api/contact', { method: 'POST', body: formData }) polite('Message sent successfully') } catch (error) { assertive('Error: Failed to send message') } } </script> ``` ## Use Cases ### Form Validation ```vue [app/components/LoginForm.vue] <script setup lang="ts"> const { assertive } = useAnnouncer() function validateForm () { const errors = [] if (!email.value) { errors.push('Email is required') } if (!password.value) { errors.push('Password is required') } if (errors.length) { assertive(`Form has ${errors.length} errors: ${errors.join(', ')}`) return false } return true } </script> ``` ### Loading States ```vue [app/pages/dashboard.vue] <script setup lang="ts"> const { polite } = useAnnouncer() const { data, status } = await useFetch('/api/data') watch(status, (newStatus) => { if (newStatus === 'pending') { polite('Loading data...') } else if (newStatus === 'success') { polite('Data loaded successfully') } }) </script> ``` ### Search Results ```vue [app/components/Search.vue] <script setup lang="ts"> const { polite } = useAnnouncer() const results = ref([]) watch(results, (newResults) => { polite(`Found ${newResults.length} results`) }) </script> ``` <callout> You need to add the [`<NuxtAnnouncer>`](https://nuxt.com/docs/5.x/api/components/nuxt-announcer) component to your app for the announcements to be rendered in the DOM. </callout> <callout> For automatic announcements of route/page changes, use [`useRouteAnnouncer`](https://nuxt.com/docs/5.x/api/composables/use-route-announcer) with the [`<NuxtRouteAnnouncer>`](https://nuxt.com/docs/5.x/api/components/nuxt-route-announcer) component instead. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/announcer.ts) # useAppConfig > Access the reactive app config defined in the project. ## Usage ```ts const appConfig = useAppConfig() console.log(appConfig) ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/app-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/config.ts) # useAsyncData > useAsyncData provides access to data that resolves asynchronously in an SSR-friendly composable. Within your pages, components, and plugins you can use useAsyncData to get access to data that resolves asynchronously. <note> [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) is a composable meant to be called directly in the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context). It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client **without re-fetching the data on client side** when the page hydrates. </note> ## Usage ```vue [app/pages/index.vue] <script setup lang="ts"> const { data, status, pending, error, refresh, clear } = await useAsyncData( 'mountains', (_nuxtApp, { signal }) => $fetch('https://api.nuxtjs.dev/mountains', { signal }), ) </script> ``` <tip to="https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch"> Need a custom `useAsyncData` with pre-defined defaults? Use `createUseAsyncData` to create a fully typed custom composable. See the [custom useFetch recipe](https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch) for details. </tip> <note> You do not need to `await` `useAsyncData`. On the server, Nuxt waits for the promise to resolve before rendering in either case, so the returned HTML always contains the data. The `await` affects what happens after the call: with it, execution pauses until `data` is populated, and client-side navigation is blocked until the data is ready; without it, execution continues immediately, `data` starts as its default value until the request resolves, and on client-side navigation you handle the loading and error states yourself using the returned `status` and `error` refs. This has a similar effect to the [`lazy`](#parameters) option, though `lazy` is the explicit way to opt into non-blocking navigation. </note> <note> `data`, `status`, `pending`, and `error` are Vue refs. Access their values with `.value` in `<script setup>`. `refresh`/`execute` and `clear` are plain functions. </note> ### Watch Parameters The built-in `watch` option allows automatically rerunning the fetcher function when any changes are detected. ```vue [app/pages/index.vue] <script setup lang="ts"> const page = ref(1) const { data: posts } = await useAsyncData( 'posts', (_nuxtApp, { signal }) => $fetch('https://fakeApi.com/posts', { params: { page: page.value, }, signal, }), { watch: [page], }, ) </script> ``` ### Reactive Keys You can use a computed ref, plain ref or a getter function as the key, allowing for dynamic data fetching that automatically updates when the key changes: ```vue [app/pages/[id].vue] <script setup lang="ts"> const route = useRoute() const userId = computed(() => `user-${route.params.id}`) // When the route changes and userId updates, the data will be automatically refetched const { data: user } = useAsyncData( userId, () => fetchUserById(route.params.id), ) </script> ``` ### Make Your `handler` Abortable You can make your `handler` function abortable by using the `signal` provided in the second argument. This is useful for cancelling requests when they are no longer needed, such as when a user navigates away from a page. `$fetch` natively supports abort signals. ```ts [app/pages/index.vue] const { data, error } = await useAsyncData( 'users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), ) refresh() // will actually cancel the $fetch request (if dedupe: cancel) refresh() // will actually cancel the $fetch request (if dedupe: cancel) refresh() clear() // will cancel the latest pending handler ``` You can also pass an `AbortSignal` to the `refresh`/`execute` function to cancel individual requests manually. ```ts [app/pages/index.vue] const { refresh } = await useAsyncData( 'users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), ) let abortController: AbortController | undefined function handleUserAction () { abortController = new AbortController() refresh({ signal: abortController.signal }) } function handleCancel () { abortController?.abort() // aborts the ongoing refresh request } ``` If your `handler` function does not support abort signals, you can implement your own abort logic using the `signal` provided. ```ts [app/pages/index.vue] const { data, error } = await useAsyncData( 'users', (_nuxtApp, { signal }) => { return new Promise((resolve, reject) => { signal?.addEventListener('abort', () => { reject(new Error('Request aborted')) }) return Promise.resolve(callback.call(this, yourHandler)).then(resolve, reject) }) }, ) ``` The handler signal will be aborted when: - A new request is made with `dedupe: 'cancel'` - The `clear` function is called - The `options.timeout` duration is exceeded <warning> [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) is a reserved function name transformed by the compiler, so you should not name your own function [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data). </warning> <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching#useasyncdata"> </read-more> ## Type ```ts [Signature] export type AsyncDataHandler<ResT> = (nuxtApp: NuxtApp, options: { signal: AbortSignal }) => Promise<ResT> export function useAsyncData<ResT, DataE = unknown, DataT = ResT> ( handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> export function useAsyncData<ResT, DataE = unknown, DataT = ResT> ( key: MaybeRefOrGetter<string>, handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> type AsyncDataOptions<ResT, DataT = ResT> = { server?: boolean lazy?: boolean immediate?: boolean deep?: boolean dedupe?: 'cancel' | 'defer' default?: () => DataT | Ref<DataT> transform?: (input: ResT) => DataT | Promise<DataT> pick?: string[] watch?: MultiWatchSources getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined timeout?: number enabled?: MaybeRefOrGetter<boolean> serialize?: boolean } type AsyncDataRequestContext = { /** The reason for this data request */ cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch' } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | undefined> refresh: (opts?: AsyncDataExecuteOptions) => Promise<void> execute: (opts?: AsyncDataExecuteOptions) => Promise<void> clear: () => void error: Ref<ErrorT | undefined> status: Ref<AsyncDataRequestStatus> pending: Ref<boolean> } interface AsyncDataExecuteOptions { dedupe?: 'cancel' | 'defer' timeout?: number signal?: AbortSignal } type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> ## Parameters - `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you. - `handler`: an asynchronous function that must return a truthy value (for example, it should not be `undefined` or `null`) or the request may be duplicated on the client side. <warning> The `handler` function should be **side-effect free** to ensure predictable behavior during SSR and CSR hydration. If you need to trigger side effects, use the [`callOnce`](https://nuxt.com/docs/5.x/api/utils/call-once) utility to do so. </warning> - `options` (object): Configuration for the asynchronous function call. All options can be a static value, a `ref`, or a computed value. <table> <thead> <tr> <th> Option </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to call the function on the server. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If true, resolves after route loads (does not block navigation). </td> </tr> <tr> <td> <code> immediate </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If false, prevents function from being called immediately. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => DataT </code> </td> <td> - </td> <td> Factory for default value of <code> data </code> before async resolves. </td> </tr> <tr> <td> <code> timeout </code> <badge className="align-middle" color="info" size="xs"> v4.2 </badge> </td> <td> <code> number </code> </td> <td> - </td> <td> A number in milliseconds to wait before timing out the call (defaults to <code> undefined </code> , which means no timeout) </td> </tr> <tr> <td> <code> transform </code> </td> <td> <code> (input: DataT) => DataT | Promise<DataT> </code> </td> <td> - </td> <td> Function to transform the result after resolving. </td> </tr> <tr> <td> <code> getCachedData </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> (key, nuxtApp, ctx) => DataT | undefined </code> </td> <td> - </td> <td> Function to return cached data. See below for default. </td> </tr> <tr> <td> <code> pick </code> </td> <td> <code> string[] </code> </td> <td> - </td> <td> Only pick specified keys from the result. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> MultiWatchSources </code> </td> <td> - </td> <td> Array of reactive sources to watch and auto-refresh. </td> </tr> <tr> <td> <code> deep </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Return data in a deep ref object. Defaults to <code> false </code> for improved performance (shallow ref object). </td> </tr> <tr> <td> <code> dedupe </code> <badge className="align-middle" color="info" size="xs"> v3.9 </badge> </td> <td> <code> 'cancel' | 'defer' </code> </td> <td> <code> 'cancel' </code> </td> <td> Policy when triggering an execution more than once at a time. </td> </tr> <tr> <td> <code> enabled </code> <badge className="align-middle" color="info" size="xs"> v4.5 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Barrier that gates whether the <code> handler </code> may run. While <code> false </code> , every execution is blocked (initial fetch, <code> execute </code> /<code> refresh </code> , and watch triggers), and switching <code> true </code> โ†’ <code> false </code> cancels any in-flight request without clearing <code> data </code> . Re-enabling does not refetch on its own. </td> </tr> <tr> <td> <code> serialize </code> <badge className="align-middle" color="info" size="xs"> v4.6 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to store resolved data in the Nuxt payload (<code> __NUXT_DATA__ </code> ). When <code> false </code> , server-fetched data is kept out of the payload and the client will refetch after hydration if a component renders it. Pair with <a href="https://nuxt.com/docs/5.x/guide/best-practices/performance#lazy-hydration"> lazy hydration </a> to avoid hydration mismatches and unnecessary client fetches. </td> </tr> </tbody> </table> <note> All options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated. </note> **getCachedData default:** ```ts [Default getCachedData Implementation] const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key] ``` This only caches data when `experimental.payloadExtraction` in `nuxt.config` is enabled. <note> Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience. </note> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-lazy-async-data"> You can use `useLazyAsyncData` to have the same behavior as `lazy: true` with `useAsyncData`. </read-more> <video-accordion title="Watch a video from Alexander Lichter about client-side caching with getCachedData" video-id="aQPR0xn-MMk"> </video-accordion> ### Shared State and Option Consistency When multiple `useAsyncData` calls use the same key, they share the same `data`, `error`, `status`, and `pending` refs. Keep the options listed below consistent across these calls. The following options **must be consistent** across all calls with the same key: - `handler` function - `deep` option - `transform` function - `pick` array - `getCachedData` function - `default` value The following options **can differ** without triggering warnings: - `server` - `lazy` - `immediate` - `dedupe` - `watch` - `enabled` - `serialize` ```ts [app/pages/index.vue] // โŒ This will trigger a development warning const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true }) // โœ… This is allowed const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false }) ``` <tip> Keyed state created using `useAsyncData` can be retrieved across your Nuxt application using [`useNuxtData`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-data). </tip> ## Return Values This composable returns a `Promise` that can be awaited, which makes it possible to use `data` directly within the `<script setup>` (i.e. a value will be present, instead of being undefined). You can also directly pull the values without awaiting the return value, in which case `data` can be undefined within `<script setup>` until the fetch completes. <tip> Even if you do not await the return value, during SSR Nuxt will wait for the request to finish and send the resolved data to the client. </tip> <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) on the client side, `data` will remain `undefined` within `<script setup>`. </note> <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous function that is passed in. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. By default, Nuxt waits until a <code> refresh </code> is finished before it can be executed again. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the asynchronous function threw an error. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the asynchronous function call. Use it to distinguish <code> idle </code> , <code> pending </code> , <code> success </code> , and <code> error </code> . </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> <code> true </code> while a request is in flight. With <a href="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#pendingwhenidle"> <code> experimental.pendingWhenIdle </code> </a> , it is also <code> true </code> when <code> status </code> is <code> idle </code> and no cached data is available. </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> (or the value of <code> options.default() </code> if provided), <code> error </code> to <code> undefined </code> , set <code> status </code> to <code> idle </code> , and cancels any pending calls. </td> </tr> </tbody> </table> <tip> Functions from the `Promise` (`then`, `catch`, and `finally`) can safely be destructured, if you did not await the return value. </tip> ### Status Values - `idle`: Function has not been called yet (e.g. `{ immediate: false }` or `{ server: false }` on server render) - `pending`: Function has been called and the promise is pending - `success`: Function returned a value - `error`: Function threw an error --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # useCookie > useCookie is an SSR-friendly composable to read and write cookies. ## Usage Within your pages, components, and plugins, you can use `useCookie` to read and write cookies in an SSR-friendly way. ```ts [Usage] const cookie = useCookie(name, options) ``` <note> `useCookie` only works in the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context). </note> <tip> The returned ref will automatically serialize and deserialize cookie values to JSON. </tip> ## Type ```ts [Signature] import type { Ref } from 'vue' import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es' export interface CookieOptions<T = any> extends Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'> { decode?(value: string): T encode?(value: T): string default?: () => T | Ref<T> watch?: boolean | 'shallow' readonly?: boolean refresh?: boolean } export interface CookieRef<T> extends Ref<T> {} export function useCookie<T = string | null | undefined> ( name: string, options?: CookieOptions<T>, ): CookieRef<T> ``` ## Parameters `name`: The name of the cookie. `options`: Options to control cookie behavior. The object can have the following properties: Most of the options will be directly passed to the [cookie](https://github.com/jshttp/cookie) package. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> decode </code> </td> <td> <code> (value: string) => T </code> </td> <td> <code> decodeURIComponent </code> + <a href="https://github.com/unjs/destr" rel="nofollow"> destr </a> . </td> <td> Custom function to decode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode a previously encoded cookie value into a JavaScript string or other object. <br /> <strong> Note: </strong> If an error is thrown from this function, the original, non-decoded cookie value will be returned as the cookie's value. </td> </tr> <tr> <td> <code> encode </code> </td> <td> <code> (value: T) => string </code> </td> <td> <code> JSON.stringify </code> + <code> encodeURIComponent </code> </td> <td> Custom function to encode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to encode a value into a string suited for a cookie's value. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => T | Ref<T> </code> </td> <td> <code> undefined </code> </td> <td> Function returning the default value if the cookie does not exist. The function can also return a <code> Ref </code> . </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> boolean | 'shallow' </code> </td> <td> <code> true </code> </td> <td> Whether to watch for changes and update the cookie. <code> true </code> for deep watch, <code> 'shallow' </code> for shallow watch, i.e. data changes for only top level properties, <code> false </code> to disable. <br /> <strong> Note: </strong> Refresh <code> useCookie </code> values manually when a cookie has changed with <a href="https://nuxt.com/docs/5.x/api/utils/refresh-cookie"> <code> refreshCookie </code> </a> . </td> </tr> <tr> <td> <code> refresh </code> <badge className="align-middle" color="info" size="xs"> v4.4 </badge> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the cookie expiration will be refreshed on every explicit write (e.g. <code> cookie.value = cookie.value </code> ), even if the value itself hasnโ€™t changed. Note: the expiration is not refreshed automatically โ€” you must assign to <code> .value </code> to trigger it. </td> </tr> <tr> <td> <code> readonly </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , disables writing to the cookie, on both server and client. A <code> default </code> value is still returned by the composable but is never persisted to the browser. </td> </tr> <tr> <td> <code> maxAge </code> </td> <td> <code> number </code> </td> <td> <code> undefined </code> </td> <td> Max age in seconds for the cookie, i.e. the value for the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.2" rel="nofollow"> <code> Max-Age </code> <code> Set-Cookie </code> attribute </a> . The given number will be converted to an integer by rounding down. By default, no maximum age is set. </td> </tr> <tr> <td> <code> expires </code> </td> <td> <code> Date | (() => Date | undefined) </code> </td> <td> <code> undefined </code> </td> <td> Expiration date for the cookie, or a getter that returns one. When a function is provided, it is evaluated on every cookie write, so the expiration can be refreshed when the value is re-set. Returning <code> undefined </code> creates a session cookie. The getter should be pure (no side effects). By default, no expiration is set. Most clients will consider this a "non-persistent cookie" and will delete it on a condition like exiting a web browser application. <br /> <strong> Note: </strong> The <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.3" rel="nofollow"> cookie storage model specification </a> states that if both <code> expires </code> and <code> maxAge </code> is set, then <code> maxAge </code> takes precedence, but not all clients may obey this, so if both are set, they should point to the same date and time! <br /> If neither of <code> expires </code> and <code> maxAge </code> is set, the cookie will be session-only and removed when the user closes their browser. </td> </tr> <tr> <td> <code> httpOnly </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the HttpOnly attribute. <br /> <strong> Note: </strong> Be careful when setting this to <code> true </code> , as compliant clients will not allow client-side JavaScript to see the cookie in <code> document.cookie </code> . </td> </tr> <tr> <td> <code> secure </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.5" rel="nofollow"> <code> Secure </code> <code> Set-Cookie </code> attribute </a> . <br /> <strong> Note: </strong> Be careful when setting this to <code> true </code> , as compliant clients will not send the cookie back to the server in the future if the browser does not have an HTTPS connection. This can lead to hydration errors. </td> </tr> <tr> <td> <code> partitioned </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1" rel="nofollow"> <code> Partitioned </code> <code> Set-Cookie </code> attribute </a> . <br /> <strong> Note: </strong> This is an attribute that has not yet been fully standardized, and may change in the future. <br /> This also means many clients may ignore this attribute until they understand it.<br /> More information can be found in the <a href="https://github.com/privacycg/CHIPS" rel="nofollow"> proposal </a> . </td> </tr> <tr> <td> <code> domain </code> </td> <td> <code> string </code> </td> <td> <code> undefined </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3" rel="nofollow"> <code> Domain </code> <code> Set-Cookie </code> attribute </a> . By default, no domain is set, and most clients will consider applying the cookie only to the current domain. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> '/' </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.4" rel="nofollow"> <code> Path </code> <code> Set-Cookie </code> attribute </a> . By default, the path is considered the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4" rel="nofollow"> "default path" </a> . </td> </tr> <tr> <td> <code> sameSite </code> </td> <td> <code> boolean | string </code> </td> <td> <code> undefined </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7" rel="nofollow"> <code> SameSite </code> <code> Set-Cookie </code> attribute </a> . <br /> - <code> true </code> will set the <code> SameSite </code> attribute to <code> Strict </code> for strict same-site enforcement.<br /> - <code> false </code> will not set the <code> SameSite </code> attribute.<br /> - <code> 'lax' </code> will set the <code> SameSite </code> attribute to <code> Lax </code> for lax same-site enforcement.<br /> - <code> 'none' </code> will set the <code> SameSite </code> attribute to <code> None </code> for an explicit cross-site cookie.<br /> - <code> 'strict' </code> will set the <code> SameSite </code> attribute to <code> Strict </code> for strict same-site enforcement. </td> </tr> </tbody> </table> ## Return Values Returns a Vue `Ref<T>` representing the cookie value. Updating the ref will update the cookie (unless `readonly` is set). The ref is SSR-friendly and will work on both client and server. ## Example ### Basic Usage The example below creates a cookie called `counter`. If the cookie doesn't exist, it is initially set to a random value. Whenever we update the `counter` variable, the cookie will be updated accordingly. ```vue [app/app.vue] <script setup lang="ts"> const counter = useCookie('counter') counter.value ||= Math.round(Math.random() * 1000) </script> <template> <div> <h1>Counter: {{ counter || '-' }}</h1> <button @click="counter = null"> reset </button> <button @click="counter--"> - </button> <button @click="counter++"> + </button> </div> </template> ``` ### Readonly Cookies ```vue [app/app.vue] <script setup lang="ts"> const user = useCookie( 'userInfo', { default: () => ({ score: -1 }), watch: false, }, ) if (user.value) { // the actual `userInfo` cookie will not be updated user.value.score++ } </script> <template> <div>User score: {{ user?.score }}</div> </template> ``` ### Writable Cookies ```vue [app/app.vue] <script setup lang="ts"> const list = useCookie( 'list', { default: () => [], watch: 'shallow', }, ) function add () { list.value?.push(Math.round(Math.random() * 1000)) // list cookie won't be updated with this change } function save () { // the actual `list` cookie will be updated list.value &&= [...list.value] } </script> <template> <div> <h1>List</h1> <pre>{{ list }}</pre> <button @click="add"> Add </button> <button @click="save"> Save </button> </div> </template> ``` ### Refreshing Cookies ```vue [app/app.vue] <script setup lang="ts"> const session = useCookie( 'session', { maxAge: 60 * 60, // 1 hour refresh: true, default: () => 'active', }) // Even if the value does not change, // the cookie expiration will be refreshed // every time the setter is called session.value = 'active' </script> <template> <div>Session: {{ session }}</div> </template> ``` ### Dynamic Expiration with a Getter Use a function for `expires` when you want a fresh expiration date every time the cookie is written (for example, sliding sessions or tokens): ```vue [app/app.vue] <script setup lang="ts"> const token = useCookie('token', { // Re-evaluated on every write โ€” keep this getter pure expires: () => new Date(Date.now() + 60 * 60 * 1000), // 1 hour from now }) // Assigning a new value also refreshes the cookie expiration token.value = 'new-token' </script> ``` ### Cookies in API Routes You can use `getCookie` and `setCookie` from [`h3`](https://github.com/h3js/h3) package to set cookies in server API routes. ```ts [server/api/counter.ts] export default defineEventHandler((event) => { // Read counter cookie let counter = getCookie(event, 'counter') || 0 // Increase counter cookie by 1 setCookie(event, 'counter', ++counter) // Send JSON response return { counter } }) ``` <link-example to="https://nuxt.com/docs/5.x/examples/advanced/use-cookie"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts) # useError > useError composable returns the global Nuxt error that is being handled. ## Usage The `useError` composable returns the global Nuxt error that is being handled and is available on both client and server. It provides a reactive, SSR-friendly error state across your app. ```ts const error = useError() ``` You can use this composable in your components, pages, or plugins to access or react to the current Nuxt error. ## Type ```ts interface NuxtError<DataT = unknown> { status: number statusText?: string message: string data?: DataT cause?: unknown fatal: boolean } export const useError: () => Ref<NuxtError | undefined> ``` ## Parameters This composable does not take any parameters. ## Return Values Returns a `Ref` containing the current Nuxt error (or `undefined` if there is no error). The error object is reactive and will update automatically when the error state changes. ## Example ```vue <script setup lang="ts"> const error = useError() if (error.value) { console.error('Nuxt error:', error.value) } </script> ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # useFetch > Fetch data from an API endpoint with an SSR-friendly composable. This composable provides a convenient wrapper around [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and [`$fetch`](https://nuxt.com/docs/5.x/api/utils/dollarfetch). It automatically generates a key for the request, provides type hints for request url based on server routes, and infers API response type. <note> `useFetch` is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates. </note> ## Usage ```vue [app/pages/modules.vue] <script setup lang="ts"> const { data, status, error, refresh, clear } = await useFetch('/api/modules', { pick: ['title'], }) </script> ``` <tip to="https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch"> Need a custom `useFetch` with pre-defined defaults (like `baseURL` or auth headers)? Use `createUseFetch` to create a fully typed custom composable. </tip> <note> You do not need to `await` `useFetch`. On the server, Nuxt waits for the promise to resolve before rendering in either case, so the returned HTML always contains the data. The `await` affects what happens after the call: with it, execution pauses until `data` is populated, and client-side navigation is blocked until the data is ready; without it, execution continues immediately, `data` starts as its default value until the request resolves, and on client-side navigation you handle the loading and error states yourself using the returned `status` and `error` refs. This has a similar effect to the [`lazy`](#parameters) option, though `lazy` is the explicit way to opt into non-blocking navigation. </note> <note> `data`, `status`, and `error` are Vue refs, and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions. </note> <note> The request URL, the response, and any `body`, `query` or `headers` the matching handler validates are typed from the routes your server serves. A path built at runtime resolves to `unknown`, and naming the response type (`useFetch<Todo[]>(url)`) overrides whatever Nuxt resolved. Read more about [typed routes](https://nuxt.com/docs/5.x/getting-started/data-fetching#typed-routes). </note> Using the `query` option, you can add search parameters to your query. This option is extended from [unjs/ofetch](https://github.com/unjs/ofetch) and is using [unjs/ufo](https://github.com/unjs/ufo) to create the URL. Objects are automatically stringified. ```ts [app/pages/index.vue] const param1 = ref('value1') const { data, status, error, refresh } = await useFetch('/api/modules', { query: { param1, param2: 'value2' }, }) ``` The above example results in `https://api.nuxt.com/modules?param1=value1¶m2=value2`. You can also use [interceptors](https://github.com/unjs/ofetch#%EF%B8%8F-interceptors): ```ts [app/pages/index.vue] const { data, status, error, refresh, clear } = await useFetch('/api/auth/login', { onRequest ({ request, options }) { // Set the request headers // note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile options.headers.set('Authorization', '...') }, onRequestError ({ request, options, error }) { // Handle the request errors }, onResponse ({ request, response, options }) { // Process the response data localStorage.setItem('token', response._data.token) }, onResponseError ({ request, response, options }) { // Handle the response errors }, }) ``` ### Reactive Keys and Shared State You can use a computed ref or a plain ref as the URL, allowing for dynamic data fetching that automatically updates when the URL changes: ```vue [app/pages/[id].vue] <script setup lang="ts"> const route = useRoute() const id = computed(() => route.params.id) // When the route changes and id updates, the data will be automatically refetched const { data: post } = await useFetch(() => `/api/posts/${id.value}`) </script> ``` The auto-generated key is unique to each call site, so calling `useFetch` with the same URL and options in different components will **not** share state and each call performs its own request. Multiple instances of the same component do share state, since they use the same call site. To share the same `data`, `error` and `status` refs across different components, provide the same explicit `key` to each call: <code-group> ```vue [app/components/ComponentA.vue] <script setup lang="ts"> // shares the data with ComponentB - only one request is made const { data } = await useFetch('/api/random', { key: 'random' }) </script> ``` ```vue [app/components/ComponentB.vue] <script setup lang="ts"> // shares the data with ComponentA - only one request is made const { data } = await useFetch('/api/random', { key: 'random' }) </script> ``` </code-group> <tip> Keyed state created using `useFetch` can be retrieved across your Nuxt application using [`useNuxtData`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-data). </tip> <warning> `useFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`. To create a custom variant with pre-defined options, use [`createUseFetch`](https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch) instead. </warning> <warning> If you encounter the `data` variable destructured from a `useFetch` returns a string and not a JSON parsed object then make sure your component doesn't include an import statement like `import { useFetch } from '@vueuse/core`. </warning> <video-accordion title="Watch the video from Alexander Lichter to avoid using useFetch the wrong way" video-id="njsGVmcWviY"> </video-accordion> <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> ### Reactive Fetch Options Fetch options can be provided as reactive, supporting `computed`, `ref` and [computed getters](https://vuejs.org/guide/essentials/computed). When a reactive fetch option is updated it will trigger a refetch using the updated resolved reactive value. ```ts [app/pages/index.vue] const searchQuery = ref('initial') const { data } = await useFetch('/api/search', { query: { q: searchQuery }, }) // triggers a refetch: /api/search?q=new%20search searchQuery.value = 'new search' ``` If needed, you can opt out of this behavior using `watch: false`: ```ts [app/pages/index.vue] const searchQuery = ref('initial') const { data } = await useFetch('/api/search', { query: { q: searchQuery }, watch: false, }) // does not trigger a refetch searchQuery.value = 'new search' ``` ## Type ```ts [Signature] export function useFetch<ResT, ErrorT = NuxtError<unknown>, DataT = ResT> ( url: string | Request | Ref<string | Request> | (() => string | Request), options?: UseFetchOptions<ResT, DataT>, ): AsyncData<DataT, ErrorT> & Promise<AsyncData<DataT, ErrorT>> type UseFetchOptions<ResT, DataT = ResT> = { key?: MaybeRefOrGetter<string> method?: MaybeRefOrGetter<string> query?: MaybeRefOrGetter<SearchParams> body?: MaybeRefOrGetter<RequestInit['body'] | Record<string, any>> headers?: MaybeRefOrGetter<Record<string, string> | [key: string, value: string][] | Headers> baseURL?: MaybeRefOrGetter<string> cache?: false | 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload' server?: boolean lazy?: boolean immediate?: boolean getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined deep?: boolean dedupe?: 'cancel' | 'defer' timeout?: number enabled?: MaybeRefOrGetter<boolean> serialize?: boolean default?: () => DataT | Ref<DataT> transform?: (input: ResT) => DataT | Promise<DataT> pick?: string[] $fetch?: typeof globalThis.$fetch watch?: MultiWatchSources | false } type AsyncDataRequestContext = { /** The reason for this data request */ cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch' } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | undefined> pending: Ref<boolean> refresh: (opts?: AsyncDataExecuteOptions) => Promise<void> execute: (opts?: AsyncDataExecuteOptions) => Promise<void> clear: () => void error: Ref<ErrorT | undefined> status: Ref<AsyncDataRequestStatus> } interface AsyncDataExecuteOptions { dedupe?: 'cancel' | 'defer' timeout?: number signal?: AbortSignal } type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' ``` ## Parameters - `URL` (`string | Request | Ref<string | Request> | () => string | Request`): The URL or request to fetch. Can be a string, a Request object, a Vue ref, or a function returning a string/Request. Supports reactivity for dynamic endpoints. - `options` (object): Configuration for the fetch request. Extends [unjs/ofetch](https://github.com/unjs/ofetch) options and [`AsyncDataOptions`](https://nuxt.com/docs/5.x/api/composables/use-async-data#parameters). All options can be a static value, a `ref`, or a computed value. <table> <thead> <tr> <th> Option </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> key </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> auto-gen </td> <td> Unique key for de-duplication. If not provided, generated from the URL, options and call site location in the source code. </td> </tr> <tr> <td> <code> method </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> <code> 'GET' </code> </td> <td> HTTP request method. </td> </tr> <tr> <td> <code> query </code> </td> <td> <code> MaybeRefOrGetter<SearchParams> </code> </td> <td> - </td> <td> Query/search params to append to the URL. </td> </tr> <tr> <td> <code> body </code> </td> <td> <code> MaybeRefOrGetter<RequestInit['body'] | Record<string, any>> </code> </td> <td> - </td> <td> Request body. Objects are automatically stringified. </td> </tr> <tr> <td> <code> headers </code> </td> <td> <code> MaybeRefOrGetter<Record<string, string> | [key, value][] | Headers> </code> </td> <td> - </td> <td> Request headers. </td> </tr> <tr> <td> <code> baseURL </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> - </td> <td> Base URL for the request. </td> </tr> <tr> <td> <code> cache </code> </td> <td> <code> false | string </code> </td> <td> - </td> <td> Cache control. Boolean disables cache, or use Fetch API values: <code> default </code> , <code> no-store </code> , etc. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to fetch on the server. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If true, resolves after route loads (does not block navigation). </td> </tr> <tr> <td> <code> immediate </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If false, prevents request from firing immediately. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => DataT </code> </td> <td> - </td> <td> Factory for default value of <code> data </code> before async resolves. </td> </tr> <tr> <td> <code> timeout </code> <badge className="align-middle" color="info" size="xs"> v4.2 </badge> </td> <td> <code> number </code> </td> <td> - </td> <td> A number in milliseconds to wait before timing out the request (defaults to <code> undefined </code> , which means no timeout) </td> </tr> <tr> <td> <code> transform </code> </td> <td> <code> (input: DataT) => DataT | Promise<DataT> </code> </td> <td> - </td> <td> Function to transform the result after resolving. </td> </tr> <tr> <td> <code> getCachedData </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> (key, nuxtApp, ctx) => DataT | undefined </code> </td> <td> - </td> <td> Function to return cached data. See below for default. </td> </tr> <tr> <td> <code> pick </code> </td> <td> <code> string[] </code> </td> <td> - </td> <td> Only pick specified keys from the result. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> MultiWatchSources | false </code> </td> <td> - </td> <td> Array of reactive sources to watch and auto-refresh. <code> false </code> disables watching. </td> </tr> <tr> <td> <code> deep </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Return data in a deep ref object. Defaults to <code> false </code> for improved performance (shallow ref object). </td> </tr> <tr> <td> <code> dedupe </code> <badge className="align-middle" color="info" size="xs"> v3.9 </badge> </td> <td> <code> 'cancel' | 'defer' </code> </td> <td> <code> 'cancel' </code> </td> <td> Avoid fetching same key more than once at a time. </td> </tr> <tr> <td> <code> enabled </code> <badge className="align-middle" color="info" size="xs"> v4.5 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Barrier that gates whether the request may run. While <code> false </code> , every execution is blocked (initial fetch, <code> execute </code> /<code> refresh </code> , and watch triggers), and switching <code> true </code> โ†’ <code> false </code> cancels any in-flight request without clearing <code> data </code> . Re-enabling does not refetch on its own. </td> </tr> <tr> <td> <code> serialize </code> <badge className="align-middle" color="info" size="xs"> v4.6 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to store resolved data in the Nuxt payload (<code> __NUXT_DATA__ </code> ). When <code> false </code> , server-fetched data is kept out of the payload and the client will refetch after hydration if a component renders it. Pair with <a href="https://nuxt.com/docs/5.x/guide/best-practices/performance#lazy-hydration"> lazy hydration </a> to avoid hydration mismatches and unnecessary client fetches. </td> </tr> <tr> <td> <code> $fetch </code> <badge className="align-middle" color="info" size="xs"> v3.2 </badge> </td> <td> <code> typeof globalThis.$fetch </code> </td> <td> - </td> <td> Custom $fetch implementation. See <a href="https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch"> Custom useFetch in Nuxt </a> </td> </tr> </tbody> </table> <note> All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated (unless `watch` is set to `false`). </note> **getCachedData default:** ```ts [Default getCachedData Implementation] const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key] ``` This only caches data when `experimental.payloadExtraction` in `nuxt.config` is enabled. ## Return Values This composable returns a `Promise` that can be awaited, which makes it possible to use `data` directly within the `<script setup>` (i.e. a value will be present, instead of being undefined). You can also directly pull the values without awaiting the return value, in which case `data` can be undefined within `<script setup>` until the fetch completes. <tip> Even if you do not await the return value, during SSR Nuxt will wait for the request to finish and send the resolved data to the client. </tip> <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain undefined within `<script setup>`. </note> <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous fetch. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. By default, Nuxt waits until a <code> refresh </code> is finished before it can be executed again. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the data fetching failed. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the data request. Use it to distinguish <code> idle </code> , <code> pending </code> , <code> success </code> , and <code> error </code> . </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> <code> true </code> while a request is in flight. With <a href="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#pendingwhenidle"> <code> experimental.pendingWhenIdle </code> </a> , it is also <code> true </code> when <code> status </code> is <code> idle </code> and no cached data is available. </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> (or the value of <code> options.default() </code> if provided), <code> error </code> to <code> undefined </code> , set <code> status </code> to <code> idle </code> , and cancels any pending requests. </td> </tr> </tbody> </table> <tip> Functions from the `Promise` (`then`, `catch`, and `finally`) can safely be destructured, if you did not await the return value. </tip> ### Status Values - `idle`: Request has not started (e.g. `{ immediate: false }` or `{ server: false }` on server render) - `pending`: Request is in progress - `success`: Request completed successfully - `error`: Request failed ### Example <link-example to="https://nuxt.com/docs/5.x/examples/advanced/use-custom-fetch-composable"> </link-example> <link-example to="https://nuxt.com/docs/5.x/examples/features/data-fetching"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # useHead > useHead customizes the head properties of individual pages of your Nuxt app. ## Usage The `useHead` composable allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.unjs.io). It lets you customize the meta tags, links, scripts, and other elements in the `<head>` section of your HTML document. ```vue [app/app.vue] <script setup lang="ts"> useHead({ title: 'My App', meta: [ { name: 'description', content: 'My amazing site.' }, ], bodyAttrs: { class: 'test', }, script: [{ innerHTML: 'console.log(\'Hello world\')' }], }) </script> ``` <warning> If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](https://nuxt.com/docs/5.x/api/composables/use-head-safe). </warning> <note> The properties of `useHead` can be dynamic, accepting `ref`, `computed` and `reactive` properties. The `meta` parameter can also accept a function returning an object to make the entire object reactive. </note> ## Type ```ts [Signature] export function useHead (meta: MaybeComputedRef<MetaObject>): ActiveHeadEntry<UseHeadInput> interface MetaObject { title?: string titleTemplate?: string | ((title?: string) => string) base?: Base link?: Link[] meta?: Meta[] style?: Style[] script?: Script[] noscript?: Noscript[] htmlAttrs?: HtmlAttributes bodyAttrs?: BodyAttributes } interface ActiveHeadEntry<Input> { /** * Updates the entry with new input. * * Will first clear any side effects for previous input. */ patch: (input: Input) => void /** * Dispose the entry, removing it from the active head. * * Will queue side effects for removal. */ dispose: () => void } ``` See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types. ## Parameters `meta`: An object accepting head metadata properties to customize the page's `<head>` section. All properties support reactive values (`ref`, `computed`, `reactive`) or can be a function returning the metadata object. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> title </code> </td> <td> <code> string </code> </td> <td> Sets the page title. </td> </tr> <tr> <td> <code> titleTemplate </code> </td> <td> <code> string | ((title?: string) => string) </code> </td> <td> Configures a dynamic template to customize the page title. Can be a string with <code> %s </code> placeholder or a function. </td> </tr> <tr> <td> <code> base </code> </td> <td> <code> Base </code> </td> <td> Sets the <code> <base> </code> tag for the document. </td> </tr> <tr> <td> <code> link </code> </td> <td> <code> Link[] </code> </td> <td> Array of link objects. Each element is mapped to a <code> <link> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Meta[] </code> </td> <td> Array of meta objects. Each element is mapped to a <code> <meta> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> style </code> </td> <td> <code> Style[] </code> </td> <td> Array of style objects. Each element is mapped to a <code> <style> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> script </code> </td> <td> <code> Script[] </code> </td> <td> Array of script objects. Each element is mapped to a <code> <script> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> noscript </code> </td> <td> <code> Noscript[] </code> </td> <td> Array of noscript objects. Each element is mapped to a <code> <noscript> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> htmlAttrs </code> </td> <td> <code> HtmlAttributes </code> </td> <td> Sets attributes of the <code> <html> </code> tag. Each object property is mapped to the corresponding attribute. </td> </tr> <tr> <td> <code> bodyAttrs </code> </td> <td> <code> BodyAttributes </code> </td> <td> Sets attributes of the <code> <body> </code> tag. Each object property is mapped to the corresponding attribute. </td> </tr> </tbody> </table> ## Return Values This composable does not return any value. It registers the head metadata with Unhead, which manages the actual DOM updates. ## Example ### Basic Meta Tags ```vue [app/pages/about.vue] <script setup lang="ts"> useHead({ title: 'About Us', meta: [ { name: 'description', content: 'Learn more about our company' }, { property: 'og:title', content: 'About Us' }, { property: 'og:description', content: 'Learn more about our company' }, ], }) </script> ``` ### Reactive Meta Tags ```vue [app/pages/profile.vue] <script setup lang="ts"> const profile = ref({ name: 'John Doe' }) useHead({ title: computed(() => profile.value.name), meta: [ { name: 'description', content: computed(() => `Profile page for ${profile.value.name}`), }, ], }) </script> ``` ### Using a Function for Full Reactivity ```vue [app/pages/dynamic.vue] <script setup lang="ts"> const count = ref(0) useHead(() => ({ title: `Count: ${count.value}`, meta: [ { name: 'description', content: `Current count is ${count.value}` }, ], })) </script> ``` ### Adding External Scripts and Styles ```vue [app/pages/external.vue] <script setup lang="ts"> useHead({ link: [ { rel: 'stylesheet', href: 'https://cdn.example.com/styles.css', }, ], script: [ { src: 'https://cdn.example.com/script.js', async: true, }, ], }) </script> ``` ### Body and HTML Attributes ```vue [app/pages/themed.vue] <script setup lang="ts"> const isDark = ref(true) useHead({ htmlAttrs: { lang: 'en', class: computed(() => isDark.value ? 'dark' : 'light'), }, bodyAttrs: { class: 'themed-page', }, }) </script> ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useHeadSafe > The recommended way to provide head data with user input. ## Usage The `useHeadSafe` composable is a wrapper around the [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable that restricts the input to only allow safe values. This is the recommended way to manage head data when working with user input, as it prevents XSS attacks by sanitizing potentially dangerous attributes. <warning> When using `useHeadSafe`, potentially dangerous attributes like `innerHTML` in scripts or `http-equiv` in meta tags are automatically stripped out to prevent XSS attacks. Use this composable whenever you're working with user-generated content. </warning> ## Type ```ts [Signature] export function useHeadSafe (input: MaybeComputedRef<HeadSafe>): void ``` ### Allowed Attributes The following attributes are whitelisted for each head element type: ```ts const WhitelistAttributes = { htmlAttrs: ['class', 'style', 'lang', 'dir'], bodyAttrs: ['class', 'style'], meta: ['name', 'property', 'charset', 'content', 'media'], noscript: ['textContent'], style: ['media', 'textContent', 'nonce', 'title', 'blocking'], script: ['type', 'textContent', 'nonce', 'blocking'], link: ['color', 'crossorigin', 'fetchpriority', 'href', 'hreflang', 'imagesrcset', 'imagesizes', 'integrity', 'media', 'referrerpolicy', 'rel', 'sizes', 'type'], } ``` See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/safeSchema.ts) for more detailed types. ## Parameters `input`: A `MaybeComputedRef<HeadSafe>` object containing head data. You can pass all the same values as [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head), but only safe attributes will be rendered. ## Return Values This composable does not return any value. ## Example ```vue [app/pages/user-profile.vue] <script setup lang="ts"> // User-generated content that might contain malicious code const userBio = ref('<script>alert("xss")<' + '/script>') useHeadSafe({ title: `User Profile`, meta: [ { name: 'description', content: userBio.value, // Safely sanitized }, ], }) </script> ``` <read-more target="_blank" to="https://unhead.unjs.io/docs/typescript/head/api/composables/use-head-safe"> Read more on the `Unhead` documentation. </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useHydration > Allows full control of the hydration cycle to set and receive data from the server. `useHydration` is a built-in composable that provides a way to set data on the server side every time a new HTTP request is made and receive that data on the client side. This way `useHydration` allows you to take full control of the hydration cycle. <note> This is an advanced composable, primarily designed for use within plugins, mostly used by Nuxt modules. </note> <note> `useHydration` is designed to **ensure state synchronization and restoration during SSR**. If you need to create a globally reactive state that is SSR-friendly in Nuxt, [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) is the recommended choice. </note> ## Usage The data returned from the `get` function on the server is stored in `nuxtApp.payload` under the unique key provided as the first parameter to `useHydration`. During hydration, this data is then retrieved on the client, preventing redundant computations or API calls. <code-group> ```ts [With useHydration] export default defineNuxtPlugin((nuxtApp) => { const myStore = new MyStore() useHydration( 'myStoreState', () => myStore.getState(), data => myStore.setState(data), ) }) ``` ```ts [Without useHydration] export default defineNuxtPlugin((nuxtApp) => { const myStore = new MyStore() if (import.meta.server) { nuxt.hooks.hook('app:rendered', () => { nuxtApp.payload.myStoreState = myStore.getState() }) } if (import.meta.client) { nuxt.hooks.hook('app:created', () => { myStore.setState(nuxtApp.payload.myStoreState) }) } }) ``` </code-group> ## Type ```ts [Signature] export function useHydration<T> (key: string, get: () => T, set: (value: T) => void): void ``` ## Parameters <table> <thead> <tr> <th> Parameter </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> key </code> </td> <td> <code> string </code> </td> <td> A unique key that identifies the data in your Nuxt application. </td> </tr> <tr> <td> <code> get </code> </td> <td> <code> () => T </code> </td> <td> A function executed <strong> only on the server </strong> (called when SSR rendering is done) to set the initial value. </td> </tr> <tr> <td> <code> set </code> </td> <td> <code> (value: T) => void </code> </td> <td> A function executed <strong> only on the client </strong> (called when initial Vue instance is created) to receive the data. </td> </tr> </tbody> </table> ## Return Values This composable does not return any value. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/hydrate.ts) # useLayout > useLayout returns the layout resolved for the current route. ## Description `useLayout` returns a computed ref with the layout resolved for the current route, using the same chain as [`<NuxtLayout>`](https://nuxt.com/docs/5.x/api/components/nuxt-layout): the page's `layout` meta first, then the `appLayout` set via [route rules](https://nuxt.com/docs/5.x/guide/concepts/rendering#hybrid-rendering), then `'default'`. Within a rendered `<NuxtLayout>` it reflects the enclosing layout; outside of one (for example in `app.vue`) it returns the layout that would be resolved for the current route. Unlike reading `route.meta.layout` directly, this accounts for a layout set through route rules and stays in sync as the route changes. ## Return Values A read-only computed ref resolving to the layout name (a `string`), or `false` when the layout is disabled. ## Example ```vue [app.vue] <script setup lang="ts"> const layout = useLayout() </script> <template> <div> <CommandPalette v-if="layout !== 'minimal'" /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/layout.ts) # useLazyAsyncData > This wrapper around useAsyncData triggers navigation immediately. `useLazyAsyncData` provides a wrapper around [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. <note> By default, [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) blocks navigation until its async handler is resolved. `useLazyAsyncData` allows navigation to occur immediately while data fetching continues in the background. </note> ## Usage ```vue [app/pages/index.vue] <script setup lang="ts"> const { status, data: posts } = await useLazyAsyncData('posts', () => $fetch('/api/posts')) </script> <template> <div> <div v-if="status === 'pending'"> Loading... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> {{ posts }} </div> </div> </template> ``` `useLazyAsyncData` lets navigation continue while it fetches data. Check `status === 'pending'` and `status === 'error'` in your component's template before using the result. <warning> `useLazyAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyAsyncData`. </warning> ## Type ```ts [Signature] export function useLazyAsyncData<ResT, DataE = unknown, DataT = ResT> ( handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> export function useLazyAsyncData<ResT, DataE = unknown, DataT = ResT> ( key: MaybeRefOrGetter<string>, handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> ``` `useLazyAsyncData` has the same signature as [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data). ## Parameters `useLazyAsyncData` accepts the same parameters as [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data), with the `lazy` option automatically set to `true`. <read-more to="https://nuxt.com/docs/5.x/api/composables/use-async-data#parameters"> </read-more> ## Return Values `useLazyAsyncData` returns the same values as [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data). <read-more to="https://nuxt.com/docs/5.x/api/composables/use-async-data#return-values"> </read-more> ## Example ```vue [app/pages/index.vue] <script setup lang="ts"> /* useLazyAsyncData lets navigation continue before the fetch completes. Handle loading and error states in the template. */ const { status, data: count } = await useLazyAsyncData('count', () => $fetch('/api/count')) watch(count, (newCount) => { // Because count might start out null, you won't have access // to its contents immediately, but you can watch it. }) </script> <template> <div v-if="status === 'pending'"> Loading </div> <div v-else-if="status === 'error'"> Error loading count </div> <div v-else> {{ count }} </div> </template> ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # useLazyFetch > This wrapper around useFetch triggers navigation immediately. `useLazyFetch` provides a wrapper around [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. ## Usage By default, [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) blocks navigation until its async handler is resolved. `useLazyFetch` allows navigation to proceed immediately, with data being fetched in the background. ```vue [app/pages/index.vue] <script setup lang="ts"> const { status, data: posts } = await useLazyFetch('/api/posts') </script> <template> <div v-if="status === 'pending'"> Loading ... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` <note> `useLazyFetch` has the same signature as [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch). </note> <warning> Awaiting `useLazyFetch` initializes the call but does not wait for the data. During client-side navigation, check `status === 'pending'` and `status === 'error'` in your component's template before using the result. </warning> <warning> `useLazyFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyFetch`. </warning> ## Type ```ts [Signature] export function useLazyFetch<ResT, ErrorT = NuxtError<unknown>, DataT = ResT> ( url: string | Request | Ref<string | Request> | (() => string | Request), options?: UseFetchOptions<ResT, DataT>, ): AsyncData<DataT, ErrorT> & Promise<AsyncData<DataT, ErrorT>> ``` <note> `useLazyFetch` is equivalent to `useFetch` with `lazy: true` option set. See [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) for full type definitions. </note> ## Parameters `useLazyFetch` accepts the same parameters as [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch): - `URL` (`string | Request | Ref<string | Request> | () => string | Request`): The URL or request to fetch. - `options` (object): Same as [`useFetch` options](https://nuxt.com/docs/5.x/api/composables/use-fetch#parameters), with `lazy` automatically set to `true`. <read-more to="https://nuxt.com/docs/5.x/api/composables/use-fetch#parameters"> </read-more> ## Return Values Returns the same `AsyncData` object as [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch): <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous fetch. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the data fetching failed. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the data request. Use it to distinguish <code> idle </code> , <code> pending </code> , <code> success </code> , and <code> error </code> . </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> <code> true </code> while a request is in flight. See <a href="https://nuxt.com/docs/5.x/api/composables/use-fetch#return-values"> <code> useFetch </code> </a> . </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> , <code> error </code> to <code> undefined </code> , sets <code> status </code> to <code> idle </code> , and cancels any pending requests. </td> </tr> </tbody> </table> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-fetch#return-values"> </read-more> ## Example ### Handling Loading State ```vue [app/pages/index.vue] <script setup lang="ts"> /* useLazyFetch lets navigation continue before the fetch completes. * Handle loading and error states in the template. */ const { status, data: posts } = await useLazyFetch('/api/posts') watch(posts, (newPosts) => { // Because posts might start out null, you won't have access // to its contents immediately, but you can watch it. }) </script> <template> <div v-if="status === 'pending'"> Loading ... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # useLoadingIndicator > This composable gives you access to the loading state of the app page. ## Description A composable which returns the loading state of the page. Used by [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/5.x/api/components/nuxt-loading-indicator) and controllable. It hooks into [`page:loading:start`](https://nuxt.com/docs/5.x/api/advanced/hooks#app-hooks-runtime) and [`page:loading:end`](https://nuxt.com/docs/5.x/api/advanced/hooks#app-hooks-runtime) to change its state. ## Parameters - `duration`: Duration of the loading bar, in milliseconds (default `2000`). - `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`). - `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100. ## Properties ### `isLoading` - **type**: `Readonly<ShallowRef<boolean>>` - **description**: The loading state ### `error` - **type**: `Readonly<ShallowRef<boolean>>` - **description**: The error state ### `progress` - **type**: `Readonly<ShallowRef<number>>` - **description**: The progress state. From `0` to `100`. ## Methods ### `start()` Set `isLoading` to true and start to increase the `progress` value. `start` accepts a `{ force: true }` option to skip the interval and show the loading state immediately. ### `set()` Set the `progress` value to a specific value. `set` accepts a `{ force: true }` option to skip the interval and show the loading state immediately. ### `finish()` Set the `progress` value to `100`, stop all timers and intervals then reset the loading state `500` ms later. `finish` accepts a `{ force: true }` option to skip the interval before the state is reset, and `{ error: true }` to change the loading bar color and set the error property to true. ### `clear()` Used by `finish()`. Clear all timers and intervals used by the composable. ## Example ```vue <script setup lang="ts"> const { progress, isLoading, start, finish, clear } = useLoadingIndicator({ duration: 2000, throttle: 200, // This is how progress is calculated by default estimatedProgress: (duration, elapsed) => (2 / Math.PI * 100) * Math.atan(elapsed / duration * 100 / 50), }) </script> ``` ```vue <script setup lang="ts"> const { start, set } = useLoadingIndicator() // same as set(0, { force: true }) // set the progress to 0, and show loading immediately start({ force: true }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/loading-indicator.ts) # useNuxtApp > Access the shared runtime context of the Nuxt Application. `useNuxtApp` is a built-in composable that provides a way to access shared runtime context of Nuxt, also known as the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context), which is available on both client and server side (but not within Nitro routes). It helps you access the Vue app instance, runtime hooks, runtime config variables and internal states, such as `ssrContext` and `payload`. ```vue [app/app.vue] <script setup lang="ts"> const nuxtApp = useNuxtApp() </script> ``` If runtime context is unavailable in your scope, `useNuxtApp` will throw an exception when called. You can use [`tryUseNuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#tryusenuxtapp) instead for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception. ## Methods ### `provide (name, value)` `nuxtApp` is a runtime context that you can extend using [Nuxt plugins](https://nuxt.com/docs/5.x/directory-structure/app/plugins). Use the `provide` function to create Nuxt plugins to make values and helper methods available in your Nuxt application across all composables and components. `provide` function accepts `name` and `value` parameters. ```ts [app/plugins/hello.ts] const nuxtApp = useNuxtApp() nuxtApp.provide('hello', name => `Hello ${name}!`) // Prints "Hello name!" console.log(nuxtApp.$hello('name')) ``` As you can see in the example above, `$hello` has become the new and custom part of `nuxtApp` context and it is available in all places where `nuxtApp` is accessible. ### `hook(name, cb)` Hooks available in `nuxtApp` allows you to customize the runtime aspects of your Nuxt application. You can use runtime hooks in Vue.js composables and [Nuxt plugins](https://nuxt.com/docs/5.x/directory-structure/app/plugins) to hook into the rendering lifecycle. `hook` function is useful for adding custom logic by hooking into the rendering lifecycle at a specific point. `hook` function is mostly used when creating Nuxt plugins. See [Runtime Hooks](https://nuxt.com/docs/5.x/api/advanced/hooks#app-hooks-runtime) for available runtime hooks called by Nuxt. ```ts [app/plugins/test.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:start', () => { /* your code goes here */ }) nuxtApp.hook('vue:error', (..._args) => { console.log('vue:error') // if (import.meta.client) { // console.log(..._args) // } }) }) ``` ### `callHook(name, ...args)` `callHook` returns a promise when called with any of the existing hooks. ```ts [app/plugins/my-plugin.ts] await nuxtApp.callHook('my-plugin:init') ``` ## Properties `useNuxtApp()` exposes the following properties that you can use to extend and customize your app and share state, data and variables. ### `vueApp` `vueApp` is the global Vue.js [application instance](https://vuejs.org/api/application#application-api) that you can access through `nuxtApp`. Some useful methods: - [`component()`](https://vuejs.org/api/application#app-component) - Registers a global component if passing both a name string and a component definition, or retrieves an already registered one if only the name is passed. - [`directive()`](https://vuejs.org/api/application#app-directive) - Registers a global custom directive if passing both a name string and a directive definition, or retrieves an already registered one if only the name is passed[(example)](https://nuxt.com/docs/5.x/directory-structure/app/plugins#vue-directives). - [`use()`](https://vuejs.org/api/application#app-use) - Installs a **Vue.js Plugin** [(example)](https://nuxt.com/docs/5.x/directory-structure/app/plugins#vue-plugins). <read-more to="https://vuejs.org/api/application.html#application-api" icon="i-simple-icons-vuedotjs"> </read-more> ### `ssrContext` `ssrContext` is generated during server-side rendering and it is only available on the server side. Nuxt exposes the following properties through `ssrContext`: - `url` (string) - Current request url. - `event` ([h3js/h3](https://github.com/h3js/h3) request event) - Access the request & response of the current route. - `payload` (object) - NuxtApp payload object. ### `payload` `payload` exposes data and state variables from server side to client side. The following keys will be available on the client after they have been passed from the server side: - `serverRendered` (boolean) - Indicates if response is server-side-rendered. - `data` (object) - When you fetch the data from an API endpoint using either [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) , resulting payload can be accessed from the `payload.data`. This data is cached and helps you prevent fetching the same data in case an identical request is made more than once.<code-group> ```vue [app/app.vue] <script setup lang="ts"> const { data } = await useAsyncData('count', (_nuxtApp, { signal }) => $fetch('/api/count', { signal })) </script> ``` ```ts [server/api/count.ts] export default defineEventHandler((event) => { return { count: 1 } }) ``` </code-group> <br /> After fetching the value of `count` using [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) in the example above, if you access `payload.data`, you will see `{ count: 1 }` recorded there.<br /> When accessing the same `payload.data` from [`ssrcontext`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#ssrcontext), you can access the same value on the server side as well. - `state` (object) - When you use [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) composable in Nuxt to set shared state, this state data is accessed through `payload.state.[name-of-your-state]`.```ts [app/plugins/my-plugin.ts] export const useColor = () => useState<string>('color', () => 'pink') export default defineNuxtPlugin((nuxtApp) => { if (import.meta.server) { const color = useColor() } }) ``` <br /> It is also possible to use more advanced types, such as `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError`. #### Custom Reducer/Reviver <badge className="align-middle" color="info" size="xs">v3.4</badge> Since [Nuxt v3.4](https://nuxt.com/blog/v3-4#payload-enhancements), it is possible to define your own reducer/reviver for types that are not supported by Nuxt. <video-accordion title="Watch a video from Alexander Lichter about serializing payloads, especially with regards to classes" video-id="8w6ffRBs8a4"> </video-accordion> In the example below, we define a reducer (or a serializer) and a reviver (or deserializer) for the [Luxon](https://moment.github.io/luxon/#/) DateTime class, using a payload plugin. ```ts [app/plugins/date-time-payload.ts] /** * This kind of plugin runs very early in the Nuxt lifecycle, before we revive the payload. * You will not have access to the router or other Nuxt-injected properties. * * Note that the "DateTime" string is the type identifier and must * be the same on both the reducer and the reviver. */ export default definePayloadPlugin((nuxtApp) => { definePayloadReducer('DateTime', (value) => { return value instanceof DateTime && value.toJSON() }) definePayloadReviver('DateTime', (value) => { return DateTime.fromISO(value) }) }) ``` ### `isHydrating` Use `nuxtApp.isHydrating` (boolean) to check if the Nuxt app is hydrating on the client side. ```ts [app/components/nuxt-error-boundary.ts] export default defineComponent({ setup (_props, { slots, emit }) { const nuxtApp = useNuxtApp() onErrorCaptured((err) => { if (import.meta.client && !nuxtApp.isHydrating) { // ... } }) }, }) ``` ### `runWithContext` <note> You are likely here because you got a "Nuxt instance unavailable" message. Please use this method sparingly, and report examples that are causing issues, so that it can ultimately be solved at the framework level. </note> The `runWithContext` method is meant to be used to call a function and give it an explicit Nuxt context. Typically, the Nuxt context is passed around implicitly and you do not need to worry about this. However, when working with complex `async`/`await` scenarios in middleware/plugins, you can run into instances where the current instance has been unset after an async call. ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware(async (to, from) => { const nuxtApp = useNuxtApp() let user try { user = await fetchUser() // the Vue/Nuxt compiler loses context here because of the try/catch block. } catch (e) { user = null } if (!user) { // apply the correct Nuxt context to our `navigateTo` call. return nuxtApp.runWithContext(() => navigateTo('/auth')) } }) ``` #### Usage ```ts [Usage] const result = nuxtApp.runWithContext(() => functionWithContext()) ``` - `functionWithContext`: Any function that requires the context of the current Nuxt application. This context will be correctly applied automatically. `runWithContext` will return whatever is returned by `functionWithContext`. #### A Deeper Explanation of Context Vue.js Composition API (and Nuxt composables similarly) work by depending on an implicit context. During the lifecycle, Vue sets the temporary instance of the current component (and Nuxt temporary instance of nuxtApp) to a global variable and unsets it in same tick. When rendering on the server side, there are multiple requests from different users and nuxtApp running in a same global context. Because of this, Nuxt and Vue immediately unset this global instance to avoid leaking a shared reference between two users or components. What it does mean? The Composition API and Nuxt Composables are only available during lifecycle and in same tick before any async operation: ```ts [Conceptual Example] // --- Vue internal --- const _vueInstance = null const getCurrentInstance = () => _vueInstance // --- // Vue / Nuxt sets a global variable referencing to current component in _vueInstance when calling setup() async function setup () { getCurrentInstance() // Works await someAsyncOperation() // Vue unsets the context in same tick before async operation! getCurrentInstance() // null } ``` The classic solution to this, is caching the current instance on first call to a local variable like `const instance = getCurrentInstance()` and use it in the next composable call but the issue is that any nested composable calls now needs to explicitly accept the instance as an argument and not depend on the implicit context of composition-api. This is design limitation with composables and not an issue per-se. To overcome this limitation, Vue does some behind the scenes work when compiling our application code and restores context after each call for `<script setup>`: ```ts [Compiled Output] const __instance = getCurrentInstance() // Generated by Vue compiler getCurrentInstance() // Works! await someAsyncOperation() // Vue unsets the context __restoreInstance(__instance) // Generated by Vue compiler getCurrentInstance() // Still works! ``` For a better description of what Vue actually does, see [unjs/unctx#2 (comment)](https://github.com/unjs/unctx/issues/2#issuecomment-942193723). #### Solution This is where `runWithContext` can be used to restore context, similarly to how `<script setup>` works. Nuxt internally uses [unjs/unctx](https://github.com/unjs/unctx) to support composables similar to Vue for plugins and middleware. This enables composables like `navigateTo()` to work without directly passing `nuxtApp` to them - bringing the DX and performance benefits of Composition API to the whole Nuxt framework. Nuxt composables have the same design as the Vue Composition API and therefore need a similar solution to magically do this transform. Check out [unjs/unctx#2](https://github.com/unjs/unctx/issues/2) (proposal), [unjs/unctx#4](https://github.com/unjs/unctx/pull/4) (transform implementation), and [nuxt/framework#3884](https://github.com/nuxt/framework/pull/3884) (Integration to Nuxt). Vue currently only supports async context restoration for `<script setup>` for async/await usage. In Nuxt, the transform support for `defineNuxtPlugin()` and `defineNuxtRouteMiddleware()` was added, which means when you use them Nuxt automatically transforms them with context restoration. #### Remaining Issues The `unjs/unctx` transformation to automatically restore context seems buggy with `try/catch` statements containing `await` which ultimately needs to be solved in order to remove the requirement of the workaround suggested above. #### Native Async Context Using a new experimental feature, it is possible to enable native async context support using [Node.js `AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) and new unctx support to make async context available **natively** to **any nested async composable** without needing a transform or manual passing/calling with context. <tip> Native async context support works currently in Bun and Node. </tip> <read-more to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#asynccontext"> </read-more> ## tryUseNuxtApp <badge className="align-middle" color="info" size="xs">v3.10</badge> This function works exactly the same as `useNuxtApp`, but returns `null` if context is unavailable instead of throwing an exception. You can use it for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception. Example usage: ```ts [composable.ts] export function useStandType () { // Always works on the client if (tryUseNuxtApp()) { return useRuntimeConfig().public.STAND_TYPE } else { return process.env.STAND_TYPE } } ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # useNuxtData > Access the current cached value of data fetching composables. <note> `useNuxtData` gives you access to the current cached value of [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) , [`useLazyAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-lazy-async-data), [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) and [`useLazyFetch`](https://nuxt.com/docs/5.x/api/composables/use-lazy-fetch) with explicitly provided key. </note> ## Usage The `useNuxtData` composable is used to access the current cached value of data-fetching composables such as `useAsyncData`, `useLazyAsyncData`, `useFetch`, and `useLazyFetch`. By providing the key used during the data fetch, you can retrieve the cached data and use it as needed. This is particularly useful for optimizing performance by reusing already-fetched data or implementing features like Optimistic Updates or cascading data updates. To use `useNuxtData`, ensure that the data-fetching composable (`useFetch`, `useAsyncData`, etc.) has been called with an explicitly provided key. <video-accordion title="Watch a video from LearnVue about useNuxtData" video-id="e-_u6swXRWk"> </video-accordion> ## Type ```ts [Signature] export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | undefined> } ``` ## Parameters - `key`: The unique key that identifies the cached data. This key should match the one used during the original data fetch. ## Return Values - `data`: A reactive reference to the cached data associated with the provided key. If no cached data exists, the value will be `undefined`. This `Ref` automatically updates if the cached data changes, allowing seamless reactivity in your components. ## Example The example below shows how you can use cached data as a placeholder while the most recent data is being fetched from the server. ```vue [app/pages/posts.vue] <script setup lang="ts"> // We can access same data later using 'posts' key const { data } = await useFetch('/api/posts', { key: 'posts' }) </script> ``` ```vue [app/pages/posts/[id].vue] <script setup lang="ts"> // Access to the cached value of useFetch in posts.vue (parent route) const { data: posts } = useNuxtData('posts') const route = useRoute() const { data } = useLazyFetch(`/api/posts/${route.params.id}`, { key: `post-${route.params.id}`, default () { // Find the individual post from the cache and set it as the default value. return posts.value.find(post => post.id === route.params.id) }, }) </script> ``` ## Optimistic Updates The example below shows how implementing Optimistic Updates can be achieved using useNuxtData. Optimistic Updates is a technique where the user interface is updated immediately, assuming a server operation will succeed. If the operation eventually fails, the UI is rolled back to its previous state. ```vue [app/pages/todos.vue] <script setup lang="ts"> // We can access same data later using 'todos' key const { data } = await useAsyncData('todos', (_nuxtApp, { signal }) => $fetch('/api/todos', { signal })) </script> ``` ```vue [app/components/NewTodo.vue] <script setup lang="ts"> const newTodo = ref('') let previousTodos = [] // Access to the cached value of useAsyncData in todos.vue const { data: todos } = useNuxtData('todos') async function addTodo () { await $fetch('/api/addTodo', { method: 'post', body: { todo: newTodo.value, }, onRequest () { // Store the previously cached value to restore if fetch fails. previousTodos = todos.value // Optimistically update the todos. todos.value = [...todos.value, newTodo.value] }, onResponseError () { // Rollback the data if the request failed. todos.value = previousTodos }, async onResponse () { // Invalidate todos in the background if the request succeeded. await refreshNuxtData('todos') }, }) } </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # `usePreviewMode` Preview mode allows you to see how your changes would be displayed on a live site without revealing them to users. You can use the built-in `usePreviewMode` composable to access and control preview state in Nuxt. If the composable detects preview mode it will automatically force any updates necessary for [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) to rerender preview content. ```ts const { enabled, state } = usePreviewMode() ``` ## Options ### Custom `enable` check You can specify a custom way to enable preview mode. By default the `usePreviewMode` composable will enable preview mode if there is a `preview` param in url that is equal to `true` (for example, `http://localhost:3000?preview=true`). You can wrap the `usePreviewMode` into custom composable, to keep options consistent across usages and prevent any errors. ```ts export function useMyPreviewMode () { const route = useRoute() return usePreviewMode({ shouldEnable: () => { return !!route.query.customPreview }, }) } ``` ### Modify default state `usePreviewMode` will try to store the value of a `token` param from url in state. You can modify this state and it will be available for all [`usePreviewMode`](https://nuxt.com/docs/5.x/api/composables/use-preview-mode) calls. ```ts const data1 = ref('data1') const { enabled, state } = usePreviewMode({ getState: (currentState) => { return { data1, data2: 'data2' } }, }) ``` <note> The `getState` function will append returned values to current state, so be careful not to accidentally overwrite important state. </note> ### Customize the `onEnable` and `onDisable` callbacks By default, when `usePreviewMode` is enabled, it will call `refreshNuxtData()` to re-fetch all data from the server. When preview mode is disabled, the composable will attach a callback to call `refreshNuxtData()` to run after a subsequent router navigation. You can specify custom callbacks to be triggered by providing your own functions for the `onEnable` and `onDisable` options. ```ts const { enabled, state } = usePreviewMode({ onEnable: () => { console.log('preview mode has been enabled') }, onDisable: () => { console.log('preview mode has been disabled') }, }) ``` ## Example The example below creates a page where part of a content is rendered only in preview mode. ```vue [app/pages/some-page.vue] <script setup> const { enabled, state } = usePreviewMode() const { data } = await useFetch('/api/preview', { query: { apiKey: state.token, }, }) </script> <template> <div> Some base content <p v-if="enabled"> Only preview content: {{ state.token }} <br> <button @click="enabled = false"> disable preview mode </button> </p> </div> </template> ``` Now you can generate your site and serve it: ```bash [Terminal] npx nuxt generate npx nuxt preview ``` Then you can see your preview page by adding the query param `preview` to the end of the page you want to see once, for example `http://localhost:3000/?preview=true`. <note> `usePreviewMode` should be tested locally with `nuxt generate` and then `nuxt preview` rather than `nuxt dev`. (The [preview command](https://nuxt.com/docs/5.x/api/commands/preview) is not related to preview mode.) </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preview.ts) # useRequestEvent > Access the incoming request event with the useRequestEvent composable. Within the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context) you can use `useRequestEvent` to access the incoming request. ```ts // Get underlying request event const event = useRequestEvent() // Get the URL const url = event?.path ``` <tip> In the browser, `useRequestEvent` will return `undefined`. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestFetch > Forward the request context and headers for server-side fetch requests with the useRequestFetch composable. You can use `useRequestFetch` to forward the request context and headers when making server-side fetch requests. When making a client-side fetch request, the browser automatically sends the necessary headers. However, when making a request during server-side rendering, due to security considerations, we need to forward the headers manually. <note> Headers that are **not meant to be forwarded** will **not be included** in the request. These headers include, for example: `transfer-encoding`, `connection`, `keep-alive`, `upgrade`, `expect`, `host`, `accept` </note> <tip> The [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) composable uses `useRequestFetch` under the hood to automatically forward the request context and headers. </tip> <code-group> ```vue [app/pages/index.vue] <script setup lang="ts"> // This will forward the user's headers to the `/api/cookies` event handler // Result: { cookies: { foo: 'bar' } } const requestFetch = useRequestFetch() const { data: forwarded } = await useAsyncData(() => requestFetch('/api/cookies')) // This will NOT forward anything // Result: { cookies: {} } const { data: notForwarded } = await useAsyncData((_nuxtApp, { signal }) => $fetch('/api/cookies', { signal })) </script> ``` ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` </code-group> <tip> In the browser during client-side navigation, `useRequestFetch` will behave just like regular [`$fetch`](https://nuxt.com/docs/5.x/api/utils/dollarfetch). </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestHeader > Use useRequestHeader to access a certain incoming request header. You can use the built-in [`useRequestHeader`](https://nuxt.com/docs/5.x/api/composables/use-request-header) composable to access any incoming request header within your pages, components, and plugins. ```ts // Get the authorization request header const authorization = useRequestHeader('authorization') ``` <tip> In the browser, `useRequestHeader` will return `undefined`. </tip> ## Example We can use `useRequestHeader` to easily figure out if a user is authorized or not. The example below reads the `authorization` request header to find out if a person can access a restricted resource. ```ts [app/middleware/authorized-only.ts] export default defineNuxtRouteMiddleware((to, from) => { if (!useRequestHeader('authorization')) { return navigateTo('/not-authorized') } }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestHeaders > Use useRequestHeaders to access the incoming request headers. You can use built-in [`useRequestHeaders`](https://nuxt.com/docs/5.x/api/composables/use-request-headers) composable to access the incoming request headers within your pages, components, and plugins. ```ts // Get all request headers const headers = useRequestHeaders() // Get only cookie request header const { cookie } = useRequestHeaders(['cookie']) ``` <tip> In the browser, `useRequestHeaders` will return an empty object. </tip> ## Example We can use `useRequestHeaders` to access and proxy the initial request's `authorization` header to any future internal requests during SSR. The example below adds the `authorization` request header to an isomorphic `$fetch` call. ```vue [app/pages/some-page.vue] <script setup lang="ts"> const { data } = await useFetch('/api/confidential', { headers: useRequestHeaders(['authorization']), }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestURL > Access the incoming request URL with the useRequestURL composable. `useRequestURL` is a helper function that returns an [URL object](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) working on both server-side and client-side. <important> When utilizing [Hybrid Rendering](https://nuxt.com/docs/5.x/guide/concepts/rendering#hybrid-rendering) with cache strategies, all incoming request headers are dropped when handling the cached responses via the [Nitro caching layer](https://nitro.build/guide/cache) (meaning `useRequestURL` will return `localhost` for the `host`). You can define the [`cache.varies` option](https://nitro.build/guide/cache#options) to specify headers that will be considered when caching and serving the responses, such as `host` and `x-forwarded-host` for multi-tenant environments. </important> <note> If you have set [`app.baseURL`](https://nuxt.com/docs/5.x/api/nuxt-config#baseurl), the path returned on the server is relative to it, so `/base/about` is served as `/about`. On the client, `useRequestURL` reads `window.location`, which includes the base URL. </note> <code-group> ```vue [app/pages/about.vue] <script setup lang="ts"> const url = useRequestURL() </script> <template> <p>URL is: {{ url }}</p> <p>Path is: {{ url.pathname }}</p> </template> ``` ```html [Result in development] <p>URL is: http://localhost:3000/about</p> <p>Path is: /about</p> ``` </code-group> <tip icon="i-simple-icons-mdnwebdocs" target="_blank" to="https://developer.mozilla.org/en-US/docs/Web/API/URL#instance_properties"> Read about the URL instance properties on the MDN documentation. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/url.ts) # useResponseHeader > Use useResponseHeader to set a server response header. <important> This composable is available in Nuxt v3.14+. </important> You can use the built-in [`useResponseHeader`](https://nuxt.com/docs/5.x/api/composables/use-response-header) composable to set any server response header within your pages, components, and plugins. ```ts // Set a custom response header const header = useResponseHeader('X-My-Header') header.value = 'my-value' ``` ## Example We can use `useResponseHeader` to easily set a response header on a per-page basis. ```vue [app/pages/test.vue] <script setup> // pages/test.vue const header = useResponseHeader('X-My-Header') header.value = 'my-value' </script> <template> <h1>Test page with custom header</h1> <p>The response from the server for this "/test" page will have a custom "X-My-Header" header.</p> </template> ``` We can use `useResponseHeader` for example in Nuxt [middleware](https://nuxt.com/docs/5.x/directory-structure/app/middleware) to set a response header for all pages. ```ts [app/middleware/my-header-middleware.ts] export default defineNuxtRouteMiddleware((to, from) => { const header = useResponseHeader('X-My-Always-Header') header.value = `I'm Always here!` }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRoute > The useRoute composable returns the current route. <note> Within the template of a Vue component, you can access the route using `$route`. </note> The `useRoute` composable is a wrapper around the identically named composable from `vue-router`, providing access to the current route in a Nuxt application. The key difference is that in Nuxt, the composable ensures that the route is updated **only after** the page content has changed after navigation. In contrast, the `vue-router` version updates the route **immediately**, which can lead to synchronization issues between different parts of the template that rely on the route metadata, for example. ## Example In the following example, we call an API via [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) using a dynamic page parameter - `slug` - as part of the URL. ```html [~/pages/[slug].vue] <script setup lang="ts"> const route = useRoute() const { data: mountain } = await useFetch(`/api/mountains/${route.params.slug}`) </script> <template> <div> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </div> </template> ``` If you need to access the route query parameters (for example `example` in the path `/test?example=true`), then you can use `useRoute().query` instead of `useRoute().params`. ## API Apart from dynamic parameters and query parameters, `useRoute()` also provides the following computed references related to the current route: - `fullPath`: encoded URL associated with the current route that contains path, query and hash - `hash`: decoded hash section of the URL that starts with a # - `query`: access route query parameters - `matched`: array of normalized matched routes with current route location - `meta`: custom data attached to the record - `name`: unique name for the route record - `path`: encoded pathname section of the URL - `redirectedFrom`: route location that was attempted to access before ending up on the current route location ## Common Pitfalls ### Route Synchronization Issues Itโ€™s important to use the `useRoute()` composable from Nuxt rather than the one from `vue-router` to avoid synchronization issues during page navigation. Importing `useRoute` directly from `vue-router` bypasses Nuxt's implementation. ```tstwoslash // โŒ do not use `useRoute` from `vue-router` // @errors: 2300 import { useRoute } from 'vue-router' // โœ… use Nuxt's `useRoute` composable import { useRoute } from '#app' ``` ### Calling `useRoute` in Middleware Using `useRoute` in middleware is not recommended because it can lead to unexpected behavior. There is no concept of a "current route" in middleware. The `useRoute()` composable should only be used in the setup function of a Vue component or in a Nuxt plugin. <warning> This applies to any composable that uses `useRoute()` internally too. </warning> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/middleware"> Read more about accessing the route in the middleware section. </read-more> ### Hydration Issues with `route.fullPath` Browsers don't send [URL fragments](https://url.spec.whatwg.org/#concept-url-fragment) (for example `#foo`) when making requests. So using `route.fullPath` to affect the template can trigger hydration issues because this will include the fragment on client but not the server. <read-more to="https://router.vuejs.org/api/type-aliases/RouteLocationNormalizedLoaded.html" icon="i-simple-icons-vuedotjs"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # useRouteAnnouncer > This composable observes the page title changes and updates the announcer message accordingly. <important> This composable is available in Nuxt v3.12+. </important> ## Description A composable which observes the page title changes and updates the announcer message accordingly. Used by [`<NuxtRouteAnnouncer>`](https://nuxt.com/docs/5.x/api/components/nuxt-route-announcer) and controllable. It hooks into Unhead's `dom:rendered` hook to read the page's title and set it as the announcer message. <read-more title="Nuxt accessibility" to="https://nuxt.com/docs/5.x/guide/best-practices/accessibility#route-announcements"> </read-more> ## Parameters - `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`). ## Properties ### `message` - **type**: `Ref<string>` - **description**: The message to announce ### `politeness` - **type**: `Ref<string>` - **description**: Screen reader announcement urgency level `off`, `polite`, or `assertive` ## Methods ### `set(message, politeness = "polite")` Sets the message to announce with its urgency level. ### `polite(message)` Sets the message with `politeness = "polite"` ### `assertive(message)` Sets the message with `politeness = "assertive"` ## Example ```vue [app/pages/index.vue] <script setup lang="ts"> const { message, politeness, set, polite, assertive } = useRouteAnnouncer({ politeness: 'assertive', }) </script> ``` <callout> For announcing dynamic in-page content changes (form validation, toasts, loading states), use [`useAnnouncer`](https://nuxt.com/docs/5.x/api/composables/use-announcer) instead. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/route-announcer.ts) # useRouter > The useRouter composable returns the router instance. ```vue [app/pages/index.vue] <script setup lang="ts"> const router = useRouter() </script> ``` If you only need the router instance within your template, use `$router`: ```vue [app/pages/index.vue] <template> <button @click="$router.back()"> Back </button> </template> ``` If you have a `app/pages/` directory, `useRouter` is identical in behavior to the one provided by `vue-router`. <read-more to="https://router.vuejs.org/api/interfaces/router#Properties-currentRoute-" icon="i-simple-icons-vuedotjs" target="_blank"> Read `vue-router` documentation about the `Router` interface. </read-more> ## Basic Manipulation - [`addRoute()`](https://router.vuejs.org/api/interfaces/router#addRoute-): Add a new route to the router instance. `parentName` can be provided to add new route as the child of an existing route. - [`removeRoute()`](https://router.vuejs.org/api/interfaces/router#removeRoute-): Remove an existing route by its name. - [`getRoutes()`](https://router.vuejs.org/api/interfaces/router#getRoutes-): Get a full list of all the route records. - [`hasRoute()`](https://router.vuejs.org/api/interfaces/router#hasRoute-): Checks if a route with a given name exists. - [`resolve()`](https://router.vuejs.org/api/interfaces/router#resolve-): Returns the normalized version of a route location. Also includes an `href` property that includes any existing base. ```ts [Example] const router = useRouter() router.addRoute({ name: 'home', path: '/home', component: Home }) router.removeRoute('home') router.getRoutes() router.hasRoute('home') router.resolve({ name: 'home' }) ``` <note> `router.addRoute()` adds route details into an array of routes and it is useful while building [Nuxt plugins](https://nuxt.com/docs/5.x/directory-structure/app/plugins) while `router.push()` on the other hand, triggers a new navigation immediately and it is useful in pages, Vue components and composable. </note> ## Based on History API - [`back()`](https://router.vuejs.org/api/interfaces/router#back-): Go back in history if possible, same as `router.go(-1)`. - [`forward()`](https://router.vuejs.org/api/interfaces/router#forward-): Go forward in history if possible, same as `router.go(1)`. - [`go()`](https://router.vuejs.org/api/interfaces/router#go-): Move forward or backward through the history without the hierarchical restrictions enforced in `router.back()` and `router.forward()`. - [`push()`](https://router.vuejs.org/api/interfaces/router#push-): Programmatically navigate to a new URL by pushing an entry in the history stack. **It is recommended to use navigateTo instead.** - [`replace()`](https://router.vuejs.org/api/interfaces/router#replace-): Programmatically navigate to a new URL by replacing the current entry in the routes history stack. **It is recommended to use navigateTo instead.** ```ts [Example] const router = useRouter() router.back() router.forward() router.go(3) router.push({ path: '/home' }) router.replace({ hash: '#bio' }) ``` <read-more to="https://developer.mozilla.org/en-US/docs/Web/API/History" icon="i-simple-icons-mdnwebdocs" target="_blank"> Read more about the browser's History API. </read-more> ## Navigation Guards `useRouter` composable provides `afterEach`, `beforeEach` and `beforeResolve` helper methods that acts as navigation guards. However, Nuxt has a concept of **route middleware** that simplifies the implementation of navigation guards and provides a better developer experience. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/middleware"> </read-more> ## Promise and Error Handling - [`isReady()`](https://router.vuejs.org/api/interfaces/router#isReady-): Returns a Promise that resolves when the router has completed the initial navigation. - [`onError`](https://router.vuejs.org/api/interfaces/router#onError-): Adds an error handler that is called every time a non caught error happens during navigation. <read-more to="https://router.vuejs.org/api/interfaces/router#Methods-" icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs"> </read-more> ## Universal Router Instance If you do not have a `app/pages/` folder, then [`useRouter`](https://nuxt.com/docs/5.x/api/composables/use-router) will return a universal router instance with similar helper methods, but be aware that not all features may be supported or behave in exactly the same way as with `vue-router`. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # useRuntimeConfig > Access runtime config variables with the useRuntimeConfig composable. ## Usage ```vue [app/app.vue] <script setup lang="ts"> const config = useRuntimeConfig() </script> ``` ```ts [server/api/foo.ts] export default defineEventHandler((event) => { const config = useRuntimeConfig() }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> ## Define Runtime Config The example below shows how to set a public API base URL and a secret API token that is only accessible on the server. We should always define `runtimeConfig` variables inside `nuxt.config`. ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { // Private keys are only available on the server apiSecret: '123', // Public keys that are exposed to the client public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api', }, }, }) ``` <note> Variables that need to be accessible on the server are added directly inside `runtimeConfig`. Variables that need to be accessible on both the client and the server are defined in `runtimeConfig.public`. </note> <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> ## Access Runtime Config To access runtime config, we can use `useRuntimeConfig()` composable: ```ts [server/api/test.ts] export default defineEventHandler(async (event) => { const config = useRuntimeConfig() // Access public variables const result = await $fetch(`/test`, { baseURL: config.public.apiBase, headers: { // Access a private variable (only available on the server) Authorization: `Bearer ${config.apiSecret}`, }, }) return result }) ``` In this example, since `apiBase` is defined within the `public` namespace, it is universally accessible on both server and client-side, while `apiSecret` **is only accessible on the server-side**. ## Environment Variables It is possible to update runtime config values using a matching environment variable name prefixed with `NUXT_`. <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> ### Using the `.env` File We can set the environment variables inside the `.env` file to make them accessible during **development** and **build/generate**. ```ini [.env] NUXT_PUBLIC_API_BASE = "https://api.localhost:5555" NUXT_API_SECRET = "123" ``` <note> Any environment variables set within `.env` file are accessed using `process.env` in the Nuxt app during **development** and **build/generate**. </note> <warning> In **production runtime**, you should use platform environment variables and `.env` is not used. </warning> <read-more to="https://nuxt.com/docs/5.x/directory-structure/env"> </read-more> ## `app` namespace Nuxt uses `app` namespace in runtime-config with keys including `baseURL` and `cdnURL`. You can customize their values at runtime by setting environment variables. <note> This is a reserved namespace. You should not introduce additional keys inside `app`. </note> ### `app.baseURL` By default, the `baseURL` is set to `'/'`. However, the `baseURL` can be updated at runtime by setting the `NUXT_APP_BASE_URL` as an environment variable. Then, you can access this new base URL using `config.app.baseURL`: ```ts [/plugins/my-plugin.ts] export default defineNuxtPlugin((NuxtApp) => { const config = useRuntimeConfig() // Access baseURL universally const baseURL = config.app.baseURL }) ``` ### `app.cdnURL` This example shows how to set a custom CDN url and access them using `useRuntimeConfig()`. You can use a custom CDN for serving static assets inside `.output/public` using the `NUXT_APP_CDN_URL` environment variable. And then access the new CDN url using `config.app.cdnURL`. ```ts [server/api/foo.ts] export default defineEventHandler((event) => { const config = useRuntimeConfig() // Access cdnURL universally const cdnURL = config.app.cdnURL }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # useRuntimeHook > Registers a runtime hook in a Nuxt application and ensures it is properly disposed of when the scope is destroyed. <important> This composable is available in Nuxt v3.14+. </important> ```ts [Signature] function useRuntimeHook<THookName extends keyof RuntimeNuxtHooks> ( name: THookName, fn: RuntimeNuxtHooks[THookName] extends HookCallback ? RuntimeNuxtHooks[THookName] : never, ): void ``` ## Usage ### Parameters - `name`: The name of the runtime hook to register. You can see the full list of [runtime Nuxt hooks here](https://nuxt.com/docs/5.x/api/advanced/hooks#app-hooks-runtime). - `fn`: The callback function to execute when the hook is triggered. The function signature varies based on the hook name. ### Return Values The composable doesn't return a value, but it automatically unregisters the hook when the component's scope is destroyed. ## Example ```vue [pages/index.vue]twoslash <script setup lang="ts"> // Register a hook that runs every time a link is prefetched, but which will be // automatically cleaned up (and not called again) when the component is unmounted useRuntimeHook('link:prefetch', (link) => { console.log('Prefetching', link) }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/runtime-hook.ts) # useSeoMeta > The useSeoMeta composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. This helps you avoid common mistakes, such as using `name` instead of `property`, as well as typos - with over 100+ meta tags fully typed. <important> This is the recommended way to add meta tags to your site as it is XSS safe and has full TypeScript support. </important> <read-more to="https://nuxt.com/docs/5.x/getting-started/seo-meta"> </read-more> ## Usage ```vue [app/app.vue] <script setup lang="ts"> useSeoMeta({ title: 'My Amazing Site', ogTitle: 'My Amazing Site', description: 'This is my amazing site, let me tell you all about it.', ogDescription: 'This is my amazing site, let me tell you all about it.', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script> ``` When inserting tags that are reactive, you should use the computed getter syntax (`() => value`): ```vue [app/app.vue] <script setup lang="ts"> const title = ref('My title') useSeoMeta({ title, description: () => `This is a description for the ${title.value} page`, }) </script> ``` ## Parameters There are over 100 parameters. See the [full list of parameters in the source code](https://github.com/harlan-zw/zhead/blob/main/packages/zhead/src/metaFlat.ts#L1035). <read-more to="https://nuxt.com/docs/5.x/getting-started/seo-meta"> </read-more> ## Performance In most instances, SEO meta tags don't need to be reactive as search engine robots primarily scan the initial page load. For better performance, you can wrap your `useSeoMeta` calls in a server-only condition when the meta tags don't need to be reactive: ```vue [app/app.vue] <script setup lang="ts"> if (import.meta.server) { // These meta tags will only be added during server-side rendering useSeoMeta({ robots: 'index, follow', description: 'Static description that does not need reactivity', ogImage: 'https://example.com/image.png', // other static meta tags... }) } const dynamicTitle = ref('My title') // Only use reactive meta tags outside the condition when necessary useSeoMeta({ title: () => dynamicTitle.value, ogTitle: () => dynamicTitle.value, }) </script> ``` This previously used the [`useServerSeoMeta`](https://nuxt.com/docs/5.x/api/composables/use-server-seo-meta) composable, but it has been deprecated in favor of this approach. --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useServerSeoMeta > The useServerSeoMeta composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. <warning> `useServerSeoMeta` is deprecated. Wrap [`useSeoMeta`](https://nuxt.com/docs/5.x/api/composables/use-seo-meta) in an `if (import.meta.server)` block instead. The auto-import is removed under `future.compatibilityVersion: 5`. </warning> `useServerSeoMeta` lets you define your site's SEO meta tags as a flat object with full TypeScript support, exactly like [`useSeoMeta`](https://nuxt.com/docs/5.x/api/composables/use-seo-meta), but it only runs server-side and is tree-shaken from the client bundle. <read-more to="https://nuxt.com/docs/5.x/api/composables/use-seo-meta"> </read-more> For new code, use the server-only pattern directly: ```vue [app/app.vue] <script setup lang="ts"> if (import.meta.server) { useSeoMeta({ robots: 'index, follow', }) } </script> ``` Parameters are exactly the same as with [`useSeoMeta`](https://nuxt.com/docs/5.x/api/composables/use-seo-meta). <read-more to="https://nuxt.com/docs/5.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useState > The useState composable creates a reactive and SSR-friendly shared state. ## Usage ```ts // Create a reactive state and set default value const count = useState('counter', () => Math.round(Math.random() * 100)) ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/state-management"> </read-more> <important> Because the data inside `useState` will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. </important> <warning> `useState` is a reserved function name transformed by the compiler, so you should not name your own function `useState`. </warning> <video-accordion title="Watch a video from Alexander Lichter about why and when to use useState" video-id="mv0WcBABcIk"> </video-accordion> ## Using `shallowRef` If you don't need your state to be deeply reactive, you can combine `useState` with [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref). This can improve performance when your state contains large objects and arrays. ```ts const state = useState('my-shallow-state', () => shallowRef({ deep: 'not reactive' })) // isShallow(state) === true ``` ## Type ```ts [Signature] export function useState<T> (init?: () => T | Ref<T>): Ref<T> export function useState<T> (key: string, init?: () => T | Ref<T>): Ref<T> ``` - `key`: A unique key ensuring that data fetching is properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file and line number of the instance of [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) will be generated for you. - `init`: A function that provides initial value for the state when not initiated. This function can also return a `Ref`. - `T`: (typescript only) Specify the type of state ## Troubleshooting ### `Cannot stringify arbitrary non-POJOs` This error occurs when you try to store a non-serializable payload with `useState`, such as class instances. If you want to store class instances with `useState` that are not supported by Nuxt, you can use [`definePayloadPlugin`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#custom-reducerreviver) to add a custom serializer and deserializer for your classes. <read-more to="https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#payload"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/state.ts) # App Config > Nuxt Kit provides a set of utilities to help you access and modify Nuxt app configuration. ## `updateAppConfig` Update the app configuration that will be applied to `nuxt.options.appConfig`. This is useful for modules to set default values that can be overridden by user configuration. The update is merged with the existing configuration using [`defu`](https://github.com/unjs/defu). ### Type ```ts function updateAppConfig (appConfig: Record<string, unknown>): void ``` ### Example ```ts import { defineNuxtModule, updateAppConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { updateAppConfig({ myModule: { option: 'value', }, }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/app-config.ts) # Auto-imports > Nuxt Kit provides a set of utilities to help you work with auto-imports. These functions allow you to register your own utils, composables and Vue APIs. Nuxt auto-imports helper functions, composables and Vue APIs to use across your application without explicitly importing them. Based on the directory structure, every Nuxt application can also use auto-imports for its own composables and plugins. With Nuxt Kit you can also add your own auto-imports. `addImports` and `addImportsDir` allow you to add imports to the Nuxt application. `addImportsSources` allows you to add listed imports from 3rd party packages to the Nuxt application. These utilities are powered by [`unimport`](https://github.com/unjs/unimport), which provides the underlying auto-import mechanism used in Nuxt. <note> These functions are designed for registering your own utils, composables and Vue APIs. For pages, components and plugins, please refer to the specific sections: [Pages](https://nuxt.com/docs/5.x/api/kit/pages), [Components](https://nuxt.com/docs/5.x/api/kit/components), [Plugins](https://nuxt.com/docs/5.x/api/kit/plugins). </note> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/expanding-nuxt-s-auto-imports?friend=nuxt"> Watch Vue School video about Auto-imports Nuxt Kit utilities. </tip> ## `addImports` Add imports to the Nuxt application. It makes your imports available in the Nuxt app context without the need to import them manually. <tip> To add imports for the Nitro server context, refer to the [`addServerImports`](https://nuxt.com/docs/5.x/api/kit/nitro#addserverimports) function. </tip> ### Usage ```tstwoslash import { addImports, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const names = [ 'useStoryblok', 'useStoryblokApi', 'useStoryblokBridge', 'renderRichText', 'RichTextSchema', ] names.forEach(name => addImports({ name, as: name, from: '@storyblok/vue' }), ) }, }) ``` ### Type ```ts function addImports (imports: NuxtImport | NuxtImport[]): void ``` ### Parameters `imports`: An object or an array of objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Import name to be detected. </td> </tr> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the import; if multiple imports have the same name, the one with the highest priority will be used. </td> </tr> <tr> <td> <code> disabled </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is disabled. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Record<string, any> </code> </td> <td> <code> false </code> </td> <td> Metadata of the import. </td> </tr> <tr> <td> <code> type </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is a pure type import. </td> </tr> <tr> <td> <code> typeFrom </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Use this as the <code> from </code> value when generating type declarations. </td> </tr> <tr> <td> <code> as </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Import as this name. </td> </tr> </tbody> </table> ## `addImportsDir` Add imports from a directory to the Nuxt application. It will automatically import all files from the directory and make them available in the Nuxt application without the need to import them manually. ### Usage ```tstwoslash import { addImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: '@vueuse/motion', configKey: 'motion', }, setup (options, nuxt) { const resolver = createResolver(import.meta.url) addImportsDir(resolver.resolve('./runtime/composables')) }, }) ``` ### Type ```ts function addImportsDir (dirs: string | string[], options?: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A string or an array of strings with the path to the directory to import from. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> { </span> <span class="sZSNi"> prepend </span> <span class="sDfIl"> ?: </span> <span class="sZSNi"> boolean </span> <span class="sDfIl"> } </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the import. If <code> prepend </code> is set to <code> true </code> , the imports will be prepended to the list of imports. </td> </tr> </tbody> </table> ## `addImportsSources` Add listed imports to the Nuxt application. ### Usage ```tstwoslash import { addImportsSources, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addImportsSources([ { package: '@vueuse/core' }, { from: 'h3', imports: [ 'defineEventHandler', 'getQuery', 'getRouterParams', 'readBody', 'sendRedirect', ], }, ]) }, }) ``` ### Type ```ts function addImportsSources (importSources: NuxtImportPresetSource | NuxtImportPresetSource[]): void ``` ### Parameters **importSources**: An object or an array of objects with the following properties: - `NuxtImportPreset` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> imports </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> (NuxtImportEntry </span> <span class="sDfIl"> | </span> <span class="sZSNi"> NuxtImportPreset)[] </span> </code> </td> <td> <code> true </code> </td> <td> An array of entries, which can be import names, import objects or nested presets. </td> </tr> </tbody> </table> - `NuxtPackageImportPreset` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> package </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Name of the package. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/imports.ts) # Builder > Nuxt Kit provides a set of utilities to help you work with the builder. These functions allow you to extend the Vite and webpack configurations. Nuxt have builders based on [Vite](https://github.com/nuxt/nuxt/tree/main/packages/vite) and [webpack](https://github.com/nuxt/nuxt/tree/main/packages/webpack). You can extend the config passed to each one using `extendViteConfig` and `extendWebpackConfig` functions. You can also add additional plugins via `addVitePlugin`, `addWebpackPlugin` and `addBuildPlugin`. ## `extendViteConfig` Extends the Vite configuration. Callback function can be called multiple times, when applying to both client and server builds. <warning> This hook is now deprecated, and we recommend using a Vite plugin instead with a `config` hook, or โ€” for environment-specific configuration โ€” the `applyToEnvironment` hook. </warning> ### Usage ```tstwoslash import { defineNuxtModule, extendViteConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendViteConfig((config) => { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('cross-fetch') }) }, }) ``` For environment-specific configuration in Nuxt 5+, use `addVitePlugin()` instead: ```tstwoslash import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // For global configuration (affects all environments) addVitePlugin(() => ({ name: 'my-global-plugin', config (config) { // This runs before environment setup config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('cross-fetch') }, })) // For environment-specific configuration addVitePlugin(() => ({ name: 'my-client-plugin', applyToEnvironment (environment) { return environment.name === 'client' }, configEnvironment (name, config) { // This only affects the client environment config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('client-only-package') }, })) }, }) ``` <warning> **Important:** The `config` hook runs before `applyToEnvironment` and modifies the global configuration. Use `configEnvironment` for environment-specific configuration changes. </warning> ### Type ```tstwoslash // @errors: 2391 import type { UserConfig as ViteConfig } from 'vite' import type { ExtendViteConfigOptions } from '@nuxt/kit' // ---cut--- function extendViteConfig (callback: ((config: ViteConfig) => void), options?: ExtendViteConfigOptions): void ``` <read-more to="https://vite.dev/config/" icon="i-simple-icons-vite" target="_blank"> Check out the Vite website for more information about its configuration. </read-more> ### Parameters **callback**: A callback function that will be called with the Vite configuration object. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> addVitePlugin() </code> with <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> addVitePlugin() </code> with <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `extendWebpackConfig` Extends the webpack configuration. Callback function can be called multiple times, when applying to both client and server builds. ### Usage ```tstwoslash import { defineNuxtModule, extendWebpackConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendWebpackConfig((config) => { config.module!.rules!.push({ test: /\.txt$/, use: 'raw-loader', }) }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Configuration as WebpackConfig } from 'webpack' import type { ExtendWebpackConfigOptions } from '@nuxt/kit' // ---cut--- function extendWebpackConfig (callback: ((config: WebpackConfig) => void), options?: ExtendWebpackConfigOptions): void ``` <read-more to="https://webpack.js.org/configuration/" icon="i-simple-icons-webpack" target="_blank"> Check out webpack website for more information about its configuration. </read-more> ### Parameters **callback**: A callback function that will be called with the webpack configuration object. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addVitePlugin` Append Vite plugin to the config. <warning> In Nuxt 5+, plugins registered with `server: false` or `client: false` options will not have their `config` or `configResolved` hooks called. Instead, use the `applyToEnvironment()` method instead for environment-specific plugins. </warning> ### Usage ```tstwoslash // @errors: 2307 // ---cut--- import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' import { svg4VuePlugin } from 'vite-plugin-svg4vue' export default defineNuxtModule({ meta: { name: 'nuxt-svg-icons', configKey: 'nuxtSvgIcons', }, defaults: { svg4vue: { assetsDirName: 'assets/icons', }, }, setup (options) { addVitePlugin(svg4VuePlugin(options.svg4vue)) // or, to add a vite plugin to only one environment addVitePlugin(() => ({ name: 'my-client-plugin', applyToEnvironment (environment) { return environment.name === 'client' }, // ... rest of your client-only plugin })) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Plugin as VitePlugin } from 'vite' import type { ExtendViteConfigOptions } from '@nuxt/kit' // ---cut--- function addVitePlugin (pluginOrGetter: VitePlugin | VitePlugin[] | (() => VitePlugin | VitePlugin[]), options?: ExtendViteConfigOptions): void ``` <tip> See [Vite website](https://vite.dev/guide/api-plugin) for more information about Vite plugins. You can also use [this repository](https://github.com/vitejs/awesome-vite#plugins) to find a plugin that suits your needs. </tip> ### Parameters **pluginOrGetter**: A Vite plugin instance or an array of Vite plugin instances. If a function is provided, it must return a Vite plugin instance or an array of Vite plugin instances. The function can also be async or return a Promise, which is useful for lazy-loading plugins: ```tstwoslash // @errors: 2307 import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // Lazy load the plugin - only imported when the build actually runs addVitePlugin(() => import('my-vite-plugin').then(r => r.default())) }, }) ``` **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addWebpackPlugin` Append webpack plugin to the config. ### Usage ```ts import EslintWebpackPlugin from 'eslint-webpack-plugin' import { addWebpackPlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'nuxt-eslint', configKey: 'eslint', }, defaults: nuxt => ({ include: [`${nuxt.options.srcDir}/**/*.{js,jsx,ts,tsx,vue}`], lintOnStart: true, }), setup (options, nuxt) { const webpackOptions = { ...options, context: nuxt.options.srcDir, files: options.include, lintDirtyModulesOnly: !options.lintOnStart, } addWebpackPlugin(new EslintWebpackPlugin(webpackOptions), { server: false }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { WebpackPluginInstance } from 'webpack' import type { ExtendWebpackConfigOptions } from '@nuxt/kit' // ---cut--- function addWebpackPlugin (pluginOrGetter: WebpackPluginInstance | WebpackPluginInstance[] | (() => WebpackPluginInstance | WebpackPluginInstance[]), options?: ExtendWebpackConfigOptions): void ``` <tip> See [webpack website](https://webpack.js.org/concepts/plugins/) for more information about webpack plugins. You can also use [this collection](https://webpack.js.org/awesome-webpack/#webpack-plugins) to find a plugin that suits your needs. </tip> ### Parameters **pluginOrGetter**: A webpack plugin instance or an array of webpack plugin instances. If a function is provided, it must return a webpack plugin instance or an array of webpack plugin instances. The function can also be async or return a Promise, enabling lazy-loading of plugins. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addBuildPlugin` Builder-agnostic version of `addVitePlugin` and `addWebpackPlugin`. It will add the plugin to both Vite and webpack configurations if they are present. ### Type ```tstwoslash // @errors: 2391 import type { ExtendConfigOptions } from '@nuxt/kit' import type { Plugin as VitePlugin } from 'vite' import type { WebpackPluginInstance } from 'webpack' import type { RspackPluginInstance } from '@rspack/core' interface AddBuildPluginFactory { vite?: () => VitePlugin | VitePlugin[] webpack?: () => WebpackPluginInstance | WebpackPluginInstance[] rspack?: () => RspackPluginInstance | RspackPluginInstance[] } // ---cut--- function addBuildPlugin (pluginFactory: AddBuildPluginFactory, options?: ExtendConfigOptions): void ``` ### Parameters **pluginFactory**: A factory function that returns an object with `vite` and/or `webpack` properties. These properties must be functions that return a Vite plugin instance or an array of Vite plugin instances and/or a webpack plugin instance or an array of webpack plugin instances. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `setBuildOutput` Set a build output provider for the given key. Build outputs are the contract between builders (Vite, webpack, Rspack, or a custom builder) and the Nitro server runtime: each key maps to a `nuxt/*` subpath import the server runtime resolves at build time. This is typically called from inside a builder, or from a module that participates in the build. <read-more to="https://nuxt.com/docs/5.x/guide/going-further/builders#the-build-output-contract"> Learn how the build output contract works. </read-more> ### Type ```tstwoslash // @errors: 2391 import type { NuxtBuildOutputs } from '@nuxt/schema' // ---cut--- function setBuildOutput<K extends keyof NuxtBuildOutputs> (key: K, provider: NuxtBuildOutputs[K]): void ``` ### Parameters **key**: The build output key. One of `serverEntry`, `clientManifest`, `clientPrecomputed`, `ssrStyles`, `entryChunkName` or `entryIds`. **provider**: The value for that key: a (possibly async) function returning the module body as a string, read lazily when the server build resolves the corresponding `nuxt/*` import. ### Example ```ts import { setBuildOutput } from '@nuxt/kit' // Re-export the built SSR entry by absolute specifier. setBuildOutput('serverEntry', () => `export { default } from ${JSON.stringify(serverEntryURL)}`) // Provide the serialized client manifest. setBuildOutput('clientManifest', () => `export default ${serializedManifest}`) // Re-export the emitted per-component styles map for `nuxt/internal/styles`. setBuildOutput('ssrStyles', () => `export { default } from ${JSON.stringify(pathToFileURL(resolve(serverDir, 'styles.mjs')).href)}`) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/build.ts) # Compatibility > Nuxt Kit provides a set of utilities to help you check the compatibility of your modules with different Nuxt versions. Nuxt Kit utilities can be used in Nuxt 3, Nuxt 2 with Bridge and even Nuxt 2 without Bridge. To make sure your module is compatible with all versions, you can use the `checkNuxtCompatibility`, `assertNuxtCompatibility` and `hasNuxtCompatibility` functions. They will check if the current Nuxt version meets the constraints you provide. Also you can use `isNuxt2`, `isNuxt3` and `getNuxtVersion` functions for more granular checks. ## `checkNuxtCompatibility` Checks if constraints are met for the current Nuxt version. If not, returns an array of messages. Nuxt 2 version also checks for `bridge` support. ### Usage ```tstwoslash import { checkNuxtCompatibility, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (_options, nuxt) { const issues = await checkNuxtCompatibility({ nuxt: '^2.16.0' }, nuxt) if (issues.length) { console.warn('Nuxt compatibility issues found:\n' + issues.toString()) } else { // do something } }, }) ``` ### Type ```ts function checkNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<NuxtCompatibilityIssues> ``` ### Parameters **constraints**: Version and builder constraints to check against. It accepts the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> nuxt </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Nuxt version in semver format. Versions may be defined in Node.js way, for example: <code> >=2.15.0 <3.0.0 </code> . </td> </tr> <tr> <td> <code> bridge </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sbKd-"> false </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Specifies version constraints or disables compatibility for specific Nuxt builders like <code> vite </code> , <code> webpack </code> , or <code> rspack </code> . Use <code> false </code> to disable. </td> </tr> </tbody> </table> **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `assertNuxtCompatibility` Asserts that constraints are met for the current Nuxt version. If not, throws an error with the list of issues as string. ### Type ```tstwoslash // @errors: 2391 import type { Nuxt, NuxtCompatibility } from '@nuxt/schema' // ---cut--- function assertNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<true> ``` ### Parameters **constraints**: Version and builder constraints to check against. Refer to the [constraints table in `checkNuxtCompatibility`](https://nuxt.com/docs/5.x/api/kit/compatibility#parameters) for details. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `hasNuxtCompatibility` Checks if constraints are met for the current Nuxt version. Return `true` if all constraints are met, otherwise returns `false`. Nuxt 2 version also checks for `bridge` support. ### Usage ```tstwoslash import { defineNuxtModule, hasNuxtCompatibility } from '@nuxt/kit' export default defineNuxtModule({ async setup (_options, nuxt) { const usingNewPostcss = await hasNuxtCompatibility({ nuxt: '^2.16.0' }, nuxt) if (usingNewPostcss) { // do something } else { // do something else } }, }) ``` ### Type ```ts function hasNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<boolean> ``` ### Parameters **constraints**: Version and builder constraints to check against. Refer to the [constraints table in `checkNuxtCompatibility`](https://nuxt.com/docs/5.x/api/kit/compatibility#parameters) for details. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxtMajorVersion` Check if current Nuxt instance is of specified major version ### Usage ```tstwoslash import { defineNuxtModule, isNuxtMajorVersion } from '@nuxt/kit' export default defineNuxtModule({ setup () { if (isNuxtMajorVersion(3)) { // do something for Nuxt 3 } else { // do something else for other versions } }, }) ``` ### Type ```ts function isNuxtMajorVersion (major: number, nuxt?: Nuxt): boolean ``` ### Parameters **major**: Major version to check against. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxt3` Checks if the current Nuxt version is 3.x. <note> Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in @nuxt/kit v5 or a future major version. </note> ### Type ```ts function isNuxt3 (nuxt?: Nuxt): boolean ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxt2` Checks if the current Nuxt version is 2.x. <note> Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in @nuxt/kit v5 or a future major version. </note> ### Type ```ts function isNuxt2 (nuxt?: Nuxt): boolean ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `getNuxtVersion` Returns the current Nuxt version. ### Type ```ts function getNuxtVersion (nuxt?: Nuxt): string ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/compatibility.ts) # Components > Nuxt Kit provides a set of utilities to help you work with components. You can register components globally or locally, and also add directories to be scanned for components. Components are the building blocks of your Nuxt application. They are reusable Vue instances that can be used to create a user interface. In Nuxt, components from the components directory are automatically imported by default. However, if you need to import components from an alternative directory or wish to selectively import them as needed, `@nuxt/kit` provides the `addComponentsDir` and `addComponent` methods. These utils allow you to customize the component configuration to better suit your needs. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-components-and-component-directories?friend=nuxt"> Watch Vue School video about injecting components. </tip> ## `addComponentsDir` Register a directory to be scanned for components and imported only when used. Keep in mind, that this does not register components globally, until you specify `global: true` option. ### Usage ```ts export default defineNuxtModule({ meta: { name: '@nuxt/ui', configKey: 'ui', }, setup () { addComponentsDir({ path: resolve('./runtime/components'), prefix: 'U', pathPrefix: false, }) }, }) ``` ### Type ```ts function addComponentsDir (dir: ComponentsDir, opts: { prepend?: boolean } = {}): void ``` ### Parameters `dir` An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path (absolute or relative) to the directory containing your components. You can use Nuxt aliases (~ or @) to refer to directories inside project or directly use an npm package path similar to require. </td> </tr> <tr> <td> <code> pattern </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> false </code> </td> <td> Accept Pattern that will be run against specified path. </td> </tr> <tr> <td> <code> ignore </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Ignore patterns that will be run against specified path. </td> </tr> <tr> <td> <code> prefix </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Prefix all matched components with this string. </td> </tr> <tr> <td> <code> pathPrefix </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Prefix component name by its path. </td> </tr> <tr> <td> <code> prefetch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> preload </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> isAsync </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> This flag indicates, component should be loaded async (with a separate chunk) regardless of using Lazy prefix or not. </td> </tr> <tr> <td> <code> extendComponent </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> component </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Component </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> Component </span> <span class="sDfIl"> | </span> <span class="sDfIl"> void> </span> <span class="sDfIl"> | </span> <span class="sZSNi"> (Component </span> <span class="sDfIl"> | </span> <span class="sDfIl"> void </span> <span class="sZSNi"> ) </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called for each component found in the directory. It accepts a component object and should return a component object or a promise that resolves to a component object. </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers components to be globally available. </td> </tr> <tr> <td> <code> island </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers components as islands. You can read more about islands in <a href="https://nuxt.com/docs/5.x/api/components/nuxt-island"> <code> <NuxtIsland/> </code> </a> component description. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Watch specified path for changes, including file additions and file deletions. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Extensions supported by Nuxt builder. </td> </tr> <tr> <td> <code> transpile </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> auto </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sZSNi"> boolean </span> </code> </td> <td> <code> false </code> </td> <td> Transpile specified path using build.transpile. If set to <code> 'auto' </code> , it will set <code> transpile: true </code> if <code> node_modules/ </code> is in path. </td> </tr> </tbody> </table> `opts` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the directory will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addComponent` Register a component to be automatically imported. ### Usage ```ts import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: '@nuxt/image', configKey: 'image', }, setup () { const resolver = createResolver(import.meta.url) addComponent({ name: 'NuxtImg', filePath: resolver.resolve('./runtime/components/NuxtImg.vue'), }) addComponent({ name: 'NuxtPicture', filePath: resolver.resolve('./runtime/components/NuxtPicture.vue'), }) }, }) ``` ### Type ```ts function addComponent (options: AddComponentOptions): void ``` ### Parameters `options`: An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Component name. </td> </tr> <tr> <td> <code> filePath </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the component. </td> </tr> <tr> <td> <code> declarationPath </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to component's declaration file. It is used to generate components' <a href="https://nuxt.com/docs/5.x/api/kit/templates#addtypetemplate"> type templates </a> ; if not provided, <code> filePath </code> is used instead. </td> </tr> <tr> <td> <code> pascalName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Pascal case component name. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> kebabName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Kebab case component name. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> export </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Specify named or default export. If not provided, it will be set to <code> 'default' </code> . </td> </tr> <tr> <td> <code> shortPath </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Short path to the component. If not provided, it will be generated from the component path. </td> </tr> <tr> <td> <code> chunkName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Chunk name for the component. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> prefetch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> preload </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers component to be globally available. </td> </tr> <tr> <td> <code> island </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers component as island. You can read more about islands in <a href="https://nuxt.com/docs/5.x/api/components/nuxt-island"> <code> <NuxtIsland/> </code> </a> component description. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> This options indicates if component should render on client, server or both. By default, it will render on both client and server. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the component, if multiple components have the same name, the one with the highest priority will be used. </td> </tr> </tbody> </table> ### Example If you want to auto-import a component from an npm package, and the component is a named export (rather than the default), you can use the `export` option to specify it. ```ts import { addComponent, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // import { MyComponent as MyAutoImportedComponent } from 'my-npm-package' addComponent({ name: 'MyAutoImportedComponent', export: 'MyComponent', filePath: 'my-npm-package', }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/components.ts) # Context > Nuxt Kit provides a set of utilities to help you work with context. Nuxt modules allow you to enhance Nuxt's capabilities. They offer a structured way to keep your code organized and modular. If you're looking to break down your module into smaller components, Nuxt offers the `useNuxt` and `tryUseNuxt` functions. These functions enable you to conveniently access the Nuxt instance from the context without having to pass it as an argument. <note> When you're working with the `setup` function in Nuxt modules, Nuxt is already provided as the second argument. This means you can access it directly without needing to call `useNuxt()`. </note> ## `useNuxt` Get the Nuxt instance from the context. It will throw an error if Nuxt is not available. ### Usage ```ts import { useNuxt } from '@nuxt/kit' const setupSomeFeature = () => { const nuxt = useNuxt() // You can now use the nuxt instance console.log(nuxt.options) } ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function useNuxt (): Nuxt ``` ### Return Value The `useNuxt` function returns the Nuxt instance, which contains all the options and methods available in Nuxt. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> options </code> </td> <td> <code> NuxtOptions </code> </td> <td> The resolved Nuxt configuration. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code> NuxtHookRegistry<NuxtHooks> </code> </td> <td> The Nuxt hook system. Allows registering and listening to lifecycle events. </td> </tr> <tr> <td> <code> hook </code> </td> <td> <code> (name: string, (...args: any[]) => Promise<void> | void) => () => void </code> </td> <td> Shortcut for <code> nuxt.hooks.hook </code> . Registers a single callback for a specific lifecycle hook. </td> </tr> <tr> <td> <code> callHook </code> </td> <td> <code> (name: string, ...args: any[]) => Promise<any> </code> </td> <td> Shortcut for <code> nuxt.hooks.callHook </code> . Triggers a lifecycle hook manually and runs all registered callbacks. </td> </tr> <tr> <td> <code> addHooks </code> </td> <td> <code> (configHooks: NuxtNestedHooks) => () => void </code> </td> <td> Shortcut for <code> nuxt.hooks.addHooks </code> . Registers multiple hooks at once. </td> </tr> </tbody> </table> ### Example <code-group> ```ts [setupTranspilation.ts]twoslash import { useNuxt } from '@nuxt/kit' export const setupTranspilation = () => { const nuxt = useNuxt() if (nuxt.options.builder === '@nuxt/webpack-builder') { nuxt.options.build.transpile ||= [] nuxt.options.build.transpile.push('xstate') } } ``` ```ts [module.ts]twoslash // @module: esnext // @filename: setupTranspilation.ts export const setupTranspilation = () => {} // @filename: module.ts import { defineNuxtModule } from '@nuxt/kit' // ---cut--- import { setupTranspilation } from './setupTranspilation' export default defineNuxtModule({ setup () { setupTranspilation() }, }) ``` </code-group> ## `tryUseNuxt` Get the Nuxt instance from the context. It will return `null` if Nuxt is not available. ### Usage ```tstwoslash import { tryUseNuxt } from '@nuxt/kit' function setupSomething () { const nuxt = tryUseNuxt() if (nuxt) { // You can now use the nuxt instance console.log(nuxt.options) } else { console.log('Nuxt is not available') } } ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function tryUseNuxt (): Nuxt | null ``` ### Return Value The `tryUseNuxt` function returns the Nuxt instance if available, or `null` if Nuxt is not available. The Nuxt instance as described in the `useNuxt` section. ### Example <code-group> ```ts [requireSiteConfig.ts]twoslash declare module '@nuxt/schema' { interface NuxtOptions { siteConfig: SiteConfig } } // ---cut--- import { tryUseNuxt } from '@nuxt/kit' interface SiteConfig { title?: string } export const requireSiteConfig = (): SiteConfig => { const nuxt = tryUseNuxt() if (!nuxt) { return {} } return nuxt.options.siteConfig } ``` ```ts [module.ts]twoslash // @module: esnext // @filename: requireSiteConfig.ts interface SiteConfig { title?: string } export const requireSiteConfig = (): SiteConfig => { return {} } // @filename: module.ts // ---cut--- import { defineNuxtModule, useNuxt } from '@nuxt/kit' import { requireSiteConfig } from './requireSiteConfig' export default defineNuxtModule({ setup (_, nuxt) { const config = requireSiteConfig() nuxt.options.app.head.title = config.title }, }) ``` </code-group> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/context.ts) # Examples > Examples of Nuxt Kit utilities in use. ## Accessing Nuxt Vite Config If you are building an integration that needs access to the runtime Vite or webpack config that Nuxt uses, it is possible to extract this using Kit utilities. Some examples of projects doing this already: - [histoire](https://github.com/histoire-dev/histoire/blob/main/packages/histoire-plugin-nuxt/src/index.ts) - [nuxt-vitest](https://github.com/danielroe/nuxt-vitest/blob/main/packages/nuxt-vitest/src/config.ts) - [@storybook-vue/nuxt](https://github.com/storybook-vue/storybook-nuxt/blob/main/packages/storybook-nuxt/src/preset.ts) Here is a brief example of how you might access the Vite config from a project; you could implement a similar approach to get the webpack configuration. ```js import { buildNuxt, loadNuxt } from '@nuxt/kit' // https://github.com/nuxt/nuxt/issues/14534 async function getViteConfig () { const nuxt = await loadNuxt({ cwd: process.cwd(), dev: false, overrides: { ssr: false } }) return new Promise((resolve, reject) => { nuxt.hook('vite:extend', (config) => { resolve(config) throw new Error('_stop_') }) buildNuxt(nuxt).catch((err) => { if (!err.toString().includes('_stop_')) { reject(err) } }) }).finally(() => nuxt.close()) } const viteConfig = await getViteConfig() console.log(viteConfig) ``` # Head > Nuxt Kit provides utilities to help you manage head configuration in modules. ## `setGlobalHead` Sets global head configuration for your Nuxt application. This utility allows modules to programmatically configure meta tags, links, scripts, and other head elements that will be applied across all pages. The provided head configuration will be merged with any existing head configuration using deep merging, with your provided values taking precedence. <tip> This is particularly useful for modules that need to inject global meta tags, stylesheets, or scripts into the application head. </tip> ### Type ```tstwoslash // @errors: 2391 // ---cut--- import type { SerializableHead } from '@unhead/vue/types' interface AppHeadMetaObject extends SerializableHead { charset?: string viewport?: string } function setGlobalHead (head: AppHeadMetaObject): void ``` ### Parameters #### `head` **Type**: `AppHeadMetaObject` An object containing head configuration. All properties are optional and will be merged with existing configuration: - `charset`: Character encoding for the document - `viewport`: Viewport meta tag configuration - `meta`: Array of meta tag objects - `link`: Array of link tag objects (stylesheets, icons, etc.) - `style`: Array of inline style tag objects - `script`: Array of script tag objects - `noscript`: Array of noscript tag objects - `title`: Default page title - `titleTemplate`: Template for formatting page titles - `bodyAttrs`: Attributes to add to the `<body>` tag - `htmlAttrs`: Attributes to add to the `<html>` tag ### Example #### Adding Global Meta Tags ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ meta: [ { name: 'theme-color', content: '#ffffff' }, { name: 'author', content: 'Your Name' }, ], }) }, }) ``` #### Injecting Global Stylesheets ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ link: [ { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap', }, ], }) }, }) ``` #### Adding Global Scripts ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ script: [ { src: 'https://cdn.example.com/analytics.js', async: true, defer: true, }, ], }) }, }) ``` #### Setting HTML Attributes ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ htmlAttrs: { lang: 'en', dir: 'ltr', }, bodyAttrs: { class: 'custom-body-class', }, }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/head.ts) # Layers > Nuxt Kit provides utilities to help you work with layers and their directory structures. Nuxt layers provide a powerful way to share and extend functionality across projects. When working with layers in modules, you often need to access directory paths from each layer. Nuxt Kit provides the `getLayerDirectories` utility to access resolved directory paths for all layers in your Nuxt application. ## `getLayerDirectories` Get the resolved directory paths for all layers in a Nuxt application. This function provides a structured way to access layer directories without directly accessing the private `nuxt.options._layers` property. ### Usage ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Access directories from all layers for (const [index, layer] of layerDirs.entries()) { console.log(`Layer ${index}:`) console.log(` Root: ${layer.root}`) console.log(` App: ${layer.app}`) console.log(` Server: ${layer.server}`) console.log(` Pages: ${layer.appPages}`) // ... other directories } }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function getLayerDirectories (nuxt?: Nuxt): LayerDirectories[] interface LayerDirectories { /** Nuxt rootDir (`/` by default) */ readonly root: string /** Nitro source directory (`/server` by default) */ readonly server: string /** Local modules directory (`/modules` by default) */ readonly modules: string /** Shared directory (`/shared` by default) */ readonly shared: string /** Public directory (`/public` by default) */ readonly public: string /** Nuxt srcDir (`/app/` by default) */ readonly app: string /** Layouts directory (`/app/layouts` by default) */ readonly appLayouts: string /** Middleware directory (`/app/middleware` by default) */ readonly appMiddleware: string /** Pages directory (`/app/pages` by default) */ readonly appPages: string /** Plugins directory (`/app/plugins` by default) */ readonly appPlugins: string } ``` ### Parameters **nuxt** (optional): The Nuxt instance to get layers from. If not provided, the function will use the current Nuxt context. ### Return Value The `getLayerDirectories` function returns an array of `LayerDirectories` objects, one for each layer in the application. **Layer Priority Ordering**: The layers are ordered by priority, where: - The **first layer** is the user/project layer (highest priority) - **Earlier layers override later layers** in the array - **Base layers appear last** in the array (lowest priority) This ordering matches Nuxt's layer resolution system, where user-defined configurations and files take precedence over those from base layers. **LayerDirectories**: An object containing the resolved directory paths for a layer. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> root </code> </td> <td> <code> string </code> </td> <td> The root directory of the layer (equivalent to <code> rootDir </code> ) </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> string </code> </td> <td> The server directory for Nitro server-side code </td> </tr> <tr> <td> <code> modules </code> </td> <td> <code> string </code> </td> <td> The local modules directory </td> </tr> <tr> <td> <code> shared </code> </td> <td> <code> string </code> </td> <td> The shared directory for code used by both client and server </td> </tr> <tr> <td> <code> app </code> </td> <td> <code> string </code> </td> <td> The source directory of the layer (equivalent to <code> srcDir </code> ) </td> </tr> <tr> <td> <code> public </code> </td> <td> <code> string </code> </td> <td> The public directory for static assets </td> </tr> <tr> <td> <code> appLayouts </code> </td> <td> <code> string </code> </td> <td> The layouts directory for Vue layout components </td> </tr> <tr> <td> <code> appMiddleware </code> </td> <td> <code> string </code> </td> <td> The middleware directory for route middleware </td> </tr> <tr> <td> <code> appPages </code> </td> <td> <code> string </code> </td> <td> The pages directory for file-based routing </td> </tr> <tr> <td> <code> appPlugins </code> </td> <td> <code> string </code> </td> <td> The plugins directory for Nuxt plugins </td> </tr> </tbody> </table> ### Example **Processing files from all layers:** ```tstwoslash // @errors: 2307 // ---cut--- import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { resolve } from 'pathe' import { globby } from 'globby' export default defineNuxtModule({ async setup () { const layerDirs = getLayerDirectories() // Find all component files across layers // Note: layerDirs[0] is the user layer (highest priority) // Later layers in the array have lower priority const componentFiles = [] for (const [index, layer] of layerDirs.entries()) { const files = await globby('**/*.vue', { cwd: resolve(layer.app, 'components'), absolute: true, }) console.log(`Layer ${index} (${index === 0 ? 'user' : 'base'}):`, files.length, 'components') componentFiles.push(...files) } }, }) ``` **Adding templates from multiple layers:** ```tstwoslash import { addTemplate, defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { basename, resolve } from 'pathe' import { existsSync } from 'node:fs' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Add a config file from each layer that has one for (const dirs of layerDirs) { const configPath = resolve(dirs.app, 'my-module.config.ts') if (existsSync(configPath)) { addTemplate({ filename: `my-module-${basename(dirs.root)}.config.ts`, src: configPath, }) } } }, }) ``` **Respecting layer priority:** ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { resolve } from 'pathe' import { existsSync, readFileSync } from 'node:fs' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Find the first (highest priority) layer that has a specific config file // This respects the layer priority system let configContent = null for (const dirs of layerDirs) { const configPath = resolve(dirs.app, 'my-config.json') if (existsSync(configPath)) { configContent = readFileSync(configPath, 'utf-8') console.log(`Using config from layer: ${dirs.root}`) break // Use the first (highest priority) config found } } // Alternative: Collect configs from all layers, with user layer taking precedence const allConfigs = {} for (const dirs of layerDirs.reverse()) { // Process from lowest to highest priority const configPath = resolve(dirs.app, 'my-config.json') if (existsSync(configPath)) { const config = JSON.parse(readFileSync(configPath, 'utf-8')) Object.assign(allConfigs, config) // Later assignments override earlier ones } } }, }) ``` **Checking for layer-specific directories:** ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { existsSync } from 'node:fs' import { resolve } from 'pathe' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Find layers that have a specific custom directory const layersWithAssets = layerDirs.filter((layer) => { return existsSync(resolve(layer.app, 'assets')) }) console.log(`Found ${layersWithAssets.length} layers with assets directory`) }, }) ``` <note> The `getLayerDirectories` function includes caching via a WeakMap to avoid recomputing directory paths for the same layers repeatedly, improving performance when called multiple times. </note> <note> Directory paths returned by this function always include a trailing slash for consistency. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/layers.ts) # Layout > Nuxt Kit provides a set of utilities to help you work with layouts. Layouts is used to be a wrapper around your pages. It can be used to wrap your pages with common components, for example, a header and a footer. Layouts can be registered using `addLayout` utility. ## `addLayout` Register template as layout and add it to the layouts. <note> In Nuxt 2 `error` layout can also be registered using this utility. In Nuxt 3+ `error` layout [replaced](https://nuxt.com/docs/5.x/getting-started/error-handling#error-page) with `error.vue` page in project root. </note> ### Usage ```tstwoslash import { addLayout, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addLayout({ src: resolve('templates/custom-layout.ts'), filename: 'custom-layout.ts', }, 'custom') }, }) ``` ### Type ```ts function addLayout (layout: NuxtTemplate | string, name: string): void ``` ### Parameters **layout**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> </tbody> </table> **name**: The name to register the layout under (e.g., `default`, `custom`, etc.). ### Example This will register a layout named `custom` that wraps pages with a header and footer. ```tstwoslash import { addLayout, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addLayout({ write: true, filename: 'my-layout.vue', getContents: () => `<template> <div> <header>My Header</header> <slot /> <footer>My Footer</footer> </div> </template>`, }, 'custom') }, }) ``` You can then use this layout in your pages: ```vue [app/pages/about.vue] <script setup lang="ts"> definePageMeta({ layout: 'custom', }) </script> <template> <div>About Page</div> </template> ``` <warning> Due to the lack of support for virtual `.vue` files by `@vitejs/plugin-vue`, you can work around this limitation by passing `write: true` to the first argument of `addLayout`. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/layout.ts) # Logging > Nuxt Kit provides a set of utilities to help you work with logging. These functions allow you to log messages with extra features. Nuxt provides a logger instance that you can use to log messages with extra features. `useLogger` allows you to get a logger instance. ## `useLogger` Returns a logger instance. It uses [consola](https://github.com/unjs/consola) under the hood. ### Usage ```tstwoslash import { defineNuxtModule, useLogger } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const logger = useLogger('my-module') logger.info('Hello from my module!') }, }) ``` ### Type ```ts function useLogger (tag?: string, options?: NuxtLoggerOptions): NuxtLogger ``` ### Parameters **tag**: A tag to suffix all log messages with, displayed on the right near the timestamp. **options**: Logger options, such as `level`, `reporters`, `defaults` and `formatOptions`. ### Example ```tstwoslash import { defineNuxtModule, useLogger } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const logger = useLogger('my-module', { level: options.quiet ? 0 : 3 }) logger.info('Hello from my module!') }, }) ``` ## `useTerminal` Returns a set of primitives for interacting with the user's terminal. When Nuxt is running inside an interactive host such as the `nuxt dev` terminal UI, prompts, tasks and notifications are handed to it, so they are answerable and rendered in one place. Otherwise they fall back to logging. ### Usage ```tstwoslash declare function runPackageInstall (name: string): Promise<void> // ---cut--- import { defineNuxtModule, useTerminal } from '@nuxt/kit' export default defineNuxtModule({ async setup () { const terminal = useTerminal() const install = await terminal.prompt('Do you want to install `my-module`?', { type: 'confirm' }) if (!install) { return } const task = terminal.startTask('Installing `my-module`...') // run your actual task await runPackageInstall('my-module') task.stop('Installed `my-module`') }, }) ``` ### Type ```ts function useTerminal (): NuxtTerminal interface NuxtTerminal { readonly interactive: boolean withTerminal: <T>(work: () => Promise<T>) => Promise<T> prompt: (message: string, options?: NuxtPromptOptions) => Promise<any> startTask: (label: string) => NuxtTerminalTask notify: (notification: NuxtTerminalNotification) => NuxtTerminalNotice } ``` ### Properties **interactive**: Whether an interactive host is present. When `false`, the primitives below log to the current process streams instead. **withTerminal**: Borrows the terminal for the duration of `work`, suspending any host UI and releasing `stdin`. Use it when you need to write to the terminal or read from `stdin` directly. Concurrent callers are serialised, and a nested call from within a borrow runs immediately. **prompt**: Asks the user a question, borrowing the terminal for as long as the prompt is open. Takes the same options as `logger.prompt`. **startTask**: Starts a long-running task, rendered on the host's status surface where available. Finish it with `task.stop(message?, outcome?)`, or change its label with `task.update(label)`. **notify**: Shows a message and holds it on screen until the user acknowledges it or `notice.dismiss()` is called. `notice.dismissed` settles once the notice is gone. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/logger.ts) # Modules > Nuxt Kit provides a set of utilities to help you create and use modules. You can use these utilities to create your own modules or to reuse existing modules. Modules are the building blocks of Nuxt. Kit provides a set of utilities to help you create and use modules. You can use these utilities to create your own modules or to reuse existing modules. For example, you can use the `defineNuxtModule` function to define a module and specify dependencies using the `moduleDependencies` option. ## `defineNuxtModule` Define a Nuxt module, automatically merging defaults with user provided options, installing any hooks that are provided, and calling an optional setup function for full control. ### Usage ```tstwoslash import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, defaults: { enabled: true, }, setup (options) { if (options.enabled) { console.log('My Nuxt module is enabled!') } }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { ModuleDefinition, ModuleOptions, NuxtModule } from '@nuxt/schema' // ---cut--- export function defineNuxtModule<TOptions extends ModuleOptions> ( definition?: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>, ): NuxtModule<TOptions, TOptions, false> export function defineNuxtModule<TOptions extends ModuleOptions> (): { with: <TOptionsDefaults extends Partial<TOptions>> ( definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>, ) => NuxtModule<TOptions, TOptionsDefaults, true> } ``` ### Parameters **definition**: A module definition object or a module function. The module definition object should contain the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> meta </code> </td> <td> <code> ModuleMeta </code> </td> <td> <code> false </code> </td> <td> Metadata of the module. It defines the module name, version, config key and compatibility. </td> </tr> <tr> <td> <code> defaults </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> T </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> T) </span> </code> </td> <td> <code> false </code> </td> <td> Default options for the module. If a function is provided, it will be called with the Nuxt instance as the first argument. </td> </tr> <tr> <td> <code> schema </code> </td> <td> <code> T </code> </td> <td> <code> false </code> </td> <td> Schema for the module options. If provided, options will be applied to the schema. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Partial </span> <span class="sDfIl"> < </span> <span class="sZSNi"> NuxtHooks </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Hooks to be installed for the module. If provided, the module will install the hooks. </td> </tr> <tr> <td> <code> moduleDependencies </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> ModuleDependency </span> <span class="sDfIl"> > </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> ModuleDependency </span> <span class="sDfIl"> > </span> <span class="sZSNi"> ) </span> </code> </td> <td> <code> false </code> </td> <td> Dependencies on other modules with version constraints and configuration. Can be an object or a function that receives the Nuxt instance. See <a href="https://nuxt.com/docs/5.x/api/kit/modules#specifying-module-dependencies"> example </a> . </td> </tr> <tr> <td> <code> onInstall </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void> </span> </code> </td> <td> <code> false </code> </td> <td> Lifecycle hook called when the module is first installed. Requires <code> meta.name </code> and <code> meta.version </code> to be defined. </td> </tr> <tr> <td> <code> onUpgrade </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> , </span> <span class="s1nJG"> options </span> <span class="sDfIl"> : </span> <span class="s52Pk"> T </span> <span class="sDfIl"> , </span> <span class="s1nJG"> previousVersion </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void> </span> </code> </td> <td> <code> false </code> </td> <td> Lifecycle hook called when the module is upgraded to a newer version. Requires <code> meta.name </code> and <code> meta.version </code> to be defined. </td> </tr> <tr> <td> <code> setup </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s8R28"> this </span> <span class="sDfIl"> : </span> <span class="s52Pk"> void </span> <span class="sDfIl"> , </span> <span class="s1nJG"> resolvedOptions </span> <span class="sDfIl"> : </span> <span class="s52Pk"> T </span> <span class="sDfIl"> , </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void </span> <span class="sDfIl"> | </span> <span class="sbKd-"> false </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ModuleSetupInstallResult </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Setup function for the module. If provided, the module will call the setup function. </td> </tr> </tbody> </table> ### Example #### Using `configKey` to Make Your Module Configurable When defining a Nuxt module, you can set a `configKey` to specify how users should configure the module in their `nuxt.config`. ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, defaults: { // Module options enabled: true, }, setup (options) { if (options.enabled) { console.log('My Nuxt module is enabled!') } }, }) ``` Users can provide options for this module under the corresponding key in `nuxt.config`. ```ts export default defineNuxtConfig({ myModule: { enabled: false, }, }) ``` Users can also completely disable a module by setting the config key to `false`. This prevents the module's setup function from running while still generating types for module options. ```ts export default defineNuxtConfig({ // Disable the module entirely myModule: false, }) ``` <tip> This is particularly useful when you want to disable modules inherited from [Nuxt layers](https://nuxt.com/docs/5.x/guide/going-further/layers#disabling-modules-from-layers). </tip> #### Defining Module Compatibility Requirements If you're developing a Nuxt module and using APIs that are only supported in specific Nuxt versions, it's highly recommended to include `compatibility.nuxt`. ```ts export default defineNuxtModule({ meta: { name: '@nuxt/icon', configKey: 'icon', compatibility: { // Required nuxt version in semver format. nuxt: '>=3.0.0', // or use '^3.0.0' }, }, setup () { const resolver = createResolver(import.meta.url) // Implement }, }) ``` If the user tries to use your module with an incompatible Nuxt version, they will receive a warning in the console. ```terminal WARN Module @nuxt/icon is disabled due to incompatibility issues: - [nuxt] Nuxt version ^3.1.0 is required but currently using 3.0.0 ``` #### Type Safety for Resolved Options with `.with()` When you need type safety for your resolved/merged module options, you can use the `.with()` method. This enables TypeScript to properly infer the relationship between your module's defaults and the final resolved options that your setup function receives. ```ts import { defineNuxtModule } from '@nuxt/kit' // Define your module options interface interface ModuleOptions { apiKey: string baseURL: string timeout?: number retries?: number } export default defineNuxtModule<ModuleOptions>().with({ meta: { name: '@nuxtjs/my-api', configKey: 'myApi', }, defaults: { baseURL: 'https://api.example.com', timeout: 5000, retries: 3, }, setup (resolvedOptions, nuxt) { // resolvedOptions is properly typed as: // { // apiKey: string // Required, no default provided // baseURL: string // Required, has default value // timeout: number // Optional, has default value // retries: number // Optional, has default value // } console.log(resolvedOptions.baseURL) // โœ… TypeScript knows this is always defined console.log(resolvedOptions.timeout) // โœ… TypeScript knows this is always defined console.log(resolvedOptions.retries) // โœ… TypeScript knows this is always defined }, }) ``` Without using `.with()`, the `resolvedOptions` parameter would be typed as the raw `ModuleOptions` interface, where `timeout` and `retries` could be `undefined` even when defaults are provided. The `.with()` method enables TypeScript to understand that default values make those properties non-optional in the resolved options. #### Using Lifecycle Hooks for Module Installation and Upgrade You can define lifecycle hooks that run when your module is first installed or upgraded to a new version. These hooks are useful for performing one-time setup tasks, database migrations, or cleanup operations. <important> For lifecycle hooks to work, you **must** provide both `meta.name` and `meta.version` in your module definition. The hooks use these values to track the module's installation state in the project's `.nuxtrc` file. </important> Lifecycle hooks run before the main `setup` function, and if a hook throws an error, it's logged but doesn't stop the build process. **onInstall** runs only once when the module is first added to a project. **onUpgrade** runs each time the module version increases (using semver comparison) โ€” but only once for each version bump. ##### Example ```ts import { defineNuxtModule } from '@nuxt/kit' import { isLess } from 'verkit' export default defineNuxtModule({ meta: { name: 'my-awesome-module', version: '1.2.0', // Required for lifecycle hooks configKey: 'myAwesomeModule', }, defaults: { apiKey: '', enabled: true, }, onInstall (nuxt) { // This runs only when the module is first installed console.log('Setting up my-awesome-module for the first time!') // You might want to: // - Create initial configuration files // - Set up database schemas // - Display welcome messages // - Perform initial data migration }, onUpgrade (nuxt, options, previousVersion) { // This runs when the module is upgraded to a newer version console.log(`Upgrading my-awesome-module from ${previousVersion} to 1.2.0`) // You might want to: // - Migrate configuration files // - Update database schemas // - Clean up deprecated files // - Display upgrade notes if (isLess(previousVersion, '1.1.0')) { console.log('โš ๏ธ Breaking changes in 1.1.0 - please check the migration guide') } }, setup (options, nuxt) { // Regular setup logic runs on every build if (options.enabled) { // Configure the module } }, }) ``` #### Specifying Module Dependencies You can use the `moduleDependencies` option to declare dependencies on other modules. This provides a robust way to ensure proper setup order, version compatibility, and configuration management. The `moduleDependencies` option can be either an object or a function that receives the Nuxt instance: ##### Example ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', }, moduleDependencies: { '@nuxtjs/tailwindcss': { // Specify a version constraint (semver format) version: '>=6.0.0', // Configuration that overrides user settings overrides: { exposeConfig: true, }, // Configuration that sets defaults but respects user settings defaults: { config: { darkMode: 'class', }, }, }, '@nuxtjs/fontaine': { // Optional dependencies won't be installed but ensure that options // can be set if they _are_ installed optional: true, defaults: { fonts: [ { family: 'Roboto', fallbacks: ['Impact'], }, ], }, }, }, setup (options, nuxt) { }, }) ``` You can also use a function to dynamically determine dependencies based on the Nuxt configuration: ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', }, moduleDependencies (nuxt) { const dependencies: Record<string, any> = { '@nuxtjs/tailwindcss': { version: '>=6.0.0', }, } // Conditionally add dependencies based on Nuxt config if (nuxt.options.experimental?.someFeature) { dependencies['@nuxtjs/fontaine'] = { optional: true, } } return dependencies }, setup (options, nuxt) { // Your setup logic runs after all dependencies are initialized }, }) ``` ## `installModule` <callout type="warning"> **Deprecated:** Use the [`moduleDependencies`](https://nuxt.com/docs/5.x/api/kit/modules#specifying-module-dependencies) option in `defineNuxtModule` instead. The `installModule` function will be removed (or may become non-blocking) in a future version. </callout> Install specified Nuxt module programmatically. This is helpful when your module depends on other modules. You can pass the module options as an object to `inlineOptions` and they will be passed to the module's `setup` function. ### Usage ```tstwoslash import { defineNuxtModule, installModule } from '@nuxt/kit' export default defineNuxtModule({ async setup () { // will install @nuxtjs/fontaine with Roboto font and Impact fallback await installModule('@nuxtjs/fontaine', { // module configuration fonts: [ { family: 'Roboto', fallbacks: ['Impact'], fallbackName: 'fallback-a', }, ], }) }, }) ``` ### Type ```ts async function installModule (moduleToInstall: string | NuxtModule, inlineOptions?: any, nuxt?: Nuxt) ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> moduleToInstall </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> NuxtModule </span> </code> </td> <td> <code> true </code> </td> <td> The module to install. Can be either a string with the module name or a module object itself. </td> </tr> <tr> <td> <code> inlineOptions </code> </td> <td> <code> any </code> </td> <td> <code> false </code> </td> <td> An object with the module options to be passed to the module's <code> setup </code> function. </td> </tr> <tr> <td> <code> nuxt </code> </td> <td> <code> Nuxt </code> </td> <td> <code> false </code> </td> <td> Nuxt instance. If not provided, it will be retrieved from the context via <code> useNuxt() </code> call. </td> </tr> </tbody> </table> ### Example ```ts import { defineNuxtModule, installModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (options, nuxt) { // will install @nuxtjs/fontaine with Roboto font and Impact fallback await installModule('@nuxtjs/fontaine', { // module configuration fonts: [ { family: 'Roboto', fallbacks: ['Impact'], fallbackName: 'fallback-a', }, ], }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/tree/main/packages/kit/src/module) # Nitro > Nuxt Kit provides a set of utilities to help you work with Nitro. These functions allow you to add server handlers, plugins, and prerender routes. Nitro is an open source TypeScript framework to build ultra-fast web servers. Nuxt uses Nitro as its server engine. You can use `useNitro` to access the Nitro instance (or `tryUseNitro` if your module should also work without Nitro), `addServerHandler` to add a server handler, `addDevServerHandler` to add a server handler to be used only in development mode, `addNitroPlugin` to add a plugin to extend Nitro's runtime behavior, and `addPrerenderRoutes` to add routes to be prerendered by Nitro. ## `addServerHandler` Adds a Nitro server handler. Use this if you want to create server middleware or a custom route. ### Usage ```tstwoslash import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) addServerHandler({ route: '/robots.txt', handler: resolve('./runtime/robots.get'), }) }, }) ``` ### Type ```ts function addServerHandler (handler: ServerHandlerInput): void ``` ### Parameters **handler**: A handler object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> handler </code> </td> <td> <code> string | { nuxt?: string, nitro2?: string, nitro3?: string } </code> </td> <td> <code> true </code> </td> <td> Path to the event handler, or one path per server API. Nuxt registers the implementation the application's server can run. </td> </tr> <tr> <td> <code> route </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The route to match, exactly. End it in <code> /** </code> to match the paths below it as well. If an empty string is used, the handler is registered as middleware. </td> </tr> <tr> <td> <code> middleware </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Specifies this is a middleware handler. Middleware are called on every route and should normally return nothing to pass to the next handlers. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Use lazy loading to import the handler. This is useful when you only want to load the handler on demand. </td> </tr> <tr> <td> <code> method </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Router method matcher. If handler name contains method name, it will be used as a default value. </td> </tr> </tbody> </table> A route ending in `/**` matches its base path too, so `route: '/_fonts/**'` serves `/_fonts` and everything below it. On a Nitro 2 host, whose router matches only the paths below the base, Nuxt registers the base path as a second route so that one registration behaves the same on both. <read-more to="https://nuxt.com/docs/5.x/guide/modules/server-compatibility"> Learn when to register one path per server API, and which key to write your handler against. </read-more> ### Example #### Basic Usage You can use `addServerHandler` to add a server handler from your module. <code-group> ```ts [module.ts]twoslash import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) addServerHandler({ route: '/robots.txt', handler: resolve('./runtime/robots.get'), }) }, }) ``` ```ts [runtime/robots.get.ts]twoslash import { defineEventHandler } from 'nitro/h3' export default defineEventHandler(() => { return { body: `User-agent: *\nDisallow: /`, } }) ``` </code-group> When you access `/robots.txt`, it will return the following response: ```txt User-agent: * Disallow: / ``` ## `addDevServerHandler` Adds a Nitro server handler to be used only in development mode. This handler will be excluded from production build. ### Usage ```tstwoslash import { defineEventHandler } from 'nitro/h3' import { addDevServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addDevServerHandler({ handler: defineEventHandler(() => { return { body: `Response generated at ${new Date().toISOString()}`, } }), route: '/_handler', }) }, }) ``` ### Type ```ts function addDevServerHandler (handler: DevServerHandlerInput): void ``` ### Parameters **handler**: A handler object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> handler </code> </td> <td> <code> EventHandler </code> </td> <td> <code> true </code> </td> <td> Event handler. </td> </tr> <tr> <td> <code> route </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path prefix or route. If an empty string used, will be used as a middleware. </td> </tr> </tbody> </table> ### Example #### Basic Usage In some cases, you may want to create a server handler specifically for development purposes, such as a Tailwind config viewer. ```ts import { joinURL } from 'ufo' import { addDevServerHandler, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (options, nuxt) { const route = joinURL(nuxt.options.app?.baseURL, '/_tailwind') // @ts-expect-error - tailwind-config-viewer does not have correct types const createServer = await import('tailwind-config-viewer/server/index.js').then(r => r.default || r) as any const viewerDevMiddleware = createServer({ tailwindConfigProvider: () => options, routerPrefix: route }).asMiddleware() addDevServerHandler({ route, handler: viewerDevMiddleware }) }, }) ``` ## `useNitro` Returns the Nitro instance. <warning> You can call `useNitro()` only after `ready` hook. </warning> <note> Changes to the Nitro instance configuration are not applied. </note> ### Usage ```ts import { defineNuxtModule, useNitro } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const resolver = createResolver(import.meta.url) nuxt.hook('ready', () => { const nitro = useNitro() // Do something with Nitro instance }) }, }) ``` ### Type ```ts function useNitro (): Nitro ``` ## `tryUseNitro` Returns the Nitro instance, or `undefined` when there is none. There is no Nitro instance before the `ready` hook has run, and none at all when the configured [`server.builder`](https://nuxt.com/docs/5.x/api/nuxt-config#builder-1) does not use Nitro, such as a builder that outputs a client-only SPA. Use this rather than `useNitro()` for anything that should keep working without a server: server routes, route rules and prerendering are all absent in that case. ### Usage ```ts import { defineNuxtModule, tryUseNitro } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { nuxt.hook('ready', () => { const nitro = tryUseNitro() if (!nitro) { // no server: skip anything that would only run there return } }) }, }) ``` ### Type ```ts function tryUseNitro (): Nitro | undefined ``` ## `addNitroPlugin` Add plugin to extend Nitro's runtime behavior. <note> This was named `addServerPlugin` before Nuxt v4.6. </note> <tip> You can read more about Nitro plugins in the [Nitro documentation](https://nitro.build/guide/plugins). </tip> <warning> It is necessary to explicitly import `definePlugin` from `nitro` within your plugin file. The same requirement applies to utilities such as `useRuntimeConfig`. </warning> ### Usage ```tstwoslash import { addNitroPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addNitroPlugin(resolve('./runtime/plugin.ts')) }, }) ``` ### Type ```ts function addNitroPlugin (plugin: string | { nitro2?: string, nitro3?: string }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> plugin </code> </td> <td> <code> string | { nitro2?: string, nitro3?: string } </code> </td> <td> <code> true </code> </td> <td> Path to the plugin, or one path per nitro major for a module shipping an implementation for each. The plugin must export a default function that accepts the Nitro instance as an argument. </td> </tr> </tbody> </table> ### Example <code-group> ```ts [module.ts] import { addNitroPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addNitroPlugin(resolve('./runtime/plugin.ts')) }, }) ``` ```ts [runtime/plugin.ts] import { definePlugin } from 'nitro' export default definePlugin((nitroApp) => { nitroApp.hooks.hook('request', (event) => { console.log('on request', event.req.url) }) nitroApp.hooks.hook('response', async (res) => { console.log('on response', await res.text()) }) }) ``` </code-group> ## `addPrerenderRoutes` Add routes to be prerendered to Nitro. ### Usage ```ts import { addPrerenderRoutes, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'nuxt-sitemap', configKey: 'sitemap', }, defaults: { sitemapUrl: '/sitemap.xml', prerender: true, }, setup (options) { if (options.prerender) { addPrerenderRoutes(options.sitemapUrl) } }, }) ``` ### Type ```ts function addPrerenderRoutes (routes: string | string[]): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> routes </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A route or an array of routes to prerender. </td> </tr> </tbody> </table> ## `addServerImports` Add imports to the server. It makes your imports available in Nitro without the need to import them manually. <warning> If you want to provide a utility that works in both server and client contexts and is usable in the [`shared/`](https://nuxt.com/docs/5.x/directory-structure/shared) directory, the function must be imported from the same source file for both [`addImports`](https://nuxt.com/docs/5.x/api/kit/autoimports#addimports) and `addServerImports` and should have identical signature. That source file should not import anything context-specific (i.e., Nitro context, Nuxt app context) or else it might cause errors during type-checking. </warning> ### Usage ```tstwoslash import { addServerImports, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const names = [ 'useStoryblok', 'useStoryblokApi', 'useStoryblokBridge', 'renderRichText', 'RichTextSchema', ] names.forEach(name => addServerImports({ name, as: name, from: '@storyblok/vue' }), ) }, }) ``` ### Type ```ts function addServerImports (dirs: NuxtImport | NuxtImport[]): void ``` ### Parameters `imports`: An object or an array of objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Import name to be detected. </td> </tr> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the import; if multiple imports have the same name, the one with the highest priority will be used. </td> </tr> <tr> <td> <code> disabled </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is disabled. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Record<string, any> </code> </td> <td> <code> false </code> </td> <td> Metadata of the import. </td> </tr> <tr> <td> <code> type </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is a pure type import. </td> </tr> <tr> <td> <code> typeFrom </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Use this as the <code> from </code> value when generating type declarations. </td> </tr> <tr> <td> <code> as </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Import as this name. </td> </tr> </tbody> </table> ## `addServerImportsDir` Add a directory to be scanned for auto-imports by Nitro. ### Usage ```tstwoslash import { addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerImportsDir(resolve('./runtime/server/composables')) }, }) ``` ### Type ```ts function addServerImportsDir (dirs: string | string[], opts: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A directory or an array of directories to register to be scanned by Nitro. </td> </tr> <tr> <td> <code> opts </code> </td> <td> <code> { prepend?: boolean } </code> </td> <td> <code> false </code> </td> <td> Options for the import directory. If <code> prepend </code> is <code> true </code> , the directory is added to the beginning of the scan list. </td> </tr> </tbody> </table> ### Example You can use `addServerImportsDir` to add a directory to be scanned by Nitro. This is useful when you want Nitro to auto-import functions from a custom server directory. <code-group> ```ts [module.ts]twoslash import { addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerImportsDir(resolve('./runtime/server/composables')) }, }) ``` ```ts [runtime/server/composables/index.ts]twoslash export function useApiSecret () { const { apiSecret } = useRuntimeConfig() return apiSecret } ``` </code-group> You can then use the `useApiSecret` function in your server code: ```ts [runtime/server/api/hello.ts]twoslash import { defineEventHandler } from 'nitro/h3' const useApiSecret = (): string => '' // ---cut--- export default defineEventHandler(() => { const apiSecret = useApiSecret() // Do something with the apiSecret }) ``` ## `addServerScanDir` Add directories to be scanned by Nitro. It will check for subdirectories, which will be registered just like the `~~/server` folder is. <note> Only `~~/server/api`, `~~/server/routes`, `~~/server/middleware`, and `~~/server/utils` are scanned. </note> ### Usage ```tstwoslash import { addServerScanDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerScanDir(resolve('./runtime/server')) }, }) ``` ### Type ```ts function addServerScanDir (dirs: string | string[], opts: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A directory or an array of directories to register to be scanned for by Nitro as server dirs. </td> </tr> <tr> <td> <code> opts </code> </td> <td> <code> { prepend?: boolean } </code> </td> <td> <code> false </code> </td> <td> Options for the import directory. If <code> prepend </code> is <code> true </code> , the directory is added to the beginning of the scan list. </td> </tr> </tbody> </table> ### Example You can use `addServerScanDir` to add a directory to be scanned by Nitro. This is useful when you want to add a custom server directory. <code-group> ```ts [module.ts]twoslash import { addServerScanDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerScanDir(resolve('./runtime/server')) }, }) ``` ```ts [runtime/server/utils/index.ts]twoslash export function hello () { return 'Hello from server utils!' } ``` </code-group> You can then use the `hello` function in your server code. ```ts [runtime/server/api/hello.ts]twoslash import { defineEventHandler } from 'nitro/h3' function hello () { return 'Hello from server utils!' } // ---cut--- export default defineEventHandler(() => { return hello() // Hello from server utils! }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/nitro.ts) # Pages > Nuxt Kit provides a set of utilities to help you create and use pages. You can use these utilities to manipulate the pages configuration or to define route rules. ## `extendPages` In Nuxt, routes are automatically generated based on the structure of the files in the `app/pages` directory. However, there may be scenarios where you'd want to customize these routes. For instance, you might need to add a route for a dynamic page not generated by Nuxt, remove an existing route, or modify the configuration of a route. For such customizations, Nuxt offers the `extendPages` feature, which allows you to extend and alter the pages configuration. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/extend-and-alter-nuxt-pages?friend=nuxt"> Watch Vue School video about extendPages. </tip> ### Usage ```tstwoslash import { createResolver, defineNuxtModule, extendPages } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) extendPages((pages) => { pages.unshift({ name: 'prismic-preview', path: '/preview', file: resolve('runtime/preview.vue'), }) }) }, }) ``` ### Type ```ts function extendPages (callback: (pages: NuxtPage[]) => void): void ``` ### Parameters **callback**: A function that will be called with the pages configuration. You can alter this array by adding, deleting, or modifying its elements. Note: You should modify the provided pages array directly, as changes made to a copied array will not be reflected in the configuration. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The name of the route. Useful for programmatic navigation and identifying routes. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The route URL path. If not set, Nuxt will infer it from the file location. </td> </tr> <tr> <td> <code> file </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the Vue file that should be used as the component for the route. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> NuxtPageMeta </span> </code> </td> <td> <code> false </code> </td> <td> Custom metadata for the route. Can be used in layouts, middlewares, or navigation guards. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string[] </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string </span> </code> </td> <td> <code> false </code> </td> <td> One or more alias paths for the route. Useful for supporting multiple URLs. </td> </tr> <tr> <td> <code> redirect </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> RouteLocationRaw </span> </code> </td> <td> <code> false </code> </td> <td> Redirect rule for the route. Supports named routes, objects, or string paths. </td> </tr> <tr> <td> <code> children </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> NuxtPage[] </span> </code> </td> <td> <code> false </code> </td> <td> Nested child routes under this route for layout or view nesting. </td> </tr> </tbody> </table> ### Typing Custom Page Metadata You can augment the `NuxtPageMeta` interface to add type-safe custom metadata for pages when using `extendPages` or the `pages:extend` hook: ```ts [index.d.ts] declare module '@nuxt/schema' { interface NuxtPageMeta { requiresAuth?: boolean } } export {} ``` ```ts [modules/auth.ts] import { defineNuxtModule, extendPages } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendPages((pages) => { for (const page of pages) { // requiresAuth is now typed as boolean | undefined if (page.meta?.requiresAuth) { // ... } } }) }, }) ``` ## `extendRouteRules` Nuxt is powered by the [Nitro](https://nitro.build/) server engine. With Nitro, you can incorporate high-level logic directly into your configuration, which is useful for actions like redirects, proxying, caching, and appending headers to routes. This configuration works by associating route patterns with specific route settings. <tip> You can read more about Nitro route rules in the [Nitro documentation](https://nitro.build/guide/routing#route-rules). </tip> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/adding-route-rules-and-route-middlewares?friend=nuxt"> Watch Vue School video about adding route rules and route middlewares. </tip> ### Usage ```tstwoslash import { createResolver, defineNuxtModule, extendPages, extendRouteRules } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) extendPages((pages) => { pages.unshift({ name: 'preview-new', path: '/preview-new', file: resolve('runtime/preview.vue'), }) }) extendRouteRules('/preview', { redirect: { to: '/preview-new', status: 302, }, }) extendRouteRules('/preview-new', { cache: { maxAge: 60 * 60 * 24 * 7, }, }) }, }) ``` ### Type ```ts function extendRouteRules (route: string, rule: NitroRouteConfig, options?: ExtendRouteRulesOptions): void ``` ### Parameters **route**: A route pattern to match against.<br /> **rule**: A route rule configuration to apply to the matched route. `NitroRouteConfig` is a union of `NitroRouteConfigV2` and `NitroRouteConfigV3`, so a rule has to be valid for one Nitro major as a whole. A few rules differ between them: Nitro v3 takes `redirect: { status }` where v2 takes `redirect: { statusCode }`, and v3 additionally accepts CORS options on `cors` and `false` on `redirect`/`proxy` to reset an inherited rule. <tip> About route rules configurations, you can get more detail in [Hybrid Rendering > Route Rules](https://nuxt.com/docs/5.x/guide/concepts/rendering#route-rules). </tip> **options**: An object to pass to the route configuration. If `override` is set to `true`, it will override the existing route configuration. <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> override </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Override route rule config, default is false </td> </tr> </tbody> </table> ## `addRouteMiddleware` Registers route middlewares to be available for all routes or for specific routes. Route middlewares can be also defined in plugins via [`addRouteMiddleware`](https://nuxt.com/docs/5.x/api/utils/add-route-middleware) composable. <tip> Read more about route middlewares in the [Route middleware documentation](https://nuxt.com/docs/5.x/getting-started/routing#route-middleware). </tip> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/adding-route-rules-and-route-middlewares?friend=nuxt"> Watch Vue School video about adding route rules and route middlewares. </tip> ### Usage <code-group> ```ts [module.ts]twoslash import { addRouteMiddleware, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addRouteMiddleware({ name: 'auth', path: resolve('runtime/auth'), global: true, }, { prepend: true }) }, }) ``` ```ts [runtime/auth.ts]twoslash function isAuthenticated (): boolean { return false } // ---cut--- export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (to.path !== '/login' && isAuthenticated() === false) { return navigateTo('/login') } }) ``` </code-group> ### Type ```ts function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], options?: AddRouteMiddlewareOptions): void ``` ### Parameters **input**: A middleware object or an array of middleware objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> The name of the middleware. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> The file path to the middleware. </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , applies middleware to all routes. </td> </tr> </tbody> </table> **options**: An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> override </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , replaces middleware with the same name. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , prepends middleware before existing middlewares. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/pages.ts) # Plugins > Nuxt Kit provides a set of utilities to help you create and use plugins. You can add plugins or plugin templates to your module using these functions. Plugins are self-contained code that usually add app-level functionality to Vue. In Nuxt, plugins are automatically imported from the `app/plugins/` directory. However, if you need to ship a plugin with your module, Nuxt Kit provides the `addPlugin` and `addPluginTemplate` methods. These utils allow you to customize the plugin configuration to better suit your needs. ## `addPlugin` Registers a Nuxt plugin and adds it to the plugins array. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-plugins?friend=nuxt"> Watch Vue School video about `addPlugin`. </tip> ### Usage ```tstwoslash import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addPlugin({ src: resolve('runtime/plugin.js'), mode: 'client', }) }, }) ``` ### Type ```ts function addPlugin (plugin: NuxtPlugin | string, options?: AddPluginOptions): NuxtPlugin ``` ### Parameters **plugin**: A plugin object or a string with the path to the plugin. If a string is provided, it will be converted to a plugin object with `src` set to the string value. If a plugin object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the plugin file. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> If set to <code> 'all' </code> , the plugin will be included in both client and server bundles. If set to <code> 'server' </code> , the plugin will only be included in the server bundle. If set to <code> 'client' </code> , the plugin will only be included in the client bundle. You can also use <code> .client </code> and <code> .server </code> modifiers when specifying <code> src </code> option to use plugin only in client or server side. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Order of the plugin. This allows more granular control over plugin order and should only be used by advanced users. Lower numbers run first, and user plugins default to <code> 0 </code> . It's recommended to set <code> order </code> to a number between <code> -20 </code> for <code> pre </code> -plugins (plugins that run before Nuxt plugins) and <code> 20 </code> for <code> post </code> -plugins (plugins that run after Nuxt plugins). </td> </tr> </tbody> </table> <warning> Avoid using `order` unless necessary. Use `append` if you simply need to register plugins after Nuxt defaults. </warning> **options**: Optional object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> append </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the plugin will be appended to the plugins array. If <code> false </code> , it will be prepended. Defaults to <code> false </code> . </td> </tr> </tbody> </table> ### Example <code-group> ```ts [module.ts] import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addPlugin({ src: resolve('runtime/plugin.js'), mode: 'client', }) }, }) ``` ```ts [runtime/plugin.ts] export default defineNuxtPlugin((nuxtApp) => { const colorMode = useColorMode() nuxtApp.hook('app:mounted', () => { if (colorMode.preference !== 'dark') { colorMode.preference = 'dark' } }) }) ``` </code-group> ## `addPluginTemplate` Adds a template and registers as a nuxt plugin. This is useful for plugins that need to generate code at build time. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-plugin-templates?friend=nuxt"> Watch Vue School video about `addPluginTemplate`. </tip> ### Usage ```tstwoslash import { addPluginTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { addPluginTemplate({ filename: 'module-plugin.mjs', getContents: () => `import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'module-plugin', setup (nuxtApp) { ${options.log ? 'console.log("Plugin install")' : ''} } })`, }) }, }) ``` ### Type ```ts function addPluginTemplate (pluginOptions: NuxtPluginTemplate, options?: AddPluginOptions): NuxtPlugin ``` ### Parameters **pluginOptions**: A plugin template object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> If set to <code> 'all' </code> , the plugin will be included in both client and server bundles. If set to <code> 'server' </code> , the plugin will only be included in the server bundle. If set to <code> 'client' </code> , the plugin will only be included in the client bundle. You can also use <code> .client </code> and <code> .server </code> modifiers when specifying <code> src </code> option to use plugin only in client or server side. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Record </span> <span class="sDfIl"> < </span> <span class="s52Pk"> string </span> <span class="sDfIl"> , </span> <span class="s52Pk"> any </span> <span class="sDfIl"> >) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Order of the plugin. This allows more granular control over plugin order and should only be used by advanced users. Lower numbers run first, and user plugins default to <code> 0 </code> . It's recommended to set <code> order </code> to a number between <code> -20 </code> for <code> pre </code> -plugins (plugins that run before Nuxt plugins) and <code> 20 </code> for <code> post </code> -plugins (plugins that run after Nuxt plugins). </td> </tr> </tbody> </table> <warning> Prefer using `getContents` for dynamic plugin generation. Avoid setting `order` unless necessary. </warning> **options**: Optional object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> append </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the plugin will be appended to the plugins array. If <code> false </code> , it will be prepended. Defaults to <code> false </code> . </td> </tr> </tbody> </table> ### Example #### Generate a plugin template with different options Use `addPluginTemplate` when you need to generate plugin code dynamically at build time. This allows you to generate different plugin contents based on the options passed to it. For example, Nuxt internally uses this function to generate Vue app configurations. ```ts [module.ts]twoslash import { addPluginTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (_, nuxt) { if (nuxt.options.vue.config && Object.values(nuxt.options.vue.config).some(v => v !== null && v !== undefined)) { addPluginTemplate({ filename: 'vue-app-config.mjs', write: true, getContents: () => `import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { ${Object.keys(nuxt.options.vue.config!) .map(k => `nuxtApp.vueApp.config[${JSON.stringify(k)}] = ${JSON.stringify(nuxt.options.vue.config![k as 'idPrefix'])}`) .join('\n') } } })`, }) } }, }) ``` This generates different plugin code depending on the provided configuration. <code-group> ```ts [nuxt.config.ts] export default defineNuxtConfig({ vue: { config: { idPrefix: 'nuxt', }, }, }) ``` ```ts [#build/vue-app-config.mjs] import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { nuxtApp.vueApp.config.idPrefix = 'nuxt' }, }) ``` </code-group> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/plugin.ts) # Programmatic Usage > Nuxt Kit provides a set of utilities to help you work with Nuxt programmatically. These functions allow you to load Nuxt, build Nuxt, and load Nuxt configuration. Programmatic usage can be helpful when you want to use Nuxt programmatically, for example, when building a [CLI tool](https://github.com/nuxt/cli) or [test utils](https://github.com/nuxt/test-utils). ## `loadNuxt` Load Nuxt programmatically. It will load the Nuxt configuration, instantiate and return the promise with Nuxt instance. ### Type ```ts function loadNuxt (loadOptions?: LoadNuxtOptions): Promise<Nuxt> ``` ### Parameters **loadOptions**: Loading conditions for Nuxt. `loadNuxt` uses [`c12`](https://github.com/unjs/c12) under the hood, so it accepts the same options as `c12.loadConfig` with some additional options: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , Nuxt will be loaded in development mode. </td> </tr> <tr> <td> <code> ready </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If set to <code> true </code> , Nuxt will be ready to use after the <code> loadNuxt </code> call. If set to <code> false </code> , you will need to call <code> nuxt.ready() </code> to make sure Nuxt is ready to use. </td> </tr> </tbody> </table> ## `buildNuxt` Build Nuxt programmatically. It will invoke the builder (currently [@nuxt/vite-builder](https://github.com/nuxt/nuxt/tree/main/packages/vite) or [@nuxt/webpack-builder](https://github.com/nuxt/nuxt/tree/main/packages/webpack)) to bundle the application. ### Type ```ts function buildNuxt (nuxt: Nuxt): Promise<any> ``` ### Parameters **nuxt**: Nuxt instance to build. It can be retrieved from the context via `useNuxt()` call. ## `loadNuxtConfig` Load Nuxt configuration. It will return the promise with the configuration object. ### Type ```ts function loadNuxtConfig (options: LoadNuxtConfigOptions): Promise<NuxtOptions> ``` ### Parameters **options**: Options to pass in [`c12`](https://github.com/unjs/c12#options) `loadConfig` call. ## `writeTypes` Generates `tsconfig.json` and writes it to the project buildDir. ### Type ```ts function writeTypes (nuxt?: Nuxt): void ``` ### Parameters **nuxt**: Nuxt instance to build. It can be retrieved from the context via `useNuxt()` call. --- - [Source](https://github.com/nuxt/nuxt/tree/main/packages/kit/src/loader) # Resolving > Nuxt Kit provides utilities to resolve paths from the Nuxt root directory or a custom base. Sometimes you need to resolve a path without knowing its name or extension. For example, you may want to add a plugin that is located in the same directory as a module. To handle these cases, Nuxt provides a set of utilities to resolve paths. `resolvePath` resolves paths from the Nuxt root directory by default, while `resolveAlias` applies configured aliases. `findPath` finds the first existing file in a given set of paths. `createResolver` creates a resolver relative to a base path. ## `resolvePath` Resolves the full path to a file or directory, respecting Nuxt alias and extensions options. If a path could not be resolved, a normalized input path will be returned. ### Usage ```ts import { defineNuxtModule, resolvePath } from '@nuxt/kit' export default defineNuxtModule({ async setup () { const entrypoint = await resolvePath('@unhead/vue') console.log(`Unhead entrypoint is ${entrypoint}`) }, }) ``` ### Type ```ts function resolvePath (path: string, options?: ResolvePathOptions): Promise<string> ``` ### Parameters **path**: A path to resolve. **options**: Options to pass to the resolver. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> cwd </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Base for resolving paths from. Default is Nuxt rootDir. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> An object of aliases. Default is Nuxt configured aliases. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> The file extensions to try. Default is Nuxt configured extensions. </td> </tr> <tr> <td> <code> virtual </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template). </td> </tr> <tr> <td> <code> fallbackToOriginal </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to fallback to the original path if the resolved path does not exist instead of returning the normalized input path. </td> </tr> </tbody> </table> <note> `resolvePath` follows standard module resolution and does not search dependencies nested inside other packages. To resolve a dependency declared by your Nuxt module, use `createResolver(import.meta.url).resolvePath()`. This makes resolution independent of whether the package manager hoists the dependency. </note> ### Example ```ts import { defineNuxtModule, resolvePath } from '@nuxt/kit' import { join } from 'pathe' const headlessComponents: ComponentGroup[] = [ { relativePath: 'combobox/combobox.js', chunkName: 'headlessui/combobox', exports: [ 'Combobox', 'ComboboxLabel', 'ComboboxButton', 'ComboboxInput', 'ComboboxOptions', 'ComboboxOption', ], }, ] export default defineNuxtModule({ meta: { name: 'nuxt-headlessui', configKey: 'headlessui', }, defaults: { prefix: 'Headless', }, async setup (options) { const entrypoint = await resolvePath('@headlessui/vue') const root = join(entrypoint, '../components') for (const group of headlessComponents) { for (const e of group.exports) { addComponent( { name: e, export: e, filePath: join(root, group.relativePath), chunkName: group.chunkName, mode: 'all', }, ) } } }, }) ``` ## `resolveAlias` Resolves path aliases respecting Nuxt alias options. ### Type ```ts function resolveAlias (path: string, alias?: Record<string, string>): string ``` ### Parameters **path**: A path to resolve. **alias**: An object of aliases. If not provided, it will be read from `nuxt.options.alias`. ## `findPath` Try to resolve first existing file in a given set of paths. ### Usage ```ts import { defineNuxtModule, findPath } from '@nuxt/kit' import { join } from 'pathe' export default defineNuxtModule({ async setup (_, nuxt) { // Resolve main (app.vue) const mainComponent = await findPath([ join(nuxt.options.srcDir, 'App'), join(nuxt.options.srcDir, 'app'), ]) }, }) ``` ### Type ```ts function findPath (paths: string | string[], options?: ResolvePathOptions, pathType: 'file' | 'dir'): Promise<string | null> ``` ### Parameters **paths**: A path or an array of paths to resolve. **options**: Options to pass to the resolver. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> cwd </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Base for resolving paths from. Default is Nuxt rootDir. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> An object of aliases. Default is Nuxt configured aliases. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> The file extensions to try. Default is Nuxt configured extensions. </td> </tr> <tr> <td> <code> virtual </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template). </td> </tr> <tr> <td> <code> fallbackToOriginal </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to fallback to the original path if the resolved path does not exist instead of returning the normalized input path. </td> </tr> </tbody> </table> ## `createResolver` Creates resolver relative to base path. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/resolving-paths-and-injecting-assets-to-the-app?friend=nuxt"> Watch Vue School video about createResolver. </tip> ### Usage ```ts import { createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (_, nuxt) { const { resolve, resolvePath } = createResolver(import.meta.url) }, }) ``` ### Type ```ts function createResolver (basePath: string | URL): Resolver ``` ### Parameters **basePath**: A base path to resolve from. It can be a string or a URL. ### Return Value The `createResolver` function returns an object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> resolve </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> path </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> </code> </td> <td> A function that resolves a path relative to the base path. </td> </tr> <tr> <td> <code> resolvePath </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> path </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> , </span> <span class="s1nJG"> options </span> <span class="sDfIl"> ?: </span> <span class="s52Pk"> ResolvePathOptions </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> A function that resolves a path relative to the base path and respects Nuxt alias and extensions options. </td> </tr> </tbody> </table> ### Example ```ts import { createResolver, defineNuxtModule, isNuxt2 } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const resolver = createResolver(import.meta.url) nuxt.hook('modules:done', () => { if (isNuxt2()) { addPlugin(resolver.resolve('./runtime/plugin.vue2')) } else { addPlugin(resolver.resolve('./runtime/plugin.vue3')) } }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/resolve.ts) # Runtime Config > Nuxt Kit provides a set of utilities to help you access and modify Nuxt runtime configuration. ## `useRuntimeConfig` At build-time, it is possible to access the resolved Nuxt [runtime config](https://nuxt.com/docs/5.x/guide/going-further/runtime-config). ### Type ```ts function useRuntimeConfig (): Record<string, unknown> ``` ## `updateRuntimeConfig` It is also possible to update runtime configuration. This will be merged with the existing runtime configuration, and if Nitro has already been initialized it will trigger an HMR event to reload the Nitro runtime config. ### Type ```ts function updateRuntimeConfig (config: Record<string, unknown>): void | Promise<void> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/runtime-config.ts) # Templates > Nuxt Kit provides a set of utilities to help you work with templates. These functions allow you to generate extra files during development and build time. Templates allow you to generate extra files during development and build time. These files will be available in virtual filesystem and can be used in plugins, layouts, components, etc. `addTemplate` and `addTypeTemplate` allow you to add templates to the Nuxt application. `updateTemplates` allows you to regenerate templates that match the filter. ## `addTemplate` Renders given template during build into the virtual file system, and optionally to disk in the project `buildDir` ### Usage ```tstwoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' import { defu } from 'defu' export default defineNuxtModule({ setup (options, nuxt) { const globalMeta = defu(nuxt.options.app.head, { charset: options.charset, viewport: options.viewport, }) addTemplate({ filename: 'meta.config.mjs', getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' }), }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NuxtTemplate, ResolvedNuxtTemplate } from '@nuxt/schema' // ---cut--- function addTemplate (template: NuxtTemplate | string): ResolvedNuxtTemplate ``` ### Parameters **template**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code> Options </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Options </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> <tr> <td> <code> dependsOn </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Array </span> <span class="sDfIl"> < </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> pages </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> plugins </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> > </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> change </span> <span class="sDfIl"> : </span> <span class="sDfIl"> { </span> <span class="sRlkE"> event </span> <span class="sDfIl"> , </span> <span class="sRlkE"> path </span> <span class="sDfIl"> }, </span> <span class="s1nJG"> ctx </span> <span class="sDfIl"> : </span> <span class="sDfIl"> { </span> <span class="sRlkE"> nuxt </span> <span class="sDfIl"> , </span> <span class="sRlkE"> app </span> <span class="sDfIl"> , </span> <span class="sRlkE"> options </span> <span class="sDfIl"> }) </span> <span class="smZ93"> => </span> <span class="sZSNi"> boolean) </span> </code> </td> <td> <code> false </code> </td> <td> The watched inputs the output of the template can depend on, beyond <code> nuxt.options </code> and the resolved structure of the app. Set to <code> [] </code> if the template never reads the contents of a watched file, so that Nuxt can skip recompiling it in dev mode when a file changes without any file being added or removed. List well-known keys if the template reads those sources, or pass a function to decide per change. A template that declares nothing is regenerated on every change. </td> </tr> </tbody> </table> ### Example #### Creating a Virtual File for Runtime Plugin In this example, we merge an object inside a module and consume the result in a runtime plugin. ```ts [module.ts]twoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' import { defu } from 'defu' export default defineNuxtModule({ setup (options, nuxt) { const globalMeta = defu(nuxt.options.app.head, { charset: options.charset, viewport: options.viewport, }) addTemplate({ filename: 'meta.config.mjs', getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' }), }) }, }) ``` #### Skipping Regeneration in Development By default, Nuxt recompiles a template on every watched file event because it cannot know what the template reads. If your template is built only from configuration and from which files exist, declare that so Nuxt can leave it alone when a file is edited: ```ts [module.ts]twoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { addTemplate({ filename: 'my-module/config.mjs', dependsOn: [], getContents: () => 'export default ' + JSON.stringify(options), }) }, }) ``` If the template reads well-known sources, declare them by key: ```ts addTemplate({ filename: 'my-module/routes.mjs', dependsOn: ['pages'], getContents: ({ app }) => generateRoutes(app.pages), }) ``` And if it reads files Nuxt doesn't know about, say a set of YAML files you scan yourself, pass a function instead: ```ts addTemplate({ filename: 'my-module/content.mjs', dependsOn: ({ path }) => path.endsWith('.yaml'), getContents: () => generateContents(), }) ``` In the module above, we generate a virtual file named `meta.config.mjs`. In the runtime plugin, we can import it using the `#build` alias: ```ts [runtime/plugin.ts] import { createHead as createServerHead } from '@unhead/vue/server' import { createHead as createClientHead } from '@unhead/vue/client' import { defineNuxtPlugin } from '#imports' // @ts-expect-error - virtual file import metaConfig from '#build/meta.config.mjs' export default defineNuxtPlugin((nuxtApp) => { const createHead = import.meta.server ? createServerHead : createClientHead const head = createHead() head.push(metaConfig.globalMeta) nuxtApp.vueApp.use(head) }) ``` ## `addTypeTemplate` Renders given template during build into the project buildDir, then registers it as types. ### Usage ```tstwoslash import { addTypeTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addTypeTemplate({ filename: 'types/markdown.d.ts', getContents: () => `declare module '*.md' { import type { ComponentOptions } from 'vue' const Component: ComponentOptions export default Component }`, }) }, }) ``` ### Type ```ts function addTypeTemplate (template: NuxtTypeTemplate | string, context?: { nitro?: boolean, nuxt?: boolean }): ResolvedNuxtTemplate ``` ### Parameters **template**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code> Options </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Options </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> </tbody> </table> **context**: An optional context object can be passed to control where the type is added. If omitted, the type will only be added to the Nuxt context. This object supports the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> nuxt </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the type will be added to the Nuxt context. </td> </tr> <tr> <td> <code> nitro </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the type will be added to the Nitro context. </td> </tr> </tbody> </table> ### Example #### Adding Type Templates to the Nitro Context By default, ๏ผ๏ผ only adds the type declarations to the Nuxt context. To also add them to the Nitro context, set nitro to true. ```tstwoslash import { addTypeTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addTypeTemplate({ filename: 'types/auth.d.ts', getContents: () => `declare module '#auth-utils' { interface User { id: string; name: string; } }`, }, { nitro: true, }) }, }) ``` This allows the `#auth-utils` module to be used within the Nitro context. ```ts [server/api/auth.ts] import type { User } from '#auth-utils' export default eventHandler(() => { const user: User = { id: '123', name: 'John Doe', } // do something with the user return user }) ``` ## `addServerTemplate` Adds a virtual file that can be used within the Nuxt Nitro server build. ### Usage ```tstwoslash import { addServerTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addServerTemplate({ filename: '#my-module/test.mjs', getContents () { return 'export const test = 123' }, }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NuxtServerTemplate } from '@nuxt/schema' // ---cut--- function addServerTemplate (template: NuxtServerTemplate): NuxtServerTemplate ``` ### Parameters **template**: A template object. It must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Filename of the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> () </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> true </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. </td> </tr> </tbody> </table> ### Example ### Creating a Virtual File for Nitro In this example, we create a virtual file that can be used within the Nuxt Nitro server build. ```tstwoslash import { addServerTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addServerTemplate({ filename: '#my-module/test.mjs', getContents () { return 'export const test = 123' }, }) }, }) ``` And then in a runtime file ```ts [server/api/test.ts] import { test } from '#my-module/test.js' export default eventHandler(() => { return test }) ``` ## `updateTemplates` Regenerate templates that match the filter. If no filter is provided, all templates will be regenerated. ### Usage ```ts import { defineNuxtModule, updateTemplates } from '@nuxt/kit' import { resolve } from 'pathe' export default defineNuxtModule({ setup (options, nuxt) { const updateTemplatePaths = [ resolve(nuxt.options.srcDir, 'pages'), ] // watch and rebuild routes template list when one of the pages changes nuxt.hook('builder:watch', async (event, relativePath) => { if (event === 'change') { return } const path = resolve(nuxt.options.srcDir, relativePath) if (updateTemplatePaths.some(dir => path.startsWith(dir))) { await updateTemplates({ filter: template => template.filename === 'routes.mjs', }) } }) }, }) ``` ### Type ```ts async function updateTemplates (options: UpdateTemplatesOptions): void ``` ### Parameters **options**: Options to pass to the template. This object can have the following property: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> filter </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> template </span> <span class="sDfIl"> : </span> <span class="s52Pk"> ResolvedNuxtTemplate </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> boolean </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> template </code> object. It should return a boolean indicating whether the template should be regenerated. If <code> filter </code> is not provided, all templates will be regenerated. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/template.ts) # Nuxt Configuration > Discover all the options you can use in your nuxt.config.ts file. ## alias You can improve your DX by defining additional aliases to access custom directories within your JavaScript and CSS. - **Type**: `object` - **Default** ```json { "~": "/<rootDir>/app", "@": "/<rootDir>/app", "~~": "/<rootDir>", "@@": "/<rootDir>", "#shared": "/<rootDir>/shared", "#server": "/<rootDir>/server", "assets": "/<rootDir>/app/assets", "public": "/<rootDir>/public", "#build": "/<rootDir>/.nuxt", "#internal/nuxt/paths": "/<rootDir>/.nuxt/paths.mjs" } ``` <callout> **Note**: Within a webpack context (image sources, CSS - but not JavaScript) you *must* access your alias by prefixing it with `~`. </callout> <callout> **Note**: These aliases will be automatically added to the generated TypeScript configurations (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, etc.) so you can get full type support and path auto-complete. In case you need to extend options provided by the generated configurations further, make sure to add them here or within the `typescript.tsConfig` property in `nuxt.config`. </callout> **Example**: ```ts import { fileURLToPath } from 'node:url' export default defineNuxtConfig({ alias: { 'images': fileURLToPath(new URL('./assets/images', import.meta.url)), 'style': fileURLToPath(new URL('./assets/style', import.meta.url)), 'data': fileURLToPath(new URL('./assets/other/data', import.meta.url)), }, }) ``` ```html <template> <img src="~images/main-bg.jpg"> </template> <script> import data from 'data/test.json' </script> <style> // Uncomment the below //@import '~style/variables.scss'; //@import '~style/utils.scss'; //@import '~style/base.scss'; body { background-image: url('~images/main-bg.jpg'); } </style> ``` ## analyzeDir The directory where Nuxt will store the generated files when running `nuxt analyze`. If a relative path is specified, it will be relative to your `rootDir`. - **Type**: `string` - **Default:** `"/<rootDir>/.nuxt/analyze"` ## app Nuxt App configuration. ### `baseURL` The base path of your Nuxt application. For example: - **Type**: `string` - **Default:** `"/"` **Example**: ```ts export default defineNuxtConfig({ app: { baseURL: '/prefix/', }, }) ``` This can also be set at runtime by setting the NUXT_APP_BASE_URL environment variable. **Example**: ```bash NUXT_APP_BASE_URL=/prefix/ node .output/server/index.mjs ``` <note> Relative paths (like `./`) are not supported directly in `nuxt.config.ts` due to Nitro limitations. For static hosting with relative asset paths, use one of these approaches: ```bash # Option 1: Environment variable at build time NUXT_APP_BASE_URL=./ npm run generate ``` ```ts // Option 2: Nitro runtime config export default defineNuxtConfig({ nitro: { runtimeConfig: { app: { baseURL: './', }, }, }, }) ``` </note> ### `buildAssetsDir` The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set). This is set at build time and should not be customized at runtime. - **Type**: `string` - **Default:** `"/_nuxt/"` ### `cdnURL` An absolute URL to serve the public folder from (production-only). For example: - **Type**: `string` - **Default:** `""` **Example**: ```ts export default defineNuxtConfig({ app: { cdnURL: 'https://mycdn.org/', }, }) ``` This can be set to a different value at runtime by setting the `NUXT_APP_CDN_URL` environment variable. **Example**: ```bash NUXT_APP_CDN_URL=https://mycdn.org/ node .output/server/index.mjs ``` ### `head` Set default configuration for `<head>` on every page. - **Type**: `object` - **Default** ```json { "meta": [ { "name": "viewport", "content": "width=device-width, initial-scale=1" }, { "charset": "utf-8" } ], "link": [], "style": [], "script": [], "noscript": [] } ``` **Example**: ```ts export default defineNuxtConfig({ app: { head: { meta: [ // <meta name="viewport" content="width=device-width, initial-scale=1"> { name: 'viewport', content: 'width=device-width, initial-scale=1' }, ], script: [ // <script src="https://myawesome-lib.js"></script> { src: 'https://awesome-lib.js' }, ], link: [ // <link rel="stylesheet" href="https://myawesome-lib.css"> { rel: 'stylesheet', href: 'https://awesome-lib.css' }, ], // please note that this is an area that is likely to change style: [ // <style>:root { color: red }</style> { textContent: ':root { color: red }' }, ], noscript: [ // <noscript>JavaScript is required</noscript> { textContent: 'JavaScript is required' }, ], }, }, }) ``` ### `keepalive` Default values for KeepAlive configuration between pages. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean` - **Default:** `false` **See**: [Vue KeepAlive](https://vuejs.org/api/built-in-components#keepalive) ### `layoutTransition` Default values for layout transitions. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean | TransitionProps` - **Default:** `false` **See**: [Vue Transition docs](https://vuejs.org/api/built-in-components#transition) ### `pageTransition` Default values for page transitions. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean | TransitionProps` - **Default:** `false` **See**: [Vue Transition docs](https://vuejs.org/api/built-in-components#transition) ### `rootAttrs` Customize Nuxt root element id. - **Type**: `object` - **Default** ```json { "id": "__nuxt" } ``` ### `rootId` Customize Nuxt root element id. - **Type**: `string` - **Default:** `"__nuxt"` ### `rootTag` Customize Nuxt root element tag. - **Type**: `string` - **Default:** `"div"` ### `spaLoaderAttrs` Customize Nuxt SPA loading template element attributes. - **Type**: `object` - **Default:** ```json { "id": "__nuxt-loader" } ``` #### `id` - **Type**: `string` - **Default:** `"__nuxt-loader"` ### `spaLoaderTag` Customize Nuxt SpaLoader element tag. - **Type**: `string` - **Default:** `"div"` ### `teleportAttrs` Customize Nuxt Teleport element attributes. - **Type**: `object` - **Default** ```json { "id": "teleports" } ``` ### `teleportId` Customize Nuxt Teleport element id. - **Type**: `string` - **Default:** `"teleports"` ### `teleportTag` Customize Nuxt Teleport element tag. - **Type**: `string` - **Default:** `"div"` ### `viewTransition` Default values for view transitions. This only has an effect when **experimental** support for View Transitions is [enabled in your nuxt.config file](https://nuxt.com/docs/5.x/getting-started/transitions#view-transitions-api-experimental). This can be overridden with `definePageMeta` on an individual page. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt View Transition API docs](https://nuxt.com/docs/5.x/getting-started/transitions#view-transitions-api-experimental) ## appConfig Additional app configuration For programmatic usage and type support, you can directly provide app config with this option. It will be merged with `app.config` file as default value. ### `nuxt` ## appId For multi-app projects, the unique id of the Nuxt application. Defaults to `nuxt-app`. - **Type**: `string` - **Default:** `"nuxt-app"` ## build Shared build configuration. ### `analyze` Nuxt allows visualizing your bundles and how to optimize them. Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - **Type**: `object` - **Default** ```json { "template": "treemap", "projectRoot": "/<rootDir>", "filename": "/<rootDir>/.nuxt/analyze/{name}.html" } ``` **Example**: ```ts export default defineNuxtConfig({ analyze: { analyzerMode: 'static', }, }) ``` ### `templates` It is recommended to use `addTemplate` from `@nuxt/kit` instead of this option. - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ build: { templates: [ { src: '~~/modules/support/plugin.js', // `src` can be absolute or relative dst: 'support.js', // `dst` is relative to project `.nuxt` dir }, ], }, }) ``` ### `transpile` If you want to transpile specific dependencies with Babel, you can add them here. Each item in transpile can be a package name, a function, a string or regex object matching the dependency's file name. You can also use a function to conditionally transpile. The function will receive an object ({ isDev, isServer, isClient, isModern, isLegacy }). - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ build: { transpile: [({ isLegacy }) => isLegacy && 'ky'], }, }) ``` ## buildDir Define the directory where your built Nuxt files will be placed. Many tools assume that `.nuxt` is a hidden directory (because it starts with a `.`). If that is a problem, you can use this option to prevent that. - **Type**: `string` - **Default:** `"/<rootDir>/.nuxt"` **Example**: ```ts export default defineNuxtConfig({ buildDir: 'nuxt-build', }) ``` ## buildId A unique identifier matching the build. This may contain the hash of the current state of the project. - **Type**: `string` - **Default:** `"4a2e2d30-418f-41df-8e58-ed5df06de7fd"` ## builder The builder to use for bundling the Vue part of your application. Nuxt supports multiple builders for the client-side application. By default, Vite is used, but you can switch to webpack, Rspack, or even provide a custom builder implementation. - **Type**: `'vite' | 'webpack' | 'rspack' | string | { bundle: (nuxt: Nuxt) => Promise<void> }` - **Default:** `"@nuxt/vite-builder"` **Using supported builders:** ```ts export default defineNuxtConfig({ // default - uses @nuxt/vite-builder // builder: 'vite', // uses @nuxt/webpack-builder // builder: 'webpack', // uses @nuxt/rspack-builder builder: 'rspack', }) ``` If you are using `webpack` or `rspack` you will need to make sure `@nuxt/webpack-builder` or `@nuxt/rspack-builder` is explicitly installed in your project. **Using a custom builder object:** You can provide a custom builder by passing an object with a `bundle` function: ```ts export default defineNuxtConfig({ builder: { async bundle (nuxt) { const entry = await resolvePath(resolve(nuxt.options.appDir, 'entry')) // Build client and server bundles await buildClient(nuxt, entry) if (nuxt.options.ssr) { await buildServer(nuxt, entry) } // ... it's a bit more complicated than that, of course! }, }, }) ``` **Creating a custom builder package:** To create a custom builder as a separate package, it should export a `bundle` function. You can then specify the package name in your `nuxt.config.ts`: ```ts export default defineNuxtConfig({ builder: 'my-custom-builder', }) ``` ## compatibilityDate Specify a compatibility date for your app. This is used to control the behavior of presets in Nitro, Nuxt Image and other modules that may change behavior without a major version bump. We plan to improve the tooling around this feature in the future. ## components Configure Nuxt component auto-registration. Any components in the directories configured here can be used throughout your pages, layouts (and other components) without needing to explicitly import them. - **Type**: `object` - **Default** ```json { "dirs": [ { "path": "~/components/global", "global": true }, "~/components" ] } ``` **See**: [`app/components/` directory documentation](https://nuxt.com/docs/5.x/directory-structure/app/components) ## css You can define the CSS files/modules/libraries you want to set globally (included in every page). Nuxt will automatically guess the file type by its extension and use the appropriate pre-processor. You will still need to install the required loader if you need to use them. - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ css: [ // Load a Node.js module directly (here it's a Sass file). 'bulma', // CSS file in the project '~/assets/css/main.css', // SCSS file in the project '~/assets/css/main.scss', ], }) ``` ## debug Set to `true` to enable debug mode. At the moment, it prints out hook names and timings on the server, and logs hook arguments as well in the browser. You can also set this to an object to enable specific debug options. - **Type**: `boolean` - **Default:** `false` ## dev Whether Nuxt is running in development mode. Normally, you should not need to set this. - **Type**: `boolean` - **Default:** `false` ## devServer ### `cors` Set CORS options for the dev server #### `origin` - **Type**: `array` - **Default** ```json [ {} ] ``` ### `host` Dev server listening host ### `https` Whether to enable HTTPS. - **Type**: `boolean` - **Default:** `false` **Example**: ```ts export default defineNuxtConfig({ devServer: { https: { key: './server.key', cert: './server.crt', }, }, }) ``` ### `loadingTemplate` Template to show a loading screen - **Type**: `function` ### `port` Dev server listening port - **Type**: `number` - **Default:** `3000` ### `url` Listening dev server URL. This should not be set directly as it will always be overridden by the dev server with the full URL (for module and internal use). - **Type**: `string` - **Default:** `"http://localhost:3000"` ## devServerHandlers Nitro development-only server handlers. - **Type**: `array` **See**: [Nitro server routes documentation](https://nitro.build/guide/routing) ## devtools Enable Nuxt DevTools for development. Breaking changes for devtools might not reflect on the version of Nuxt. **See**: [Nuxt DevTools](https://devtools.nuxt.com/) for more information. ## dir Customize default directory structure used by Nuxt. It is better to stick with defaults unless needed. ### `app` - **Type**: `string` - **Default:** `"app"` ### `assets` The assets directory (aliased as `~assets` in your build). - **Type**: `string` - **Default:** `"app/assets"` ### `layouts` The layouts directory, each file of which will be auto-registered as a Nuxt layout. - **Type**: `string` - **Default:** `"app/layouts"` ### `middleware` The middleware directory, each file of which will be auto-registered as a Nuxt middleware. - **Type**: `string` - **Default:** `"app/middleware"` ### `modules` The modules directory, each file in which will be auto-registered as a Nuxt module. - **Type**: `string` - **Default:** `"modules"` ### `pages` The directory which will be processed to auto-generate your application page routes. - **Type**: `string` - **Default:** `"app/pages"` ### `plugins` The plugins directory, each file of which will be auto-registered as a Nuxt plugin. - **Type**: `string` - **Default:** `"app/plugins"` ### `public` The directory containing your static files, which will be directly accessible via the Nuxt server and copied across into your `dist` folder when your app is generated. - **Type**: `string` - **Default:** `"public"` ### `shared` The shared directory. This directory is shared between the app and the server. - **Type**: `string` - **Default:** `"shared"` ## esbuild ### `options` Configure shared esbuild options used within Nuxt and passed to other builders, such as Vite or webpack. #### `jsxFactory` - **Type**: `string` - **Default:** `"h"` #### `jsxFragment` - **Type**: `string` - **Default:** `"Fragment"` #### `target` - **Type**: `string` - **Default:** `"esnext"` #### `tsconfigRaw` - **Type**: `object` ## experimental <read-more to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features"> Learn more about Nuxt's experimental features. </read-more> ## extends Extend project from multiple local or remote sources. Value should be either a string or array of strings pointing to source directories or config path relative to current config. You can use `github:`, `gh:` `gitlab:` or `bitbucket:` **See**: [`c12` docs on extending config layers](https://github.com/unjs/c12#extending-config-layer-from-remote-sources) **See**: [`giget` documentation](https://github.com/unjs/giget) ## extensions The extensions that should be resolved by the Nuxt resolver. - **Type**: `array` - **Default** ```json [ ".js", ".jsx", ".mjs", ".ts", ".tsx", ".vue" ] ``` ## features <read-more to="https://nuxt.com/docs/5.x/guide/going-further/features#features"> Learn more about Nuxt's opt-in features. </read-more> ## future <read-more to="https://nuxt.com/docs/5.x/guide/going-further/features#features"> Learn more about opting-in to new features that will become default in a future (possibly major) version of the framework. </read-more> ## hooks Hooks are listeners to Nuxt events that are typically used in modules, but are also available in `nuxt.config`. Internally, hooks follow a naming pattern using colons (e.g., build:done). For ease of configuration, you can also structure them as an hierarchical object in `nuxt.config` (as below). **Example**: ```ts import fs from 'node:fs' import path from 'node:path' export default defineNuxtConfig({ hooks: { build: { done (builder) { const extraFilePath = path.join( builder.nuxt.options.buildDir, 'extra-file', ) fs.writeFileSync(extraFilePath, 'Something extra') }, }, }, }) ``` ## ignore More customizable than `ignorePrefix`: all files matching glob patterns specified inside the `ignore` array will be ignored in building. - **Type**: `array` - **Default** ```json [ "**/*.stories.{js,cts,mts,ts,jsx,tsx}", "**/*.{spec,test}.{js,cts,mts,ts,jsx,tsx}", "**/*.d.{cts,mts,ts}", "**/*.d.vue.{cts,mts,ts}", "**/.{pnpm-store,vercel,netlify,output,git,cache,data}", "**/*.sock", ".nuxt/analyze", ".nuxt", "**/-*.*" ] ``` ## ignoreOptions Pass options directly to `node-ignore` (which is used by Nuxt to ignore files). **See**: [node-ignore](https://github.com/kaelzhang/node-ignore) **Example**: ```ts export default defineNuxtConfig({ ignoreOptions: { ignorecase: false, }, }) ``` ## ignorePrefix Any file in `app/pages/`, `app/layouts/`, `app/middleware/`, and `public/` directories will be ignored during the build process if its filename starts with the prefix specified by `ignorePrefix`. This is intended to prevent certain files from being processed or served in the built application. By default, the `ignorePrefix` is set to '-', ignoring any files starting with '-'. - **Type**: `string` - **Default:** `"-"` ## imports Configure how Nuxt auto-imports composables into your application. **See**: [Nuxt documentation](https://nuxt.com/docs/5.x/directory-structure/app/composables) ### `dirs` An array of custom directories that will be auto-imported. Note that this option will not override the default directories (~/composables, ~/utils). - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ imports: { // Auto-import pinia stores defined in `~/stores` dirs: ['stores'], }, }) ``` ### `global` - **Type**: `boolean` - **Default:** `false` ### `scan` Whether to scan your `app/composables/` and `app/utils/` directories for composables to auto-import. Auto-imports registered by Nuxt or other modules, such as imports from `vue` or `nuxt`, will still be enabled. - **Type**: `boolean` - **Default:** `true` ## logLevel Log level when building logs. Defaults to 'silent' when running in CI or when a TTY is not available. This option is then used as 'silent' in Vite and 'none' in webpack - **Type**: `string` - **Default:** `"info"` ## modules Modules are Nuxt extensions which can extend its core functionality and add endless integrations. Each module is either a string (which can refer to a package, or be a path to a file), a tuple with the module as first string and the options as a second object, or an inline module function. Nuxt tries to resolve each item in the modules array using node require path (in `node_modules`) and then will be resolved from project `rootDir` if `~~` alias is used. - **Type**: `array` <callout> **Note**: Modules are executed sequentially so the order is important. First, the modules defined in `nuxt.config.ts` are loaded. Then, modules found in the `modules/` directory are executed, and they load in alphabetical order. </callout> **Example**: ```ts export default defineNuxtConfig({ modules: [ // Using package name '@nuxt/scripts', // Relative to your project rootDir '~~/custom-modules/awesome.js', // Providing options ['@nuxtjs/google-analytics', { ua: 'X1234567' }], // Inline definition function () {}, ], }) ``` ## modulesDir Used to set the modules directories for path resolving (for example, webpack's `resolveLoading`, `nodeExternals` and `postcss`). The configuration path is relative to `options.rootDir` (default is current working directory). Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository. - **Type**: `array` - **Default** ```json [ "/<rootDir>/node_modules" ] ``` **Example**: ```ts export default defineNuxtConfig({ modulesDir: ['../../node_modules'], }) ``` ## nitro Configuration for Nitro. **See**: [Nitro configuration docs](https://nitro.build/config) ### `routeRules` - **Type**: `object` ### `runtimeConfig` - **Type**: `object` - **Default** ```json { "public": {}, "app": { "buildId": "4a2e2d30-418f-41df-8e58-ed5df06de7fd", "baseURL": "/", "buildAssetsDir": "/_nuxt/", "cdnURL": "" }, "nitro": { "envPrefix": "NUXT_" } } ``` ## optimization Build time optimization configuration. ### `asyncTransforms` Options passed directly to the transformer from `unctx` that preserves async context after `await`. #### `asyncFunctions` - **Type**: `array` - **Default** ```json [ "defineNuxtPlugin", "defineNuxtRouteMiddleware" ] ``` #### `objectDefinitions` ##### `defineNuxtComponent` - **Type**: `array` - **Default** ```json [ "asyncData", "setup" ] ``` ##### `defineNuxtPlugin` - **Type**: `array` - **Default** ```json [ "setup" ] ``` ##### `definePageMeta` - **Type**: `array` - **Default** ```json [ "middleware", "validate" ] ``` ### `keyedComposables` Functions to inject a key for. As long as the number of arguments passed to the function is less than `argumentLength`, an additional magic string will be injected as the last argument. This key is stable between SSR and client-side hydration. You will need to take steps to handle this additional key. The key is unique based on the location of the function being invoked within the file. <read-more to="https://nuxt.com/docs/5.x/guide/modules/recipes-basics#add-keyed-functions"> Learn more about keyed functions. </read-more> - **Type**: `array` - **Default** ```json [ { "name": "callOnce", "argumentLength": 3, "source": "#app/composables/once" }, { "name": "defineNuxtComponent", "argumentLength": 2, "source": "#app/composables/component" }, { "name": "useState", "argumentLength": 2, "source": "#app/composables/state" }, { "name": "useFetch", "argumentLength": 3, "source": "#app/composables/fetch" }, { "name": "useAsyncData", "argumentLength": 3, "source": "#app/composables/asyncData" }, { "name": "useLazyAsyncData", "argumentLength": 3, "source": "#app/composables/asyncData" }, { "name": "useLazyFetch", "argumentLength": 3, "source": "#app/composables/fetch" } ] ``` ### `treeShake` Tree shake code from specific builds. #### `composables` Tree shake composables from the server or client builds. **Example**: ```ts export default defineNuxtConfig({ optimization: { treeShake: { composables: { client: { vue: ['onMounted'] }, server: { vue: ['onServerPrefetch'] }, }, }, }, }) ``` ##### `client` - **Type**: `object` - **Default** ```json { "vue": [ "onRenderTracked", "onRenderTriggered", "onServerPrefetch" ], "#app": [ "definePayloadReducer", "definePageMeta", "onPrehydrate" ] } ``` ##### `server` - **Type**: `object` - **Default** ```json { "vue": [ "onMounted", "onUpdated", "onUnmounted", "onBeforeMount", "onBeforeUpdate", "onBeforeUnmount", "onRenderTracked", "onRenderTriggered", "onActivated", "onDeactivated" ], "#app": [ "definePayloadReviver", "definePageMeta" ] } ``` ## pages Whether to use the vue-router integration in Nuxt 3. If you do not provide a value it will be enabled if you have a `app/pages/` directory in your source folder. Additionally, you can provide a glob pattern or an array of patterns to scan only certain files for pages. **Example**: ```ts export default defineNuxtConfig({ pages: { pattern: ['**/*/*.vue', '!**/*.spec.*'], }, }) ``` ## plugins An array of nuxt app plugins. Each plugin can be a string (which can be an absolute or relative path to a file). If it ends with `.client` or `.server` then it will be automatically loaded only in the appropriate context. It can also be an object with `src` and `mode` keys. - **Type**: `array` <callout> **Note**: Plugins are also auto-registered from the `~/plugins` directory and these plugins do not need to be listed in `nuxt.config` unless you need to customize their order. All plugins are deduplicated by their src path. </callout> **See**: [`app/plugins/` directory documentation](https://nuxt.com/docs/5.x/directory-structure/app/plugins) **Example**: ```ts export default defineNuxtConfig({ plugins: [ '~/custom-plugins/foo.client.js', // only in client side '~/custom-plugins/bar.server.js', // only in server side '~/custom-plugins/baz.js', // both client & server { src: '~/custom-plugins/both-sides.js' }, { src: '~/custom-plugins/client-only.js', mode: 'client' }, // only on client side { src: '~/custom-plugins/server-only.js', mode: 'server' }, // only on server side ], }) ``` ## postcss ### `order` A strategy for ordering PostCSS plugins. - **Type**: `function` ### `plugins` Options for configuring PostCSS plugins. **See**: [PostCSS docs](https://postcss.org/) #### `autoprefixer` Plugin to parse CSS and add vendor prefixes to CSS rules. **See**: [`autoprefixer`](https://github.com/postcss/autoprefixer) #### `cssnano` - **Type**: `object` **See**: [`cssnano` configuration options](https://cssnano.github.io/cssnano/docs/config-file/#configuration-options) ## rootDir Define the root directory of your application. This property can be overwritten (for example, running `nuxt ./my-app/` will set the `rootDir` to the absolute path of `./my-app/` from the current/working directory. It is normally not needed to configure this option. - **Type**: `string` - **Default:** `"/<rootDir>"` ## routeRules Global route options applied to matching server routes. **Experimental**: This is an experimental feature and API may change in the future. **See**: [Nitro route rules documentation](https://nitro.build/config#routerules) ## router ### `options` Additional router options passed to `vue-router`. On top of the options for `vue-router`, Nuxt offers additional options to customize the router (see below). <callout> **Note**: Only JSON serializable options should be passed by Nuxt config. For more control, you can use an `router.options.ts` file. </callout> **See**: [Vue Router documentation](https://router.vuejs.org/api/interfaces/routeroptions) #### `hashMode` You can enable hash history in SPA mode. In this mode, router uses a hash character (#) before the actual URL that is internally passed. When enabled, the **URL is never sent to the server** and **SSR is not supported**. - **Type**: `boolean` - **Default:** `false` **Default**: false #### `scrollBehaviorType` Customize the scroll behavior for hash links. - **Type**: `string` - **Default:** `"auto"` **Default**: 'auto' ## runtimeConfig Runtime config allows passing dynamic config and environment variables to the Nuxt app context. The value of this object is accessible from server only using `useRuntimeConfig`. It mainly should hold *private* configuration which is not exposed on the frontend. This could include a reference to your API secret tokens. Anything under `public` and `app` will be exposed to the frontend as well. Values are automatically replaced by matching env variables at runtime, e.g. setting an environment variable `NUXT_API_KEY=my-api-key NUXT_PUBLIC_BASE_URL=/foo/` would overwrite the two values in the example below. - **Type**: `object` - **Default** ```json { "public": {}, "app": { "buildId": "4a2e2d30-418f-41df-8e58-ed5df06de7fd", "baseURL": "/", "buildAssetsDir": "/_nuxt/", "cdnURL": "" } } ``` **Example**: ```ts export default defineNuxtConfig({ runtimeConfig: { apiKey: '', // Default to an empty string, automatically set at runtime using process.env.NUXT_API_KEY public: { baseURL: '', // Exposed to the frontend as well. }, }, }) ``` ## server Configuration for Nuxt's server builder. ### `builder` Specify the server builder to use for bundling the server part of your application. By default, Nuxt uses `@nuxt/nitro-server`, which provides standalone Nitro integration. This architecture allows for different Nitro integration patterns, such as using Nitro as a Vite plugin (with the Vite Environment API). `"nitro"` and `"vite"` are shorthands for `@nuxt/nitro-server` and `@nuxt/vite-server`. The latter is experimental and implemented with Vite alone: with `ssr: false` it produces a static SPA, and with SSR enabled it builds a server from the Nuxt SSR renderer whose entry exports a web-standard `{ fetch }` (`.output/server/index.mjs` serves the static output in front of it, and `nuxt preview` runs it). Every dependency is bundled into that output, so it deploys without `node_modules`. `nuxt generate` crawls that server at the end of the build and writes a static `.output/public`. It ships no server runtime, so server routes, route rules other than `prerender`, inlined styles and server components are unavailable, and modules that need a server will not work. - **Type**: `string | { bundle: (nuxt: Nuxt) => Promise<void> }` - **Default:** `"@nuxt/nitro-server"` <callout type="warning"> This option is intended for internal use and the API is not finalized. Please open an issue before relying on the current implementation. </callout> ## serverDir Define the server directory of your Nuxt application, where Nitro routes, middleware and plugins are kept. If a relative path is specified, it will be relative to your `rootDir`. - **Type**: `string` - **Default:** `"/<rootDir>/server"` ## serverHandlers Nitro server handlers. Each handler accepts the following options: - handler: The path to the file defining the handler. - route: The route under which the handler is available. This follows the conventions of [rou3](https://github.com/h3js/rou3). - method: The HTTP method of requests that should be handled. - middleware: Specifies whether it is a middleware handler. - lazy: Specifies whether to use lazy loading to import the handler. - **Type**: `array` **See**: [`server/` directory documentation](https://nuxt.com/docs/5.x/directory-structure/server) <callout> **Note**: Files from `server/api`, `server/middleware` and `server/routes` will be automatically registered by Nuxt. </callout> **Example**: ```ts export default defineNuxtConfig({ serverHandlers: [ { route: '/path/foo/**:name', handler: '#server/foohandler.ts' }, ], }) ``` ## sourcemap Configures whether and how sourcemaps are generated for server and/or client bundles. If set to a single boolean, that value applies to both server and client. Additionally, the `'hidden'` option is also available for both server and client. Available options for both client and server: - `true`: Generates sourcemaps and includes source references in the final bundle. - `false`: Does not generate any sourcemaps. - `'hidden'`: Generates sourcemaps but does not include references in the final bundle. - **Type**: `object` - **Default** ```json { "server": true, "client": false } ``` ## spaLoadingTemplate Boolean or a path to an HTML file with the contents of which will be inserted into any HTML page rendered with `ssr: false`. - If it is unset, it will use `~/spa-loading-template.html` file in one of your layers, if it exists. - If it is false, no SPA loading indicator will be loaded. - If true, Nuxt will look for `~/spa-loading-template.html` file in one of your layers, or a default Nuxt image will be used. Some good sources for spinners are [SpinKit](https://github.com/tobiasahlin/SpinKit) or [SVG Spinners](https://icones.js.org/collection/svg-spinners). - **Default:** `null` **Example**: ~/spa-loading-template.html ```html <!-- https://github.com/barelyhuman/snips/blob/dev/pages/css-loader.md --> <div class="loader"></div> <style> .loader { display: block; position: fixed; z-index: 1031; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 18px; height: 18px; box-sizing: border-box; border: solid 2px transparent; border-top-color: #000; border-left-color: #000; border-bottom-color: #efefef; border-right-color: #efefef; border-radius: 50%; -webkit-animation: loader 400ms linear infinite; animation: loader 400ms linear infinite; } @-webkit-keyframes loader { 0% { -webkit-transform: translate(-50%, -50%) rotate(0deg); } 100% { -webkit-transform: translate(-50%, -50%) rotate(360deg); } } @keyframes loader { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } </style> ``` ## srcDir Define the source directory of your Nuxt application. If a relative path is specified, it will be relative to the `rootDir`. - **Type**: `string` - **Default:** `"app"` (Nuxt 4), `"."` (Nuxt 3 with `compatibilityMode: 3`) **Example**: ```ts export default defineNuxtConfig({ srcDir: 'app/', }) ``` This expects the following folder structure: ```bash -| app/ ---| assets/ ---| components/ ---| composables/ ---| layouts/ ---| middleware/ ---| pages/ ---| plugins/ ---| utils/ ---| app.config.ts ---| app.vue ---| error.vue -| server/ -| shared/ -| public/ -| modules/ -| layers/ -| nuxt.config.ts -| package.json ``` ## ssr Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time. If set to `false` generated pages will have no content. - **Type**: `boolean` - **Default:** `true` ## telemetry Manually disable nuxt telemetry. **See**: [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information. ## test Whether your app is being unit tested. - **Type**: `boolean` - **Default:** `false` ## theme Extend project from a local or remote source. Value should be a string pointing to source directory or config path relative to current config. You can use `github:`, `gitlab:`, `bitbucket:` or `https://` to extend from a remote git repository. - **Type**: `string` ## typescript Configuration for Nuxt's TypeScript integration. ### `appTsConfig` You can extend the generated `.nuxt/tsconfig.app.json` (and legacy `.nuxt/tsconfig.json`) TypeScript configuration using this option. Options set here take precedence over `tsConfig`. **See**: [tsconfig.json information](https://nuxt.com/docs/5.x/directory-structure/tsconfig) ### `builder` Which builder types to include for your project. By default Nuxt infers this based on your `builder` option (defaulting to 'vite') but you can either turn off builder environment types (with `false`) to handle this fully yourself, or opt for a 'shared' option. The 'shared' option is advised for module authors, who will want to support multiple possible builders. - **Default:** `null` ### `hoist` Modules to generate deep aliases for within `compilerOptions.paths`. This does not yet support subpaths. It may be necessary when using Nuxt within a pnpm monorepo with `shamefully-hoist=false`. - **Type**: `array` - **Default** ```json [ "nitro/types", "nitro/runtime-config", "nitro", "defu", "h3", "consola", "ofetch", "@unhead/vue", "@nuxt/devtools", "vue", "@vue/runtime-core", "@vue/compiler-sfc", "vue-router", "vue-router/auto-routes", "unplugin-vue-router/client", "@nuxt/schema", "nuxt" ] ``` ### `includeWorkspace` Include parent workspace in the Nuxt project. Mostly useful for themes and module authors. - **Type**: `boolean` - **Default:** `false` ### `nodeTsConfig` You can extend the generated `.nuxt/tsconfig.node.json` TypeScript configuration using this option. **See**: [tsconfig.json information](https://nuxt.com/docs/5.x/directory-structure/tsconfig) ### `serverTsConfig` You can extend the generated `.nuxt/tsconfig.server.json` TypeScript configuration using this option. Options set here take precedence over `tsConfig`. **See**: [tsconfig.json information](https://nuxt.com/docs/5.x/directory-structure/tsconfig) ### `sharedTsConfig` You can extend the generated `.nuxt/tsconfig.shared.json` TypeScript configuration using this option. **See**: [tsconfig.json information](https://nuxt.com/docs/5.x/directory-structure/tsconfig) ### `shim` Generate a `*.vue` shim. We recommend instead letting the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) generate accurate types for your components. Note that you may wish to set this to `true` if you are using other libraries, such as ESLint, that are unable to understand the type of `.vue` files. - **Type**: `boolean` - **Default:** `false` ### `strict` TypeScript comes with certain checks to give you more safety and analysis of your program. Once youโ€™ve converted your codebase to TypeScript, you can start enabling these checks for greater safety. [Read More](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) - **Type**: `boolean` - **Default:** `true` ### `tsConfig` You can extend the generated tsconfig files with shared options using this option. `compilerOptions` apply to all generated tsconfigs (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, `.nuxt/tsconfig.node.json` and `.nuxt/tsconfig.shared.json`), while `include`, `exclude` and `vueCompilerOptions` apply only to `.nuxt/tsconfig.app.json` (and the legacy `.nuxt/tsconfig.json`). Two groups of `compilerOptions` are exceptions: DOM- and Vue-specific options (such as `lib`, `jsx` and `jsxImportSource`) apply only to `.nuxt/tsconfig.app.json`, and `types`, `paths` and `noEmit` are managed by Nuxt per context, so they cannot be set globally for the `node`, `shared` and `server` tsconfigs. Use `appTsConfig`, `serverTsConfig`, `nodeTsConfig` or `sharedTsConfig` for context-specific overrides; they take precedence over this option. **See**: [tsconfig.json information](https://nuxt.com/docs/5.x/directory-structure/tsconfig) ### `typeCheck` Enable build-time type checking. If set to true, this will type check in development. You can restrict this to build-time type checking by setting it to `build`. Requires to install `typescript` and `vue-tsc` as dev dependencies. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt TypeScript docs](https://nuxt.com/docs/5.x/guide/concepts/typescript) ## unhead An object that allows us to configure the `unhead` nuxt module. ### `legacy` Enable the legacy compatibility mode for `unhead` module. This applies the following changes: - Disables Capo.js sorting - Adds the `DeprecationsPlugin`: supports `hid`, `vmid`, `children`, `body` - Adds the `PromisesPlugin`: supports promises as input - **Type**: `boolean` - **Default:** `false` **See**: [`unhead` migration documentation](https://unhead.unjs.io/docs/typescript/head/guides/get-started/migration) **Example**: ```ts export default defineNuxtConfig({ unhead: { legacy: true, }, }) ``` ### `renderSSRHeadOptions` An object that will be passed to `renderSSRHead` to customize the output. - **Type**: `object` - **Default** ```json { "omitLineBreaks": false } ``` **Example**: ```ts export default defineNuxtConfig({ unhead: { renderSSRHeadOptions: { omitLineBreaks: true, }, }, }) ``` ## vite Configuration that will be passed directly to Vite. Top-level `vite` options are shared across both client and server environments. Use `$client` and `$server` to provide environment-specific configuration that will be merged into their respective builds. **Example**: ```ts export default defineNuxtConfig({ vite: { $client: { build: { rollupOptions: { output: { manualChunks: { analytics: ['analytics-package'], }, }, }, }, }, $server: { build: { sourcemap: 'inline', }, }, }, }) ``` **See**: [Vite configuration docs](https://vite.dev/config/) for more information. Please note that not all vite options are supported in Nuxt. ### `$client` Configuration that will be merged into Vite's configuration for the client (browser) build. - **Type**: `object` ### `$server` Configuration that will be merged into Vite's configuration for the server build. - **Type**: `object` ### `build` #### `assetsDir` - **Type**: `string` - **Default:** `"_nuxt/"` #### `emptyOutDir` - **Type**: `boolean` - **Default:** `false` ### `cacheDir` - **Type**: `string` - **Default:** `"/<rootDir>/node_modules/.cache/vite"` ### `clearScreen` - **Type**: `boolean` - **Default:** `true` ### `define` - **Type**: `object` - **Default** ```json { "__VUE_PROD_HYDRATION_MISMATCH_DETAILS__": false, "process.dev": false, "import.meta.dev": false, "process.test": false, "import.meta.test": false } ``` ### `esbuild` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` ### `mode` - **Type**: `string` - **Default:** `"production"` ### `optimizeDeps` #### `esbuildOptions` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` #### `exclude` - **Type**: `array` - **Default** ```json [ "vue-demi" ] ``` ### `publicDir` ### `resolve` #### `extensions` - **Type**: `array` - **Default** ```json [ ".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue" ] ``` ### `root` - **Type**: `string` - **Default:** `"/<rootDir>"` ### `server` #### `fs` ##### `allow` - **Type**: `array` - **Default** ```json [ "/<rootDir>/.nuxt", "/<rootDir>/app", "/<rootDir>", "/<workspaceDir>" ] ``` ### `vue` #### `features` ##### `propsDestructure` - **Type**: `boolean` - **Default:** `true` #### `isProduction` - **Type**: `boolean` - **Default:** `true` #### `script` ##### `hoistStatic` #### `template` ##### `compilerOptions` - **Type**: `object` ##### `transformAssetUrls` - **Type**: `object` - **Default** ```json { "video": [ "src", "poster" ], "source": [ "src" ], "img": [ "src" ], "image": [ "xlink:href", "href" ], "use": [ "xlink:href", "href" ] } ``` ### `vueJsx` - **Type**: `object` - **Default** ```json { "isCustomElement": { "$schema": { "title": "", "description": "", "tags": [] } } } ``` ## vue Vue.js config ### `compilerOptions` Options for the Vue compiler that will be passed at build time. **See**: [Vue documentation](https://vuejs.org/api/application#app-config-compileroptions) ### `config` It is possible to pass configure the Vue app globally. Only serializable options may be set in your `nuxt.config`. All other options should be set at runtime in a Nuxt plugin. **See**: [Vue app config documentation](https://vuejs.org/api/application#app-config) ### `propsDestructure` Enable reactive destructure for `defineProps` - **Type**: `boolean` - **Default:** `true` ### `runtimeCompiler` Include Vue compiler in runtime bundle. Enabling this allows components to compile templates at runtime (for example, string `template` options or templates supplied via data). - **Type**: `boolean` - **Default:** `false` <warning> Runtime template compilation executes the compiled template as JavaScript. Never compile templates built from user-provided or otherwise untrusted input; doing so is equivalent to `eval` and can lead to cross-site scripting or remote code execution. See the [Vue security guide](https://vuejs.org/guide/best-practices/security.html). </warning> ### `transformAssetUrls` #### `image` - **Type**: `array` - **Default** ```json [ "xlink:href", "href" ] ``` #### `img` - **Type**: `array` - **Default** ```json [ "src" ] ``` #### `source` - **Type**: `array` - **Default** ```json [ "src" ] ``` #### `use` - **Type**: `array` - **Default** ```json [ "xlink:href", "href" ] ``` #### `video` - **Type**: `array` - **Default** ```json [ "src", "poster" ] ``` ## watch The watch property lets you define patterns that will restart the Nuxt dev server when changed. It is an array of strings or regular expressions. Strings should be either absolute paths or relative to the `srcDir` (and the `srcDir` of any layers). Regular expressions will be matched against the path relative to the project `srcDir` (and the `srcDir` of any layers). - **Type**: `array` ## watchers The watchers property lets you overwrite watchers configuration in your `nuxt.config`. ### `chokidar` Options to pass directly to `chokidar`. **See**: [chokidar](https://github.com/paulmillr/chokidar#api) #### `ignoreInitial` - **Type**: `boolean` - **Default:** `true` #### `ignorePermissionErrors` - **Type**: `boolean` - **Default:** `true` ### `rewatchOnRawEvents` An array of event types, which, when received, will cause the watcher to restart. ### `webpack` `watchOptions` to pass directly to webpack. **See**: [webpack@4 watch options](https://v4.webpack.js.org/configuration/watch/#watchoptions). #### `aggregateTimeout` - **Type**: `number` - **Default:** `1000` ## webpack ### `aggressiveCodeRemoval` Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle. - **Type**: `boolean` - **Default:** `false` ### `analyze` If you are using webpack, Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them. Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - **Type**: `object` - **Default** ```json { "template": "treemap", "projectRoot": "/<rootDir>", "filename": "/<rootDir>/.nuxt/analyze/{name}.html" } ``` **Example**: ```ts export default defineNuxtConfig({ webpack: { analyze: { analyzerMode: 'static', }, }, }) ``` ### `cssSourceMap` Enables CSS source map support (defaults to `true` in development). - **Type**: `boolean` - **Default:** `false` ### `devMiddleware` See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options. #### `stats` - **Type**: `string` - **Default:** `"none"` ### `experiments` Configure [webpack experiments](https://webpack.js.org/configuration/experiments/) ### `extractCSS` Enables Common CSS Extraction. Using [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin) under the hood, your CSS will be extracted into separate files, usually one per component. This allows caching your CSS and JavaScript separately. - **Type**: `boolean` - **Default:** `true` **Example**: ```ts export default defineNuxtConfig({ webpack: { extractCSS: true, // or extractCSS: { ignoreOrder: true, }, }, }) ``` If you want to extract all your CSS to a single file, there is a workaround for this. However, note that it is not recommended to extract everything into a single file. Extracting into multiple CSS files is better for caching and preload isolation. It can also improve page performance by downloading and resolving only those resources that are needed. **Example**: ```ts export default defineNuxtConfig({ webpack: { extractCSS: true, optimization: { splitChunks: { cacheGroups: { styles: { name: 'styles', test: /\.(css|vue)$/, chunks: 'all', enforce: true, }, }, }, }, }, }) ``` ### `filenames` Customize bundle filenames. To understand a bit more about the use of manifests, take a look at [webpack documentation](https://webpack.js.org/guides/code-splitting/). <callout> **Note**: Be careful when using non-hashed based filenames in production as most browsers will cache the asset and not detect the changes on first load. </callout> This example changes fancy chunk names to numerical ids: **Example**: ```ts export default defineNuxtConfig({ webpack: { filenames: { chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js'), }, }, }) ``` #### `app` - **Type**: `function` #### `chunk` - **Type**: `function` #### `css` - **Type**: `function` #### `font` - **Type**: `function` #### `img` - **Type**: `function` #### `video` - **Type**: `function` ### `friendlyErrors` Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin). - **Type**: `boolean` - **Default:** `true` ### `hotMiddleware` See [webpack-hot-middleware](https://github.com/webpack/webpack-hot-middleware) for available options. ### `loaders` Customize the options of Nuxt's integrated webpack loaders. #### `css` See [css-loader](https://github.com/webpack/css-loader) for available options. ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `importLoaders` - **Type**: `number` - **Default:** `0` ##### `url` ###### `filter` - **Type**: `function` #### `cssModules` See [css-loader](https://github.com/webpack/css-loader) for available options. ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `importLoaders` - **Type**: `number` - **Default:** `0` ##### `modules` ###### `localIdentName` - **Type**: `string` - **Default:** `"[local]_[hash:base64:5]"` ##### `url` ###### `filter` - **Type**: `function` #### `esbuild` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` **See**: [esbuild loader](https://github.com/privatenumber/esbuild-loader) #### `file` **See**: [`file-loader` Options](https://github.com/webpack/file-loader#options) **Default**: ```json { "esModule": false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `fontUrl` **See**: [`file-loader` Options](https://github.com/webpack/file-loader#options) **Default**: ```json { "esModule": false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `imgUrl` **See**: [`file-loader` Options](https://github.com/webpack/file-loader#options) **Default**: ```json { "esModule": false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `less` - **Default** ```json { "sourceMap": false } ``` **See**: [`less-loader` Options](https://github.com/webpack/less-loader#options) #### `pugPlain` **See**: [`pug` options](https://pugjs.org/api/reference.html#options) #### `sass` **See**: [`sass-loader` Options](https://github.com/webpack/sass-loader#options) **Default**: ```json { "sassOptions": { "indentedSyntax": true } } ``` ##### `sassOptions` ###### `indentedSyntax` - **Type**: `boolean` - **Default:** `true` #### `scss` - **Default** ```json { "sourceMap": false } ``` **See**: [`sass-loader` Options](https://github.com/webpack/sass-loader#options) #### `stylus` - **Default** ```json { "sourceMap": false } ``` **See**: [`stylus-loader` Options](https://github.com/webpack/stylus-loader#options) #### `vue` See [vue-loader](https://github.com/vuejs/vue-loader) for available options. ##### `compilerOptions` - **Type**: `object` ##### `propsDestructure` - **Type**: `boolean` - **Default:** `true` ##### `transformAssetUrls` - **Type**: `object` - **Default** ```json { "video": [ "src", "poster" ], "source": [ "src" ], "img": [ "src" ], "image": [ "xlink:href", "href" ], "use": [ "xlink:href", "href" ] } ``` #### `vueStyle` - **Default** ```json { "sourceMap": false } ``` ### `optimization` Configure [webpack optimization](https://webpack.js.org/configuration/optimization/). #### `minimize` Set minimize to `false` to disable all minimizers. (It is disabled in development by default). - **Type**: `boolean` - **Default:** `true` #### `minimizer` You can set minimizer to a customized array of plugins. #### `runtimeChunk` - **Type**: `string` - **Default:** `"single"` #### `splitChunks` ##### `automaticNameDelimiter` - **Type**: `string` - **Default:** `"/"` ##### `cacheGroups` ##### `chunks` - **Type**: `string` - **Default:** `"all"` ### `optimizeCSS` OptimizeCSSAssets plugin options. Defaults to true when `extractCSS` is enabled. - **Type**: `boolean` - **Default:** `false` **See**: [css-minimizer-webpack-plugin documentation](https://github.com/webpack/css-minimizer-webpack-plugin). ### `plugins` Add webpack plugins. - **Type**: `array` **Example**: ```ts import webpack from 'webpack' import { version } from './package.json' export default defineNuxtConfig({ webpack: { plugins: [ // ... new webpack.DefinePlugin({ 'process.VERSION': version, }), ], }, }) ``` ### `postcss` Customize PostCSS Loader. same options as [`postcss-loader` options](https://github.com/webpack/postcss-loader#options) #### `postcssOptions` ##### `plugins` - **Type**: `object` - **Default** ```json { "autoprefixer": {}, "cssnano": {} } ``` ### `profile` Enable the profiler in webpackbar. It is normally enabled by CLI argument `--profile`. - **Type**: `boolean` - **Default:** `false` **See**: [webpackbar](https://github.com/unjs/webpackbar#profile). ### `serverURLPolyfill` The polyfill library to load to provide URL and URLSearchParams. Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)). - **Type**: `string` - **Default:** `"url"` ### `warningIgnoreFilters` Filters to hide build warnings. - **Type**: `array` ## workspaceDir Define the workspace directory of your application. Often this is used when in a monorepo setup. Nuxt will attempt to detect your workspace directory automatically, but you can override it here. It is normally not needed to configure this option. - **Type**: `string` - **Default:** `"/<workspaceDir>"` # abortNavigation > abortNavigation is a helper function that prevents navigation from taking place and throws an error if one is set as a parameter. <warning> `abortNavigation` is only usable inside a [route middleware handler](https://nuxt.com/docs/5.x/directory-structure/app/middleware). </warning> ## Type ```ts [Signature] export function abortNavigation (err?: Error | string): false ``` ## Parameters ### `err` - **Type**: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) | `string`<br /> Optional error to be thrown by `abortNavigation`. ## Example The example below shows how you can use `abortNavigation` in a route middleware to prevent unauthorized route access: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const user = useState('user') if (!user.value.isAuthorized) { return abortNavigation() } if (to.path !== '/edit-post') { return navigateTo('/edit-post') } }) ``` ### `err` as a String You can pass the error as a string: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const user = useState('user') if (!user.value.isAuthorized) { return abortNavigation('Insufficient permissions.') } }) ``` ### `err` as an Error Object You can pass the error as an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object, e.g. caught by the `catch`-block: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { try { /* code that might throw an error */ } catch (err) { return abortNavigation(err) } }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # addRouteMiddleware > addRouteMiddleware() is a helper function to dynamically add middleware in your application. <note> Route middleware are navigation guards stored in the [`app/middleware/`](https://nuxt.com/docs/5.x/directory-structure/app/middleware) directory of your Nuxt application (unless [set otherwise](https://nuxt.com/docs/5.x/api/nuxt-config#middleware)). </note> ## Type ```ts [Signature] function addRouteMiddleware (name: string, middleware: RouteMiddleware, options?: AddRouteMiddlewareOptions): void function addRouteMiddleware (middleware: RouteMiddleware): void interface AddRouteMiddlewareOptions { global?: boolean } ``` ## Parameters ### `name` - **Type:** `string` | `RouteMiddleware` Can be either a string or a function of type `RouteMiddleware`. Function takes the next route `to` as the first argument and the current route `from` as the second argument, both of which are Vue route objects. Learn more about available properties of [route objects](https://nuxt.com/docs/5.x/api/composables/use-route). ### `middleware` - **Type:** `RouteMiddleware` The second argument is a function of type `RouteMiddleware`. Same as above, it provides `to` and `from` route objects. It becomes optional if the first argument in `addRouteMiddleware()` is already passed as a function. ### `options` - **Type:** `AddRouteMiddlewareOptions` An optional `options` argument lets you set the value of `global` to `true` to indicate whether the router middleware is global or not (set to `false` by default). ## Example ### Named Route Middleware Named route middleware is defined by providing a string as the first argument and a function as the second: ```ts [app/plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware('named-middleware', () => { console.log('named middleware added in Nuxt plugin') }) }) ``` When defined in a plugin, it overrides any existing middleware of the same name located in the `app/middleware/` directory. ### Global Route Middleware Global route middleware can be defined in two ways: - Pass a function directly as the first argument without a name. It will automatically be treated as global middleware and applied on every route change.```ts [app/plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware((to, from) => { console.log('anonymous global middleware that runs on every route change') }) }) ``` - Set an optional, third argument `{ global: true }` to indicate whether the route middleware is global.```ts [app/plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware('global-middleware', (to, from) => { console.log('global middleware that runs on every route change') }, { global: true }, ) }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # callOnce > Run a given function or block of code once during SSR or CSR. <important> This utility is available since [Nuxt v3.9](https://nuxt.com/blog/v3-9). </important> ## Purpose The `callOnce` function is designed to execute a given function or block of code only once during: - server-side rendering but not hydration - client-side navigation This is useful for code that should be executed only once, such as logging an event or setting up a global state. ## Usage The default mode of `callOnce` is to run code only once. For example, if the code runs on the server it won't run again on the client. It also won't run again if you `callOnce` more than once on the client, for example by navigating back to this page. ```vue [app/app.vue] <script setup lang="ts"> const websiteConfig = useState('config') await callOnce(async () => { console.log('This will only be logged once') websiteConfig.value = await $fetch('https://my-cms.com/api/website-config') }) </script> ``` It is also possible to run on every navigation while still avoiding the initial server/client double execution. For this, it is possible to use the `navigation` mode <badge className="align-middle" color="info" size="xs"> v3.15 </badge> : ```vue [app/app.vue] <script setup lang="ts"> const websiteConfig = useState('config') await callOnce(async () => { console.log('This will only be logged once and then on every client side navigation') websiteConfig.value = await $fetch('https://my-cms.com/api/website-config') }, { mode: 'navigation' }) </script> ``` <important> `navigation` mode is available since [Nuxt v3.15](https://nuxt.com/blog/v3-15). </important> <tip to="https://nuxt.com/docs/5.x/getting-started/state-management#usage-with-pinia"> `callOnce` is useful in combination with the [Pinia module](https://nuxt.com/modules/pinia) to call store actions. </tip> <read-more to="https://nuxt.com/docs/5.x/getting-started/state-management"> </read-more> <warning> Note that `callOnce` doesn't return anything. You should use [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) or [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) if you want to do data fetching during SSR. </warning> <note> `callOnce` is a composable meant to be called directly in a setup function, plugin, or route middleware, because it needs to add data to the Nuxt payload to avoid re-calling the function on the client when the page hydrates. </note> ## Type ```ts [Signature] export function callOnce (key?: string, fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void> export function callOnce (fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void> type CallOnceOptions = { /** * Execution mode for the callOnce function * @default 'render' */ mode?: 'navigation' | 'render' } ``` ## Parameters - `key`: A unique key ensuring that the code is run once. If you do not provide a key, then a key that is unique to the file and line number of the instance of `callOnce` will be generated for you. - `fn`: The function to run once. It can be asynchronous. - `options`: Setup the mode, either to re-execute on navigation (`navigation`) or just once for the lifetime of the app (`render`). Defaults to `render`. - `render`: Executes once during initial render (either SSR or CSR) - Default mode - `navigation`: Executes once during initial render and once per subsequent client-side navigation --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/once.ts) # clearError > The clearError composable clears all handled errors. Within your pages, components, and plugins, you can use `clearError` to clear all errors and redirect the user. **Parameters:** - `options?: { redirect?: string }` You can provide an optional path to redirect to (for example, if you want to navigate to a 'safe' page). ```ts // Without redirect clearError() // With redirect clearError({ redirect: '/homepage' }) ``` Errors are set in state using [`useError()`](https://nuxt.com/docs/5.x/api/composables/use-error). The `clearError` composable will reset this state and calls the `app:error:cleared` hook with the provided options. <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # clearNuxtData > Delete cached data, error status and pending promises of useAsyncData and useFetch. <note> This method is useful if you want to invalidate the data fetching for another page. </note> ## Type ```ts [Signature] export function clearNuxtData (keys?: string | string[] | ((key: string) => boolean)): void ``` ## Parameters - `keys`: One or an array of keys that are used in [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) to delete their cached data. If no keys are provided, **all data** will be invalidated. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # clearNuxtState > Delete the cached state of useState. <note> This method is useful if you want to invalidate the state of `useState`. You can also reset the state to its initial value by passing `{ reset: true }` as the second parameter. </note> ## Type ```ts [Signature] export function clearNuxtState (keys?: string | string[] | ((key: string) => boolean), opts?: ClearNuxtStateOptions): void ``` ## Parameters - `keys`: One or an array of keys that are used in [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) to delete their cached state. If no keys are provided, **all state** will be invalidated. - `opts`: An options object to configure the clear behavior. - `reset` <badge className="align-middle" color="info" size="xs"> v4.4 </badge> : When set to `true`, resets the state to the initial value provided by the `init` function of [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) instead of setting it to `undefined`. When not specified, defaults to the value of `experimental.defaults.useState.resetOnClear` in your Nuxt config (which is `true` with `compatibilityVersion: 5`). --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/state.ts) # createError > Create an error object with additional metadata. You can use this function to create an error object with additional metadata. It is usable in both the Vue and Nitro portions of your app, and is meant to be thrown. ## Parameters - `err`: `string | { cause, data, message, name, stack, status, statusText, fatal }` You can pass either a string or an object to the `createError` function. If you pass a string, it will be used as the error `message`, and the `status` will default to `500`. If you pass an object, you can set multiple properties of the error, such as `status`, `message`, and other error properties. ## In Vue App If you throw an error created with `createError`: - on server-side, it will trigger a full-screen error page which you can clear with `clearError`. - on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`. ### Example ```vue [app/pages/movies/[slug].vue] <script setup lang="ts"> const route = useRoute() const { data } = await useFetch(`/api/movies/${route.params.slug}`) if (!data.value) { throw createError({ status: 404, statusText: 'Page Not Found' }) } </script> ``` ### Error Causes You can pass a `cause` when creating an error to preserve the original error you are wrapping: ```ts try { await fetchMovie(route.params.slug) } catch (cause) { throw createError({ status: 500, message: 'Could not load movie', cause, }) } ``` In development, the cause chain is exposed to your [error page](https://nuxt.com/docs/5.x/getting-started/error-handling#error-page) via the `cause` property of the error, serialized as `{ name, message, stack, cause }` (primitive causes are passed through as-is; other values are omitted). In production, causes are never included in error responses or in the error page payload. ## In API Routes Use `createError` to trigger error handling in server API routes. ### Example ```ts [server/api/error.ts] export default eventHandler(() => { throw createError({ status: 404, statusText: 'Page Not Found', }) }) ``` In API routes, using `createError` by passing an object with a short `statusText` is recommended because it can be accessed on the client side. Otherwise, a `message` passed to `createError` on an API route will not propagate to the client. Alternatively, you can use the `data` property to pass data back to the client. When handling the error with `useFetch`, the custom data is available at `error.value.data.data`. In any case, always consider avoiding to put dynamic user input to the message to avoid potential security issues. <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # defineLazyHydrationComponent > Define a lazy hydration component with a specific strategy. `defineLazyHydrationComponent` is a compiler macro that helps you create a component with a specific lazy hydration strategy. Lazy hydration defers hydration until components become visible or until the browser has completed more critical tasks. This can significantly reduce the initial performance cost, especially for non-essential components. ## Usage ### Visibility Strategy Hydrates the component when it becomes visible in the viewport. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'visible', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the element(s) is 100px away from entering the viewport. --> <LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" /> </div> </template> ``` The `hydrateOnVisible` prop is optional. You can pass an object to customize the behavior of the `IntersectionObserver` under the hood. <read-more title="IntersectionObserver options" to="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver"> Read more about the options for `hydrate-on-visible`. </read-more> <note> Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible). </note> ### Idle Strategy Hydrates the component when the browser is idle. This is suitable if you need the component to load as soon as possible, but not block the critical rendering path. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'idle', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the browser is idle or after 2000ms. --> <LazyHydrationMyComponent :hydrate-on-idle="2000" /> </div> </template> ``` The `hydrateOnIdle` prop is optional. You can pass a positive number to specify the maximum timeout. Idle strategy is for components that can be hydrated when the browser is idle. <note> Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle). </note> ### Interaction Strategy Hydrates the component after a specified interaction (e.g., click, mouseover). ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'interaction', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the element(s) is hovered over by the pointer. --> <LazyHydrationMyComponent hydrate-on-interaction="mouseover" /> </div> </template> ``` The `hydrateOnInteraction` prop is optional. If you do not pass an event or a list of events, it defaults to hydrating on `pointerenter`, `click`, and `focus`. <note> Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction). </note> ### Media Query Strategy Hydrates the component when the window matches a media query. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'mediaQuery', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the window width is greater than or equal to 768px. --> <LazyHydrationMyComponent hydrate-on-media-query="(min-width: 768px)" /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query). </note> ### Time Strategy Hydrates the component after a specified delay (in milliseconds). ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'time', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration is triggered after 1000ms. --> <LazyHydrationMyComponent :hydrate-after="1000" /> </div> </template> ``` Time strategy is for components that can wait a specific amount of time. ### If Strategy Hydrates the component based on a boolean condition. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'if', () => import('./components/MyComponent.vue'), ) const isReady = ref(false) function myFunction () { // Trigger custom hydration strategy... isReady.value = true } </script> <template> <div> <!-- Hydration is triggered when isReady becomes true. --> <LazyHydrationMyComponent :hydrate-when="isReady" /> </div> </template> ``` If strategy is best for components that might not always need to be hydrated. ### Never Hydrate Never hydrates the component. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'never', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- This component will never be hydrated by Vue. --> <LazyHydrationMyComponent /> </div> </template> ``` ### Listening to Hydration Events All delayed hydration components emit a `@hydrated` event when they are hydrated. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'visible', () => import('./components/MyComponent.vue'), ) function onHydrate () { console.log('Component has been hydrated!') } </script> <template> <div> <LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" @hydrated="onHydrated" /> </div> </template> ``` ## Parameters <warning> To ensure that the compiler correctly recognizes this macro, avoid using external variables. The following approach will prevent the macro from being properly recognized: ```vue <script setup lang="ts"> const strategy = 'visible' const source = () => import('./components/MyComponent.vue') const LazyHydrationMyComponent = defineLazyHydrationComponent(strategy, source) </script> ``` </warning> ### `strategy` - **Type**: `'visible' | 'idle' | 'interaction' | 'mediaQuery' | 'if' | 'time' | 'never'` - **Required**: `true` <table> <thead> <tr> <th> Strategy </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> visible </code> </td> <td> Hydrates when the component becomes visible in the viewport. </td> </tr> <tr> <td> <code> idle </code> </td> <td> Hydrates when the browser is idle or after a delay. </td> </tr> <tr> <td> <code> interaction </code> </td> <td> Hydrates upon user interaction (e.g., click, hover). </td> </tr> <tr> <td> <code> mediaQuery </code> </td> <td> Hydrates when the specified media query condition is met. </td> </tr> <tr> <td> <code> if </code> </td> <td> Hydrates when a specified boolean condition is met. </td> </tr> <tr> <td> <code> time </code> </td> <td> Hydrates after a specified time delay. </td> </tr> <tr> <td> <code> never </code> </td> <td> Prevents Vue from hydrating the component. </td> </tr> </tbody> </table> ### `source` - **Type**: `() => Promise<Component>` - **Required**: `true` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/components/plugins/lazy-hydration-macro-transform.ts) # defineNuxtComponent > defineNuxtComponent() is a helper function for defining type safe components with Options API. <note> `defineNuxtComponent()` is a helper function for defining type safe Vue components using options API similar to [`defineComponent()`](https://vuejs.org/api/general#definecomponent). `defineNuxtComponent()` wrapper also adds support for `asyncData` and `head` component options. </note> <note> Using `<script setup lang="ts">` is the recommended way of declaring Vue components in Nuxt. </note> <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> ## `asyncData()` If you choose not to use `setup()` in your app, you can use the `asyncData()` method within your component definition: ```vue [app/pages/index.vue] <script lang="ts"> export default defineNuxtComponent({ asyncData () { return { data: { greetings: 'hello world!', }, } }, }) </script> ``` ## `head()` If you choose not to use `setup()` in your app, you can use the `head()` method within your component definition: ```vue [app/pages/index.vue] <script lang="ts"> export default defineNuxtComponent({ head (nuxtApp) { return { title: 'My site', } }, }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/component.ts) # defineNuxtPlugin > defineNuxtPlugin() is a helper function for creating Nuxt plugins. `defineNuxtPlugin` is a helper function for creating Nuxt plugins with enhanced functionality and type safety. This utility normalizes different plugin formats into a consistent structure that works seamlessly within Nuxt's plugin system. ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp }) ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/plugins#creating-plugins"> </read-more> ## Type ```ts [Signature] export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPlugin<T>): Plugin<T> & ObjectPlugin<T> type Plugin<T> = (nuxt: NuxtApp) => Promise<void> | Promise<{ provide?: T }> | void | { provide?: T } interface ObjectPlugin<T> { name?: string enforce?: 'pre' | 'default' | 'post' dependsOn?: string[] order?: number parallel?: boolean setup?: Plugin<T> hooks?: Partial<RuntimeNuxtHooks> env?: { islands?: boolean } } ``` ## Parameters **plugin**: A plugin can be defined in two ways: 1. **Function Plugin**: A function that receives the [`NuxtApp`](https://nuxt.com/docs/5.x/guide/going-further/internals#the-nuxtapp-interface) instance and can return a promise with a potential object with a [`provide`](https://nuxt.com/docs/5.x/directory-structure/app/plugins#providing-helpers) property if you want to provide a helper on [`NuxtApp`](https://nuxt.com/docs/5.x/guide/going-further/internals#the-nuxtapp-interface) instance. 2. **Object Plugin**: An object that can include various properties to configure the plugin's behavior, such as `name`, `enforce`, `dependsOn`, `order`, `parallel`, `setup`, `hooks`, and `env`. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Optional name for the plugin, useful for debugging and dependency management. </td> </tr> <tr> <td> <code> enforce </code> </td> <td> <code> 'pre' </code> | <code> 'default' </code> | <code> 'post' </code> </td> <td> <code> false </code> </td> <td> Controls when the plugin runs relative to other plugins. </td> </tr> <tr> <td> <code> dependsOn </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Array of plugin names this plugin depends on. Ensures proper execution order. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> This allows more granular control over plugin order and should only be used by advanced users. <strong> It overrides the value of <code> enforce </code> and is used to sort plugins. </strong> </td> </tr> <tr> <td> <code> parallel </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to execute the plugin in parallel with other parallel plugins. </td> </tr> <tr> <td> <code> setup </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Plugin </span> <span class="sDfIl"> < </span> <span class="sZSNi"> T </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> The main plugin function, equivalent to a function plugin. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Partial </span> <span class="sDfIl"> < </span> <span class="sZSNi"> RuntimeNuxtHooks </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Nuxt app runtime hooks to register directly. </td> </tr> <tr> <td> <code> env </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> { </span> <span class="sZSNi"> islands </span> <span class="sDfIl"> ?: </span> <span class="sZSNi"> boolean </span> <span class="sDfIl"> } </span> </code> </td> <td> <code> false </code> </td> <td> Set this value to <code> false </code> if you don't want the plugin to run when rendering server-only or island components. </td> </tr> </tbody> </table> <video-accordion title="Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins" video-id="2aXZyXB1QGQ"> </video-accordion> ## Example ### Basic Usage The example below demonstrates a simple plugin that adds global functionality: ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Add a global method return { provide: { hello: (name: string) => `Hello ${name}!`, }, } }) ``` ### Object Syntax Plugin The example below shows the object syntax with advanced configuration: ```ts [plugins/advanced.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', enforce: 'pre', async setup (nuxtApp) { // Plugin setup logic const data = await $fetch('/api/config') return { provide: { config: data, }, } }, hooks: { 'app:created' () { console.log('App created!') }, }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # defineNuxtRouteMiddleware > Create named route middleware using defineNuxtRouteMiddleware helper function. Route middleware are stored in the [`app/middleware/`](https://nuxt.com/docs/5.x/directory-structure/app/middleware) of your Nuxt application (unless [set otherwise](https://nuxt.com/docs/5.x/api/nuxt-config#middleware)). ## Type ```ts [Signature] export function defineNuxtRouteMiddleware (middleware: RouteMiddleware): RouteMiddleware interface RouteMiddleware { (to: RouteLocationNormalized, from: RouteLocationNormalized): ReturnType<NavigationGuard> } ``` ## Parameters ### `middleware` - **Type**: `RouteMiddleware` A function that takes two Vue Router's route location objects as parameters: the next route `to` as the first, and the current route `from` as the second. Learn more about available properties of `RouteLocationNormalized` in the **Vue Router docs**. ## Example ### Showing Error Page You can use route middleware to throw errors and show helpful error messages: ```ts [app/middleware/error.ts] export default defineNuxtRouteMiddleware((to) => { if (to.params.id === '1') { throw createError({ status: 404, statusText: 'Page Not Found' }) } }) ``` The above route middleware will redirect a user to the custom error page defined in the `~/error.vue` file, and expose the error message and code passed from the middleware. ### Redirection Use [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) in combination with `navigateTo` helper function inside the route middleware to redirect users to different routes based on their authentication status: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const auth = useState('auth') if (!auth.value.isAuthenticated) { return navigateTo('/login') } if (to.path !== '/dashboard') { return navigateTo('/dashboard') } }) ``` Both [navigateTo](https://nuxt.com/docs/5.x/api/utils/navigate-to) and [abortNavigation](https://nuxt.com/docs/5.x/api/utils/abort-navigation) are globally available helper functions that you can use inside `defineNuxtRouteMiddleware`. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # definePageMeta > Define metadata for your page components. `definePageMeta` is a compiler macro that you can use to set metadata for your **page** components located in the [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) directory (unless [set otherwise](https://nuxt.com/docs/5.x/api/nuxt-config#pages)). This way you can set custom metadata for each static or dynamic route of your Nuxt application. ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ layout: 'default', }) </script> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/pages#page-metadata"> </read-more> ## Type ```ts [Signature] export function definePageMeta (meta: PageMeta): void interface PageMeta { validate?: ((route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>) redirect?: RouteRecordRedirectOption name?: string path?: string props?: RouteRecordRaw['props'] alias?: string | string[] groups?: string[] pageTransition?: boolean | TransitionProps layoutTransition?: boolean | TransitionProps viewTransition?: ViewTransitionPageOptions['enabled'] | ViewTransitionPageOptions key?: false | string | ((route: RouteLocationNormalizedLoaded) => string) keepalive?: boolean | KeepAliveProps layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey> | { name?: LayoutKey | false, props?: Record<string, unknown> /* or the selected layout's props */ } middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard> scrollToTop?: boolean | ((to: RouteLocationNormalizedLoaded, from: RouteLocationNormalizedLoaded) => boolean) [key: string]: unknown } ``` ## Parameters ### `meta` - **Type**: `PageMeta`<br /> An object accepting the following page metadata:<br /> **name** - **Type**: `string`<br /> You may define a name for this page's route. By default, name is generated based on path inside the [`app/pages/` directory](https://nuxt.com/docs/5.x/directory-structure/app/pages).<br /> **path** - **Type**: `string`<br /> You may define a [custom regular expression](https://nuxt.com/docs/5.x/api/utils/define-page-meta#using-a-custom-regular-expression) if you have a more complex pattern than can be expressed with the file name.<br /> **props** - **Type**: [`RouteRecordRaw['props']`](https://router.vuejs.org/guide/essentials/passing-props)<br /> Allows accessing the route `params` as props passed to the page component.<br /> **alias** - **Type**: `string | string[]`<br /> Aliases for the record. Allows defining extra paths that will behave like a copy of the record. Allows having paths shorthands like `/users/:id` and `/u/:id`. All `alias` and `path` values must share the same params.<br /> **groups** <badge className="align-middle" color="info" size="xs"> v4.3 </badge> - **Type**: `string[]`<br /> Route groups the page belongs to, based on the folder structure. Automatically populated for pages within [route groups](https://nuxt.com/docs/5.x/guide/directory-structure/app/pages#route-groups).<br /> **keepalive** - **Type**: `boolean` | [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive)<br /> Set to `true` when you want to preserve page state across route changes or use the [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive) for a fine-grained control.<br /> **key** - **Type**: `false` | `string` | `((route: RouteLocationNormalizedLoaded) => string)`<br /> Set `key` value when you need more control over when the `<NuxtPage>` component is re-rendered.<br /> **layout** - **Type**: `false` | `LayoutKey` | `Ref<LayoutKey>` | `ComputedRef<LayoutKey>` | `{ name?: LayoutKey | false; props?: Record<string, unknown> /* or the selected layout's props */ }`<br /> Set a static or dynamic name of the layout for each route. This can be set to `false` in case the default layout needs to be disabled.<br /> You can also pass an object with `name` and `props` to pass typed props to your layout component. When your layout defines props with `defineProps`, they will be fully typed in `definePageMeta`.<br /> **layoutTransition** - **Type**: `boolean` | [`TransitionProps`](https://vuejs.org/api/built-in-components#transition)<br /> Set name of the transition to apply for current layout. You can also set this value to `false` to disable the layout transition.<br /> **middleware** - **Type**: `MiddlewareKey` | [`NavigationGuard`](https://router.vuejs.org/api/interfaces/navigationguard) | `Array<MiddlewareKey | NavigationGuard>`<br /> Define anonymous or named middleware directly within `definePageMeta`. Learn more about [route middleware](https://nuxt.com/docs/5.x/directory-structure/app/middleware).<br /> **pageTransition** - **Type**: `boolean` | [`TransitionProps`](https://vuejs.org/api/built-in-components#transition)<br /> Set name of the transition to apply for current page. You can also set this value to `false` to disable the page transition.<br /> **viewTransition** - **Type**: `boolean | 'always' | ViewTransitionPageOptions`<br /> **Experimental feature, only available when enabled in your nuxt.config file**<br /> Enable/disable View Transitions for the current page. If set to true, Nuxt will not apply the transition if the users browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition.<br /> You can also pass a `ViewTransitionPageOptions` object to configure [view transition types](https://nuxt.com/docs/5.x/getting-started/transitions#view-transition-types): - `enabled`: `boolean | 'always'` - enable/disable the transition - `types`: `string[] | (to, from) => string[]` - types applied to any transition involving this page - `toTypes`: `string[] | (to, from) => string[]` - types applied only when navigating **to** this page - `fromTypes`: `string[] | (to, from) => string[]` - types applied only when navigating **from** this page<br /> **redirect** - **Type**: [`RouteRecordRedirectOption`](https://router.vuejs.org/guide/essentials/redirect-and-alias)<br /> Where to redirect if the route is directly matched. The redirection happens before any navigation guard and triggers a new navigation with the new target location.<br /> **validate** - **Type**: `(route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>`<br /> Validate whether a given route can validly be rendered with this page. Return true if it is valid, or false if not. If another match can't be found, this will mean a 404. You can also directly return an object with `status`/`statusText` to respond immediately with an error (other matches will not be checked).<br /> **scrollToTop** - **Type**: `boolean | (to: RouteLocationNormalized, from: RouteLocationNormalized) => boolean`<br /> Tell Nuxt to scroll to the top before rendering the page or not. Navigation is independent from rendering, so scroll behavior is always triggered even when the page doesn't re-render (e.g. when using a fixed [`key`](https://nuxt.com/docs/5.x/api/utils/define-page-meta#key)). Set `scrollToTop: false` to disable scrolling in such cases. If you want to overwrite the default scroll behavior of Nuxt, you can do so in `~/router.options.ts` (see [custom routing](https://nuxt.com/docs/5.x/guide/recipes/custom-routing#using-routeroptions)) for more info.<br /> **[key: string]** - **Type**: `any`<br /> Apart from the above properties, you can also set **custom** metadata. You may wish to do so in a type-safe way by [augmenting the type of the `meta` object](https://nuxt.com/docs/5.x/directory-structure/app/pages/#typing-custom-metadata). ## Example ### Basic Usage The example below demonstrates: - how `key` can be a function that returns a value; - how `keepalive` property makes sure that the `<modal>` component is not cached when switching between multiple components; - adding `pageType` as a custom property: ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, keepalive: { exclude: ['modal'], }, pageType: 'Checkout', }) </script> ``` ### Defining Middleware The example below shows how the middleware can be defined using a `function` directly within the `definePageMeta` or set as a `string` that matches the middleware file name located in the `app/middleware/` directory: ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ // define middleware as a function middleware: [ function (to, from) { const auth = useState('auth') if (!auth.value.authenticated) { return navigateTo('/login') } if (to.path !== '/checkout') { return navigateTo('/checkout') } }, ], // ... or a string middleware: 'auth', // ... or multiple strings middleware: ['auth', 'another-named-middleware'], }) </script> ``` ### Using a Custom Regular Expression A custom regular expression is a good way to resolve conflicts between overlapping routes, for instance: The two routes "/test-category" and "/1234-post" match both `[postId]-[postSlug].vue` and `[categorySlug].vue` page routes. To make sure that we are only matching digits (`\d+`) for `postId` in the `[postId]-[postSlug]` route, we can add the following to the `[postId]-[postSlug].vue` page template: ```vue [app/pages/[postId]-[postSlug].vue] <script setup lang="ts"> definePageMeta({ path: '/:postId(\\d+)-:postSlug', }) </script> ``` For more examples see [Vue Router's Matching Syntax](https://router.vuejs.org/guide/essentials/route-matching-syntax). ### Defining Layout You can define the layout that matches the layout's file name located (by default) in the [`app/layouts/` directory](https://nuxt.com/docs/5.x/directory-structure/app/layouts). You can also disable the layout by setting the `layout` to `false`: ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ // set custom layout layout: 'admin', // ... or disable a default layout layout: false, }) </script> ``` ### Passing Props to a Layout You can pass props to a layout by using the object syntax for `layout`. If your layout defines props with `defineProps`, the props will be fully typed. <code-group> ```vue [app/pages/dashboard.vue] <script setup lang="ts"> definePageMeta({ layout: { name: 'panel', props: { sidebar: true, title: 'Dashboard', }, }, }) </script> ``` ```vue [app/layouts/panel.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` </code-group> <tip> Layout props set via `definePageMeta` are fully typed based on the layout's `defineProps`. You'll get autocomplete and type-checking in your editor. </tip> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/layouts#passing-props-to-layouts"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/composables.ts) # defineRouteRules > Define route rules for hybrid rendering at the page level. <read-more icon="i-lucide-star" to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#inlinerouterules"> This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`. </read-more> ## Usage ```vue [app/pages/index.vue] <script setup lang="ts"> defineRouteRules({ prerender: true, }) </script> <template> <h1>Hello world!</h1> </template> ``` Will be translated to: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, }) ``` <note> When running [`nuxt build`](https://nuxt.com/docs/5.x/api/commands/build), the home page will be pre-rendered in `.output/public/index.html` and statically served. </note> ## Notes - A rule defined in `~/pages/foo/bar.vue` will be applied to `/foo/bar` requests. - A rule in `~/pages/foo/[id].vue` will be applied to `/foo/*` requests. - A rule in a page with a finite set of alternatives, such as a custom `path` of `/:locale(en|fr)/about`, will generate one rule per alternative (`/en/about` and `/fr/about`). If a page path cannot be converted to an equivalent route rule pattern (for example, a param with a regular expression like `/:id(\d+)`, a partial segment like `/prefix-:id`, or a repeatable param like `/:slug+`), the rules for that page are **not** applied and Nuxt warns during build. In that case, define the rules explicitly in `nitro.routeRules` in your `nuxt.config`. For more control, such as if you are using a custom `path` or `alias` set in the page's [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta), you should set `routeRules` directly within your `nuxt.config`. <read-more icon="i-lucide-medal" to="https://nuxt.com/docs/5.x/guide/concepts/rendering#hybrid-rendering"> Read more about the `routeRules`. </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/composables.ts) # $fetch > Nuxt uses ofetch to expose globally the $fetch helper for making HTTP requests. Nuxt uses [ofetch](https://github.com/unjs/ofetch) to expose globally the `$fetch` helper for making HTTP requests within your Vue app or API routes. <tip icon="i-lucide-rocket"> During server-side rendering, calling `$fetch` to fetch your internal [API routes](https://nuxt.com/docs/5.x/directory-structure/server) will directly call the relevant function (emulating the request), **saving an additional API call**. </tip> <note color="blue" icon="i-lucide-info"> Using `$fetch` in components without wrapping it with [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) causes fetching the data twice: initially on the server, then again on the client-side during hydration, because `$fetch` does not transfer state from the server to the client. Thus, the fetch will be executed on both sides because the client has to get the data again. </note> ## Usage We recommend using [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) + `$fetch` to prevent double data fetching when fetching the component data. ```vue [app/app.vue] <script setup lang="ts"> // During SSR data is fetched twice, once on the server and once on the client. const dataTwice = await $fetch('/api/item') // During SSR data is fetched only on the server side and transferred to the client. const { data } = await useAsyncData('item', () => $fetch('/api/item')) // You can also useFetch as shortcut of useAsyncData + $fetch const { data } = await useFetch('/api/item') </script> ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> You can use `$fetch` in any methods that are executed only on client-side. ```vue [app/pages/contact.vue] <script setup lang="ts"> async function contactForm () { await $fetch('/api/contact', { method: 'POST', body: { hello: 'world' }, }) } </script> <template> <button @click="contactForm"> Contact </button> </template> ``` <tip> `$fetch` is the preferred way to make HTTP calls in Nuxt instead of [@nuxt/http](https://github.com/nuxt/http) and [@nuxtjs/axios](https://github.com/nuxt-community/axios-module) that are made for Nuxt 2. </tip> <note> If you use `$fetch` to call an (external) HTTPS URL with a self-signed certificate in development, you will need to set `NODE_TLS_REJECT_UNAUTHORIZED=0` in your environment. </note> ## Typed Requests `$fetch` is typed from the routes your server serves, so a response is typed by the handler that answers it, and a body, query or headers the handler validates are enforced on the call. A path built at runtime, an absolute URL or a `Request` object resolves to `unknown`; naming the response type (`$fetch<Todo[]>(url)`) overrides whatever Nuxt resolved. <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching#typed-routes"> Read more about typed routes, including how to declare a route Nuxt cannot see and how to reject a path no route answers. </read-more> ### Passing Headers and Cookies When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. However, during Server-Side Rendering, due to security risks such as **Server-Side Request Forgery (SSRF)** or **Authentication Misuse**, the `$fetch` wouldn't include the user's browser cookies, nor pass on cookies from the fetch response. <code-group> ```vue [app/pages/index.vue] <script setup lang="ts"> // This will NOT forward headers or cookies during SSR const { data } = await useAsyncData(() => $fetch('/api/cookies')) </script> ``` ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const foo = getCookie(event, 'foo') // ... Do something with the cookie }) ``` </code-group> If you need to forward headers and cookies on the server, you must manually pass them: ```vue [app/pages/index.vue] <script setup lang="ts"> // This will forward the user's headers and cookies to `/api/cookies` const requestFetch = useRequestFetch() const { data } = await useAsyncData(() => requestFetch('/api/cookies')) </script> ``` However, when calling `useFetch` with a relative URL on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/5.x/api/composables/use-request-fetch) to proxy headers and cookies (with the exception of headers not meant to be forwarded, like `host`). --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/entry.ts) # navigateTo > navigateTo is a helper function that programmatically navigates users. ## Usage `navigateTo` is available on both server side and client side. It can be used within the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context), or directly, to perform page navigation. <warning> Make sure to always use `await` or `return` on result of `navigateTo` when calling it. </warning> <note> `navigateTo` cannot be used within Nitro routes. To perform a server-side redirect in Nitro routes, use [`sendRedirect`](https://h3.dev/utils/response#redirectlocation-status-statustext) instead. </note> ### Within a Vue Component ```vue <script setup lang="ts"> // passing 'to' as a string await navigateTo('/search') // ... or as a route object await navigateTo({ path: '/search' }) // ... or as a route object with query parameters await navigateTo({ path: '/search', query: { page: 1, sort: 'asc', }, }) </script> ``` <note> Calling `navigateTo` does not stop execution of the rest of your `<script setup>` code. If you want a successful navigation to return early from `setup()`, enable [`experimental.navigateToEarlyReturn`](https://nuxt.com/docs/5.x/guide/going-further/experimental-features#navigatetoearlyreturn). </note> ### Within Route Middleware ```ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { // setting the redirect code to '301 Moved Permanently' return navigateTo('/search', { redirectCode: 301 }) } }) ``` When using `navigateTo` within route middleware, you must **return its result** to ensure the middleware execution flow works correctly. For example, the following implementation **will not work as expected**: ```ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { // โŒ This will not work as expected navigateTo('/search', { redirectCode: 301 }) return } }) ``` In this case, `navigateTo` will be executed but not returned, which may lead to unexpected behavior. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/middleware"> </read-more> ### Navigating to an External URL The `external` parameter in `navigateTo` influences how navigating to URLs is handled: - **Without external: true**: - Internal URLs navigate as expected. - External URLs throw an error. - **With external: true**: - Internal URLs navigate with a full-page reload. - External URLs navigate as expected. #### Example ```vue <script setup lang="ts"> // will throw an error; // navigating to an external URL is not allowed by default await navigateTo('https://nuxt.com') // will redirect successfully with the 'external' parameter set to 'true' await navigateTo('https://nuxt.com', { external: true, }) </script> ``` ### Opening a Page in a New Tab ```vue <script setup lang="ts"> // will open 'https://nuxt.com' in a new tab await navigateTo('https://nuxt.com', { open: { target: '_blank', windowFeatures: { width: 500, height: 500, }, }, }) </script> ``` ## Type ```ts [Signature] export function navigateTo ( to: RouteLocationRaw | undefined | null, options?: NavigateToOptions, ): Promise<void | NavigationFailure | false> | false | void | RouteLocationRaw interface NavigateToOptions { replace?: boolean redirectCode?: number external?: boolean open?: OpenOptions } type OpenOptions = { target: string windowFeatures?: OpenWindowFeatures } type OpenWindowFeatures = { popup?: boolean noopener?: boolean noreferrer?: boolean } & XOR<{ width?: number }, { innerWidth?: number }> & XOR<{ height?: number }, { innerHeight?: number }> & XOR<{ left?: number }, { screenX?: number }> & XOR<{ top?: number }, { screenY?: number }> ``` ## Parameters ### `to` **Type**: [`RouteLocationRaw`](https://router.vuejs.org/api/interfaces/routelocationoptions) | `undefined` | `null` **Default**: `'/'` `to` can be a plain string or a route object to redirect to. When passed as `undefined` or `null`, it will default to `'/'`. #### Example ```ts // Passing the URL directly will redirect to the '/blog' page await navigateTo('/blog') // Using the route object, will redirect to the route with the name 'blog' await navigateTo({ name: 'blog' }) // Redirects to the 'product' route while passing a parameter (id = 1) using the route object. await navigateTo({ name: 'product', params: { id: 1 } }) ``` ### `options` (optional) **Type**: `NavigateToOptions` An object accepting the following properties: - `replace` - **Type**: `boolean` - **Default**: `false` - By default, `navigateTo` pushes the given route into the Vue Router's instance on the client side.<br /> This behavior can be changed by setting `replace` to `true`, to indicate that given route should be replaced. - `redirectCode` - **Type**: `number` - **Default**: `302` - `navigateTo` redirects to the given path and sets the redirect code to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) by default when the redirection takes place on the server side.<br /> This default behavior can be modified by providing different `redirectCode`. Commonly, [`301 Moved Permanently`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) can be used for permanent redirections. - `external` - **Type**: `boolean` - **Default**: `false` - Allows navigating to an external URL when set to `true`. Otherwise, `navigateTo` will throw an error, as external navigation is not allowed by default. - `open` - **Type**: `OpenOptions` - Allows navigating to the URL using the [open()](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) method of the window. This option is only applicable on the client side and will be ignored on the server side.<br /> An object accepting the following properties: - `target` - **Type**: `string` - **Default**: `'_blank'` - A string, without whitespace, specifying the name of the browsing context the resource is being loaded into. - `windowFeatures` - **Type**: `OpenWindowFeatures` - An object accepting the following properties:<table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> popup </code> </td> <td> <code> boolean </code> </td> <td> Requests a minimal popup window instead of a new tab, with UI features decided by the browser. </td> </tr> <tr> <td> <code> width </code> or <code> innerWidth </code> </td> <td> <code> number </code> </td> <td> Specifies the content area's width (minimum 100 pixels), including scrollbars. </td> </tr> <tr> <td> <code> height </code> or <code> innerHeight </code> </td> <td> <code> number </code> </td> <td> Specifies the content area's height (minimum 100 pixels), including scrollbars. </td> </tr> <tr> <td> <code> left </code> or <code> screenX </code> </td> <td> <code> number </code> </td> <td> Sets the horizontal position of the new window relative to the left edge of the screen. </td> </tr> <tr> <td> <code> top </code> or <code> screenY </code> </td> <td> <code> number </code> </td> <td> Sets the vertical position of the new window relative to the top edge of the screen. </td> </tr> <tr> <td> <code> noopener </code> </td> <td> <code> boolean </code> </td> <td> Prevents the new window from accessing the originating window via <code> window.opener </code> . </td> </tr> <tr> <td> <code> noreferrer </code> </td> <td> <code> boolean </code> </td> <td> Prevents the Referer header from being sent and implicitly enables <code> noopener </code> . </td> </tr> </tbody> </table> <br /> Refer to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#windowfeatures) for more detailed information on the **windowFeatures** properties. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onBeforeRouteLeave > The onBeforeRouteLeave composable allows registering a route guard within a component. <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs" to="https://router.vuejs.org/api/functions/onbeforerouteleave"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onBeforeRouteUpdate > The onBeforeRouteUpdate composable allows registering a route guard within a component. <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs" to="https://router.vuejs.org/api/functions/onbeforerouteupdate"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onNuxtReady > The onNuxtReady composable allows running a callback after your app has finished initializing. <important> `onNuxtReady` only runs on the client-side. <br /> It is ideal for running code that should not block the initial rendering of your app. </important> ```ts [app/plugins/ready.client.ts] export default defineNuxtPlugin(() => { onNuxtReady(async () => { const myAnalyticsLibrary = await import('my-big-analytics-library') // do something with myAnalyticsLibrary }) }) ``` It is 'safe' to run even after your app has initialized. In this case, then the code will be registered to run in the next idle callback. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ready.ts) # prefetchComponents > Nuxt provides utilities to give you control over prefetching components. Prefetching component downloads the code in the background, this is based on the assumption that the component will likely be used for rendering, enabling the component to load instantly if and when the user requests it. The component is downloaded and cached for anticipated future use without the user making an explicit request for it. Use `prefetchComponents` to manually prefetch individual components that have been registered globally in your Nuxt app. By default Nuxt registers these as async components. You must use the Pascal-cased version of the component name. ```ts await prefetchComponents('MyGlobalComponent') await prefetchComponents(['MyGlobalComponent1', 'MyGlobalComponent2']) ``` <note> Current implementation behaves exactly the same as [`preloadComponents`](https://nuxt.com/docs/5.x/api/utils/preload-components) by preloading components instead of just prefetching we are working to improve this behavior. </note> <note> On server, `prefetchComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # preloadComponents > Nuxt provides utilities to give you control over preloading components. Preloading components loads components that your page will need very soon, which you want to start loading early in rendering lifecycle. This ensures they are available earlier and are less likely to block the page's render, improving performance. Use `preloadComponents` to manually preload individual components that have been registered globally in your Nuxt app. By default Nuxt registers these as async components. You must use the Pascal-cased version of the component name. ```ts await preloadComponents('MyGlobalComponent') await preloadComponents(['MyGlobalComponent1', 'MyGlobalComponent2']) ``` <note> On server, `preloadComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # preloadRouteComponents > preloadRouteComponents allows you to manually preload individual pages in your Nuxt app. Preloading routes loads the components of a given route that the user might navigate to in future. This ensures that the components are available earlier and less likely to block the navigation, improving performance. <tip icon="i-lucide-rocket"> Nuxt already automatically preloads the necessary routes if you're using the `NuxtLink` component. </tip> <read-more to="https://nuxt.com/docs/5.x/api/components/nuxt-link"> </read-more> ## Example Preload a route when using `navigateTo`. ```ts // we don't await this async function, to avoid blocking rendering // this component's setup function preloadRouteComponents('/dashboard') const submit = async () => { const results = await $fetch('/api/authentication') if (results.token) { await navigateTo('/dashboard') } } ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/navigate-to"> </read-more> <note> On server, `preloadRouteComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # prerenderRoutes > prerenderRoutes hints to Nitro to prerender an additional route. When prerendering, you can hint to Nitro to prerender additional paths, even if their URLs do not show up in the HTML of the generated page. <important> `prerenderRoutes` can only be called within the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context). </important> <note> `prerenderRoutes` has to be executed during prerendering. If the `prerenderRoutes` is used in dynamic pages/routes which are not prerendered, then it will not be executed. </note> ```ts const route = useRoute() prerenderRoutes('/') prerenderRoutes(['/', '/about']) ``` <note> In the browser, or if called outside prerendering, `prerenderRoutes` will have no effect. </note> You can even prerender API routes which is particularly useful for full statically generated sites (SSG) because you can then `$fetch` data as if you have an available server! ```ts prerenderRoutes('/api/content/article/name-of-article') // Somewhere later in App const articleContent = await $fetch('/api/content/article/name-of-article', { responseType: 'json', }) ``` <warning> Prerendered API routes in production may not return the expected response headers, depending on the provider you deploy to. For example, a JSON response might be served with an `application/octet-stream` content type. Always manually set `responseType` when fetching prerendered API routes. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # refreshCookie > Refresh useCookie values manually when a cookie has changed <important> This utility is available since [Nuxt v3.10](https://nuxt.com/blog/v3-10). </important> ## Purpose The `refreshCookie` function is designed to refresh cookie value returned by `useCookie`. This is useful for updating the `useCookie` ref when we know the new cookie value has been set in the browser. ## Usage ```vue [app/app.vue] <script setup lang="ts"> const tokenCookie = useCookie('token') const login = async (username, password) => { const token = await $fetch('/api/token', { /** ... */ }) // Sets `token` cookie on response refreshCookie('token') } const loggedIn = computed(() => !!tokenCookie.value) </script> ``` <note to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#cookiestore"> Since [Nuxt v3.12.0](https://github.com/nuxt/nuxt/releases/tag/v3.12.0), the experimental `cookieStore` option is enabled by default. It automatically refreshes the `useCookie` value when cookies change in the browser. </note> ## Type ```ts [Signature] export function refreshCookie (name: string): void ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts) # refreshNuxtData > Refresh all or specific asyncData instances in Nuxt `refreshNuxtData` is used to refetch all or specific `asyncData` instances, including those from [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data), [`useLazyAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-lazy-async-data), [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch), and [`useLazyFetch`](https://nuxt.com/docs/5.x/api/composables/use-lazy-fetch). <note> If your component is cached by `<KeepAlive>` and enters a deactivated state, the `asyncData` inside the component will still be refetched until the component is unmounted. </note> ## Type ```ts [Signature] export function refreshNuxtData (keys?: string | string[]) ``` ## Parameters - `keys`: A single string or an array of strings as `keys` that are used to fetch the data. This parameter is **optional**. All [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) keys are re-fetched when no `keys` are explicitly specified. ## Return Values `refreshNuxtData` returns a promise, resolving when all or specific `asyncData` instances have been refreshed. ## Example ### Refresh All Data This example below refreshes all data being fetched using `useAsyncData` and `useFetch` in Nuxt application. ```vue [app/pages/some-page.vue] <script setup lang="ts"> const refreshing = ref(false) async function refreshAll () { refreshing.value = true try { await refreshNuxtData() } finally { refreshing.value = false } } </script> <template> <div> <button :disabled="refreshing" @click="refreshAll" > Refetch All Data </button> </div> </template> ``` ### Refresh Specific Data This example below refreshes only data where the key matches to `count` and `user`. ```vue [app/pages/some-page.vue] <script setup lang="ts"> const refreshing = ref(false) async function refresh () { refreshing.value = true try { // you could also pass an array of keys to refresh multiple data await refreshNuxtData(['count', 'user']) } finally { refreshing.value = false } } </script> <template> <div v-if="refreshing"> Loading </div> <button @click="refresh"> Refresh </button> </template> ``` <note> If you have access to the `asyncData` instance, it is recommended to use its `refresh` or `execute` method as the preferred way to refetch the data. </note> <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # reloadNuxtApp > reloadNuxtApp will perform a hard reload of the page. <note> `reloadNuxtApp` will perform a hard reload of your app, re-requesting a page and its dependencies from the server. </note> By default, it will also save the current `state` of your app (that is, any state you could access with `useState`). <read-more icon="i-lucide-star" to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#restorestate"> You can enable experimental restoration of this state by enabling the `experimental.restoreState` option in your `nuxt.config` file. </read-more> ## Type ```ts [Signature] export function reloadNuxtApp (options?: ReloadNuxtAppOptions) interface ReloadNuxtAppOptions { ttl?: number force?: boolean path?: string persistState?: boolean } ``` ### `options` (optional) **Type**: `ReloadNuxtAppOptions` An object accepting the following properties: - `path` (optional)<br /> **Type**: `string`<br /> **Default**: `window.location.pathname`<br /> The path to reload (defaulting to the current path). If this is different from the current window location it will trigger a navigation and add an entry in the browser history. - `ttl` (optional)<br /> **Type**: `number`<br /> **Default**: `10000`<br /> The number of milliseconds in which to ignore future reload requests. If called again within this time period, `reloadNuxtApp` will not reload your app to avoid reload loops. - `force` (optional)<br /> **Type**: `boolean`<br /> **Default**: `false`<br /> This option allows bypassing reload loop protection entirely, forcing a reload even if one has occurred within the previously specified TTL. - `persistState` (optional)<br /> **Type**: `boolean`<br /> **Default**: `false`<br /> Whether to dump the current Nuxt state to sessionStorage (as `nuxt:reload:state`). By default this will have no effect on reload unless `experimental.restoreState` is also set, or unless you handle restoring the state yourself. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/chunk.ts) # setPageLayout > setPageLayout allows you to dynamically change the layout of a page. <important> `setPageLayout` allows you to dynamically change the layout of a page. It relies on access to the Nuxt context and therefore can only be called within the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context). </important> ```ts [app/middleware/custom-layout.ts] export default defineNuxtRouteMiddleware((to) => { // Set the layout on the route you are navigating _to_ setPageLayout('other') }) ``` ## Passing Props to Layouts <badge className="align-middle" color="info" size="xs">v4.3</badge> You can pass props to the layout by providing an object as the second argument: ```ts [app/middleware/admin-layout.ts] export default defineNuxtRouteMiddleware((to) => { setPageLayout('admin', { sidebar: true, title: 'Dashboard', }) }) ``` The layout can then receive these props: ```vue [app/layouts/admin.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` <note> If you choose to set the layout dynamically on the server side, you *must* do so before the layout is rendered by Vue (that is, within a plugin or route middleware) to avoid a hydration mismatch. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # setResponseStatus > setResponseStatus sets the status (and optionally the statusText) of the response. Nuxt provides composables and utilities for first-class server-side-rendering support. `setResponseStatus` sets the status (and optionally the statusText) of the response. <important> `setResponseStatus` can only be called in the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context). </important> ```ts const event = useRequestEvent() // event will be undefined in the browser if (event) { // Set the status code to 404 for a custom 404 page setResponseStatus(event, 404) // Set the status message as well setResponseStatus(event, 404, 'Page Not Found') } ``` <note> In the browser, `setResponseStatus` will have no effect. </note> <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # showError > Nuxt provides a quick and simple way to show a full screen error page if needed. Within the [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context) you can use `showError` to show an error. **Parameters:** - `error`: `string | Error | Partial<{ cause, data, message, name, stack, status, statusText }>` ```ts showError('๐Ÿ˜ฑ Oh no, an error has been thrown.') showError({ status: 404, statusText: 'Page Not Found', }) ``` The error is set in the state using [`useError()`](https://nuxt.com/docs/5.x/api/composables/use-error) to create a reactive and SSR-friendly shared error state across components. <tip> `showError` calls the `app:error` hook. </tip> <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # updateAppConfig > Update the App Config at runtime. <note> Updates the [`app.config`](https://nuxt.com/docs/5.x/directory-structure/app/app-config) using deep assignment. Existing (nested) properties will be preserved. </note> ## Usage ```js import { updateAppConfig, useAppConfig } from '#imports' const appConfig = useAppConfig() // { foo: 'bar' } const newAppConfig = { foo: 'baz' } updateAppConfig(newAppConfig) console.log(appConfig) // { foo: 'baz' } ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/app-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/config.ts) # Legacy Composition API > Learn how to migrate to Composition API with Nuxt Bridge. Nuxt Bridge provides access to Composition API syntax. It is specifically designed to be aligned with Nuxt 3. Because of this, there are a few extra steps to take when enabling Nuxt Bridge, if you have been using the Composition API previously. ## Remove Modules - Remove `@vue/composition-api` from your dependencies. - Remove `@nuxtjs/composition-api` from your dependencies (and from your modules in `nuxt.config`). ## Using `@vue/composition-api` If you have been using just `@vue/composition-api` and not `@nuxtjs/composition-api`, then things are very straightforward. 1. First, remove the plugin where you are manually registering the Composition API. Nuxt Bridge will handle this for you.```diff - import Vue from 'vue' - import VueCompositionApi from '@vue/composition-api' - - Vue.use(VueCompositionApi) ``` 2. Otherwise, there is nothing you need to do. However, if you want, you can remove your explicit imports from `@vue/composition-api` and rely on Nuxt Bridge auto-importing them for you. ## Migrating from `@nuxtjs/composition-api` Nuxt Bridge implements the Composition API slightly differently from `@nuxtjs/composition-api` and provides different composables (designed to be aligned with the composables that Nuxt 3 provides). Because some composables have been removed and don't yet have a replacement, this will be a slightly more complicated process. ### Remove `@nuxtjs/composition-api/module` from your buildModules You don't have to immediately update your imports yet - Nuxt Bridge will automatically provide a 'shim' for most imports you currently have, to give you time to migrate to the new, Nuxt 3-compatible composables, with the following exceptions: - `withContext` has been removed. See [below](https://nuxt.com/docs/5.x/bridge/nuxt3-compatible-api#usecontext-and-withcontext). - `useStatic` has been removed. There is no current replacement. Feel free to raise a discussion if you have a use case for this. - `reqRef` and `reqSsrRef`, which were deprecated, have now been removed entirely. Follow the instructions below regarding [ssrRef](https://nuxt.com/docs/5.x/bridge/nuxt3-compatible-api#ssrref-and-shallowssrref) to replace this. ### Set `bridge.capi` ```ts import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { capi: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` For each other composable you are using from `@nuxtjs/composition-api`, follow the steps below. ### useFetch `$fetchState` and `$fetch` have been removed. ```diff const { - $fetch, - $fetchState, + fetch, + fetchState, } = useFetch(() => { posts.value = await $fetch('/api/posts') }) ``` ### `defineNuxtMiddleware` This was a type-helper stub function that is now removed. Remove the `defineNuxtMiddleware` wrapper: ```diff - import { defineNuxtMiddleware } from '@nuxtjs/composition-api` - export default defineNuxtMiddleware((ctx) => {}) + export default (ctx) => {} ``` For typescript support, you can use `@nuxt/types`: ```ts import type { Middleware } from '@nuxt/types' export default <Middleware> function (ctx) { } ``` ### `defineNuxtPlugin` This was a type-helper stub function that is now removed. You may also keep using Nuxt 2-style plugins, by removing the function (as with [defineNuxtMiddleware](https://nuxt.com/docs/5.x/bridge/bridge-composition-api#definenuxtmiddleware)). Remove the `defineNuxtPlugin` wrapper: ```diff - import { defineNuxtPlugin } from '@nuxtjs/composition-api' - export default defineNuxtPlugin((ctx, inject) => {}) + export default (ctx, inject) => {} ``` For typescript support, you can use `@nuxt/types`: ```ts import type { Plugin } from '@nuxt/types' export default <Plugin> function (ctx, inject) {} ``` <warning> While this example is valid, Nuxt 3 introduces a new defineNuxtPlugin function that has a slightly different signature. </warning> <read-more link="/docs/5.x/directory-structure/app/plugins#creating-plugins"> </read-more> ### `useRouter` and `useRoute` Nuxt Bridge provides direct replacements for these composables via [`useRouter`](https://nuxt.com/docs/5.x/api/composables/use-router) and `useRoute`. The only key difference is that [`useRoute`](https://nuxt.com/docs/5.x/api/composables/use-route) no longer returns a computed property. ```diff - import { useRouter, useRoute } from '@nuxtjs/composition-api' const router = useRouter() const route = useRoute() - console.log(route.value.path) + console.log(route.path) ``` # Configuration > Learn how to configure Nuxt Bridge to your own needs. ## Feature Flags You can optionally disable some features from bridge or opt-in to less stable ones. In normal circumstances, it is always best to stick with defaults! You can check [bridge/src/module.ts](https://github.com/nuxt/bridge/blob/main/packages/bridge/src/module.ts) for latest defaults. ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { // -- Opt-in features -- // Use Vite as the bundler instead of webpack 4 // vite: true, // Enable Nuxt 3 compatible useHead // meta: true, // Enable definePageMeta macro // macros: { // pageMeta: true // }, // Enable transpiling TypeScript with esbuild // typescript: { // esbuild: true // }, // -- Default features -- // Use legacy server instead of Nitro // nitro: false, // Disable Nuxt 3 compatible `nuxtApp` interface // app: false, // Disable Composition API support // capi: false, // ... or just disable legacy Composition API support // capi: { // legacy: false // }, // Do not transpile modules // transpile: false, // Disable <script setup> support // scriptSetup: false, // Disable composables auto importing // imports: false, // Do not warn about module incompatibilities // constraints: false }, vite: { // Config for Vite }, }) ``` ## Migration of Each Option ### router.base ```diff export default defineNuxtConfig({ - router: { - base: '/my-app/' - } + app: { + baseURL: '/my-app/' + } }) ``` ### build.publicPath ```diff export default defineNuxtConfig({ - build: { - publicPath: 'https://my-cdn.net' - } + app: { + cdnURL: 'https://my-cdn.net' + } }) ``` # Meta Tags > Learn how to migrate from Nuxt 2 to Nuxt Bridge new meta tags. If you need to access the component state with `head`, you should migrate to using [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) . If you need to use the Options API, there is a `head()` method you can use when you use `defineNuxtComponent`. ## Migration ### Set `bridge.meta` ```js import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { meta: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` ### Update head properties In your `nuxt.config`, rename `head` to `app.head`. (Note that objects no longer have a `hid` key for deduplication.) <code-group> ```ts [Nuxt 2] export default { head: { titleTemplate: '%s - Nuxt', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'Meta description' }, ], }, } ``` ```ts [Nuxt 3] export default defineNuxtConfig({ app: { head: { titleTemplate: '%s - Nuxt', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { name: 'description', content: 'Meta description' }, ], }, }, }) ``` </code-group> ## `useHead` Composables Nuxt Bridge provides a new Nuxt 3 meta API that can be accessed with a new [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable. ```vue <script setup lang="ts"> useHead({ title: 'My Nuxt App', }) </script> ``` <tip> This [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`. </tip> <warning> We recommend not using the native Nuxt 2 `head()` properties in addition to [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) , as they may conflict. </warning> For more information on how to use this composable, see [the docs](https://nuxt.com/docs/5.x/getting-started/seo-meta). ## Options API ```vue <script> // if using options API `head` method you must use `defineNuxtComponent` export default defineNuxtComponent({ head (nuxtApp) { // `head` receives the nuxt app but cannot access the component instance return { meta: [{ name: 'description', content: 'This is my page description.', }], } }, }) </script> ``` <warning> Possible breaking change: `head` receives the nuxt app but cannot access the component instance. If the code in your `head` tries to access the data object through `this` or `this.$data`, you will need to migrate to the `useHead` composable. </warning> ## Title Template If you want to use a function (for full control), then this cannot be set in your nuxt.config, and it is recommended instead to set it within your `/layouts` directory. ```vue [app/layouts/default.vue] <script setup lang="ts"> useHead({ titleTemplate: (titleChunk) => { return titleChunk ? `${titleChunk} - Site Title` : 'Site Title' }, }) </script> ``` # Nitro > Activate Nitro to your Nuxt 2 application with Nuxt Bridge. ## Remove Modules - Remove `@nuxt/nitro`: Bridge injects same functionality ## Update Config ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { nitro: true, }, }) ``` ## Update Your Scripts You will also need to update your scripts within your `package.json` to reflect the fact that Nuxt will now produce a Nitro server as build output. ### Install Nuxi Install `nuxi` as a development dependency: <code-group sync="pm"> ```bash [npm] npm install -D nuxi ``` ```bash [yarn] yarn add --dev nuxi ``` ```bash [pnpm] pnpm add -D nuxi ``` ```bash [bun] bun add -D nuxi ``` ```bash [deno] deno add -D npm:nuxi ``` </code-group> ### Nuxi Nuxt 3 introduced the new Nuxt CLI command [`nuxi`](https://nuxt.com/docs/5.x/api/commands/add). Update your scripts as follows to leverage the better support from Nuxt Bridge: ```diff { "scripts": { - "dev": "nuxt", + "dev": "nuxi dev", - "build": "nuxt build", + "build": "nuxi build", - "start": "nuxt start", + "start": "nuxi preview" } } ``` <tip> If `nitro: false`, use the `nuxt2` command. </tip> ### Static Target If you have set `target: 'static'` in your `nuxt.config` then you need to ensure that you update your build script to be `nuxi generate`. ```json [package.json] { "scripts": { "build": "nuxi generate" } } ``` ### Server Target For all other situations, you can use the `nuxi build` command. ```json [package.json] { "scripts": { "build": "nuxi build", "start": "nuxi preview" } } ``` ## Exclude Built Nitro Folder From Git Add the folder `.output` to the `.gitignore` file. ## Ensure Everything Goes Well โœ”๏ธ Try with `nuxi dev` and `nuxi build` (or `nuxi generate`) to see if everything goes well. # New Composition API > Nuxt Bridge implements composables compatible with Nuxt 3. By migrating from `@nuxtjs/composition-api` to the Nuxt 3 compatible API, there will be less rewriting when migrating to Nuxt 3. ## `ssrRef` and `shallowSsrRef` These two functions have been replaced with a new composable that works very similarly under the hood: `useState`. The key differences are that you must provide a *key* for this state (which Nuxt generated automatically for `ssrRef` and `shallowSsrRef`), and that it can only be called within a Nuxt 3 plugin (which is defined by `defineNuxtPlugin`) or a component instance. (In other words, you cannot use [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) with a global/ambient context, because of the danger of shared state across requests.) ```diff - import { ssrRef } from '@nuxtjs/composition-api' - const ref1 = ssrRef('initialData') - const ref2 = ssrRef(() => 'factory function') + const ref1 = useState('ref1-key', () => 'initialData') + const ref2 = useState('ref2-key', () => 'factory function') // accessing the state console.log(ref1.value) ``` Because the state is keyed, you can access the same state from multiple locations, as long as you are using the same key. You can read more about how to use this composable in [the Nuxt 3 docs](https://nuxt.com/docs/5.x/api/composables/use-state). ## `ssrPromise` This function has been removed, and you will need to find an alternative implementation if you were using it. If you have a use case for `ssrPromise`, please let us know via a discussion. ## `onGlobalSetup` This function has been removed, but its use cases can be met by using [`useNuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) or [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) within `defineNuxtPlugin`. You can also run any custom code within the `setup()` function of a layout. ```diff - import { onGlobalSetup } from '@nuxtjs/composition-api' - export default () => { - onGlobalSetup(() => { + export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.hook('vue:setup', () => { // ... }) - } + }) ``` ## `useStore` In order to access Vuex store instance, you can use `useNuxtApp().$store`. ```diff - import { useStore } from '@nuxtjs/composition-api` + const { $store } = useNuxtApp() ``` ## `useContext` and `withContext` You can access injected helpers using `useNuxtApp`. ```diff - import { useContext } from '@nuxtjs/composition-api` + const { $axios } = useNuxtApp() ``` <note> `useNuxtApp()` also provides a key called `nuxt2Context` which contains all the same properties you would normally access from Nuxt 2 context, but it's advised *not* to use this directly, as it won't exist in Nuxt 3. Instead, see if there is another way to access what you need. (If not, please raise a feature request or discussion.) </note> ## `wrapProperty` This helper function is not provided any more but you can replace it with the following code: ```ts import { computed, getCurrentInstance } from 'vue' const wrapProperty = (property: string, makeComputed = true) => () => { const vm = getCurrentInstance().proxy return makeComputed ? computed(() => vm[property]) : vm[property] } ``` ## `useAsync` and `useFetch` These two composables can be replaced with `useLazyAsyncData` and `useLazyFetch`, which are documented [in the Nuxt 3 docs](https://nuxt.com/docs/5.x/getting-started/data-fetching). Just like the previous `@nuxtjs/composition-api` composables, these composables do not block route navigation on the client-side (hence the 'lazy' part of the name). <important> Note that the API is entirely different, despite similar sounding names. Importantly, you should not attempt to change the value of other variables outside the composable (as you may have been doing with the previous `useFetch`). </important> <warning> The `useLazyFetch` must have been configured for [Nitro](https://nuxt.com/docs/5.x/bridge/nitro). </warning> Migrating to the new composables from `useAsync`: ```diff <script setup> - import { useAsync } from '@nuxtjs/composition-api' - const posts = useAsync(() => $fetch('/api/posts')) + const { data: posts } = useLazyAsyncData('posts', () => $fetch('/api/posts')) + // or, more simply! + const { data: posts } = useLazyFetch('/api/posts') </script> ``` Migrating to the new composables from `useFetch`: ```diff <script setup> - import { useFetch } from '@nuxtjs/composition-api' - const posts = ref([]) - const { fetch } = useFetch(() => { posts.value = await $fetch('/api/posts') }) + const { data: posts, refresh } = useLazyAsyncData('posts', () => $fetch('/api/posts')) + // or, more simply! + const { data: posts, refresh } = useLazyFetch('/api/posts') function updatePosts() { - return fetch() + return refresh() } </script> ``` ### `useMeta` In order to interact with `vue-meta`, you may use `useNuxt2Meta`, which will work in Nuxt Bridge (but not Nuxt 3) and will allow you to manipulate your meta tags in a `vue-meta`-compatible way. ```diff <script setup> - import { useMeta } from '@nuxtjs/composition-api' useNuxt2Meta({ title: 'My Nuxt App', }) </script> ``` You can also pass in computed values or refs, and the meta values will be updated reactively: ```vue <script setup> const title = ref('my title') useNuxt2Meta({ title, }) title.value = 'new title' </script> ``` <note> Be careful not to use both `useNuxt2Meta()` and the Options API `head()` within the same component, as behavior may be unpredictable. </note> Nuxt Bridge also provides a Nuxt 3-compatible meta implementation that can be accessed with the [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable. ```diff <script setup> - import { useMeta } from '@nuxtjs/composition-api' useHead({ title: 'My Nuxt App', }) </script> ``` You will also need to enable it explicitly in your `nuxt.config`: ```js import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { meta: true, }, }) ``` This [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`. Accordingly, it is recommended not to use both the native Nuxt 2 `head()` properties as well as [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) , as they may conflict. For more information on how to use this composable, see [the Nuxt 3 docs](https://nuxt.com/docs/5.x/getting-started/seo-meta). ### Explicit Imports Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed: ```vue <script setup lang="ts"> import { computed, ref } from '#imports' const count = ref(1) const double = computed(() => count.value * 2) </script> ``` ### Disabling Auto-imports If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ imports: { autoImport: false, }, }) ``` This will disable auto-imports completely but it's still possible to use [explicit imports](https://nuxt.com/docs/5.x/bridge/nuxt3-compatible-api#explicit-imports) from `#imports`. # Overview > Reduce the differences with Nuxt 3 and reduce the burden of migration to Nuxt 3. <note> If you're starting a fresh Nuxt 3 project, please skip this section and go to [Nuxt 3 Installation](https://nuxt.com/docs/5.x/getting-started/introduction). </note> <warning> Nuxt Bridge provides identical features to Nuxt 3 ([docs](https://nuxt.com/docs/5.x/guide/concepts/auto-imports)) but there are some limitations, notably that [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) composables are not available. Please read the rest of this page for details. </warning> Bridge is a forward-compatibility layer that allows you to experience many of the new Nuxt 3 features by simply installing and enabling a Nuxt module. Using Nuxt Bridge, you can make sure your project is (almost) ready for Nuxt 3 and you can gradually proceed with the transition to Nuxt 3. ## First Step ### Upgrade Nuxt 2 Make sure your dev server (`nuxt dev`) isn't running, remove any package lock files (`package-lock.json` and `yarn.lock`), and install the latest Nuxt 2 version: ```diff [package.json] - "nuxt": "^2.16.3" + "nuxt": "^2.17.3" ``` Then, reinstall your dependencies: <code-group sync="pm"> ```bash [npm] npm install ``` ```bash [yarn] yarn install ``` ```bash [pnpm] pnpm install ``` ```bash [bun] bun install ``` ```bash [deno] deno install ``` </code-group> <note> Once the installation is complete, make sure both development and production builds are working as expected before proceeding. </note> ### Install Nuxt Bridge Install `@nuxt/bridge` and `nuxi` as development dependencies: <code-group sync="pm"> ```bash [npm] npm install -D @nuxt/bridge nuxi ``` ```bash [yarn] yarn add --dev @nuxt/bridge nuxi ``` ```bash [pnpm] pnpm add -D @nuxt/bridge nuxi ``` ```bash [bun] bun add -D @nuxt/bridge nuxi ``` ```bash [deno] deno add -D npm:@nuxt/bridge npm:nuxi ``` </code-group> ### Update `nuxt.config` Please make sure to avoid any CommonJS syntax such as `module.exports`, `require` or `require.resolve` in your config file. It will soon be deprecated and unsupported. You can use static `import`, dynamic `import()` and `export default` instead. Using TypeScript by renaming to [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) is also possible and recommended. ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: false, }) ``` ### Update Commands The `nuxt` command should now be changed to the `nuxt2` command. ```diff { "scripts": { - "dev": "nuxt", + "dev": "nuxt2", - "build": "nuxt build", + "build": "nuxt2 build", - "start": "nuxt start", + "start": "nuxt2 start" } } ``` Try running `nuxt2` once here. You will see that the application works as before. (If 'bridge' is set to false, your application will operate without any changes as before.) ## Upgrade Steps With Nuxt Bridge, the migration to Nuxt 3 can proceed in steps. The below `Upgrade Steps` does not need to be done all at once. - [TypeScript](https://nuxt.com/docs/5.x/bridge/typescript) - [Migrate Legacy Composition API](https://nuxt.com/docs/5.x/bridge/bridge-composition-api) - [Plugins and Middleware](https://nuxt.com/docs/5.x/bridge/plugins-and-middleware) - [Migrate New Composition API](https://nuxt.com/docs/5.x/bridge/nuxt3-compatible-api) - [Meta Tags](https://nuxt.com/docs/5.x/bridge/meta) - [Runtime Config](https://nuxt.com/docs/5.x/bridge/runtime-config) - [Nitro](https://nuxt.com/docs/5.x/bridge/nitro) - [Vite](https://nuxt.com/docs/5.x/bridge/vite) ## Migrate from CommonJS to ESM Nuxt 3 natively supports TypeScript and ECMAScript Modules. Please check [Native ES Modules](https://nuxt.com/docs/5.x/guide/concepts/esm) for more info and upgrading. # Plugins and Middleware > Learn how to migrate from Nuxt 2 to Nuxt Bridge new plugins and middleware. ## New Plugins Format You can now migrate to the Nuxt 3 plugins API, which is slightly different in format from Nuxt 2. Plugins now take only one argument (`nuxtApp`). You can find out more in [the docs](https://nuxt.com/docs/5.x/directory-structure/app/plugins). ```ts [app/plugins/hello.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.provide('injected', () => 'my injected function') // now available on `nuxtApp.$injected` }) ``` <note> If you want to use the new Nuxt composables (such as [`useNuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) or `useRuntimeConfig`) within your plugins, you will need to use the `defineNuxtPlugin` helper for those plugins. </note> <warning> Although a compatibility interface is provided via `nuxtApp.vueApp` you should avoid registering plugins, directives, mixins or components this way without adding your own logic to ensure they are not installed more than once, or this may cause a memory leak. </warning> ## New Middleware Format You can now migrate to the Nuxt 3 middleware API, which is slightly different in format from Nuxt 2. Middleware now take only two argument (`to`, `from`). You can find out more in [the docs](https://nuxt.com/docs/5.x/directory-structure/app/middleware). ```tstwoslash export default defineNuxtRouteMiddleware((to) => { if (to.path !== '/') { return navigateTo('/') } }) ``` <important> Use of `defineNuxtRouteMiddleware` is not supported outside of the `app/middleware` directory. </important> ## definePageMeta You can also use [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) in Nuxt Bridge. It can be enabled with the `macros.pageMeta` option in your configuration file ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { macros: { pageMeta: true, }, }, }) ``` <note> But only for `middleware` and `layout`. </note> # Runtime Config > Nuxt provides a runtime config API to expose configuration and secrets within your application. <warning> When using `runtimeConfig` option, [nitro](https://nuxt.com/docs/5.x/bridge/nitro) must have been configured. </warning> ## Update Runtime Config Nuxt 3 approaches runtime config differently than Nuxt 2, using a new combined `runtimeConfig` option. First, you'll need to combine your `publicRuntimeConfig` and `privateRuntimeConfig` properties into a new one called `runtimeConfig`, with the public config within a key called `public`. ```diff // nuxt.config.js - privateRuntimeConfig: { - apiKey: process.env.NUXT_API_KEY || 'super-secret-key' - }, - publicRuntimeConfig: { - websiteURL: 'https://public-data.com' - } + runtimeConfig: { + apiKey: process.env.NUXT_API_KEY || 'super-secret-key', + public: { + websiteURL: 'https://public-data.com' + } + } ``` This also means that when you need to access public runtime config, it's behind a property called `public`. If you use public runtime config, you'll need to update your code. ```diff // MyWidget.vue - <div>Website: {{ $config.websiteURL }}</div> + <div>Website: {{ $config.public.websiteURL }}</div> ``` # TypeScript > Learn how to use TypeScript with Nuxt Bridge. ## Remove Modules - Remove `@nuxt/typescript-build`: Bridge enables same functionality - Remove `@nuxt/typescript-runtime` and `nuxt-ts`: Nuxt 2 has built-in runtime support ### Set `bridge.typescript` ```ts import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { typescript: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` ## Update `tsconfig.json` If you are using TypeScript, you can edit your `tsconfig.json` to benefit from auto-generated Nuxt types: ```diff [tsconfig.json] { + "extends": "./.nuxt/tsconfig.json", "compilerOptions": { ... } } ``` <note> As `.nuxt/tsconfig.json` is generated and not checked into version control, you'll need to generate that file before running your tests. Add `nuxi prepare` as a step before your tests, otherwise you'll see `TS5083: Cannot read file '~/.nuxt/tsconfig.json'` For modern Nuxt projects, we recommend using [TypeScript project references](https://nuxt.com/docs/5.x/directory-structure/tsconfig) instead of directly extending `.nuxt/tsconfig.json`. </note> <note> Keep in mind that all options extended from `./.nuxt/tsconfig.json` will be overwritten by the options defined in your `tsconfig.json`. Overwriting options such as `"compilerOptions.paths"` with your own configuration will lead TypeScript to not factor in the module resolutions from `./.nuxt/tsconfig.json`. This can lead to module resolutions such as `#imports` not being recognized. In case you need to extend options provided by `./.nuxt/tsconfig.json` further, you can use the `alias` property within your `nuxt.config`. `nuxi` will pick them up and extend `./.nuxt/tsconfig.json` accordingly. </note> # Vite > Activate Vite to your Nuxt 2 application with Nuxt Bridge. <warning> When using `vite`, [nitro](https://nuxt.com/docs/5.x/bridge/nitro) must have been configured. </warning> ## Remove Modules - Remove `nuxt-vite`: Bridge enables same functionality ## Update Config ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { vite: true, nitro: true, }, }) ``` ## Configuration ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ vite: { // Config for Vite }, }) ``` # Releases > Discover the latest releases of Nuxt & Nuxt official modules. <card-group> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/nuxt" to="https://github.com/nuxt/nuxt/releases"> Nuxt framework releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/cli" to="https://github.com/nuxt/cli/releases"> Nuxt CLI (`@nuxt/cli`) releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/a11y" to="https://github.com/nuxt/a11y/releases"> Nuxt A11y releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/content" to="https://github.com/nuxt/content/releases"> Nuxt Content releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/devtools" to="https://github.com/nuxt/devtools/releases"> Nuxt DevTools releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/fonts" to="https://github.com/nuxt/fonts/releases"> Nuxt Fonts releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/hints" to="https://github.com/nuxt/hints/releases"> Nuxt Hints releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/image" to="https://github.com/nuxt/image/releases"> Nuxt Image releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/scripts" to="https://github.com/nuxt/scripts/releases"> Nuxt Scripts releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/ui" to="https://github.com/nuxt/ui/releases"> Nuxt UI releases. </card> </card-group> <read-more icon="i-simple-icons-github" target="_blank" to="https://github.com/nuxt"> Discover the `nuxt` organization on GitHub </read-more> # Contribution > Nuxt is a community project - and so we love contributions of all kinds! โค๏ธ There is a range of different ways you might be able to contribute to the Nuxt ecosystem. ## Ecosystem The Nuxt ecosystem includes many different projects and organizations: - [nuxt/](https://github.com/nuxt) - core repositories for the Nuxt framework itself. [**nuxt/nuxt**](https://github.com/nuxt/nuxt) contains the Nuxt framework (both versions 2 and 3). - [nuxt-modules/](https://github.com/nuxt-modules) - community-contributed and maintained modules and libraries. There is a [process to migrate a module](https://nuxt.com/docs/5.x/guide/modules/ecosystem) to `nuxt-modules`. While these modules have individual maintainers, they are not dependent on a single person. - [unjs/](https://github.com/unjs) - many of these libraries are used throughout the Nuxt ecosystem. They are designed to be universal libraries that are framework- and environment-agnostic. We welcome contributions and usage by other frameworks and projects. ## How To Contribute ### Triage Issues and Help Out in Discussions Check out the issues and discussions for the project you want to help. For example, here are [the issues board](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) for Nuxt. Helping other users, sharing workarounds, creating reproductions, or even poking into a bug a little bit and sharing your findings makes a huge difference. ### Creating an Issue Thank you for taking the time to create an issue! โค๏ธ - **Reporting bugs**: Check out [our guide](https://nuxt.com/docs/5.x/community/reporting-bugs) for some things to do before opening an issue. - **Feature requests**: Check that there is not an existing issue or discussion covering the scope of the feature you have in mind. If the feature is to another part of the Nuxt ecosystem (such as a module), please consider raising a feature request there first. If the feature you have in mind is general or the API is not entirely clear, consider opening a discussion in the **Ideas** section to discuss with the community first. We'll do our best to follow our [internal issue decision making flowchart](https://mermaid.live/view#pako:eNqFlE1v2zAMhv8K4UuToslhx2Bo0TZt12Edhm7YMCAXWqJtorLk6qOpkfS_j7KdfpyWQ-BQr8mHL6nsCuU0FauiMm6rGvQRfq03FuRzvvvTYIQHthpcBT_ugQNwPHuZjheLxf4i1VDx8x4udrf5EBCOQvSsYg4ffS79KS9pmX9QALTgyid2KYB7Ih-4bmKWbDk2YB0E1gRUVaRi-FDmmjAmT3u4nB3DmoNKIUA1BsGSohA49jnVMQhHbDh_EZQUImyxh-gAtfaiG-KWSJ-N8nt6YtpCdgEeE5rXPOdav5YwWJIJU7zrvNADV9C7JBIyIC07Wxupkx3LFQ5vCkguRno5f9fP2qnUko0Y2dk9rGdvHAa9IIhVGlCp5FFNPN-ce4DKeXBd53xMliOLp9IZtyORQVsnrGm-WJzejtUu5fFqdr5FGQ3bLslYvGthjZbJTLpReZG5_lLYw7XQ_CbPVT92ws9gnEJj-v84dk-PiaXnmF1XGAaPsOsMKywNvYmG80ZohV8k4wDR9_N3KN_dHm5mh1lnkM5FsYzRfNiTvJoT5gnQsl6uxjqXLhkNQ9syHJ0UZZ8ERUIlNShr6N8gZDEliR-ow7QZa0fhY4LoHLRo-8N7ZxPwjRj5ZZYXpvOSNs9v3Jjs8NXB4ets92xan3zydXZHvj64lKMayh4-gZC1bjASW2ipLeWuzIuToiXfImu5rbucclMIc0ubYiWPGv3DptjYF9Fhiu5nb1Wxij7RSZE6jZHWjLXHtlhVaIJESXN0_m68_sO_wMs_oO9gyg) when responding to issues. ### Send a Pull Request We always welcome pull requests! โค๏ธ #### Before You Start Before you fix a bug, we recommend that you check whether **there's an issue that describes it**, as it's possible it's a documentation issue or that there is some context that would be helpful to know. If you're working on a feature, then we ask that you **open a feature request issue first** to discuss with the maintainers whether the feature is desired - and the design of those features. This helps save time for both the maintainers and the contributors and means that features can be shipped faster. The issue **should be confirmed** by a framework team member before building out a feature in a pull request. For typo fixes, it's recommended to batch multiple typo fixes into one pull request to maintain a cleaner commit history. For bigger changes to Nuxt itself, we recommend that you first [create a Nuxt module](https://nuxt.com/docs/5.x/community/contribution#create-a-module) and implement the feature there. This allows for quick proof-of-concept. You can then [create an RFC](https://nuxt.com/docs/5.x/community/contribution#make-an-rfc) in the form of a discussion. As users adopt it and you gather feedback, it can then be refined and either added to Nuxt core or continue as a standalone module. #### Commit Conventions We use [Conventional Commits](https://www.conventionalcommits.org) for commit messages, which [allows a changelog to be auto-generated](https://github.com/unjs/changelogen) based on the commits. Please read the guide through if you aren't familiar with it already. Note that `fix:` and `feat:` are for **actual code changes** (that might affect logic). For typo or document changes, use `docs:` or `chore:` instead: - ~~fix: typo~~ -> `docs: fix typo` If you are working in a project with a monorepo, like `nuxt/nuxt`, ensure that you specify the main scope of your commit in brackets. For example: `feat(kit): add 'addMagicStuff' utility`. #### Making the Pull Request If you don't know how to send a pull request, we recommend reading [the guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). When sending a pull request, make sure your PR's title also follows the [Commit Convention](https://nuxt.com/docs/5.x/community/contribution#commit-conventions). If your PR fixes or resolves existing issues, please make sure you mention them in the PR description. It's ok to have multiple commits in a single PR; you don't need to rebase or force push for your changes as we will use `Squash and Merge` to squash the commits into one commit when merging. We do not add any commit hooks to allow for quick commits. But before you make a pull request, you should ensure that any lint/test scripts are passing. In general, please also make sure that there are no *unrelated* changes in a PR. For example, if your editor has made any changes to whitespace or formatting elsewhere in a file that you edited, please revert these so it is more obvious what your PR changes. And please avoid including multiple unrelated features or fixes in a single PR. If it is possible to separate them, it is better to have multiple PRs to review and merge separately. In general, a PR should do *one thing only*. #### Once You've Made a Pull Request Once you've made a pull request, we'll do our best to review it promptly. If we assign it to a maintainer, then that means that person will take special care to review it and implement any changes that may be required. If we request changes on a PR, please ignore the red text! It doesn't mean we think it's a bad PR - it's just a way of easily telling the status of a list of pull requests at a glance. If we mark a PR as 'pending', that means we likely have another task to do in reviewing the PR - it's an internal note-to-self, and not necessarily a reflection on whether the PR is a good idea or not. We will do our best to explain via a comment the reason for the pending status. We'll do our best to follow [our PR decision making flowchart](https://mermaid.live/view#pako:eNp9VE1v2kAQ_SsjXzBSEqlALlaUisSh0ACK2l4qcVm8Y9hi7672Iwly-O-ZtYPt5FAOCHbee_PmzdpVlCmOURLlhXrJ9sw4-JNuJNBnWs1UQafIQVjrERyWumAOv58-AJeXt29_0b7BXbWwwL0uRPa1vlZvcB_fF8oiMMmB2QM4BXkt3UoON7Lh3LWaDz2SVkK6QGt7DHvw0CKt5sxCKaQoWQEGtVHcZ04oGdw04LTVngW_LHOeFcURGGz97mw6PSv-iJdsi0UCA4nI7SfNwc3W3JZit3eQ1SZFDlKB15yswQ2MgbOjbYeatY3n8bcr-IWlekYYaJRcyB04I9gOB1CEfkF5dAVTzmFAtnqn4-bUYAiMMmHZgWhNPRhgus5mW2BATxq0NkIZ4Y4NbNjzE2ZchBzcHmGLe_ZMSKCcyRXyLrVFa_5n_PBK2xKy3kk9eOjULUdltk6C8kI-7NFDr8f4EVGDoqlp-wa4sJm3ltIMIuZ_mTQXJyTSkQZtunPqsKxShV9GKdkBYe1fHXjpbcjlvONlO9Kqx_M7YHmOmav_luxfE5zKwVs09hM5DLSupgYDlr5flDkwo7ykixKG-xDsUly1LZ-uY32dgDc7lG7YqwbNp0msJwmIUivjWFtfd-xRrEcJ7Omydz37qFplHOtxEp4GskI2qB5dRCWakglOz3oV8JuITJa4iRL6yZk5bKKNPBGOead-H2UWJc54vIiaW53SPgwrz4fIhVNm1bw76lfI6R2_MW21) when responding and reviewing to pull requests. ### AI-Assisted Contributions We welcome the thoughtful use of AI tools when contributing to Nuxt, yet ask all contributors to follow [two core principles](https://roe.dev/blog/using-ai-in-open-source). #### Never let an LLM speak for you - All comments, issues, and pull request descriptions should be written in your own voice - We value clear, human communication over perfect grammar or spelling - Avoid copy-pasting AI-generated summaries that don't reflect your own understanding #### Never let an LLM think for you - Feel free to use AI tools to generate code or explore ideas - Only submit contributions you fully understand and can explain - Contributions should reflect your own reasoning and problem-solving Our aim is ensuring quality and maintaining the joy of collaborating and communicating with real people. If you have ideas for improving our policy on AI in the Nuxt community, we'd love to hear them! โค๏ธ ### Create a Module If you've built something with Nuxt that's cool, why not [extract it into a module](https://nuxt.com/docs/5.x/guide/modules), so it can be shared with others? We have [many excellent modules already](https://nuxt.com/modules), but there's always room for more. If you need help while building it, feel free to [check in with us](https://nuxt.com/docs/5.x/community/getting-help). ### Make an RFC We highly recommend [creating a module](https://nuxt.com/docs/5.x/community/contribution#create-a-module) first to test out big new features and gain community adoption. If you have done this already, or it's not appropriate to create a new module, then please start by creating a new discussion. Make sure it explains your thinking as clearly as possible. Include code examples or function signatures for new APIs. Reference existing issues or pain points with examples. If we think this should be an RFC, we'll change the category to RFC and broadcast it more widely for feedback. An RFC will then move through the following stages: - `rfc: active` - currently open for comment - `rfc: approved` - approved by the Nuxt team - `rfc: ready to implement` - an issue has been created and assigned to implement - `rfc: shipped` - implemented - `rfc: archived` - not approved, but archived for future reference ### Conventions Across Ecosystem The following conventions are *required* within the `nuxt/` organization and recommended for other maintainers in the ecosystem. #### Module Conventions Modules should follow the [Nuxt module template](https://github.com/nuxt/starter/tree/module). See [module guide](https://nuxt.com/docs/5.x/guide/modules) for more information. #### Use Core `unjs/` Libraries We recommend the following libraries which are used throughout the ecosystem: - [pathe](https://github.com/unjs/pathe) - universal path utilities (replacement for node `path`) - [ufo](https://github.com/unjs/ufo) - URL parsing and joining utilities - [obuild](https://github.com/unjs/obuild) - rolldown-powered build system - ... check out the rest of the [unjs/](https://github.com/unjs) organization for many more! #### Use ESM Syntax and Default to `type: module` Most of the Nuxt ecosystem can consume ESM directly. In general we advocate that you avoid using CJS-specific code, such as `__dirname` and `require` statements. You can [read more about ESM](https://nuxt.com/docs/5.x/guide/concepts/esm). #### What's Corepack [Corepack](https://github.com/nodejs/corepack) makes sure you are using the correct version for package manager when you run corresponding commands. Projects might have `packageManager` field in their `package.json`. Under projects with configuration as shown below, Corepack will install `v7.5.0` of `pnpm` (if you don't have it already) and use it to run your commands. ```jsonc [package.json] { "packageManager": "pnpm@7.5.0" } ``` #### Use ESLint We use [ESLint](https://eslint.org) for both linting and formatting with [`@nuxt/eslint`](https://github.com/nuxt/eslint). ##### IDE Setup We recommend using [VS Code](https://code.visualstudio.com) along with the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint). If you would like, you can enable auto-fix and formatting when you save the code you are editing: ```json [settings.json] { "editor.codeActionsOnSave": { "source.fixAll": "never", "source.fixAll.eslint": "explicit" } } ``` #### No Prettier Since ESLint is already configured to format the code, there is no need to duplicate the functionality with Prettier. To format the code, you can run `yarn lint --fix`, `pnpm lint --fix`, `bun run lint --fix`, or `deno run lint --fix` or referring the [ESLint section](https://nuxt.com/docs/5.x/community/contribution#use-eslint) for IDE Setup. If you have Prettier installed in your editor, we recommend you disable it when working on the project to avoid conflict. #### Package Manager We recommend `pnpm` as a package manager for modules, libraries and apps. It is important to enable Corepack to ensure you are on the same version of the package manager as the project. Corepack is built-in to new node versions for seamless package manager integration. To enable it, run ```bash [Terminal] corepack enable ``` You only need to do this one time, after Node.js is installed on your computer. ## Documentation Style Guide Documentation is an essential part of Nuxt. We aim to be an intuitive framework - and a big part of that is making sure that both the developer experience and the docs are perfect across the ecosystem. ๐Ÿ‘Œ Here are some tips that may help improve your documentation: ### Language - Use **American English** spelling (*behavior* rather than *behaviour*, *customize* rather than *customise*). - Write tool and project names using their official capitalization, even when the npm package name is lowercase (for example, *PostCSS* rather than *postcss*, *Vite* rather than *vite*, *ESLint* rather than *eslint*). Use the lowercase npm package name in backticks only when referring to the package itself, such as in installation instructions.<caution icon="i-lucide-circle-x"> Nuxt supports postcss out of the box. </caution> <tip icon="i-lucide-circle-check"> Nuxt supports PostCSS out of the box. You don't need to install `postcss` manually. </tip> <note> Casing of common tool names is checked automatically by [case police](https://github.com/antfu/case-police) when you run `pnpm lint:docs`. </note> ### Headings - Capitalize headings following Chicago title case. In short: capitalize the first word, the last word, and all major words (nouns, verbs, adjectives, adverbs, pronouns); lowercase articles, coordinating conjunctions, and prepositions regardless of length (for example, a, and, or, with, from, and to). When in doubt, [capitalizemytitle.com](https://capitalizemytitle.com/style/Chicago) can help.<caution icon="i-lucide-circle-x"> How to contribute to the docs </caution> <tip icon="i-lucide-circle-check"> How to Contribute to the Docs </tip> - Code in headings keeps its original casing and is not counted for capitalization purposes (for example, *Using useFetch in Components*). ### Inline Code Wrap the following in backticks so they render as inline code: - File names and paths: `nuxt.config.ts`, `server/api/` - npm package names: `@nuxt/kit`, `postcss` - Configuration keys, options, and values: `ssr: false`, the `css` option - Code identifiers such as functions, composables, components, variables, and types: `useFetch`, `<NuxtLink>`, `defineNuxtConfig` - Terminal commands: `npx nuxt init` Do not use backticks for names of tools, projects, or general concepts (use *Vite*, not `vite`, when referring to the tool). ### Code Examples - Add a filename to code blocks so readers know where the code belongs. If the code doesn't belong in a particular file (for example, a shell command), use a descriptive label like `[Terminal]`.```markdown ```ts [nuxt.config.ts] export default defineNuxtConfig({ ssr: false, }) ``` ``` - Make examples copy-pasteable. Include the necessary imports and avoid placeholders such as `...` in the middle of code that a reader would paste into their project. A reader should be able to copy an example into their project and have it work with minimal changes. ### Links - When linking to other documentation pages, use relative paths without the domain or a version segment: `/docs/getting-started/installation` rather than `/docs/4.x/getting-started/installation` or `https://nuxt.com/docs/4.x/getting-started/installation`. nuxt.com inserts the version segment of the branch the page was built from, so the same link resolves correctly on every version and docs changes can be cherry-picked between branches unchanged. - Only write a version segment when you deliberately mean *another* version's docs (the release table in the roadmap, for example). In that case use the full URL, `https://nuxt.com/docs/3.x/getting-started/introduction`, so the intent is obvious in review. - When linking to external resources, link to the final URL rather than one that redirects. You can check with:```bash [Terminal] curl -sILo /dev/null -w '%{http_code} %{url_effective}\n' https://example.com/some-page ``` <br /> This follows any chain of redirects and prints the final status and URL. A `200` status with the URL you requested means the link is fine. If the final URL differs, link to that instead. ### Tone We aim for a tone that is friendly and professional. Write directly to the reader ("you"), be concise, and assume good faith: readers come from many different backgrounds and levels of experience, so avoid language that could make anyone feel talked down to. It's fine to be warm - the docs can have personality - but clarity always comes first. ### Writing Style - Avoid subjective words like *simply*, *just*, *obviously...* when possible.<br /> Keep in mind your readers can have different backgrounds and experiences. Therefore, these words don't convey meaning and can be harmful.<caution icon="i-lucide-circle-x"> Simply make sure the function returns a promise. </caution> <tip icon="i-lucide-circle-check"> Make sure the function returns a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). </tip> - Prefer [active voice](https://developers.google.com/tech-writing/one/active-voice).<caution icon="i-lucide-circle-x"> An error will be thrown by Nuxt. </caution> <tip icon="i-lucide-circle-check"> Nuxt will throw an error. </tip> - Use consistent section names and ordering when documenting API pages, including composables, utilities, and components. Include only the sections that apply: 1. **Usage**: Explain how to use the API and cover common use cases. 2. **Type**: Provide the relevant TypeScript declarations. 3. **Parameters**: Describe each input, including its type, default value, and available options. 4. **Return Values**: Describe the returned value and its type. 5. **Example**: Show a practical example.<br /> Use these exact section names. For example, use `Parameters` rather than `Params` and `Example` rather than `Examples`. - When documenting API pages (composables, utils, components), add the **minimal Nuxt version** when a feature or utility was introduced, so readers know which version they need.<br /> Use two levels: - **Global (whole page):** Add `minimalVersion: "3.9"` in the frontmatter (without the "v" prefix). The docs layout renders the version badge automatically from this field, displaying it as `vX.Y` (e.g. `v3.9`, `v3.15`). - **Local (specific option or feature):** Add a small badge next to the option or section: `:badge[v3.8]{color="info" size="xs" class="align-middle"}` (e.g. for `getCachedData` in useFetch, or for the `navigation` mode in callOnce).<br /> To find the version, check `@since` in JSDoc in the source, the [release notes](https://github.com/nuxt/nuxt/releases), or the [Nuxt blog](https://nuxt.com/blog). <read-more to="https://nuxt.com/docs/5.x/community/framework-contribution#documentation-guide"> Learn how to contribute to the documentation. </read-more> # Framework > Some specific points about contributions to the framework repository. Once you've read the [general contribution guide](https://nuxt.com/docs/5.x/community/contribution), here are some specific points to make about contributions to the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository. ## Monorepo Guide - `packages/kit`: Toolkit for authoring Nuxt modules, published as [`@nuxt/kit`](https://www.npmjs.com/package/@nuxt/kit). - `packages/nuxt`: The core of Nuxt, published as [`nuxt`](https://www.npmjs.com/package/nuxt). - `packages/schema`: Cross-version Nuxt typedefs and defaults, published as [`@nuxt/schema`](https://www.npmjs.com/package/@nuxt/schema). - `packages/rspack`: The [Rspack](https://rspack.rs) bundler for Nuxt, published as [`@nuxt/rspack-builder`](https://www.npmjs.com/package/@nuxt/rspack-builder). - `packages/vite`: The [Vite](https://vite.dev) bundler for Nuxt, published as [`@nuxt/vite-builder`](https://www.npmjs.com/package/@nuxt/vite-builder). - `packages/webpack`: The [webpack](https://webpack.js.org) bundler for Nuxt, published as [`@nuxt/webpack-builder`](https://www.npmjs.com/package/@nuxt/webpack-builder). ## Setup To contribute to Nuxt, you need to set up a local environment. 1. [Fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository to your own GitHub account and then [clone](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) it to your local device. 2. Ensure using the latest [Node.js](https://nodejs.org/en) 3. Enable [Corepack](https://github.com/nodejs/corepack) to have `pnpm` and `yarn````bash [Terminal] corepack enable ``` 4. Run `pnpm install --frozen-lockfile` to Install the dependencies with pnpm: ```bash [Terminal] pnpm install --frozen-lockfile ``` <note> If you are adding a dependency, please use `pnpm add`. <br /> The `pnpm-lock.yaml` file is the source of truth for all Nuxt dependencies. </note> 5. Activate the passive development system ```bash [Terminal] pnpm dev:prepare ``` 6. Check out a branch where you can work and commit your changes: ```bash [Terminal] git checkout -b my-new-branch ``` Then, test your changes against the [playground](https://nuxt.com/docs/5.x/community/framework-contribution#playground) and [test](https://nuxt.com/docs/5.x/community/framework-contribution#testing) your changes before submitting a pull request. ### Playground While working on a pull request, you will likely want to check if your changes are working correctly. You can modify the example app in `playground/`, and run: ```bash [Terminal] pnpm dev ``` <important> Please make sure not to commit it to your branch, but it could be helpful to add some example code to your PR description. This can help reviewers and other Nuxt users understand the feature you've built in-depth. </important> ### Testing Every new feature should have a corresponding unit test (if possible). The `test/` directory in this repository is currently a work in progress, but do your best to create a new test following the example of what's already there. Before creating a PR or marking it as ready-to-review, ensure that all tests pass by running: ```bash [Terminal] pnpm test ``` ### Linting You might have noticed already that we use ESLint to enforce a coding standard. Before committing your changes, to verify that the code style is correct, run: ```bash [Terminal] pnpm lint ``` <note> You can use `pnpm lint --fix` to fix most of the style changes. <br /> If there are still errors left, you must correct them manually. </note> ### Documentation If you are adding a new feature or refactoring or changing the behavior of Nuxt in any other manner, you'll likely want to document the changes. Please include any changes to the docs in the same PR. You don't have to write documentation up on the first commit (but please do so as soon as your pull request is mature enough). <important> Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/5.x/community/contribution#documentation-style-guide). </important> ### Final Checklist When submitting your PR, there is a simple template that you have to fill out. Please tick all appropriate "answers" in the checklists. ## Documentation Guide If you spot an area where we can improve documentation or error messages, please do open a PR - even if it's just to fix a typo! <important> Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/5.x/community/contribution#documentation-style-guide). </important> ### Quick Edits If you spot a typo or want to rephrase a sentence, you can click on the **Edit this page** link located on the right aside in the **Community** section. Make the change directly in the GitHub interface and open a Pull Request. ### Longer Edits The documentation content is inside the `docs/` directory of the [nuxt/nuxt](https://github.com/nuxt/nuxt) repository and written in markdown. <note> To preview the docs locally, follow the steps on [nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) repository. </note> <note> We recommend that you install the [MDC extension](https://marketplace.visualstudio.com/items?itemName=Nuxt.mdc) for VS Code. </note> ### Linting Docs Documentation is linted using [MarkdownLint](https://github.com/DavidAnson/markdownlint) and [case police](https://github.com/antfu/case-police) to keep the documentation cohesive. ```bash [Terminal] pnpm lint:docs ``` <note> You can also run `pnpm lint:docs:fix` to highlight and resolve any lint issues. </note> ### Open a PR Please make sure your PR title adheres to the [conventional commits](https://www.conventionalcommits.org) guidelines. ```bash [Example of PR title] docs: update the section about the nuxt.config.ts file ``` # Getting Help > We're a friendly community of developers and we'd love to help. At some point, you may find that there's an issue you need some help with. But don't worry! We're a friendly community of developers and we'd love to help. <card-group> <card icon="i-simple-icons-discord" target="_blank" title="Discord" to="https://go.nuxt.com/discord"> Get real-time help, exchange with the core team and the community, and stay updated on the latest Nuxt news. </card> <card icon="i-simple-icons-nuxt" target="_blank" title="Nuxters" to="https://nuxters.nuxt.com"> Connect with other Nuxt enthusiasts. </card> </card-group> ## "I can't figure out how to (...)." You've read through these docs and you think it should be possible, but it's not clear how. The best thing is to [open a GitHub Discussion](https://github.com/nuxt/nuxt/discussions). Please don't feel embarrassed about asking a question that you think is easy - we've all been there! โค๏ธ Everyone you'll encounter is helping out because they care, not because they are paid to do so. The kindest thing to do is make it easy for them to help you. Here are some ideas: - *Explain what your objective is, not just the problem you're facing.* "I need to ensure my form inputs are accessible, so I'm trying to get the ids to match between server and client." - *Make sure you've first read the docs and used your favorite search engine*. Let people know by saying something like "I've Googled for 'nuxt script setup' but I couldn't find code examples anywhere." - *Explain what you've tried.* Tell people the kind of solutions you've experimented with, and why. Often this can make people's advice more relevant to your situation. - *Share your code.* People probably won't be able to help if they just see an error message or a screenshot - but that all changes if you share your code in a copy/pasteable format - preferably in the form of a minimal reproduction like a CodeSandbox. And finally, just ask the question! There's no need to [ask permission to ask a question](https://dontasktoask.com) or [wait for someone to reply to your 'hello'](https://www.nohello.com). If you do, you might not get a response because people are waiting for the whole question before engaging. ## "Could there be a bug?" Something isn't working the way that the docs say that it should. You're not sure if it's a bug. You've searched through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) but you can't find anything. (if there is a closed issue, please create a new one) We recommend taking a look at [how to report bugs](https://nuxt.com/docs/5.x/community/reporting-bugs). Nuxt is still in active development, and every issue helps make it better. ## "I need professional help" If the community couldn't provide the help you need in the time-frame you have, NuxtLabs offers professional support with the [Nuxt Experts](https://nuxt.com/enterprise/agencies). The objective of the Nuxt Expert is to provide support to the Vue ecosystem, while also creating freelance opportunities for those contributing to open-source solutions, thus helping to maintain the sustainability of the ecosystem. The Nuxt experts are Vue, Nuxt and Vite chosen contributors providing professional support and consulting services. # Reporting Bugs > One of the most valuable roles in open source is taking the time to report bugs helpfully. Try as we might, we will never completely eliminate bugs. Even if you can't fix the underlying code, reporting a bug well can enable someone else with a bit more familiarity with the codebase to spot a pattern or make a quick fix. Here are a few key steps. ## Is It Really a Bug? Consider if you're looking to get help with something, or whether you think there's a bug with Nuxt itself. If it's the former, we'd love to help you - but the best way to do that is through [asking for help](https://nuxt.com/docs/5.x/community/getting-help) rather than reporting a bug. ## Search the Issues Search through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) first. If you find anything that seems like the same bug, it's much better to comment on an existing thread than create a duplicate. ## Create a Minimal Reproduction It's important to be able to reproduce the bug reliably - in a minimal way and apart from the rest of your project. This narrows down what could be causing the issue and makes it possible for someone not only to find the cause, but also to test a potential solution. Start with the Nuxt sandbox and add the **minimum** amount of code necessary to reproduce the bug you're experiencing. <note> If your issue concerns Vue or Vite, please try to reproduce it first with the Vue SSR starter. </note> **Nuxt**: <card-group> <card icon="i-simple-icons-stackblitz" target="_blank" title="Nuxt on StackBlitz" to="https://nuxt.new/s/v4"> </card> <card icon="i-simple-icons-codesandbox" target="_blank" title="Nuxt on CodeSandbox" to="https://nuxt.new/c/v4"> </card> </card-group> **Vue**: <card-group> <card icon="i-simple-icons-stackblitz" target="_blank" title="Vue SSR on StackBlitz" to="https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter/tree/main?terminal=dev"> </card> <card icon="i-simple-icons-codesandbox" target="_blank" title="Vue SSR on CodeSandbox" to="https://codesandbox.io/p/sandbox/github/nuxt-contrib/vue3-ssr-starter/main"> </card> <card icon="i-simple-icons-github" target="_blank" title="Vue SSR Template on GitHub" to="https://github.com/nuxt-contrib/vue3-ssr-starter/generate"> </card> </card-group> Once you've reproduced the issue, remove as much code from your reproduction as you can (while still recreating the bug). The time spent making the reproduction as minimal as possible will make a huge difference to whoever sets out to fix the issue. ## Figure Out What the Cause Might Be With a Nuxt project, there are lots of moving pieces - from [Nuxt modules](https://nuxt.com/modules) to [other JavaScript libraries](https://www.npmjs.com). Try to report the bug at the most relevant and specific place. That will likely be the Nuxt module causing an issue, or the upstream library that Nuxt is depending on. # Roadmap > Nuxt is constantly evolving, with new features and modules being added all the time. <read-more to="https://nuxt.com/blog"> See our blog for the latest framework and ecosystem announcements. </read-more> ## Status Reports <read-more to="https://github.com/nuxt/nuxt/issues/13653" icon="i-simple-icons-github" target="_blank"> Documentation Progress </read-more> <read-more to="https://github.com/nuxt/nuxt/discussions/16119" icon="i-simple-icons-github" target="_blank"> Rendering Optimizations: Today and Tomorrow </read-more> <read-more to="https://github.com/nuxt/image/discussions/563" icon="i-simple-icons-github" target="_blank"> Nuxt Image: Performance and Status </read-more> ## Roadmap In roadmap below are some features we are planning or working on at the moment. <tip> Check [Discussions](https://github.com/nuxt/nuxt/discussions) and [RFCs](https://github.com/nuxt/nuxt/discussions/categories/rfcs) for more upcoming features and ideas. </tip> <table> <thead> <tr> <th> Milestone </th> <th> Expected date </th> <th> Notes </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> SEO & PWA </td> <td> 2025 </td> <td> <a href="https://github.com/nuxt/nuxt/discussions/18395" rel="nofollow"> nuxt/nuxt#18395 </a> </td> <td> Migrating from <a href="https://github.com/nuxt-community/pwa-module" rel="nofollow"> nuxt-community/pwa-module </a> for built-in SEO utils and service worker support </td> </tr> <tr> <td> Assets </td> <td> 2025 </td> <td> <a href="https://github.com/nuxt/nuxt/discussions/22012" rel="nofollow"> nuxt/nuxt#22012 </a> </td> <td> Allow developers and modules to handle loading third-party assets. </td> </tr> <tr> <td> Translations </td> <td> - </td> <td> <a href="https://github.com/nuxt/nuxt.com/issues/1711" rel="nofollow"> nuxt/nuxt.com#1711 </a> </td> <td> A collaborative project for a stable translation process for Nuxt docs. Currently pending for ideas and documentation tooling support. </td> </tr> </tbody> </table> ## Core Modules Roadmap In addition to the Nuxt framework, there are modules that are vital for the ecosystem. Their status will be updated below. <table> <thead> <tr> <th> Module </th> <th> Status </th> <th> Nuxt Support </th> <th> Repository </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> Auth Utils </td> <td> Planned </td> <td> 4.x, 5.x </td> <td> <code> nuxt/auth-utils </code> to be announced </td> <td> The temporary repository <a href="https://github.com/atinux/nuxt-auth-utils" rel="nofollow"> atinux/nuxt-auth-utils </a> is available while awaiting its official integration into Nuxt via RFC. </td> </tr> <tr> <td> <a href="https://github.com/nuxt/a11y" rel="nofollow"> a11y </a> </td> <td> Public Alpha </td> <td> 4.x, 5.x </td> <td> <a href="https://github.com/nuxt/a11y" rel="nofollow"> nuxt/a11y </a> . </td> <td> Real-time accessibility feedback and automated testing in your browser during development (see <a href="https://github.com/nuxt/nuxt/issues/23255" rel="nofollow"> nuxt/nuxt#23255 </a> ). </td> </tr> </tbody> </table> ## Release Cycle Since January 2023, we've adopted a consistent release cycle for Nuxt, following [semver](https://semver.org). We aim for major framework releases every year, with an expectation of patch releases every week or so and minor releases every month or so. They should never contain breaking changes except within options clearly marked as `experimental`. We are planning a slight variation from this plan for Nuxt 4 and Nuxt 5. Nuxt 4 will be a stability-focused release containing all `compatibilityVersion: 4` features, and will be followed shortly by Nuxt 5 which will include an upgrade to Nitro v3 and additional changes. This approach separates breaking changes into manageable phases, allowing for better ecosystem testing and smoother migrations. ### Ongoing Support for Nuxt We commit to support each major version of Nuxt for a minimum of six months after the release of the next major version, and to providing an upgrade path for current users at that point. ### Current Packages The current active version of [Nuxt](https://nuxt.com) is **v4** which is available as `nuxt` on npm with the `latest` tag. Nuxt 3 reached end of life on 31 July 2026 and no longer receives bug fixes or security patches. If you are still on Nuxt 3, follow the [upgrade guide](https://nuxt.com/docs/5.x/getting-started/upgrade) to move to Nuxt 4. Each active version has its own nightly releases which are generated automatically. For more about enabling the Nuxt nightly release channel, see [the nightly release channel docs](https://nuxt.com/docs/5.x/guide/going-further/nightly-release-channel). <table> <thead> <tr> <th> Release </th> <th> </th> <th> Initial release </th> <th> End Of Life </th> <th> Docs </th> </tr> </thead> <tbody> <tr> <td> <strong> 5.x </strong> (scheduled) </td> <td> </td> <td> Q4 2026 (estimated) </td> <td> TBA </td> <td> </td> </tr> <tr> <td> <strong> 4.x </strong> (stable) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt latest version" src="https://img.shields.io/npm/v/nuxt.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2025-07-16 </td> <td> 6 months after 5.x release </td> <td> <a href="https://nuxt.com/docs/4.x/getting-started/introduction" rel="nofollow"> nuxt.com </a> </td> </tr> <tr> <td> <strong> 3.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 3.x version" src="https://img.shields.io/npm/v/nuxt/3x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2022-11-16 </td> <td> 2026-07-31 </td> <td> <a href="https://nuxt.com/docs/3.x/getting-started/introduction" rel="nofollow"> nuxt.com </a> </td> </tr> <tr> <td> <strong> 2.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 2.x version" src="https://img.shields.io/npm/v/nuxt/2x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2018-09-21 </td> <td> 2024-06-30 </td> <td> <a href="https://v2.nuxt.com/docs/get-started/installation/" rel="nofollow"> v2.nuxt.com </a> </td> </tr> <tr> <td> <strong> 1.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 1.x version" src="https://img.shields.io/npm/v/nuxt/1x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2018-01-08 </td> <td> 2019-09-21 </td> <td> </td> </tr> </tbody> </table> ### Support Status <table> <thead> <tr> <th> Status </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> Unsupported </td> <td> This version is not maintained any more and will not receive security patches </td> </tr> <tr> <td> Maintenance </td> <td> This version will only receive security patches </td> </tr> <tr> <td> Stable </td> <td> This version is being developed for and will receive security patches </td> </tr> <tr> <td> Development </td> <td> This version could be unstable </td> </tr> <tr> <td> Scheduled </td> <td> This version does not exist yet but is planned </td> </tr> </tbody> </table> # Nuxt Directory Structure > Learn about the directory structure of a Nuxt application and how to use it. Nuxt applications have a specific directory structure that is used to organize the code. This structure is designed to be easy to understand and to be used in a consistent way. ## Root Directory The root directory of a Nuxt application is the directory that contains the `nuxt.config.ts` file. This file is used to configure the Nuxt application. ## App Directory The `app/` directory is the main directory of the Nuxt application. It contains the following subdirectories: - [`assets/`](https://nuxt.com/docs/5.x/directory-structure/app/assets): website's assets that the build tool (Vite or webpack) will process - [`components/`](https://nuxt.com/docs/5.x/directory-structure/app/components): Vue components of the application - [`composables/`](https://nuxt.com/docs/5.x/directory-structure/app/composables): add your Vue composables - [`layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts): Vue components that wrap around your pages and avoid re-rendering between pages - [`middleware/`](https://nuxt.com/docs/5.x/directory-structure/app/middleware): run code before navigating to a particular route - [`pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages): file-based routing to create routes within your web application - [`plugins/`](https://nuxt.com/docs/5.x/directory-structure/app/plugins): use Vue plugins and more at the creation of your Nuxt application - [`utils/`](https://nuxt.com/docs/5.x/directory-structure/app/utils): add functions throughout your application that can be used in your components, composables, and pages. This directory also includes specific files: - [`app.config.ts`](https://nuxt.com/docs/5.x/directory-structure/app/app-config): a reactive configuration within your application - [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app): the root component of your Nuxt application - [`error.vue`](https://nuxt.com/docs/5.x/directory-structure/app/error): the error page of your Nuxt application ## Public Directory The [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory is the directory that contains the public files of the Nuxt application. Files contained within this directory are served at the root and are not modified by the build process. This is suitable for files that have to keep their names (e.g. `robots.txt`) *or* likely won't change (e.g. `favicon.ico`). ## Server Directory The [`server/`](https://nuxt.com/docs/5.x/directory-structure/server) directory is the directory that contains the server-side code of the Nuxt application. It contains the following subdirectories: - [`api/`](https://nuxt.com/docs/5.x/directory-structure/server#server-routes): contains the API routes of the application. - [`routes/`](https://nuxt.com/docs/5.x/directory-structure/server#server-routes): contains the server routes of the application (e.g. dynamic `/sitemap.xml`). - [`middleware/`](https://nuxt.com/docs/5.x/directory-structure/server#server-middleware): run code before a server route is processed - [`plugins/`](https://nuxt.com/docs/5.x/directory-structure/server#server-plugins): use plugins and more at the creation of the Nuxt server - [`utils/`](https://nuxt.com/docs/5.x/directory-structure/server#server-utilities): add functions throughout your application that can be used in your server code. ## Shared Directory The [`shared/`](https://nuxt.com/docs/5.x/directory-structure/shared) directory is the directory that contains the shared code of the Nuxt application and Nuxt server. This code can be used in both the Vue app and the Nitro server. ## Test Directory The [`test/`](https://nuxt.com/docs/5.x/directory-structure/test) directory is the recommended place for application tests (unit, Nuxt runtime, and end-to-end). See [Organizing Your Tests](https://nuxt.com/docs/5.x/getting-started/testing#organizing-your-tests) for layout and setup details. ## Content Directory The [`content/`](https://nuxt.com/docs/5.x/directory-structure/content) directory is enabled by the [Nuxt Content](https://content.nuxt.com) module. It is used to create a file-based CMS for your application using Markdown files. ## Modules Directory The [`modules/`](https://nuxt.com/docs/5.x/directory-structure/modules) directory is the directory that contains the local modules of the Nuxt application. Modules are used to extend the functionality of the Nuxt application. ## Layers Directory The [`layers/`](https://nuxt.com/docs/5.x/directory-structure/layers) directory allows you to organize and share reusable code, components, composables, and configurations. Layers within this directory are automatically registered in your project. ## Nuxt Files - [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file is the main configuration file for the Nuxt application. - [`.nuxtrc`](https://nuxt.com/docs/5.x/directory-structure/nuxtrc) file is another syntax for configuring the Nuxt application (useful for global configurations). - [`.nuxtignore`](https://nuxt.com/docs/5.x/directory-structure/nuxtignore) file is used to ignore files in the root directory during the build phase. # app.vue > The app.vue file is the main component of your Nuxt application. <tip> If you have a `app/pages/` directory, the `app.vue` file is optional. Nuxt will automatically include a default `app.vue`, but you can still add your own to customize the structure and content as needed. </tip> ## Usage ### Minimal Usage With Nuxt, the [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) directory is optional. If it is not present, Nuxt will not include the [vue-router](https://router.vuejs.org) dependency. This is useful when building a landing page or an application that does not require routing. ```vue [app/app.vue] <template> <h1>Hello World!</h1> </template> ``` <link-example to="https://nuxt.com/docs/5.x/examples/hello-world"> </link-example> ### Usage with Pages When you have a [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) directory, you need to use the [`<NuxtPage>`](https://nuxt.com/docs/5.x/api/components/nuxt-page) component to display the current page: ```vue [app/app.vue] <template> <NuxtPage /> </template> ``` You can also define the common structure of your application directly in `app.vue`. This is useful when you want to include global elements such as a header or footer: ```vue [app/app.vue] <template> <header> Header content </header> <NuxtPage /> <footer> Footer content </footer> </template> ``` <note> Remember that `app.vue` acts as the main component of your Nuxt application. Anything you add to it (JS and CSS) will be global and included in every page. </note> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/pages"> Learn more about how to structure your pages using the `app/pages/` directory. </read-more> ### Usage with Layouts When your application requires different layouts for different pages, you can use the `app/layouts/` directory with the [`<NuxtLayout>`](https://nuxt.com/docs/5.x/api/components/nuxt-layout) component. This allows you to define multiple layouts and apply them per page. ```vue [app/app.vue] <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/layouts"> Learn more about how to structure your layouts using the `app/layouts/` directory. </read-more> # app.config.ts > Expose reactive configuration within your application with the App Config file. Nuxt provides an `app/app.config.ts` config file to expose reactive configuration within your application with the ability to update it at runtime within lifecycle or using a nuxt plugin and editing it with HMR (hot-module-replacement). You can easily provide runtime app configuration using `app.config.ts` file. It can have either of `.ts`, `.js`, or `.mjs` extensions. ```ts [app/app.config.ts]twoslash export default defineAppConfig({ foo: 'bar', }) ``` <caution> Do not put any secret values inside `app.config` file. It is exposed to the user client bundle. </caution> <note> When configuring a custom [`srcDir`](https://nuxt.com/docs/5.x/api/nuxt-config#srcdir), make sure to place the `app.config` file at the root of the new `srcDir` path. </note> ## Usage To expose config and environment variables to the rest of your app, you will need to define configuration in `app.config` file. ```ts [app/app.config.ts]twoslash export default defineAppConfig({ theme: { primaryColor: '#ababab', }, }) ``` We can now universally access `theme` both when server-rendering the page and in the browser using [`useAppConfig`](https://nuxt.com/docs/5.x/api/composables/use-app-config) composable. ```vue [app/pages/index.vue] <script setup lang="ts"> const appConfig = useAppConfig() console.log(appConfig.theme) </script> ``` The [`updateAppConfig`](https://nuxt.com/docs/5.x/api/utils/update-app-config) utility can be used to update the `app.config` at runtime. ```vue [app/pages/index.vue] <script setup> const appConfig = useAppConfig() // { foo: 'bar' } const newAppConfig = { foo: 'baz' } updateAppConfig(newAppConfig) console.log(appConfig) // { foo: 'baz' } </script> ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/update-app-config"> Read more about the `updateAppConfig` utility. </read-more> ## Typing App Config Nuxt tries to automatically generate a TypeScript interface from provided app config so you won't have to type it yourself. The fully inferred type is only available in app code (components, composables, plugins and so on). In server routes, code in the `shared/` directory and `nuxt.config`, keys defined in `app.config` files are typed as `unknown` instead: typing them there would require typechecking your app code outside the app context, where app auto-imports are not available. Keys defined inline in the `appConfig` option of `nuxt.config` are typed everywhere. If you need other keys typed outside app code, you can extend the `SharedAppConfig` interface as described below. The location of the augmentation file determines which contexts see it: a `.d.ts` file in the `shared/` directory covers app code, shared code and server routes. However, there are some cases where you might want to type it yourself. There are two possible things you might want to type. ### App Config Input `AppConfigInput` might be used by module authors who are declaring what valid *input* options are when setting app config. This will not affect the type of `useAppConfig()`. ```ts [index.d.ts] declare module 'nuxt/schema' { interface AppConfigInput { /** Theme configuration */ theme?: { /** Primary app color */ primaryColor?: string } } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ### App Config Output If you want to type the result of calling [`useAppConfig()`](https://nuxt.com/docs/5.x/api/composables/use-app-config) in app code, then you will want to extend `AppConfig`. Outside app code (server routes, the `shared/` directory and `nuxt.config`) `useAppConfig()` returns `SharedAppConfig`, so extend that interface instead. <warning> Be careful when typing `AppConfig` as you will overwrite the types Nuxt infers from your actually defined app config. </warning> ```ts [index.d.ts] declare module 'nuxt/schema' { interface AppConfig { // This will entirely replace the existing inferred `theme` property theme: { // You might want to type this value to add more specific types than Nuxt can infer, // such as string literal types primaryColor?: 'red' | 'blue' } } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ## Merging Strategy Nuxt uses a custom merging strategy for the `AppConfig` within [the layers](https://nuxt.com/docs/5.x/getting-started/layers) of your application. This strategy is implemented using a [Function Merger](https://github.com/unjs/defu#function-merger), which allows defining a custom merging strategy for every key in `app.config` that has an array as value. <note> The function merger can only be used in the extended layers and not the main `app.config` in project. </note> Here's an example of how you can use: <code-group> ```ts [layer/app/app.config.ts]twoslash export default defineAppConfig({ // Default array value array: ['hello'], }) ``` ```ts [app/app.config.ts]twoslash export default defineAppConfig({ // Overwrite default array value by using a merger function array: () => ['bonjour'], }) ``` </code-group> ## Known Limitations As of Nuxt v3.3, the `app.config.ts` file is shared with Nitro, which results in the following limitations: 1. You cannot import Vue components directly in `app.config.ts`. 2. Some auto-imports are not available in the Nitro context. These limitations occur because Nitro processes the app config without full Vue component support. While it's possible to use Vite plugins in the Nitro config as a workaround, this approach is not recommended: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { vite: { plugins: [vue()], }, }, }) ``` <warning> Using this workaround may lead to unexpected behavior and bugs. The Vue plugin is one of many that are not available in the Nitro context. </warning> Related issues: - [Issue #19858](https://github.com/nuxt/nuxt/issues/19858) - [Issue #19854](https://github.com/nuxt/nuxt/issues/19854) <note> Nitro v3 will resolve these limitations by removing support for the app config. You can track the progress in [this pull request](https://github.com/nitrojs/nitro/pull/2521). </note> # assets > The assets/ directory is used to add all the website's assets that the build tool will process. The directory usually contains the following types of files: - Stylesheets (CSS, SASS, etc.) - Fonts - Images that won't be served from the [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory. If you want to serve assets from the server, we recommend taking a look at the [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory. <read-more to="https://nuxt.com/docs/5.x/getting-started/assets"> </read-more> # components > The components/ directory is where you put all your Vue components. Nuxt automatically imports any components in this directory (along with components that are registered by any modules you may be using). ```bash [Directory Structure] -| components/ ---| AppHeader.vue ---| AppFooter.vue ``` ```html [app/app.vue] <template> <div> <AppHeader /> <NuxtPage /> <AppFooter /> </div> </template> ``` ## Component Names If you have a component in nested directories such as: ```bash [Directory Structure] -| components/ ---| base/ -----| foo/ -------| Button.vue ``` ... then the component's name will be based on its own path directory and filename, with duplicate segments being removed. Therefore, the component's name will be: ```html <BaseFooButton /> ``` <note> For clarity, we recommend that the component's filename matches its name. So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue`. </note> If you want to group components in a directory without affecting their name, you can use the parenthesis `(` `)` to name the grouping directory. ```bash [Grouping Directory] -| components/ ---| base/ -----| (foo)/ -------| Button.vue ``` ... then the component's name will skip the grouping directory, resulting in: ```html <BaseButton /> ``` If you want to auto-import components based only on its name, not path, then you need to set `pathPrefix` option to `false` using extended form of the configuration object: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ { path: '~/components', pathPrefix: false, // [!code ++] }, ], }) ``` This registers the components using the same strategy as used in Nuxt 2. For example, `~/components/Some/MyComponent.vue` will be usable as `<MyComponent>` and not `<SomeMyComponent>`. ## Dynamic Components If you want to use the Vue `<component :is="someComputedComponent">` syntax, you need to use the `resolveComponent` helper provided by Vue or import the component directly from `#components` and pass it into `is` prop. For example: ```vue [app/pages/index.vue] <script setup lang="ts"> import { SomeComponent } from '#components' const MyButton = resolveComponent('MyButton') </script> <template> <component :is="clickable ? MyButton : 'div'" /> <component :is="SomeComponent" /> </template> ``` <important> If you are using `resolveComponent` to handle dynamic components, make sure not to insert anything but the name of the component, which must be a literal string and not be or contain a variable. The string is statically analyzed at the compilation step. </important> <video-accordion title="Watch Daniel Roe's short video about resolveComponent()" video-id="4kq8E5IUM2U"> </video-accordion> Alternatively, though not recommended, you can register all your components globally, which will create async chunks for all your components and make them available throughout your application. ```diff export default defineNuxtConfig({ components: { + global: true, + dirs: ['~/components'] }, }) ``` You can also selectively register some components globally by placing them in a `~/components/global` directory, or by using a `.global.vue` suffix in the filename. As noted above, each global component is rendered in a separate chunk, so be careful not to overuse this feature. <note> The `global` option can also be set per component directory. </note> ## Dynamic Imports To dynamically import a component (also known as lazy-loading a component) all you need to do is add the `Lazy` prefix to the component's name. This is particularly useful if the component is not always needed. By using the `Lazy` prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size. ```vue [app/pages/index.vue] <script setup lang="ts"> const show = ref(false) </script> <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true" > Show List </button> </div> </template> ``` ## Delayed (or Lazy) Hydration Lazy components are great for controlling the chunk sizes in your app, but they don't always enhance runtime performance, as they still load eagerly unless conditionally rendered. In real-world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive as soon as the page is loaded. Having them all load eagerly can negatively impact performance. In order to optimize your app, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks. Nuxt supports this using lazy (or delayed) hydration, allowing you to control when components become interactive. ### Hydration Strategies Nuxt provides a range of built-in hydration strategies. Only one strategy can be used per lazy component. <note> Any prop change on a lazily hydrated component will trigger hydration immediately. (e.g., changing a prop on a component with `hydrate-never` will cause it to hydrate) </note> <warning> Currently Nuxt's built-in lazy hydration only works in single-file components (SFCs), and requires you to define the prop in the template (rather than spreading an object of props via `v-bind`). It also does not work with direct imports from `#components`. </warning> #### `hydrate-on-visible` Hydrates the component when it becomes visible in the viewport. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-visible /> </div> </template> ``` <read-more to="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver" title="IntersectionObserver options"> Read more about the options for `hydrate-on-visible`. </read-more> <note> Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible). </note> #### `hydrate-on-idle` Hydrates the component when the browser is idle. This is suitable if you need the component to load as soon as possible, but not block the critical rendering path. You can also pass a number which serves as a max timeout. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-idle /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle). </note> #### `hydrate-on-interaction` Hydrates the component after a specified interaction (e.g., click, mouseover). ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-interaction="mouseover" /> </div> </template> ``` If you do not pass an event or list of events, it defaults to hydrating on `pointerenter`, `click` and `focus`. <note> Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction). </note> #### `hydrate-on-media-query` Hydrates the component when the window matches a media query. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-media-query="(max-width: 768px)" /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query). </note> #### `hydrate-after` Hydrates the component after a specified delay (in milliseconds). ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent :hydrate-after="2000" /> </div> </template> ``` #### `hydrate-when` Hydrates the component based on a boolean condition. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent :hydrate-when="isReady" /> </div> </template> <script setup lang="ts"> const isReady = ref(false) function myFunction () { // trigger custom hydration strategy... isReady.value = true } </script> ``` #### `hydrate-never` Never hydrates the component. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-never /> </div> </template> ``` ### Listening to Hydration Events All delayed hydration components emit a `@hydrated` event when they are hydrated. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-visible @hydrated="onHydrate" /> </div> </template> <script setup lang="ts"> function onHydrate () { console.log('Component has been hydrated!') } </script> ``` ### Caveats and Best Practices Delayed hydration can offer performance benefits, but it's essential to use it correctly: 1. **Prioritize In-Viewport Content:** Avoid delayed hydration for critical, above-the-fold content. It's best suited for content that isn't immediately needed. 2. **Conditional Rendering:** When using `v-if="false"` on a lazy component, you might not need delayed hydration. You can just use a normal lazy component. 3. **Shared State:** Be mindful of shared state (`v-model`) across multiple components. Updating the model in one component can trigger hydration in all components bound to that model. 4. **Use Each Strategy's Intended Use Case:** Each strategy is optimized for a specific purpose. - `hydrate-when` is best for components that might not always need to be hydrated. - `hydrate-after` is for components that can wait a specific amount of time. - `hydrate-on-idle` is for components that can be hydrated when the browser is idle. 5. **Avoid hydrate-never on interactive components:** If a component requires user interaction, it should not be set to never hydrate. ## Direct Imports You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality. ```vue [app/pages/index.vue] <script setup lang="ts"> import { LazyMountainsList, NuxtLink } from '#components' const show = ref(false) </script> <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true" > Show List </button> <NuxtLink to="/">Home</NuxtLink> </div> </template> ``` ## Custom Directories By default, only the `~/components` directory is scanned. If you want to add other directories, or change how the components are scanned within a subfolder of this directory, you can add additional directories to the configuration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ // ~/calendar-module/components/event/Update.vue => <EventUpdate /> { path: '~/calendar-module/components' }, // ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog /> { path: '~/user-module/components', pathPrefix: false }, // ~/components/special-components/Btn.vue => <SpecialBtn /> { path: '~/components/special-components', prefix: 'Special' }, // It's important that this comes last if you have overrides you wish to apply // to sub-directories of `~/components`. // // ~/components/Btn.vue => <Btn /> // ~/components/base/Btn.vue => <BaseBtn /> '~/components', ], }) ``` <note> Any nested directories need to be added first as they are scanned in order. </note> Each directory entry also accepts `pattern` and `ignore` glob options, which control which files are scanned within `path`. This is useful when your components live in nested folders that don't follow the default layout, such as a domain-driven structure: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ // ~/domains/blog/components/PostCard.vue => <PostCard /> { path: '~/domains', pattern: '*/components/**', pathPrefix: false, }, ], }) ``` <note> If `pattern` is specified, the `extensions` option has no effect, so make sure your pattern matches the file extensions you want to scan. </note> ## npm Packages If you want to auto-import components from an npm package, you can use [`addComponent`](https://nuxt.com/docs/5.x/api/kit/components#addcomponent) in a [local module](https://nuxt.com/docs/5.x/directory-structure/modules) to register them. <code-group> ```ts [~/modules/register-component.ts]twoslash import { addComponent, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // import { MyComponent as MyAutoImportedComponent } from 'my-npm-package' addComponent({ name: 'MyAutoImportedComponent', export: 'MyComponent', filePath: 'my-npm-package', }) }, }) ``` ```vue [app/app.vue] <template> <div> <!-- the component uses the name we specified and is auto-imported --> <MyAutoImportedComponent /> </div> </template> ``` </code-group> ## Component Extensions By default, any file with an extension specified in the [extensions key of `nuxt.config.ts`](https://nuxt.com/docs/5.x/api/nuxt-config#extensions) is treated as a component. If you need to restrict the file extensions that should be registered as components, you can use the extended form of the components directory declaration and its `extensions` key: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ { path: '~/components', extensions: ['.vue'], // [!code ++] }, ], }) ``` ## Client Components If a component is meant to be rendered only client-side, you can add the `.client` suffix to your component. ```bash [Directory Structure] | components/ --| Comments.client.vue ``` ```vue [app/pages/example.vue] <template> <div> <!-- this component will only be rendered on client side --> <Comments /> </div> </template> ``` <note> This feature only works with Nuxt auto-imports and `#components` imports. Explicitly importing these components from their real paths does not convert them into client-only components. </note> <important> `.client` components are rendered only after being mounted. To access the rendered template using `onMounted()`, add `await nextTick()` in the callback of the `onMounted()` hook. </important> <read-more to="https://nuxt.com/docs/5.x/api/components/client-only"> You can also achieve a similar result with the `<ClientOnly>` component. </read-more> ## Server Components Server components allow server-rendering individual components within your client-side apps. It's possible to use server components within Nuxt, even if you are generating a static site. That makes it possible to build complex sites that mix dynamic components, server-rendered HTML and even static chunks of markup. Server components can either be used on their own or paired with a [client component](https://nuxt.com/docs/5.x/directory-structure/app/components#paired-with-a-client-component). <video-accordion title="Watch Learn Vue video about Nuxt Server Components" video-id="u1yyXe86xJM"> </video-accordion> <tip icon="i-lucide-newspaper" target="_blank" to="https://roe.dev/blog/nuxt-server-components"> Read Daniel Roe's guide to Nuxt Server Components. </tip> ### Standalone server components Standalone server components will always be rendered on the server, also known as Islands components. When their props update, this will result in a network request that will update the rendered HTML in-place. Register server-only components with the `.server` suffix and use them anywhere in your application automatically. ```bash [Directory Structure] -| components/ ---| HighlightedMarkdown.server.vue ``` ```vue [app/pages/example.vue] <template> <div> <!-- this will automatically be rendered on the server, meaning your markdown parsing + highlighting libraries are not included in your client bundle. --> <HighlightedMarkdown markdown="# Headline" /> </div> </template> ``` Server-only components use [`<NuxtIsland>`](https://nuxt.com/docs/5.x/api/components/nuxt-island) under the hood, meaning that `lazy` prop and `#fallback` slot are both passed down to it. <warning> Server components (and islands) must have a single root element. (HTML comments are considered elements as well.) </warning> <read-more to="https://nuxt.com/docs/5.x/guide/concepts/server-components"> Read more about how islands are rendered, the isolated island context, selective hydration with `nuxt-client`, slots, caching and current limitations in the dedicated server components guide. </read-more> ### Paired with a Client component In this case, the `.server` + `.client` components are two 'halves' of a component and can be used in advanced use cases for separate implementations of a component on server and client side. ```bash [Directory Structure] -| components/ ---| Comments.client.vue ---| Comments.server.vue ``` ```vue [app/pages/example.vue] <template> <div> <!-- this component will render Comments.server on the server then Comments.client once mounted in the browser --> <Comments /> </div> </template> ``` ## Built-In Nuxt Components There are a number of components that Nuxt provides, including `<ClientOnly>` and `<DevOnly>`. You can read more about them in the API documentation. <read-more to="https://nuxt.com/docs/5.x/api"> </read-more> ## Library Authors Making Vue component libraries with automatic tree-shaking and component registration is super easy. โœจ You can use the [`addComponentsDir`](https://nuxt.com/docs/5.x/api/kit/components#addcomponentsdir) method provided from the `@nuxt/kit` to register your components directory in your Nuxt module. Imagine a directory structure like this: ```bash [Directory Structure] -| node_modules/ ---| awesome-ui/ -----| components/ -------| Alert.vue -------| Button.vue -----| nuxt.ts -| pages/ ---| index.vue -| nuxt.config.ts ``` Then in `awesome-ui/nuxt.ts` you can use the `addComponentsDir` hook: ```tstwoslash import { addComponentsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const resolver = createResolver(import.meta.url) // Add ./components dir to the list addComponentsDir({ path: resolver.resolve('./components'), prefix: 'awesome', }) }, }) ``` That's it! Now in your project, you can import your UI library as a Nuxt module in your `nuxt.config` file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ modules: ['awesome-ui/nuxt'], }) ``` ... and directly use the module components (prefixed with `awesome-`) in our `app/pages/index.vue`: ```vue <template> <div> My <AwesomeButton>UI button</AwesomeButton>! <awesome-alert>Here's an alert!</awesome-alert> </div> </template> ``` It will automatically import the components only if used and also support HMR when updating your components in `node_modules/awesome-ui/components/`. <link-example to="https://nuxt.com/docs/5.x/examples/features/auto-imports"> </link-example> # composables > Use the composables/ directory to auto-import your Vue composables into your application. ## Usage **Method 1:** Using named export ```ts [app/composables/useFoo.ts] export const useFoo = () => { return useState('foo', () => 'bar') } ``` **Method 2:** Using default export ```ts [app/composables/use-foo.ts or composables/useFoo.ts] // It will be available as useFoo() (camelCase of file name without extension) export default function () { return useState('foo', () => 'bar') } ``` **Usage:** You can now use auto imported composable in `.js`, `.ts` and `.vue` files ```vue [app/app.vue] <script setup lang="ts"> const foo = useFoo() </script> <template> <div> {{ foo }} </div> </template> ``` <note> The `app/composables/` directory in Nuxt does not provide any additional reactivity capabilities to your code. Instead, any reactivity within composables is achieved using Vue's Composition API mechanisms, such as ref and reactive. Note that reactive code is also not limited to the boundaries of the `app/composables/` directory. You are free to employ reactivity features wherever they're needed in your application. </note> <read-more to="https://nuxt.com/docs/5.x/guide/concepts/auto-imports"> </read-more> <link-example to="https://nuxt.com/docs/5.x/examples/features/auto-imports"> </link-example> ## Types Under the hood, Nuxt auto generates the file `.nuxt/imports.d.ts` to declare the types. Be aware that you have to run [`nuxt prepare`](https://nuxt.com/docs/5.x/api/commands/prepare), [`nuxt dev`](https://nuxt.com/docs/5.x/api/commands/dev) or [`nuxt build`](https://nuxt.com/docs/5.x/api/commands/build) in order to let Nuxt generate the types. <note> If you create a composable without having the dev server running, TypeScript will throw an error, such as `Cannot find name 'useBar'.` </note> ## Example ### Nested Composables You can use a composable within another composable using auto imports: ```ts [app/composables/test.ts] export const useFoo = () => { const nuxtApp = useNuxtApp() const bar = useBar() } ``` ### Access Plugin Injections You can access [plugin injections](https://nuxt.com/docs/5.x/directory-structure/app/plugins#providing-helpers) from composables: ```ts [app/composables/test.ts] export const useHello = () => { const nuxtApp = useNuxtApp() return nuxtApp.$hello } ``` ## How Files Are Scanned Nuxt only scans files at the top level of the [`app/composables/` directory](https://nuxt.com/docs/5.x/directory-structure/app/composables), e.g.: ```bash [Directory Structure] -| composables/ ---| index.ts // scanned ---| useFoo.ts // scanned ---| nested/ -----| utils.ts // not scanned ``` Only `app/composables/index.ts` and `app/composables/useFoo.ts` would be searched for imports. To get auto imports working for nested modules, you could either re-export them (recommended) or configure the scanner to include nested directories: **Example:** Re-export the composables you need from the `app/composables/index.ts` file: ```ts [app/composables/index.ts] // Enables auto import for this export export { utils } from './nested/utils.ts' ``` **Example:** Scan nested directories inside the `app/composables/` folder: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { dirs: [ // Scan top-level composables '~/composables', // ... or scan composables nested one level deep with a specific name and file extension '~/composables/*/index.{ts,js,mjs,mts}', // ... or scan all composables within given directory '~/composables/**', ], }, }) ``` # error.vue > The error.vue file is the error page in your Nuxt application. During the lifespan of your application, some errors may appear unexpectedly at runtime. In such case, we can use the `error.vue` file to override the default error files and display the error nicely. ```vue [error.vue] <script setup lang="ts"> import type { NuxtError } from '#app' const props = defineProps<{ error: NuxtError }>() </script> <template> <div> <h1>{{ error.status }}</h1> <NuxtLink to="/">Go back home</NuxtLink> </div> </template> ``` <note> Although it is called an 'error page' it's not a route and shouldn't be placed in your `~/pages` directory. For the same reason, you shouldn't use `definePageMeta` within this page. That being said, you can still use layouts in the error file, by utilizing the [`NuxtLayout`](https://nuxt.com/docs/5.x/api/components/nuxt-layout) component and specifying the name of the layout. </note> The error page has a single prop - `error` which contains an error for you to handle. The `error` object provides the following fields: ```ts interface NuxtError { status: number fatal: boolean unhandled: boolean statusText?: string data?: unknown cause?: unknown } ``` If you have an error with custom fields they will be lost; you should assign them to `data` instead: ```ts throw createError({ status: 404, statusText: 'Page Not Found', data: { myCustomField: true, }, }) ``` # layouts > Nuxt provides a layouts framework to extract common UI patterns into reusable layouts. <tip icon="i-lucide-rocket"> For best performance, components placed in this directory will be automatically loaded via asynchronous import when used. </tip> ## Enable Layouts Layouts are enabled by adding [`<NuxtLayout>`](https://nuxt.com/docs/5.x/api/components/nuxt-layout) to your [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app): ```vue [app/app.vue] <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` To use a layout: - Set a `layout` property in your page with [definePageMeta](https://nuxt.com/docs/5.x/api/utils/define-page-meta). - Set the `name` prop of `<NuxtLayout>`. - Set the `appLayout` property in route rules. <note> The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`. </note> <note> If no layout is specified, `app/layouts/default.vue` will be used. </note> <important> If you only have a single layout in your application, we recommend using [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app) instead. </important> <important> Unlike other components, your layouts must have a single root element to allow Nuxt to apply transitions between layout changes - and this root element cannot be a `<slot />`. </important> ## Default Layout Add a `~/layouts/default.vue`: ```vue [app/layouts/default.vue] <template> <div> <p>Some default layout content shared across all pages</p> <slot /> </div> </template> ``` In a layout file, the content of the page will be displayed in the `<slot />` component. ## Named Layout ```bash [Directory Structure] -| layouts/ ---| default.vue ---| custom.vue ``` Then you can use the `custom` layout in your page: ```vue [pages/about.vue]twoslash <script setup lang="ts"> declare module 'nuxt/app' { interface NuxtLayouts { 'custom': unknown } } // ---cut--- definePageMeta({ layout: 'custom', }) </script> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/pages#page-metadata"> Learn more about `definePageMeta`. </read-more> You can directly override the default layout for all pages using the `name` property of [`<NuxtLayout>`](https://nuxt.com/docs/5.x/api/components/nuxt-layout): ```vue [app/app.vue] <script setup lang="ts"> // You might choose this based on an API call or logged-in status const layout = 'custom' </script> <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> ``` If you have a layout in nested directories, the layout's name will be based on its own path directory and filename, with duplicate segments being removed. <table> <thead> <tr> <th> File </th> <th> Layout Name </th> </tr> </thead> <tbody> <tr> <td> <code> ~/layouts/desktop/default.vue </code> </td> <td> <code> desktop-default </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop-base/base.vue </code> </td> <td> <code> desktop-base </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop/index.vue </code> </td> <td> <code> desktop </code> </td> </tr> </tbody> </table> For clarity, we recommend that the layout's filename matches its name: <table> <thead> <tr> <th> File </th> <th> Layout Name </th> </tr> </thead> <tbody> <tr> <td> <code> ~/layouts/desktop/DesktopDefault.vue </code> </td> <td> <code> desktop-default </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop-base/DesktopBase.vue </code> </td> <td> <code> desktop-base </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop/Desktop.vue </code> </td> <td> <code> desktop </code> </td> </tr> </tbody> </table> <link-example to="https://nuxt.com/docs/5.x/examples/features/layouts"> </link-example> ## Changing the Layout Dynamically You can also use the [`setPageLayout`](https://nuxt.com/docs/5.x/api/utils/set-page-layout) helper to change the layout dynamically: ```vue [app/pages/index.vue]twoslash <script setup lang="ts"> declare module 'nuxt/app' { interface NuxtLayouts { 'custom': unknown } } // ---cut--- function enableCustomLayout () { setPageLayout('custom') } definePageMeta({ layout: false, }) </script> <template> <div> <button @click="enableCustomLayout"> Update layout </button> </div> </template> ``` You can also set layouts for specific routes using the `appLayout` property in route rules <badge className="align-middle" color="info" size="xs"> v4.3 </badge> : ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { // Set layout for specific route '/admin': { appLayout: 'admin' }, // Set layout for multiple routes '/dashboard/**': { appLayout: 'dashboard' }, // Disable layout for a route '/landing': { appLayout: false }, }, }) ``` <tip> This is useful when you want to manage layouts centrally in your configuration rather than in each page file, or when you need to apply layouts to routes that don't have corresponding page components (such as catchall pages which might match many paths). </tip> <link-example to="https://nuxt.com/docs/5.x/examples/features/layouts"> </link-example> ## Passing Props to Layouts <badge className="align-middle" color="primary">+4.4</badge> You can pass props to layouts in several ways. ### Via `definePageMeta` Use the object syntax for the `layout` property to pass props directly from your page: <code-group> ```vue [app/pages/dashboard.vue] <script setup lang="ts"> definePageMeta({ layout: { name: 'panel', props: { sidebar: true, title: 'Dashboard', }, }, }) </script> ``` ```vue [app/layouts/panel.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` </code-group> <tip> Props are fully typed based on your layout's `defineProps`. You'll get autocomplete and type-checking in your editor. </tip> ### Via `setPageLayout` You can also pass props when changing the layout dynamically with [`setPageLayout`](https://nuxt.com/docs/5.x/api/utils/set-page-layout): ```ts setPageLayout('panel', { sidebar: true, title: 'Dashboard' }) ``` ## Overriding a Layout on a Per-page Basis If you are using pages, you can take full control by setting `layout: false` and then using the `<NuxtLayout>` component within the page. <code-group> ```vue [app/pages/index.vue] <script setup lang="ts"> definePageMeta({ layout: false, }) </script> <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> The rest of the page </NuxtLayout> </div> </template> ``` ```vue [app/layouts/custom.vue] <template> <div> <header> <slot name="header"> Default header content </slot> </header> <main> <slot /> </main> </div> </template> ``` </code-group> <important> If you use `<NuxtLayout>` within your pages, make sure it is not the root element (or [disable layout/page transitions](https://nuxt.com/docs/5.x/getting-started/transitions#disable-transitions)). </important> # middleware > Nuxt provides middleware to run code before navigating to a particular route. Nuxt provides a customizable **route middleware** framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route. There are three kinds of route middleware: 1. Anonymous (or inline) route middleware are defined directly within the page. 2. Named route middleware, placed in the `app/middleware/` and automatically loaded via asynchronous import when used on a page. 3. Global route middleware, placed in the `app/middleware/` with a `.global` suffix and is run on every route change. The first two kinds of route middleware can be defined in [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta). <note> Name of middleware are normalized to kebab-case: `myMiddleware` becomes `my-middleware`. </note> <note> Only files at the top level of the directory (or index files within any subdirectories) are registered. An index file takes its name from the folder that contains it: `middleware/auth/index.ts` is registered as `auth`. </note> <note> Route middleware run within the Vue part of your Nuxt app. Despite the similar name, they are completely different from [server middleware](https://nuxt.com/docs/5.x/directory-structure/server#server-middleware), which are run in the Nitro server part of your app. </note> <video-accordion platform="vimeo" title="Watch a video from Vue School on all 3 kinds of middleware" video-id="761471577"> </video-accordion> ## Usage Route middleware are navigation guards that receive the current route and the next route as arguments. ```ts [middleware/my-middleware.ts]twoslash export default defineNuxtRouteMiddleware((to, from) => { if (to.params.id === '1') { return abortNavigation() } // In a real app you would probably not redirect every route to `/` // however it is important to check `to.path` before redirecting or you // might get an infinite redirect loop if (to.path !== '/') { return navigateTo('/') } }) ``` Nuxt provides two globally available helpers that can be returned directly from the middleware. 1. [`navigateTo`](https://nuxt.com/docs/5.x/api/utils/navigate-to) - Redirects to the given route 2. [`abortNavigation`](https://nuxt.com/docs/5.x/api/utils/abort-navigation) - Aborts the navigation, with an optional error message. Unlike [navigation guards](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) from `vue-router`, a third `next()` argument is not passed, and **redirect or route cancellation is handled by returning a value from the middleware**. Possible return values are: - nothing (a simple `return` or no return at all) - does not block navigation and will move to the next middleware function, if any, or complete the route navigation - `return navigateTo('/')` - redirects to the given path and will set the redirect code to [`302` Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) if the redirect happens on the server side - `return navigateTo('/', { redirectCode: 301 })` - redirects to the given path and will set the redirect code to [`301` Moved Permanently](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) if the redirect happens on the server side - `return abortNavigation()` - stops the current navigation - `return abortNavigation(error)` - rejects the current navigation with an error <read-more to="https://nuxt.com/docs/5.x/api/utils/navigate-to"> </read-more> <read-more to="https://nuxt.com/docs/5.x/api/utils/abort-navigation"> </read-more> <important> We recommend using the helper functions above for performing redirects or stopping navigation. Other possible return values described in [the vue-router docs](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) may work but there may be breaking changes in future. </important> ## Middleware Order Middleware runs in the following order: 1. Global Middleware 2. Page defined middleware order (if there are multiple middleware declared with the array syntax) For example, assuming you have the following middleware and component: ```bash [app/middleware/ directory] -| middleware/ ---| analytics.global.ts ---| setup.global.ts ---| auth.ts ``` ```vue [pages/profile.vue]twoslash <script setup lang="ts"> definePageMeta({ middleware: [ function (to, from) { // Custom inline middleware }, 'auth', ], }) </script> ``` You can expect the middleware to be run in the following order: 1. `analytics.global.ts` 2. `setup.global.ts` 3. Custom inline middleware 4. `auth.ts` ### Ordering Global Middleware By default, global middleware is executed alphabetically based on the filename. However, there may be times you want to define a specific order. For example, in the last scenario, `setup.global.ts` may need to run before `analytics.global.ts`. In that case, we recommend prefixing global middleware with 'alphabetical' numbering. ```bash [Directory structure] -| middleware/ ---| 01.setup.global.ts ---| 02.analytics.global.ts ---| auth.ts ``` <note> In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.new.global.ts` would come before `2.new.global.ts`. This is why the example prefixes single digit numbers with `0`. </note> ## When Middleware Runs If your site is server-rendered or generated, middleware for the initial page will be executed both when the page is rendered and then again on the client. This might be needed if your middleware needs a browser environment, such as if you have a generated site, aggressively cache responses, or want to read a value from local storage. However, if you want to avoid this behaviour you can do so: ```ts [middleware/example.ts]twoslash export default defineNuxtRouteMiddleware((to) => { // skip middleware on server if (import.meta.server) { return } // skip middleware on client side entirely if (import.meta.client) { return } // or only skip middleware on initial client load const nuxtApp = useNuxtApp() if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) { return } }) ``` This is true even if you throw an error in your middleware on the server, and an error page is rendered. The middleware will still run again in the browser. <note> Rendering an error page is an entirely separate page load, meaning any registered middleware will run again. You can use [`useError`](https://nuxt.com/docs/5.x/getting-started/error-handling#useerror) in middleware to check if an error is being handled. </note> ## Accessing Route in Middleware Always use the `to` and `from` parameters in your middleware to access the next and previous routes. Avoid using the [`useRoute()`](https://nuxt.com/docs/5.x/api/composables/use-route) composable in this context altogether. There is **no concept of a "current route" in middleware**, as middleware can abort a navigation or redirect to a different route. The `useRoute()` composable will always be inaccurate in this context. <warning> Sometimes, you might call a composable that uses `useRoute()` internally, which can trigger this warning even if there is no direct call in your middleware. This leads to the **same issue as above**, so you should structure your functions to accept the route as an argument instead when they are used in middleware. </warning> <code-group> ```ts [middleware/access-route.ts]twoslash // @errors: 2304 export default defineNuxtRouteMiddleware((to) => { // passing the route to the function to avoid calling `useRoute()` in middleware doSomethingWithRoute(to) // โŒ this will output a warning and is NOT recommended callsRouteInternally() }) ``` ```ts [utils/handle-route.ts]twoslash // providing the route as an argument so that it can be used in middleware correctly export function doSomethingWithRoute (route = useRoute()) { // ... } ``` ```ts [utils/dont-do-this.ts]twoslash // โŒ this function is not suitable for use in middleware export function callsRouteInternally () { const route = useRoute() // ... } ``` </code-group> ## Adding Middleware Dynamically It is possible to add global or named route middleware manually using the [`addRouteMiddleware()`](https://nuxt.com/docs/5.x/api/utils/add-route-middleware) helper function, such as from within a plugin. ```tstwoslash export default defineNuxtPlugin(() => { addRouteMiddleware('global-test', () => { console.log('this global middleware was added in a plugin and will be run on every route change') }, { global: true }) addRouteMiddleware('named-test', () => { console.log('this named middleware was added in a plugin and would override any existing middleware of the same name') }) }) ``` ## Example ```bash [Directory Structure] -| middleware/ ---| auth.ts ``` In your page file, you can reference this route middleware: ```vuetwoslash <script setup lang="ts"> definePageMeta({ middleware: ['auth'], // or middleware: 'auth' }) </script> ``` Now, before navigation to that page can complete, the `auth` route middleware will be run. <link-example to="https://nuxt.com/docs/5.x/examples/routing/middleware"> </link-example> ## Setting Middleware at Build Time Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook. ```ts [nuxt.config.ts]twoslash import type { NuxtPage } from 'nuxt/schema' export default defineNuxtConfig({ hooks: { 'pages:extend' (pages) { function setMiddleware (pages: NuxtPage[]) { for (const page of pages) { if (/* some condition */ Math.random() > 0.5) { page.meta ||= {} // Note that this will override any middleware set in `definePageMeta` in the page page.meta.middleware = ['named'] } if (page.children) { setMiddleware(page.children) } } } setMiddleware(pages) }, }, }) ``` # pages > Nuxt provides file-based routing to create routes within your web application. <note> To reduce your application's bundle size, this directory is **optional**, meaning that [`vue-router`](https://router.vuejs.org) won't be included if you only use [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app). To force the pages system, set `pages: true` in `nuxt.config` or have a [`router.options.ts`](https://nuxt.com/docs/5.x/guide/recipes/custom-routing#using-routeroptions). </note> ## Usage Pages are Vue components and can have any [valid extension](https://nuxt.com/docs/5.x/api/nuxt-config#extensions) that Nuxt supports (by default `.vue`, `.js`, `.jsx`, `.mjs`, `.ts` or `.tsx`). Nuxt will automatically create a route for every page in your `~/pages/` directory. <tip> Pages are only automatically registered for prerendering if you have not disabled `nitro.prerender.crawlLinks` and you have at least one page in your `nitro.prerender.routes` list. See the [prerendering guide](https://nuxt.com/docs/5.x/getting-started/prerendering). </tip> <code-group> ```vue [app/pages/index.vue] <template> <h1>Index page</h1> </template> ``` ```ts [pages/index.ts]twoslash // https://vuejs.org/guide/extras/render-function.html export default defineComponent({ render () { return h('h1', 'Index page') }, }) ``` ```tsx [pages/index.tsx]twoslash // /docs/examples/advanced/jsx // https://vuejs.org/guide/extras/render-function.html#jsx-tsx export default defineComponent({ render () { return <h1>Index page</h1> }, }) ``` </code-group> The `app/pages/index.vue` file will be mapped to the `/` route of your application. If you are using [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app), make sure to use the [`<NuxtPage/>`](https://nuxt.com/docs/5.x/api/components/nuxt-page) component to display the current page: ```vue [app/app.vue] <template> <div> <!-- Markup shared across all pages, ex: NavBar --> <NuxtPage /> </div> </template> ``` Pages **must have a single root element** to allow [route transitions](https://nuxt.com/docs/5.x/getting-started/transitions) between pages. HTML comments are considered elements as well. This means that when the route is server-rendered, or statically generated, you will be able to see its contents correctly, but when you navigate towards that route during client-side navigation the transition between routes will fail and you'll see that the route will not be rendered. Here are some examples to illustrate what a page with a single root element looks like: <code-group> ```vue [app/pages/working.vue] <template> <div> <!-- This page correctly has only one single root element --> Page content </div> </template> ``` ```vue [app/pages/bad-1.vue] <template> <!-- This page will not render when route changes during client side navigation, because of this comment --> <div>Page content</div> </template> ``` ```vue [app/pages/bad-2.vue] <template> <div>This page</div> <div>Has more than one root element</div> <div>And will not render when route changes during client side navigation</div> </template> ``` </code-group> ## Dynamic Routes If you place anything within square brackets, it will be turned into a [dynamic route](https://router.vuejs.org/guide/essentials/dynamic-matching) parameter. You can mix and match multiple parameters and even non-dynamic text within a file name or directory. If you want a parameter to be *optional*, you must enclose it in double square brackets - for example, `~/pages/[[slug]]/index.vue` or `~/pages/[[slug]].vue` will match both `/` and `/test`. ```bash [Directory Structure] -| pages/ ---| index.vue ---| users-[group]/ -----| [id].vue ``` Given the example above, you can access group/id within your component via the `$route` object: ```vue [app/pages/users-[group]/[id].vue] <template> <p>{{ $route.params.group }} - {{ $route.params.id }}</p> </template> ``` Navigating to `/users-admins/123` would render: ```html <p>admins - 123</p> ``` If you want to access the route using Composition API, there is a global [`useRoute`](https://nuxt.com/docs/5.x/api/composables/use-route) function that will allow you to access the route just like `this.$route` in the Options API. ```vuetwoslash <script setup lang="ts"> const route = useRoute() if (route.params.group === 'admins' && !route.params.id) { console.log('Warning! Make sure user is authenticated!') } </script> ``` <note> Named parent routes will take priority over nested dynamic routes. For the `/foo/hello` route, `~/pages/foo.vue` will take priority over `~/pages/foo/[slug].vue`. <br /> Use `~/pages/foo/index.vue` and `~/pages/foo/[slug].vue` to match `/foo` and `/foo/hello` with different pages,. </note> <video-accordion platform="vimeo" title="Watch a video from Vue School on dynamic routes" video-id="754465699"> </video-accordion> ## Catch-all Route If you need a catch-all route, you create it by using a file named like `[...slug].vue`. This will match *all* routes under that path. ```vue [app/pages/[...slug].vue] <template> <p>{{ $route.params.slug }}</p> </template> ``` Navigating to `/hello/world` would render: ```html <p>["hello", "world"]</p> ``` ## Nested Routes It is possible to display [nested routes](https://router.vuejs.org/guide/essentials/nested-routes) with `<NuxtPage>`. Example: ```bash [Directory Structure] -| pages/ ---| parent/ -----| child.vue ---| parent.vue ``` This file tree will generate these routes: ```js [ { path: '/parent', component: '~/pages/parent.vue', name: 'parent', children: [ { path: 'child', component: '~/pages/parent/child.vue', name: 'parent-child', }, ], }, ] ``` To display the `child.vue` component, you have to insert the `<NuxtPage>` component inside `app/pages/parent.vue`: ```vue [pages/parent.vue] <template> <div> <h1>I am the parent view</h1> <NuxtPage :foobar="123" /> </div> </template> ``` ```vue [pages/parent/child.vue] <script setup lang="ts"> const props = defineProps({ foobar: String, }) console.log(props.foobar) </script> ``` ### Child Route Keys If you want more control over when the `<NuxtPage>` component is re-rendered (for example, for transitions), you can either pass a string or function via the `pageKey` prop, or you can define a `key` value via `definePageMeta`: ```vue [pages/parent.vue] <template> <div> <h1>I am the parent view</h1> <NuxtPage :page-key="route => route.fullPath" /> </div> </template> ``` Or alternatively: ```vue [pages/parent/child.vue]twoslash <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, }) </script> ``` <link-example to="https://nuxt.com/docs/5.x/examples/routing/pages"> </link-example> ## Named Views <badge className="align-middle" color="info" size="xs">v4.5</badge> A single route can render into multiple `<NuxtPage>` outlets in a parent component by giving each outlet a `name` and providing a sibling page file for each name. Use the `name@view.vue` filename convention to declare a named view alongside the default route file: ```bash [Directory Structure] -| pages/ ---| parent/ -----| child.vue -----| child@sidebar.vue ---| parent.vue ``` Then render each outlet by name from the parent: ```vue [pages/parent.vue] <template> <div> <NuxtPage /> <aside> <NuxtPage name="sidebar" /> </aside> </div> </template> ``` When the user navigates to `/parent/child`, `child.vue` renders into the default `<NuxtPage />` and `child@sidebar.vue` renders into `<NuxtPage name="sidebar" />`. Outlets without a matching named view are left empty. <note> `definePageMeta` is read from the default route file only. Meta declared inside a `name@view.vue` sibling has no effect on the route. </note> <read-more to="https://router.vuejs.org/guide/essentials/named-views.html" target="_blank" title="Named Views"> </read-more> ## Route Groups In some cases, you may want to group a set of routes together in a way which doesn't affect file-based routing. For this purpose, you can put files in a folder which is wrapped in parentheses - `(` and `)`. For example: ```bash [Directory structure] -| pages/ ---| index.vue ---| (marketing)/ -----| about.vue -----| contact.vue ``` This will produce `/`, `/about` and `/contact` pages in your app. The `marketing` group is ignored for purposes of your URL structure. ### Accessing Route Groups <badge className="align-middle" color="info" size="xs">v4.3</badge> Route groups are automatically available in the route metadata as `route.meta.groups`. This allows you to access the group information in your components for conditional logic, styling, or other purposes. ```vue [pages/(marketing)/about.vue] <script setup lang="ts"> const route = useRoute() console.log(route.meta.groups) // Output: ['marketing'] </script> <template> <div> <p v-if="route.meta.groups?.includes('marketing')"> This is a marketing page </p> </div> </template> ``` ## Page Metadata You might want to define metadata for each route in your app. You can do this using the `definePageMeta` macro, which will work both in `<script>` and in `<script setup>`: ```vuetwoslash <script setup lang="ts"> definePageMeta({ title: 'My home page', }) </script> ``` This data can then be accessed throughout the rest of your app from the `route.meta` object. ```vuetwoslash <script setup lang="ts"> const route = useRoute() console.log(route.meta.title) // My home page </script> ``` If you are using nested routes, the page metadata from all these routes will be merged into a single object. For more on route meta, see the [vue-router docs](https://router.vuejs.org/guide/advanced/meta). Much like `defineEmits` or `defineProps` (see [Vue docs](https://vuejs.org/api/sfc-script-setup#defineprops-defineemits)), `definePageMeta` is a **compiler macro**. It will be compiled away so you cannot reference it within your component. Instead, the metadata passed to it will be hoisted out of the component. Therefore, the page meta object cannot reference the component. However, it can reference imported bindings, as well as locally defined **pure functions**. <warning> Make sure not to reference any reactive data or functions that cause side effects. This can lead to unexpected behavior. </warning> ```vue <script setup lang="ts"> import { someData } from '~/utils/example' function validateIdParam (route) { return route.params.id && !Number.isNaN(Number(route.params.id)) } const title = ref('') definePageMeta({ validate: validateIdParam, someData, title, // do not do this, the ref will be hoisted out of the component }) </script> ``` ### Special Metadata Of course, you are welcome to define metadata for your own use throughout your app. But some metadata defined with `definePageMeta` has a particular purpose: #### `alias` You can define page aliases. They allow you to access the same page from different paths. It can be either a string or an array of strings as defined [in the vue-router documentation](https://router.vuejs.org/guide/essentials/redirect-and-alias#Alias). #### `keepalive` Nuxt will automatically wrap your page in [the Vue `<KeepAlive>` component](https://vuejs.org/guide/built-ins/keep-alive#keepalive) if you set `keepalive: true` in your `definePageMeta`. This might be useful to do, for example, in a parent route that has dynamic child routes, if you want to preserve page state across route changes. When your goal is to preserve state for parent routes use this syntax: `<NuxtPage keepalive />`. You can also set props to be passed to `<KeepAlive>` (see [a full list](https://vuejs.org/api/built-in-components#keepalive)). You can set a default value for this property [in your `nuxt.config`](https://nuxt.com/docs/5.x/api/nuxt-config#keepalive). #### `key` [See above](https://nuxt.com/docs/5.x/directory-structure/app/pages#child-route-keys). #### `layout` You can define the layout used to render the route. This can be either false (to disable any layout), a string or a ref/computed, if you want to make it reactive in some way. [More about layouts](https://nuxt.com/docs/5.x/directory-structure/app/layouts). #### `layoutTransition` and `pageTransition` You can define transition properties for the `<transition>` component that wraps your pages and layouts, or pass `false` to disable the `<transition>` wrapper for that route. You can see [a list of options that can be passed](https://vuejs.org/api/built-in-components#transition) or read [more about how transitions work](https://vuejs.org/guide/built-ins/transition#transition). You can set default values for these properties [in your `nuxt.config`](https://nuxt.com/docs/5.x/api/nuxt-config#layouttransition). #### `middleware` You can define middleware to apply before loading this page. It will be merged with all the other middleware used in any matching parent/child routes. It can be a string, a function (an anonymous/inlined middleware function following [the global before guard pattern](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards)), or an array of strings/functions. [More about named middleware](https://nuxt.com/docs/5.x/directory-structure/app/middleware). #### `name` You may define a name for this page's route. #### `path` You may define a path matcher, if you have a more complex pattern than can be expressed with the file name. See [the `vue-router` docs](https://router.vuejs.org/guide/essentials/route-matching-syntax#Custom-regex-in-params) for more information. #### `props` Allows accessing the route `params` as props passed to the page component. See [the `vue-router` docs](https://router.vuejs.org/guide/essentials/passing-props) for more information. ### Typing Custom Metadata If you add custom metadata for your pages, you may wish to do so in a type-safe way. It is possible to augment the type of the object accepted by `definePageMeta`: ```ts [index.d.ts] declare module '#app' { interface PageMeta { pageType?: string } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ## Navigation To navigate between pages of your app, you should use the [`<NuxtLink>`](https://nuxt.com/docs/5.x/api/components/nuxt-link) component. This component is included with Nuxt and therefore you don't have to import it as you do with other components. A simple link to the `index.vue` page in your `app/pages` folder: ```vue <template> <NuxtLink to="/">Home page</NuxtLink> </template> ``` <read-more to="https://nuxt.com/docs/5.x/api/components/nuxt-link"> Learn more about `<NuxtLink>` usage. </read-more> ## Programmatic Navigation Nuxt allows programmatic navigation through the `navigateTo()` utility method. Using this utility method, you will be able to programmatically navigate the user in your app. This is great for taking input from the user and navigating them dynamically throughout your application. In this example, we have a simple method called `navigate()` that gets called when the user submits a search form. <note> Make sure to always `await` on `navigateTo` or chain its result by returning from functions. </note> ```vuetwoslash <script setup lang="ts"> const name = ref('') const type = ref(1) function navigate () { return navigateTo({ path: '/search', query: { name: name.value, type: type.value, }, }) } </script> ``` ## Client-Only Pages You can define a page as [client only](https://nuxt.com/docs/5.x/directory-structure/app/components#client-components) by giving it a `.client.vue` suffix. None of the content of this page will be rendered on the server. ## Server-Only Pages You can define a page as [server only](https://nuxt.com/docs/5.x/directory-structure/app/components#server-components) by giving it a `.server.vue` suffix. While you will be able to navigate to the page using client-side navigation, controlled by `vue-router`, it will be rendered with a server component automatically, meaning the code required to render the page will not be in your client-side bundle. <warning> Server-only pages must have a single root element. (HTML comments are considered elements as well.) </warning> ## Custom Routing As your app gets bigger and more complex, your routing might require more flexibility. For this reason, Nuxt directly exposes the router, routes and router options for customization in different ways. <read-more to="https://nuxt.com/docs/5.x/guide/recipes/custom-routing"> </read-more> ## Multiple Pages Directories By default, all your pages should be in one `app/pages` directory at the root of your project. However, you can use [Nuxt Layers](https://nuxt.com/docs/5.x/getting-started/layers) to create groupings of your app's pages: ```bash [Directory Structure] -| some-app/ ---| nuxt.config.ts ---| pages/ -----| app-page.vue -| nuxt.config.ts ``` ```ts [some-app/nuxt.config.ts]twoslash // some-app/nuxt.config.ts export default defineNuxtConfig({ }) ``` ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ extends: ['./some-app'], }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/layers"> </read-more> # plugins > Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application. Nuxt automatically reads the files in the `app/plugins/` directory and loads them at the creation of the Vue application. <note> All plugins inside are auto-registered, you don't need to add them to your `nuxt.config` separately. </note> <note> You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side. </note> ## Registered Plugins Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins. ```bash [Directory structure] -| plugins/ ---| foo.ts // scanned ---| bar/ -----| baz.ts // not scanned -----| foz.vue // not scanned -----| index.ts // currently scanned but deprecated ``` Only `foo.ts` and `bar/index.ts` would be registered. To add plugins in subdirectories, you can use the [`app/plugins`](https://nuxt.com/docs/5.x/api/nuxt-config#plugins-1) option in `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ plugins: [ '~/plugins/bar/baz', '~/plugins/bar/foz', ], }) ``` ## Creating Plugins The only argument passed to a plugin is [`nuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app). ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp }) ``` ### Object Syntax Plugins It is also possible to define a plugin using an object syntax, for more advanced use cases. For example: ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', enforce: 'pre', // or 'post' async setup (nuxtApp) { // this is the equivalent of a normal functional plugin }, hooks: { // You can directly register Nuxt app runtime hooks here 'app:created' () { const nuxtApp = useNuxtApp() // do something in the hook }, }, env: { // Set this value to `false` if you don't want the plugin to run when rendering server-only or island components. islands: true, }, }) ``` <video-accordion title="Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins" video-id="2aXZyXB1QGQ"> </video-accordion> <note> If you are using the object-syntax, the properties are statically analyzed to produce a more optimized build. So you should not define them at runtime. <br /> For example, setting `enforce: import.meta.server ? 'pre' : 'post'` would defeat any future optimization Nuxt is able to do for your plugins. Nuxt does statically pre-load any hook listeners when using object-syntax, allowing you to define hooks without needing to worry about order of plugin registration. </note> ## Registration Order You can control the order in which plugins are registered by prefixing with 'alphabetical' numbering to the file names. ```bash [Directory structure] plugins/ | - 01.myPlugin.ts | - 02.myOtherPlugin.ts ``` In this example, `02.myOtherPlugin.ts` will be able to access anything that was injected by `01.myPlugin.ts`. This is useful in situations where you have a plugin that depends on another plugin. <note> In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.myPlugin.ts` would come before `2.myOtherPlugin.ts`. This is why the example prefixes single digit numbers with `0`. </note> ## Loading Strategy ### Parallel Plugins By default, Nuxt loads plugins sequentially. You can define a plugin as `parallel` so Nuxt won't wait until the end of the plugin's execution before loading the next plugin. ```ts [plugins/my-plugin.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', parallel: true, async setup (nuxtApp) { // the next plugin will be executed immediately }, }) ``` ### Plugins With Dependencies If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the `dependsOn` array. ```ts [plugins/depending-on-my-plugin.ts]twoslash export default defineNuxtPlugin({ name: 'depends-on-my-plugin', dependsOn: ['my-plugin'], async setup (nuxtApp) { // this plugin will wait for the end of `my-plugin`'s execution before it runs }, }) ``` ## Using Composables You can use [composables](https://nuxt.com/docs/5.x/directory-structure/app/composables) as well as [utils](https://nuxt.com/docs/5.x/directory-structure/app/utils) within Nuxt plugins: ```ts [app/plugins/hello.ts] export default defineNuxtPlugin((nuxtApp) => { const foo = useFoo() }) ``` However, keep in mind there are some limitations and differences: <important> **If a composable depends on another plugin registered later, it might not work.** <br /> Plugins are called in order sequentially and before everything else. You might use a composable that depends on another plugin which has not been called yet. </important> <important> **If a composable depends on the Vue.js lifecycle, it won't work.** <br /> Normally, Vue.js composables are bound to the current component instance while plugins are only bound to [`nuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) instance. </important> ## Providing Helpers If you would like to provide a helper on the [`NuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) instance, return it from the plugin under a `provide` key. <code-group> ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin(() => { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }) ``` ```ts [plugins/hello-object-syntax.ts]twoslash export default defineNuxtPlugin({ name: 'hello', setup () { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }, }) ``` </code-group> You can then use the helper in your components: ```vue [app/components/Hello.vue] <script setup lang="ts"> // alternatively, you can also use it here const { $hello } = useNuxtApp() </script> <template> <div> {{ $hello('world') }} </div> </template> ``` <important> Note that we highly recommend using [`composables`](https://nuxt.com/docs/5.x/directory-structure/app/composables) instead of providing helpers to avoid polluting the global namespace and keep your main bundle entry small. </important> <warning> **If your plugin provides a ref or computed, it will not be unwrapped in a component <template>.** <br /> This is due to how Vue works with refs that aren't top-level to the template. You can read more about it [in the Vue documentation](https://vuejs.org/guide/essentials/reactivity-fundamentals#caveat-when-unwrapping-in-templates). </warning> ## Typing Plugins If you return your helpers from the plugin, they will be typed automatically; you'll find them typed for the return of `useNuxtApp()` and within your templates. <note> If you need to use a provided helper *within* another plugin, you can call [`useNuxtApp()`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) to get the typed version. But in general, this should be avoided unless you are certain of the plugins' order. </note> For advanced use-cases, you can declare the type of injected properties like this: ```ts [index.d.ts] declare module '#app' { interface NuxtApp { $hello (msg: string): string } } declare module 'vue' { interface ComponentCustomProperties { $hello (msg: string): string } } export {} ``` ## Vue Plugins If you want to use Vue plugins, like [vue-gtag](https://github.com/MatteoGabriele/vue-gtag) to add Google Analytics tags, you can use a Nuxt plugin to do so. First, install the Vue plugin dependency: <code-group sync="pm"> ```bash [npm] npm install --save-dev vue-gtag-next ``` ```bash [yarn] yarn add --dev vue-gtag-next ``` ```bash [pnpm] pnpm add -D vue-gtag-next ``` ```bash [bun] bun add -D vue-gtag-next ``` ```bash [deno] deno add -D npm:vue-gtag-next ``` </code-group> Then create a plugin file: ```ts [app/plugins/vue-gtag.client.ts] import VueGtag, { trackRouter } from 'vue-gtag-next' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(VueGtag, { property: { id: 'GA_MEASUREMENT_ID', }, }) trackRouter(useRouter()) }) ``` ## Vue Directives Similarly, you can register a custom Vue directive in a plugin. ```ts [plugins/my-directive.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.directive('focus', { mounted (el) { el.focus() }, getSSRProps (binding, vnode) { // you can provide SSR-specific props here return {} }, }) }) ``` <warning> If you register a Vue directive, you *must* register it on both client and server side unless you are only using it when rendering one side. If the directive only makes sense from a client side, you can always move it to `~/plugins/my-directive.client.ts` and provide a 'stub' directive for the server in `~/plugins/my-directive.server.ts`. </warning> <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Custom Directives on Vue Docs" to="https://vuejs.org/guide/reusability/custom-directives.html"> </read-more> # utils > Use the utils/ directory to auto-import your utility functions throughout your application. The main purpose of the [`app/utils/` directory](https://nuxt.com/docs/5.x/directory-structure/app/utils) is to allow a semantic distinction between your Vue composables and other auto-imported utility functions. ## Usage **Method 1:** Using named export ```ts [utils/index.ts]twoslash export const { format: formatNumber } = Intl.NumberFormat('en-GB', { notation: 'compact', maximumFractionDigits: 1, }) ``` **Method 2:** Using default export ```ts [utils/random-entry.ts or utils/randomEntry.ts]twoslash // It will be available as randomEntry() (camelCase of file name without extension) export default function (arr: Array<any>) { return arr[Math.floor(Math.random() * arr.length)] } ``` You can now use auto imported utility functions in `.js`, `.ts` and `.vue` files ```vue [app/app.vue] <template> <p>{{ formatNumber(1234) }}</p> </template> ``` <read-more to="https://nuxt.com/docs/5.x/guide/concepts/auto-imports"> </read-more> <link-example to="https://nuxt.com/docs/5.x/examples/features/auto-imports"> </link-example> <tip> The way `app/utils/` auto-imports work and are scanned is identical to the [`app/composables/`](https://nuxt.com/docs/5.x/directory-structure/app/composables) directory. </tip> <important> These utils are only available within the Vue part of your app. <br /> Only `server/utils` are auto-imported in the [`server/`](https://nuxt.com/docs/5.x/directory-structure/server#server-utilities) directory. </important> <tip> Types can be auto-imported the same way. Put app-only types in `app/types/`, server-only types in [`server/types/`](https://nuxt.com/docs/5.x/directory-structure/server#server-types), and types shared between both in [`shared/types/`](https://nuxt.com/docs/5.x/directory-structure/shared). </tip> # content > Use the content/ directory to create a file-based CMS for your application. [Nuxt Content](https://content.nuxt.com) reads the `content/` directory in your project and parses `.md`, `.yml`, `.csv` and `.json` files to create a file-based CMS for your application. - Render your content with built-in components. - Query your content with a MongoDB-like API. - Use your Vue components in Markdown files with the MDC syntax. - Automatically generate your navigation. <read-more target="_blank" to="https://content.nuxt.com"> Learn more in **Nuxt Content** documentation. </read-more> ## Enable Nuxt Content Install the `@nuxt/content` module in your project as well as adding it to your `nuxt.config.ts` with one command: ```bash [Terminal] npx nuxt module add content ``` ## Create Content Place your markdown files inside the `content/` directory: ```md [content/index.md] # Hello Content ``` The module automatically loads and parses them. ## Render Content To render content pages, add a [catch-all route](https://nuxt.com/docs/5.x/directory-structure/app/pages/#catch-all-route) using the [`<ContentRenderer>`](https://content.nuxt.com/docs/components/content-renderer) component: ```vue [app/pages/[...slug].vue] <script lang="ts" setup> const route = useRoute() const { data: page } = await useAsyncData(route.path, () => { return queryCollection('content').path(route.path).first() }) </script> <template> <div> <header><!-- ... --></header> <ContentRenderer v-if="page" :value="page" /> <footer><!-- ... --></footer> </div> </template> ``` ## Documentation <tip icon="i-lucide-book"> Head over to [https://content.nuxt.com](https://content.nuxt.com) to learn more about the Content module features, such as how to build queries and use Vue components in your Markdown files with the MDC syntax. </tip> # .env > A .env file specifies your build/dev-time environment variables. <important> This file should be added to your [`.gitignore`](https://nuxt.com/docs/5.x/directory-structure/gitignore) file to avoid pushing secrets to your repository. </important> ## Dev, Build and Generate Time Nuxt CLI has built-in `.env` support via [c12](https://github.com/unjs/c12) in development mode and when running [`nuxt build`](https://nuxt.com/docs/5.x/api/commands/build) and [`nuxt generate`](https://nuxt.com/docs/5.x/api/commands/generate). In addition to any process environment variables, if you have a `.env` file in your project root directory, it will be automatically loaded **at dev, build and generate time**. Any environment variables set there will be accessible within your `nuxt.config` file and modules. ```ini [.env] MY_ENV_VARIABLE=hello ``` <note> Note that removing a variable from `.env` or removing the `.env` file entirely will not unset values that have already been set. </note> ## Custom File If you want to use a different file - for example, to use `.env.local` or `.env.production` - you can do so by passing the `--dotenv` flag when using the Nuxt CLI. ```bash [Terminal] npx nuxt dev --dotenv .env.local ``` When updating `.env` in development mode, the Nuxt instance is automatically restarted to apply new values to the `process.env`. <important> In your application code, you should use [Runtime Config](https://nuxt.com/docs/5.x/guide/going-further/runtime-config) instead of plain env variables. </important> ## Production **After your server is built**, you are responsible for setting environment variables when you run the server. Your `.env` files will not be read at this point. How you do this is different for every environment. This design decision was made to ensure compatibility across various deployment environments, some of which may not have a traditional file system available, such as serverless platforms or edge networks like Cloudflare Workers. Since `.env` files are not used in production, you must explicitly set environment variables using the tools and methods provided by your hosting environment. Here are some common approaches: - You can pass the environment variables as arguments using the terminal:<br /> `$ NODE_ENV=production DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs` - You can set environment variables in shell configuration files like `.bashrc` or `.profile`. - Many cloud service providers, such as Vercel, Netlify, and AWS, provide interfaces for setting environment variables via their dashboards, CLI tools or configuration files. <important> `runtimeConfig` <span> won't pick up environment variables that don't start with `NUXT_` in production </span> (/docs/5.x/guide/going-further/runtime-config#environment-variables). </important> ## Production Preview For local production preview purpose, we recommend using [`nuxt preview`](https://nuxt.com/docs/5.x/api/commands/preview) since using this command, the `.env` file will be loaded into `process.env` for convenience. Note that this command requires dependencies to be installed in the package directory. Or you could pass the environment variables as arguments using the terminal. For example, on Linux or macOS: ```bash [Terminal] NODE_ENV=production DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs ``` Note that for a purely static site, it is not possible to set runtime configuration config after your project is prerendered. <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> <note> If you want to use environment variables set at build time but do not care about updating these down the line (or only need to update them reactively *within* your app) then `appConfig` may be a better choice. You can define `appConfig` both within your `nuxt.config` (using environment variables) and also within an `~/app.config.ts` file in your project. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/app-config"> </read-more> </note> # .gitignore > A .gitignore file specifies intentionally untracked files that git should ignore. A `.gitignore` file specifies intentionally untracked files that git should ignore. <read-more icon="i-simple-icons-git" target="_blank" title="the git documentation" to="https://git-scm.com/docs/gitignore"> </read-more> We recommend having a `.gitignore` file that has **at least** the following entries present: ```bash [.gitignore] # Nuxt dev/build outputs .output .data .nuxt .nitro .cache dist # Node dependencies node_modules # Logs logs *.log # Misc .DS_Store # Local env files .env .env.* !.env.example ``` # layers > Use the layers/ directory to organize and auto-register local layers within your application. The `layers/` directory allows you to organize and share reusable code, components, composables, and configurations across your Nuxt application. Any layers within your project in the `layers/` directory will be automatically registered. <note> The `layers/` directory auto-registration is available in Nuxt v3.12.0+. </note> <tip icon="i-lucide-lightbulb"> Layers are ideal for organizing large codebases with **Domain-Driven Design (DDD)**, creating reusable **UI libraries** or **themes**, sharing **configuration presets** across projects, and separating concerns like **admin panels** or **feature modules**. </tip> ## Structure Each subdirectory within `layers/` is treated as a separate layer. A layer can contain the same structure as a standard Nuxt application. <important> Every layer **must have** a `nuxt.config.ts` file to be recognized as a valid layer, even if it's empty. </important> ```bash [Directory structure] -| layers/ ---| base/ -----| nuxt.config.ts -----| app/ -------| components/ ---------| BaseButton.vue -------| composables/ ---------| useBase.ts -----| server/ -------| api/ ---------| hello.ts ---| admin/ -----| nuxt.config.ts -----| app/ -------| pages/ ---------| admin.vue -------| layouts/ ---------| admin.vue ``` ## Automatic Aliases Named layer aliases to the `srcDir` of each layer are automatically created. You can access a layer using the `#layers/[name]` alias: ```ts // Access the base layer import something from '#layers/base/path/to/file' // Access the admin layer import { useAdmin } from '#layers/admin/composables/useAdmin' ``` <note> Named layer aliases were introduced in Nuxt v3.16.0. </note> ## Layer Content Each layer can include: - [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) - Layer-specific configuration that will be merged with the main config - [`app.config.ts`](https://nuxt.com/docs/5.x/directory-structure/app/app-config) - Reactive application configuration - [`app/components/`](https://nuxt.com/docs/5.x/directory-structure/app/components) - Vue components (auto-imported) - [`app/composables/`](https://nuxt.com/docs/5.x/directory-structure/app/composables) - Vue composables (auto-imported) - [`app/utils/`](https://nuxt.com/docs/5.x/directory-structure/app/utils) - Utility functions (auto-imported) - [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) - Application pages - [`app/layouts/`](https://nuxt.com/docs/5.x/directory-structure/app/layouts) - Application layouts - [`app/middleware/`](https://nuxt.com/docs/5.x/directory-structure/app/middleware) - Route middleware - [`app/plugins/`](https://nuxt.com/docs/5.x/directory-structure/app/plugins) - Nuxt plugins - [`server/`](https://nuxt.com/docs/5.x/directory-structure/server) - Server routes, middleware, and utilities - [`shared/`](https://nuxt.com/docs/5.x/directory-structure/shared) - Shared code between app and server ## Priority Order When multiple layers define the same resource (component, composable, page, etc.), the layer with **higher priority wins**. Layers are sorted alphabetically, with later letters having higher priority (Z > A). To control the order, prefix directories with numbers: `1.base/`, `2.features/`, `3.admin/`. Alternatively, reference the directories in [`extends`](https://nuxt.com/docs/5.x/api/nuxt-config#extends) (e.g. `extends: ['~~/layers/admin', '~~/layers/base']`) to order them from `nuxt.config` without renaming, with the first entry taking the highest priority. <read-more to="https://nuxt.com/docs/5.x/getting-started/layers#layer-priority"> </read-more> <video-accordion title="Watch a video from Learn Vue about Nuxt Layers" video-id="lnFCM7c9f7I"> </video-accordion> # modules > Use the modules/ directory to automatically register local modules within your application. It is a good place to place any local modules you develop while building your application. The auto-registered files patterns are: - `modules/*/index.ts` - `modules/*.ts` You don't need to add those local modules to your [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) separately. <code-group> ```ts [modules/hello/index.ts]twoslash // `nuxt/kit` is a helper subpath import you can use when defining local modules // that means you do not need to add `@nuxt/kit` to your project's dependencies import { addComponentsDir, addServerHandler, createResolver, defineNuxtModule } from 'nuxt/kit' export default defineNuxtModule({ meta: { name: 'hello', }, setup () { const resolver = createResolver(import.meta.url) // Add an API route addServerHandler({ route: '/api/hello', handler: resolver.resolve('./runtime/api-route'), }) // Add components addComponentsDir({ path: resolver.resolve('./runtime/app/components'), pathPrefix: true, // Prefix your exports to avoid conflicts with user code or other modules }) }, }) ``` ```ts [modules/hello/runtime/api-route.ts]twoslash import { defineEventHandler } from 'nuxt/server' export default defineEventHandler(() => { return { hello: 'world' } }) ``` </code-group> When starting Nuxt, the `hello` module will be registered and the `/api/hello` route will be available. <note> Note that all components, pages, composables and other files that would be normally placed in your `app/` directory need to be in `modules/your-module/runtime/app/`. This ensures they can be type-checked properly. </note> Modules are executed in the following sequence: - First, the modules defined in [`nuxt.config.ts`](https://nuxt.com/docs/5.x/api/nuxt-config#modules-1) are loaded. - Then, modules found in the `modules/` directory are executed, and they load in alphabetical order. You can change the order of local module by adding a number to the front of each directory name: ```bash [Directory structure] modules/ 1.first-module/ index.ts 2.second-module.ts ``` <read-more to="https://nuxt.com/docs/5.x/guide/modules"> </read-more> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/creating-your-first-module-from-scratch?friend=nuxt"> Watch Vue School video about Nuxt private modules. </tip> # node_modules > The package manager stores the dependencies of your project in the node_modules/ directory. The package manager ([`npm`](https://docs.npmjs.com/cli/commands/npm/) or [`yarn`](https://yarnpkg.com) or [`pnpm`](https://pnpm.io/cli/install) or [`bun`](https://bun.com/package-manager) or [`deno`](https://docs.deno.com/runtime/getting_started/installation/)) creates this directory to store the dependencies of your project. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/5.x/directory-structure/gitignore) file to avoid pushing the dependencies to your repository. </important> # .nuxt > Nuxt uses the .nuxt/ directory in development to generate your Vue application. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/5.x/directory-structure/gitignore) file to avoid pushing the dev build output to your repository. </important> This directory is interesting if you want to learn more about the files Nuxt generates based on your directory structure. Nuxt also provides a Virtual File System (VFS) for modules to add templates to this directory without writing them to disk. You can explore the generated files by opening the [Nuxt DevTools](https://devtools.nuxt.com) in development mode and navigating to the **Virtual Files** tab. <warning> You should not touch any files inside since the whole directory will be re-created when running [`nuxt dev`](https://nuxt.com/docs/5.x/api/commands/dev). </warning> # nuxt.config.ts > Nuxt can be easily configured with a single nuxt.config file. The `nuxt.config` file extension can either be `.js`, `.ts` or `.mjs`. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ // My Nuxt config }) ``` <tip> `defineNuxtConfig` helper is globally available without import. </tip> You can explicitly import `defineNuxtConfig` from `nuxt/config` if you prefer: ```ts [nuxt.config.ts]twoslash import { defineNuxtConfig } from 'nuxt/config' export default defineNuxtConfig({ // My Nuxt config }) ``` <read-more to="https://nuxt.com/docs/5.x/api/configuration/nuxt-config"> Discover all the available options in the **Nuxt configuration** documentation. </read-more> To ensure your configuration is up to date, Nuxt will make a full restart when detecting changes in the main configuration file, the [`.env`](https://nuxt.com/docs/5.x/directory-structure/env), [`.nuxtignore`](https://nuxt.com/docs/5.x/directory-structure/nuxtignore) and [`.nuxtrc`](https://nuxt.com/docs/5.x/directory-structure/nuxtrc) dotfiles. # .nuxtignore > The .nuxtignore file lets Nuxt ignore files in your projectโ€™s root directory during the build phase. The `.nuxtignore` file tells Nuxt to ignore files in your projectโ€™s root directory ([`rootDir`](https://nuxt.com/docs/5.x/api/nuxt-config#rootdir)) during the build phase. It is subject to the same specification as [`.gitignore`](https://nuxt.com/docs/5.x/directory-structure/gitignore) and `.eslintignore` files, in which each line is a glob pattern indicating which files should be ignored. <tip> You can also configure [`ignoreOptions`](https://nuxt.com/docs/5.x/api/nuxt-config#ignoreoptions), [`ignorePrefix`](https://nuxt.com/docs/5.x/api/nuxt-config#ignoreprefix) and [`ignore`](https://nuxt.com/docs/5.x/api/nuxt-config#ignore) in your `nuxt.config` file. </tip> ## Usage ```bash [.nuxtignore] # ignore layout foo.vue app/layouts/foo.vue # ignore layout files whose name ends with -ignore.vue app/layouts/*-ignore.vue # ignore page bar.vue app/pages/bar.vue # ignore page inside ignore folder app/pages/ignore/*.vue # ignore route middleware files under foo folder except foo/bar.js app/middleware/foo/*.js !app/middleware/foo/bar.js ``` <read-more icon="i-simple-icons-git" target="_blank" title="the git documentation" to="https://git-scm.com/docs/gitignore"> More details about the spec are in the **gitignore documentation**. </read-more> # .nuxtrc > The .nuxtrc file allows you to define nuxt configurations in a flat syntax. The `.nuxtrc` file can be used to configure Nuxt with a flat syntax. It is based on [`unjs/rc9`](https://github.com/unjs/rc9). <tip> For more advanced configurations, use [`nuxt.config`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config). </tip> ## Usage ```bash [.nuxtrc] # Disable SSR ssr=false # Configuration for `@nuxt/devtools` devtools.enabled=true # Add Nuxt modules modules[]=@nuxt/image modules[]=nuxt-security # Module setups (automatically added by Nuxt) setups.@nuxt/test-utils="3.23.0" ``` If present, the properties in the `nuxt.config` file will overwrite the properties in `.nuxtrc` file. <note> Nuxt automatically adds a `setups` section to track module installation and upgrade state. This is used internally for [module lifecycle hooks](https://nuxt.com/docs/5.x/api/kit/modules#using-lifecycle-hooks-for-module-installation-and-upgrade) and should not be modified manually. </note> <read-more to="https://nuxt.com/docs/5.x/api/configuration/nuxt-config"> Discover all the available options in the **Nuxt configuration** documentation. </read-more> ## Global `.nuxtrc` File You can also create a global `.nuxtrc` file in your home directory to apply configurations globally. - On macOS/Linux, this file is located at:```md ~/.nuxtrc ``` - On Windows, it is located at:```md C:\Users\{username}\.nuxtrc ``` This global `.nuxtrc` file allows you to define default settings that apply to all Nuxt projects on your system. However, project-level `.nuxtrc` files will override these global settings, and `nuxt.config` will take precedence over both. # .output > Nuxt creates the .output/ directory when building your application for production. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/5.x/directory-structure/gitignore) file to avoid pushing the build output to your repository. </important> Use this directory to deploy your Nuxt application to production. <read-more to="https://nuxt.com/docs/5.x/getting-started/deployment"> </read-more> <warning> You should not touch any files inside since the whole directory will be re-created when running [`nuxt build`](https://nuxt.com/docs/5.x/api/commands/build). </warning> # package.json > The package.json file contains all the dependencies and scripts for your application. The minimal `package.json` of your Nuxt application should looks like: ```json [package.json] { "name": "nuxt-app", "private": true, "type": "module", "scripts": { "build": "nuxt build", "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare" }, "dependencies": { "nuxt": "latest", "vue": "latest", "vue-router": "latest" } } ``` <read-more icon="i-simple-icons-npm" target="_blank" to="https://docs.npmjs.com/cli/configuring-npm/package-json/"> Read more about the `package.json` file. </read-more> # public > The public/ directory is used to serve your website's static assets. Files contained within the `public/` directory are served at the root and are not modified by the build process. This is suitable for files that have to keep their names (e.g. `robots.txt`) *or* likely won't change (e.g. `favicon.ico`). ```bash [Directory structure] -| public/ ---| favicon.ico ---| og-image.png ---| robots.txt ``` ```vue [app/app.vue] <script setup lang="ts"> useSeoMeta({ ogImage: '/og-image.png', }) </script> ``` <tip target="_blank" to="https://v2.nuxt.com/docs/directory-structure/static/"> This is known as the <span> `static/` </span> directory in Nuxt 2. </tip> # server > The server/ directory is used to register API and server handlers to your application. Nuxt automatically scans files inside these directories to register API and server handlers with Hot Module Replacement (HMR) support. ```bash [Directory Structure] -| server/ ---| api/ -----| hello.ts # /api/hello ---| routes/ -----| bonjour.ts # /bonjour ---| middleware/ -----| log.ts # log all requests ``` Each file should export a default function defined with `defineEventHandler()` or `eventHandler()` (alias). The handler can directly return JSON data, a `Promise`, or a `Response` object. <important> Do not import Vue app code (components, composables, or other app-only utilities) in your server routes or utilities, and do not import server-only code in your app. </important> <read-more to="https://nuxt.com/docs/5.x/directory-structure/shared#why-you-cannot-mix-vue-and-nitro-code" title="Why You Cannot Mix Vue and Nitro Code"> </read-more> ```ts [server/api/hello.ts]twoslash import { defineEventHandler } from 'nuxt/server' export default defineEventHandler((event) => { return { hello: 'world', } }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/server-imports"> `nuxt/server` is the import surface for server utilities, and what the server auto-imports resolve to. It is not tied to a particular h3 or Nitro version. </read-more> You can now universally call this API in your pages and components: ```vue [app/pages/index.vue] <script setup lang="ts"> const { data } = await useFetch('/api/hello') </script> <template> <pre>{{ data }}</pre> </template> ``` ## Server Routes Files inside the `~~/server/api` are automatically prefixed with `/api` in their route. <video-accordion platform="vimeo" title="Watch a video from Vue School on API routes" video-id="761468863"> </video-accordion> To add server routes without `/api` prefix, put them into `~~/server/routes` directory. **Example:** ```ts [server/routes/hello.ts] export default defineEventHandler(() => 'Hello World!') ``` Given the example above, the `/hello` route will be accessible at [http://localhost:3000/hello](http://localhost:3000/hello). <note> Note that currently server routes do not support the full functionality of dynamic routes as [pages](https://nuxt.com/docs/5.x/directory-structure/app/pages#dynamic-routes) do. </note> ## Server Middleware Nuxt will automatically read in any file in the `~~/server/middleware` to create server middleware for your project. Middleware handlers will run on every request before any other server route to add or check headers, log requests, or extend the event's request object. <note> Middleware handlers should not return anything (nor close or respond to the request) and only inspect or extend the request context or throw an error. </note> **Examples:** ```ts [server/middleware/log.ts] export default defineEventHandler((event) => { console.log('New request: ' + getRequestURL(event)) }) ``` ```ts [server/middleware/auth.ts] export default defineEventHandler((event) => { event.context.auth = { user: 123 } }) ``` ## Server Plugins Nuxt will automatically read any files in the `~~/server/plugins` directory and register them as Nitro plugins. This allows extending Nitro's runtime behavior and hooking into lifecycle events. **Example:** ```ts [server/plugins/nitroPlugin.ts] import { definePlugin } from 'nitro' export default definePlugin((nitroApp) => { console.log('Nitro plugin', nitroApp) }) ``` <read-more to="https://nitro.build/guide/plugins" target="_blank" title="Nitro Plugins"> </read-more> ## Server Utilities Server routes are powered by [h3js/h3](https://github.com/h3js/h3) which comes with a handy set of helpers. <read-more to="https://www.jsdocs.io/package/h3#package-index-functions" target="_blank" title="Available H3 Request Helpers"> </read-more> You can add more helpers yourself inside the `~~/server/utils` directory. For example, you can define a custom handler utility that wraps the original handler and performs additional operations before returning the final response. **Example:** ```ts [server/utils/handler.ts] export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> ( handler: EventHandler<T, D>, ): EventHandler<T, D> => defineEventHandler<T>(async (event) => { try { // do something before the route handler const response = await handler(event) // do something after the route handler return { response } } catch (err) { // Error handling return { err } } }) ``` ```ts [server/api/hello.get.ts] export default defineWrappedResponseHandler(event => 'hello world') ``` ## Server Alias <badge className="align-middle" color="info" size="xs">v4.3</badge> You can use the `#server` alias to import files from anywhere within the `server/` directory, regardless of the importing file's location. ```ts [server/api/users/[id]/profile.ts] // Instead of relative paths like this: // import { formatUser } from '../../../utils/formatUser' // Use the #server alias: import { formatUser } from '#server/utils/formatUser' ``` This alias ensures consistent imports across your server code, especially useful in deeply nested route handlers. <note> The `#server` alias can only be used within the `server/` directory. Importing from `#server` in client code will result in an error. </note> ## Server Types Auto-imports and other types are different for the `server/` directory, as it is running in a different context from the `app/` directory. By default, Nuxt 4 generates a [`tsconfig.json`](https://nuxt.com/docs/5.x/directory-structure/tsconfig) which includes a project reference covering the `server/` folder which ensures accurate typings. Types placed in `~~/server/types/` are auto-imported in the server context only, so you can reference them in server routes, middleware, plugins, and utilities without importing them. Types that are also needed in the Vue app belong in [`shared/types/`](https://nuxt.com/docs/5.x/directory-structure/shared) instead. ```ts [server/types/todo.ts]twoslash export interface Todo { id: string title: string completed: boolean } ``` ```ts [server/api/todos.get.ts] import { defineEventHandler } from 'nuxt/server' export default defineEventHandler((): Todo[] => { return [] }) ``` Only files directly in `server/types/` are scanned; files in nested subdirectories are not auto-imported, matching how [`shared/types/`](https://nuxt.com/docs/5.x/directory-structure/shared#how-files-are-scanned) works. ## Recipes ### Route Parameters Server routes can use dynamic parameters within brackets in the file name like `/api/hello/[name].ts` and be accessed via `event.context.params`. ```ts [server/api/hello/[name].ts] export default defineEventHandler((event) => { const name = getRouterParam(event, 'name') return `Hello, ${name}!` }) ``` <tip to="https://h3.dev/examples/validate-data#validate-params"> Alternatively, use `getValidatedRouterParams` with a schema validator such as Zod or Valibot for runtime and type safety. </tip> You can now universally call this API on `/api/hello/nuxt` and get `Hello, nuxt!`. ### Matching HTTP Method Handle file names can be suffixed with `.get`, `.post`, `.put`, `.delete`, ... to match request's [HTTP Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods). ```ts [server/api/test.get.ts] export default defineEventHandler(() => 'Test get handler') ``` ```ts [server/api/test.post.ts] export default defineEventHandler(() => 'Test post handler') ``` Given the example above, fetching `/test` with: - **GET** method: Returns `Test get handler` - **POST** method: Returns `Test post handler` - Any other method: Returns 405 error You can also use `index.[method].ts` inside a directory for structuring your code differently, this is useful to create API namespaces. <code-group> ```ts [server/api/foo/index.get.ts] export default defineEventHandler((event) => { // handle GET requests for the `api/foo` endpoint }) ``` ```ts [server/api/foo/index.post.ts] export default defineEventHandler((event) => { // handle POST requests for the `api/foo` endpoint }) ``` ```ts [server/api/foo/bar.get.ts] export default defineEventHandler((event) => { // handle GET requests for the `api/foo/bar` endpoint }) ``` </code-group> ### Catch-all Route Catch-all routes are helpful for fallback route handling. For example, creating a file named `~~/server/api/foo/[...].ts` will register a catch-all route for all requests that do not match any route handler, such as `/api/foo/bar/baz`. ```ts [server/api/foo/[...].ts] export default defineEventHandler((event) => { // event.context.path to get the route path: '/api/foo/bar/baz' // event.context.params._ to get the route segment: 'bar/baz' return `Default foo handler` }) ``` You can set a name for the catch-all route by using `~~/server/api/foo/[...slug].ts` and access it via `event.context.params.slug`. ```ts [server/api/foo/[...slug].ts] export default defineEventHandler((event) => { // event.context.params.slug to get the route segment: 'bar/baz' return `Default foo handler` }) ``` ### Body Handling ```ts [server/api/submit.post.ts] export default defineEventHandler(async (event) => { const body = await readBody(event) return { body } }) ``` <tip to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web/#runtime-type-safe-request-utils"> Alternatively, use `readValidatedBody` with a schema validator such as Zod or Valibot for runtime and type safety. </tip> You can now universally call this API using: ```vue [app/app.vue] <script setup lang="ts"> async function submit () { const { body } = await $fetch('/api/submit', { method: 'post', body: { test: 123 }, }) } </script> ``` <note> We are using `submit.post.ts` in the filename only to match requests with `POST` method that can accept the request body. When using `readBody` within a GET request, `readBody` will throw a `405 Method Not Allowed` HTTP error. </note> ### Query Parameters Sample query `/api/query?foo=bar&baz=qux` ```ts [server/api/query.get.ts] export default defineEventHandler((event) => { const query = getQuery(event) return { a: query.foo, b: query.baz } }) ``` <tip to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"> Alternatively, use `getValidatedQuery` with a schema validator such as Zod or Valibot for runtime and type safety. </tip> ### Error Handling If no errors are thrown, a status code of `200 OK` will be returned. Any uncaught errors will return a `500 Internal Server Error` HTTP Error. To return other error codes, throw an exception with [`createError`](https://nuxt.com/docs/5.x/api/utils/create-error): ```ts [server/api/validation/[id].ts] export default defineEventHandler((event) => { const id = Number.parseInt(event.context.params.id) as number if (!Number.isInteger(id)) { throw createError({ status: 400, statusText: 'ID should be an integer', }) } return 'All good' }) ``` ### Status Codes To return other status codes, use the [`setResponseStatus`](https://nuxt.com/docs/5.x/api/utils/set-response-status) utility. For example, to return `202 Accepted` ```ts [server/api/validation/[id].ts] export default defineEventHandler((event) => { setResponseStatus(event, 202) }) ``` ### Runtime Config <code-group> ```ts [server/api/foo.ts] export default defineEventHandler(async (event) => { const config = useRuntimeConfig() const repo = await $fetch('https://api.github.com/repos/nuxt/nuxt', { headers: { Authorization: `token ${config.githubToken}`, }, }) return repo }) ``` ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { githubToken: '', }, }) ``` ```ini [.env] NUXT_GITHUB_TOKEN='<my-super-token>' ``` </code-group> ### Request Cookies ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` ### Forwarding Context & Headers By default, neither the headers from the incoming request nor the request context are forwarded when making fetch requests in server routes. You can use `event.$fetch` to forward the request context and headers when making fetch requests in server routes. ```ts [server/api/forward.ts] export default defineEventHandler((event) => { return event.$fetch('/api/forwarded') }) ``` <note> Headers that are **not meant to be forwarded** will **not be included** in the request. These headers include, for example: `transfer-encoding`, `connection`, `keep-alive`, `upgrade`, `expect`, `host`, `accept` </note> ### Awaiting Promises After Response When handling server requests, you might need to perform asynchronous tasks that shouldn't block the response to the client (for example, caching and logging). You can use `event.waitUntil` to await a promise in the background without delaying the response. The `event.waitUntil` method accepts a promise that will be awaited before the handler terminates, ensuring the task is completed even if the server would otherwise terminate the handler right after the response is sent. This integrates with runtime providers to leverage their native capabilities for handling asynchronous operations after the response is sent. ```ts [server/api/background-task.ts] const timeConsumingBackgroundTask = async () => { await new Promise(resolve => setTimeout(resolve, 1000)) } export default eventHandler((event) => { // schedule a background task without blocking the response event.waitUntil(timeConsumingBackgroundTask()) // immediately send the response to the client return 'done' }) ``` ## Advanced Usage ### Nitro Config You can use `nitro` key in `nuxt.config` to directly set [Nitro configuration](https://nitro.build/config). <warning> This is an advanced option. Custom config can affect production deployments, as the configuration interface might change over time when Nitro is upgraded in semver-minor versions of Nuxt. </warning> ```ts [nuxt.config.ts] export default defineNuxtConfig({ // https://nitro.build/config nitro: {}, }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/concepts/server-engine"> </read-more> ### Nested Router ```ts [server/api/hello/[...slug].ts] import { createRouter, defineEventHandler, useBase } from 'h3' const router = createRouter() router.get('/test', defineEventHandler(() => 'Hello World')) export default useBase('/api/hello', router.handler) ``` ### Sending Streams <tip> This is an experimental feature and is available in all environments. </tip> ```ts [server/api/foo.get.ts] import fs from 'node:fs' import { sendStream } from 'h3' export default defineEventHandler((event) => { return sendStream(event, fs.createReadStream('/path/to/file')) }) ``` ### Sending Redirect ```ts [server/api/foo.get.ts] export default defineEventHandler(async (event) => { await sendRedirect(event, '/path/redirect/to', 302) }) ``` ### Legacy Handler or Middleware ```ts [server/api/legacy.ts] export default fromNodeMiddleware((req, res) => { res.end('Legacy handler') }) ``` <important> Legacy support is possible using [h3js/h3](https://github.com/h3js/h3), but it is advised to avoid legacy handlers as much as you can. </important> ```ts [server/middleware/legacy.ts] export default fromNodeMiddleware((req, res, next) => { console.log('Legacy middleware') next() }) ``` <warning> Never combine `next()` callback with a legacy middleware that is `async` or returns a `Promise`. </warning> ### Server Storage Nitro provides a cross-platform [storage layer](https://nitro.build/guide/storage). In order to configure additional storage mount points, you can use `nitro.storage`, or [server plugins](https://nuxt.com/docs/5.x/directory-structure/server#server-plugins). **Example of adding a Redis storage:** Using `nitro.storage`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { storage: { redis: { driver: 'redis', /* redis connector options */ port: 6379, // Redis port host: '127.0.0.1', // Redis host username: '', // needs Redis >= 6 password: '', db: 0, // Defaults to 0 tls: {}, // tls/ssl }, }, }, }) ``` Then in your API handler: ```ts [server/api/storage/test.ts] export default defineEventHandler(async (event) => { // List all keys with const keys = await useStorage('redis').getKeys() // Set a key with await useStorage('redis').setItem('foo', 'bar') // Remove a key with await useStorage('redis').removeItem('foo') return {} }) ``` <read-more to="https://nitro.build/guide/storage" target="_blank"> Read more about Nitro Storage Layer. </read-more> Alternatively, you can create a storage mount point using a server plugin and runtime config: <code-group> ```ts [server/plugins/storage.ts] import { definePlugin } from 'nitro' import redisDriver from 'unstorage/drivers/redis' export default definePlugin(() => { const storage = useStorage() // Dynamically pass in credentials from runtime configuration, or other sources const driver = redisDriver({ base: 'redis', host: useRuntimeConfig().redis.host, port: useRuntimeConfig().redis.port, /* other redis connector options */ }) // Mount driver storage.mount('redis', driver) }) ``` ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { redis: { // Default values host: '', port: 0, /* other redis connector options */ }, }, }) ``` </code-group> # shared > Use the shared/ directory to share functionality between the Vue app and the Nitro server. The `shared/` directory allows you to share code that can be used in both the Vue app and the Nitro server. <note> The `shared/` directory is available in Nuxt v3.14+. </note> <important> Code in the `shared/` directory cannot import any Vue or Nitro code. </important> ## Why You Cannot Mix Vue and Nitro Code Nuxt builds two separate bundles: the Vue app (client and server-side rendering) and the Nitro server (API routes, server middleware, server plugins). They are bundled independently and run in different contexts. Code in the `shared/` directory is used in both bundles, so it cannot import from either. ### Vue App Code in Nitro Components and composables need the Vue app runtime and often the Nuxt context (for example `useNuxtApp()` or `useRoute()`), neither of which exists in Nitro. Importing them into server code can cause build or runtime errors, and can pull the Vue app's dependencies into your server bundle. ### Nitro Code in the Vue App Server-only code (such as Node APIs, Nitro utilities, or server route handlers) must not run in the browser. Importing it into your app can break the client build, cause runtime errors in the browser, or leak server logic into the client bundle. ### Type-Only Imports `import type` is erased at compile time and does not pull runtime code into the other bundle, so importing only types across the boundary may appear to work. Even so, keep shared types (such as API response types) in `shared/types/`, where they are auto-imported in both contexts. This keeps the boundary clear, avoids accidentally turning a type import into a value import later, and matches Nuxt's separate [type contexts](https://nuxt.com/docs/5.x/guide/concepts/typescript#project-references) for app, server, and shared code. Types that are only used in one context can live next to that context instead: `app/types/` is auto-imported in the Vue app only, and [`server/types/`](https://nuxt.com/docs/5.x/directory-structure/server#server-types) is auto-imported in the Nitro server only. Use `shared/types/` when a type is needed in both. <video-accordion title="Watch a video from Vue School on sharing utils and types between app and server" video-id="nnAR-MO3q5M"> </video-accordion> ## Usage **Method 1:** Named export ```ts [shared/utils/capitalize.ts]twoslash export const capitalize = (input: string) => { return input[0] ? input[0].toUpperCase() + input.slice(1) : '' } ``` **Method 2:** Default export ```ts [shared/utils/capitalize.ts]twoslash export default function (input: string) { return input[0] ? input[0].toUpperCase() + input.slice(1) : '' } ``` You can now use [auto-imported](https://nuxt.com/docs/5.x/directory-structure/shared) utilities in your Nuxt app and `server/` directory. ```vue [app/app.vue] <script setup lang="ts"> const hello = capitalize('hello') </script> <template> <div> {{ hello }} </div> </template> ``` ```ts [server/api/hello.get.ts] export default defineEventHandler((event) => { return { hello: capitalize('hello'), } }) ``` ## How Files Are Scanned Only files in the `shared/utils/` and `shared/types/` directories will be auto-imported. Files nested within subdirectories of these directories will not be auto-imported unless you add these directories to `imports.dirs` and `nitro.imports.dirs`. <tip> The way `shared/utils` and `shared/types` auto-imports work and are scanned is identical to the [`app/composables/`](https://nuxt.com/docs/5.x/directory-structure/app/composables) and [`app/utils/`](https://nuxt.com/docs/5.x/directory-structure/app/utils) directories. </tip> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/composables#how-files-are-scanned"> </read-more> ```bash [Directory Structure] -| shared/ ---| capitalize.ts # Not auto-imported ---| formatters -----| lower.ts # Not auto-imported ---| utils/ -----| lower.ts # Auto-imported -----| formatters -------| upper.ts # Not auto-imported ---| types/ -----| bar.ts # Auto-imported ``` Any other files you create in the `shared/` folder must be manually imported using the `#shared` alias (automatically configured by Nuxt): ```ts [Importing From #shared] // For files directly in the shared directory import capitalize from '#shared/capitalize' // For files in nested directories import lower from '#shared/formatters/lower' // For files nested in a folder within utils import upper from '#shared/utils/formatters/upper' ``` This alias ensures consistent imports across your application, regardless of the importing file's location. <read-more to="https://nuxt.com/docs/5.x/guide/concepts/auto-imports"> </read-more> # test > Use the test/ directory to organize unit, Nuxt, and end-to-end tests for your application. The `test/` directory is the recommended place for your application tests. Nuxt does not scan it the way it does `app/` or `server/`; you choose the runner and layout yourself (typically with [`@nuxt/test-utils`](https://nuxt.com/docs/5.x/getting-started/testing)). A common layout separates environments: ```bash [Directory structure] -| test/ ---| e2e/ ---| nuxt/ ---| unit/ ``` - `test/unit/` โ€” fast Node tests without the Nuxt runtime - `test/nuxt/` โ€” tests that need the Nuxt runtime environment - `test/e2e/` โ€” end-to-end tests against a running app <read-more to="https://nuxt.com/docs/5.x/getting-started/testing#organizing-your-tests"> See **Organizing Your Tests** for setup, Vitest projects, and TypeScript context. </read-more> # tsconfig.json > Learn how Nuxt manages TypeScript configuration across different parts of your project. Nuxt [automatically generates](https://nuxt.com/docs/5.x/guide/concepts/typescript#auto-generated-types) multiple TypeScript configuration files (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, `.nuxt/tsconfig.node.json` and `.nuxt/tsconfig.shared.json`) that include recommended basic TypeScript configuration for your project, references to [auto-imports](https://nuxt.com/docs/5.x/guide/concepts/auto-imports), [API route types](https://nuxt.com/docs/5.x/guide/concepts/server-engine#typed-api-routes), path aliases, and more. Your Nuxt project should include the following `tsconfig.json` file at the root of the project: ```json [tsconfig.json] { "files": [], "references": [ { "path": "./.nuxt/tsconfig.app.json" }, { "path": "./.nuxt/tsconfig.server.json" }, { "path": "./.nuxt/tsconfig.shared.json" }, { "path": "./.nuxt/tsconfig.node.json" } ] } ``` <warning> We do not recommend modifying the contents of this file directly, as doing so could overwrite important settings that Nuxt or other modules rely on. Instead, extend it via `nuxt.config.ts`. </warning> <read-more to="https://nuxt.com/docs/5.x/guide/concepts/typescript#project-references"> Read more about the different type contexts of a Nuxt project here. </read-more> ## Extending TypeScript Configuration You can customize the TypeScript configuration of your Nuxt project in the `nuxt.config.ts` file: set shared `compilerOptions` for every context at once with `typescript.tsConfig`, and override them for each context (`app`, `shared`, `node`, and `server`) individually. ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ typescript: { // shared compiler options for every generated tsconfig tsConfig: { compilerOptions: { // ... }, }, // customize tsconfig.app.json appTsConfig: { // ... }, // customize tsconfig.shared.json sharedTsConfig: { // ... }, // customize tsconfig.node.json nodeTsConfig: { // ... }, // customize tsconfig.server.json serverTsConfig: { // ... }, }, }) ``` <note> Most `compilerOptions` set in `typescript.tsConfig` are shared with every context, but a few are not. DOM- and Vue-specific options (such as `lib`, `jsx` and `jsxImportSource`) only make sense for your application code, so they are applied to `tsconfig.app.json` alone. Nuxt also manages `types`, `paths` and `noEmit` per context (the `node`, `shared` and `server` configs deliberately emit nothing and scan no ambient types), so setting these in `typescript.tsConfig` will not change them. Use the matching per-context option (`appTsConfig`, `nodeTsConfig`, `sharedTsConfig` or `serverTsConfig`) when you need to override them. </note> <note> `typescript.serverTsConfig` and `nitro.typescript.tsConfig` both extend `tsconfig.server.json` and are kept in sync, so setting either has the same effect. Prefer `typescript.serverTsConfig` to keep all four contexts in one place. </note> # B5001 No `compatibilityDate` is set in your Nuxt configuration. Nuxt uses this date to decide which behaviour defaults to apply, so your project stays stable across Nuxt and Nitro updates instead of silently picking up new defaults. ## Resolution Add `compatibilityDate` to your `nuxt.config`, using today's date so you opt in to the current defaults: ```ts export default defineNuxtConfig({ // use the current date, e.g. the day you add this line compatibilityDate: 'YYYY-MM-DD', }) ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/upgrade"> </read-more> # B5003 You have custom keys under `runtimeConfig.app`, a namespace Nuxt reserves for internal values (such as `baseURL` and `cdnURL`). Custom keys here can collide with Nuxt's own config. ## Resolution Move custom keys to `runtimeConfig.public` (exposed to the client) or to a top-level custom namespace (server-only): ```ts export default defineNuxtConfig({ runtimeConfig: { // instead of runtimeConfig.app.myKey public: { myKey: 'value', }, }, }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> # B5004 Nuxt found a standalone `vite.config` or `webpack.config` file next to your `nuxt.config`. Nuxt manages the bundler internally and ignores these files, so they are usually leftovers from a migration or a copied non-Nuxt project. ## Resolution Move the configuration into `nuxt.config` under the matching key, then delete the external file: - `vite.config`: use the `vite` key - `webpack.config`: use the `webpack` key - `nitro.config`: use the `nitro` key - `postcss.config`: use the `postcss` key ```ts export default defineNuxtConfig({ vite: { // your Vite config here }, }) ``` <read-more to="https://nuxt.com/docs/5.x/getting-started/configuration"> </read-more> # E1001 A composable that needs the Nuxt instance (`useNuxtApp()`, `useRoute()`, `useFetch()`, โ€ฆ) ran outside a plugin, Nuxt hook, route middleware, or Vue `setup()`. The most common trigger is calling it inside an async callback (`setTimeout`, `.then()`, after an `await`) where the context has been lost. ## Resolution Call the composable synchronously at the top of `setup()` / a plugin / middleware and reuse the captured result later. For server-side async work, wrap the call with `nuxtApp.runWithContext()`. <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> # E1006 `onPrehydrate()` ran without being transformed by the Nuxt build pipeline. It needs compile-time processing and only works on the server, so this happens when it is called from a dependency that Nuxt does not transpile. ## Resolution Add the offending library to `build.transpile` in `nuxt.config.ts` so the build pipeline can process its `onPrehydrate()` call. <read-more to="https://nuxt.com/docs/5.x/api/composables/on-prehydrate"> </read-more> # E1007 A compile-time macro such as `definePageMeta()` executed at runtime. These helpers are transformed away by the Nuxt build and must never run dynamically. Usually this means the macro was called inside a composable or a non-page component instead of directly in a page. ## Resolution Call the macro only at the top level of a page component's `<script setup>`. It cannot be used inside composables, conditionals, or non-page components. <read-more to="https://nuxt.com/docs/5.x/api/utils/define-page-meta"> </read-more> # E2001 `navigateTo()` received an external URL but no `{ external: true }` option. Nuxt requires explicit opt-in for external navigation to avoid accidentally redirecting users away from your app. ## Resolution ```ts navigateTo('https://example.com', { external: true }) ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/navigate-to"> </read-more> # E2002 `navigateTo()` was given a URL using a dangerous protocol (`javascript:`, `data:`, `vbscript:`). Nuxt blocks these to prevent XSS. This almost always means unsanitized user input reached `navigateTo()`. ## Resolution Validate and sanitize user-provided URLs before navigating. Allow only `http:`, `https:`, or relative paths. <read-more to="https://nuxt.com/docs/5.x/api/utils/navigate-to"> </read-more> # E2003 `abortNavigation()` was called outside a route middleware. It can only cancel navigation from within a middleware handler, so calling it from a component, plugin, composable, or a callback that lost the middleware context fails. ## Resolution Move the `abortNavigation()` call into the body of a `defineNuxtRouteMiddleware()` handler. <read-more to="https://nuxt.com/docs/5.x/api/utils/abort-navigation"> </read-more> # E2004 A route middleware was referenced (usually via `definePageMeta({ middleware: [...] })`) but no middleware with that name exists. Common causes are a typo in the name, or a middleware file that was renamed or deleted without updating its references. ## Resolution Make sure the name matches a file in `middleware/`. Names are derived from the filename: `middleware/auth.ts` is referenced as `auth`. <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/middleware"> </read-more> # E2005 `useRoute()` was called inside a route middleware (directly or via another composable). At that point the target route is not yet resolved, so `useRoute()` can return unexpected values; middleware receives the `to` and `from` routes as arguments instead. ## Resolution ```ts export default defineNuxtRouteMiddleware((to, from) => { // use `to` / `from` instead of useRoute() }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/middleware"> </read-more> # E2007 `setPageLayout()` was called from a component's `setup()` during SSR. On the server the layout must be decided before the component renders, so changing it here produces incorrect SSR output. ## Resolution Set the layout from route middleware, or statically with `definePageMeta({ layout: '...' })`. <read-more to="https://nuxt.com/docs/5.x/api/utils/set-page-layout"> </read-more> # E3001 The URL passed to `useFetch()` starts with `//`. A protocol-relative URL like this resolves to an external host, which is almost never intended and is rejected to avoid leaking requests to a different origin. ## Resolution Use an absolute URL with an explicit protocol, or a relative path: ```ts useFetch('/api/data') useFetch('https://api.example.com/data') ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-fetch"> </read-more> # E3008 `useAsyncData()` was called without a valid key. The first argument must be a non-empty string so Nuxt can cache and deduplicate the request across components. ## Resolution ```ts const { data } = useAsyncData('users', () => $fetch('/api/users')) ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-async-data"> </read-more> # E3009 `useAsyncData()` was called without a handler function. The handler is the function that performs the fetch and returns the data, so it cannot be omitted or of another type. ## Resolution ```ts const { data } = useAsyncData('users', () => $fetch('/api/users')) ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-async-data"> </read-more> # E4012 Nuxt could not parse the response returned when rendering a server component (island). This usually means the server component endpoint returned something other than the expected island payload, such as an error page or malformed HTML. ## Resolution Check the server component for errors that would prevent it from rendering, and confirm the island endpoint returns a valid response. Inspect the network response for the island request to see what the server actually returned. <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/components#server-components"> </read-more> # E4016 The current route matches a nested page, but the parent page component does not render `<NuxtPage />`. Vue Router can only display a child page inside its parent's `<NuxtPage />` outlet, so the child page is never shown. This happens with a directory structure like the following, when `parent.vue` does not contain `<NuxtPage />`: ```bash [Directory Structure] -| pages/ ---| parent/ ------| child.vue ---| parent.vue ``` ## Resolution Add `<NuxtPage />` to the parent page component so the child route can render inside it. If you did not intend to create a nested route, restructure your `pages/` directory so the page no longer has child routes. <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/pages#nested-routes"> </read-more> # E5001 Code that relies on the app manifest ran while `experimental.appManifest` is disabled. The manifest powers features such as route rules matching and prerendered-payload detection on the client, so it must be enabled for them to work. ## Resolution Enable the app manifest in your `nuxt.config`: ```ts export default defineNuxtConfig({ experimental: { appManifest: true, }, }) ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#appmanifest"> </read-more> # E6001 A head composable such as `useHead()` was called without an active Unhead instance. This happens when it runs outside a valid Nuxt context, for example in a detached async callback after the Nuxt instance is no longer available. ## Resolution Call head composables synchronously inside a component `setup()`, a Nuxt plugin, or route middleware. If you need them after an `await`, capture the Nuxt context first: ```ts const nuxtApp = useNuxtApp() await someAsyncWork() nuxtApp.runWithContext(() => useHead({ title: 'Late title' })) ``` # E7001 A payload URL was requested with a full URL that includes a hostname. Payloads are always served from the same origin as the app, so a URL with a hostname points outside the app and is rejected. ## Resolution Pass a relative path instead of a full URL: ```ts loadPayload('/some-page') ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#payload"> </read-more> # E7007 `useState()` received a non-function initial value. The initializer must be a function so that it only runs once, on the server, and its result can be serialized into the payload for hydration. ## Resolution ```ts const counter = useState('counter', () => 0) ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-state"> </read-more> # E7008 `callOnce()` received a non-function `fn` argument. The value to run once must be a function so Nuxt can execute it a single time and skip it on subsequent calls. ## Resolution ```ts await callOnce('setup', () => { // runs once }) ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/call-once"> </read-more> # E7009 `useState()` was called with a key that is not a string. The key identifies the shared state across the app and in the hydration payload, so it must be a non-empty string. ## Resolution ```ts const counter = useState('counter', () => 0) ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-state"> </read-more> # E7010 `callOnce()` was called with a key that is not a string. The key is used to track whether the function has already run, so it must be a non-empty string. ## Resolution ```ts await callOnce('setup', () => { // runs once }) ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/call-once"> </read-more> # E8007 With `features.noScripts: 'production'` (the default when `noScripts` is enabled), scripts are only stripped from rendered HTML in production builds. In development the page still ships JavaScript, so behaviour that depends on it (lazy hydration strategies, `nuxt-client` components inside server components) appears to work in dev and then silently breaks after deployment. This warning is emitted during development when a rendered route uses one of these features. ## Resolution Either remove the client-side dependency from the affected route, or scope script stripping to the routes that are genuinely static using the `noScripts` route rule (which applies in development too, so any breakage is visible immediately): ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/static/**': { noScripts: true }, }, }) ``` Alternatively, set `features.noScripts: 'all'` to strip scripts in development as well, making the production behaviour observable in dev. <read-more to="https://nuxt.com/docs/5.x/guide/going-further/features#noscripts"> </read-more> # Layers > This example shows how to use the extends key in `nuxt.config.ts`. <code-explorer default-value="nuxt.config.ts" path="examples/advanced/config-extends"> </code-explorer> <browser src="https://config-extends.example.nuxt.space"> </browser> This example shows how to use the `extends` key in `nuxt.config.ts` to use the `base/` directory as a base Nuxt application, and use its components, composables or config and override them if necessary. <read-more to="https://nuxt.com/docs/5.x/getting-started/layers"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/config-extends) # Error Handling > This example shows how to handle errors in different contexts: pages, plugins, components and middleware. <code-explorer default-value="error.vue" path="examples/advanced/error-handling"> </code-explorer> <browser src="https://error-handling.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/error-handling) # JSX / TSX > This example shows how to use JSX syntax with typescript in Nuxt pages and components. <code-explorer default-value="app.vue" path="examples/advanced/jsx"> </code-explorer> <browser src="https://jsx.example.nuxt.space"> </browser> <read-more icon="i-simple-icons-vuedotjs" target="_blank" to="https://vuejs.org/guide/extras/render-function.html#jsx-tsx"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/jsx) # Locale > This example shows how to define a locale composable to handle the application's locale, both server and client side. <code-explorer default-value="composables/locale.ts" path="examples/advanced/locale"> </code-explorer> <browser src="https://locale.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/locale) # Module Extend Pages > This example defines a new `test` page using `extendPages` within a module. <code-explorer default-value="modules/pages/index.ts" path="examples/advanced/module-extend-pages"> </code-explorer> <browser src="https://module-extend-pages.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/guide/modules"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/module-extend-pages) # Teleport > This example shows how to use the <Teleport> with client-side and server-side rendering. <code-explorer default-value="app.vue" path="examples/advanced/teleport"> </code-explorer> <browser src="https://teleport.example.nuxt.space"> </browser> Vue 3 provides the [`<Teleport>` component](https://vuejs.org/guide/built-ins/teleport.html) which allows content to be rendered elsewhere in the DOM, outside of the Vue application. This example shows how to use the `<Teleport>` with client-side and server-side rendering. <read-more to="https://nuxt.com/docs/5.x/api/components/teleports"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/teleport) # Testing > This example shows how to test your Nuxt application. <code-explorer default-value="tests/basic.test.ts" path="examples/advanced/testing"> </code-explorer> <browser src="https://testing.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/testing"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/testing) # useCookie > This example shows how to use the useCookie API to persist small amounts of data that both client and server can use. <code-explorer default-value="app.vue" path="examples/advanced/use-cookie"> </code-explorer> <browser src="https://use-cookie.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-cookie"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/use-cookie) # Use Custom Fetch Composable > This example shows a convenient wrapper for the useFetch composable from nuxt. It allows you to customize the fetch request with default values and user authentication token. <code-explorer default-value="plugins/customFetch.ts" path="examples/advanced/use-custom-fetch-composable"> </code-explorer> <browser src="https://use-custom-fetch-composable.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/use-custom-fetch-composable) # WASM > This example demonstrates the server-side support of WebAssembly in Nuxt. <code-explorer default-value="app.vue" path="examples/experimental/wasm"> </code-explorer> <browser src="https://wasm.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/experimental/wasm) # Auto Imports > This example demonstrates the auto-imports feature in Nuxt. <code-explorer default-value="app.vue" path="examples/features/auto-imports"> </code-explorer> <browser src="https://auto-imports.example.nuxt.space"> </browser> Example of the auto-imports feature in Nuxt with: - Vue components in the `components/` directory are auto-imported and can be used directly in your templates. - Vue composables in the `composables/` directory are auto-imported and can be used directly in your templates and JS/TS files. - JS/TS variables and functions in the `utils/` directory are auto-imported and can be used directly in your templates and JS/TS files. <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/components"> </read-more> <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/composables"> </read-more> <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/utils"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/auto-imports) # Data Fetching > This example demonstrates data fetching with Nuxt using built-in composables and API routes. <code-explorer default-value="pages/index.vue" path="examples/features/data-fetching"> </code-explorer> <browser src="https://data-fetching.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/data-fetching"> </read-more> <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/server"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/data-fetching) # Layouts > This example shows how to define default and custom layouts. <code-explorer default-value="pages/index.vue" path="examples/features/layouts"> </code-explorer> <browser src="https://layouts.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/views#layouts"> </read-more> <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/layouts"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/layouts) # Meta Tags > This example shows how to use the Nuxt helpers and composables for SEO and meta management. <code-explorer default-value="pages/index.vue" path="examples/features/meta-tags"> </code-explorer> <browser src="https://meta-tags.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/meta-tags) # State Management > This example shows how to use the `useState` composable to create a reactive and SSR-friendly shared state across components. <code-explorer default-value="app.vue" path="examples/features/state-management"> </code-explorer> <browser src="https://state-management.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/state-management"> </read-more> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-state"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/state-management) # Hello World > A minimal Nuxt application only requires the `app.vue` and `nuxt.config.js` files. <code-explorer default-value="app.vue" path="examples/hello-world"> </code-explorer> <browser src="https://hello-world.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/getting-started/introduction"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/hello-world) # Middleware > This example shows how to add route middleware with the middleware/ directory or with a plugin, and how to use them globally or per page. <code-explorer default-value="middleware/redirect-me.ts" path="examples/routing/middleware"> </code-explorer> <browser src="https://middleware.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/middleware"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/middleware) # Pages > This example shows how to use the pages/ directory to create application routes. <code-explorer default-value="pages/index.vue" path="examples/routing/pages"> </code-explorer> <browser src="https://pages.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/5.x/guide/directory-structure/pages"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/pages) # Universal Router > This example demonstrates Nuxt universal routing utilities without depending on `pages/` and `vue-router`. <code-explorer default-value="plugins/add.ts" path="examples/routing/universal-router"> </code-explorer> <browser src="https://universal-router.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/universal-router) # Assets > Nuxt offers two options for your assets. Nuxt uses two directories to handle assets like stylesheets, fonts or images. - The [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory content is served at the server root as-is. - The [`app/assets/`](https://nuxt.com/docs/5.x/directory-structure/app/assets) directory contains by convention every asset that you want the build tool (Vite or webpack) to process. ## Public Directory The [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory is used as a public server for static assets publicly available at a defined URL of your application. You can get a file in the [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory from your application's code or from a browser by the root URL `/`. ### Example For example, referencing an image file in the `public/img/` directory, available at the static URL `/img/nuxt.png`: ```vue [app/app.vue] <template> <img src="/img/nuxt.png" alt="Discover Nuxt" > </template> ``` ## Assets Directory Nuxt uses [Vite](https://vite.dev/guide/assets) (default) or [webpack](https://webpack.js.org/guides/asset-management/) to build and bundle your application. The main function of these build tools is to process JavaScript files, but they can be extended through [plugins](https://vite.dev/plugins/) (for Vite) or [loaders](https://webpack.js.org/loaders/) (for webpack) to process other kinds of assets, like stylesheets, fonts or SVGs. This step transforms the original file, mainly for performance or caching purposes (such as stylesheet minification or browser cache invalidation). By convention, Nuxt uses the [`app/assets/`](https://nuxt.com/docs/5.x/directory-structure/app/assets) directory to store these files but there is no auto-scan functionality for this directory, and you can use any other name for it. In your application's code, you can reference a file located in the [`app/assets/`](https://nuxt.com/docs/5.x/directory-structure/app/assets) directory by using the `~/assets/` path. ### Example For example, referencing an image file that will be processed if a build tool is configured to handle this file extension: ```vue [app/app.vue] <template> <img src="~/assets/img/nuxt.png" alt="Discover Nuxt" > </template> ``` <note> Nuxt won't serve files in the [`app/assets/`](https://nuxt.com/docs/5.x/directory-structure/app/assets) directory at a static URL like `/assets/my-file.png`. If you need a static URL, use the [`public/`](https://nuxt.com/docs/5.x/getting-started/assets#public-directory) directory. </note> ### Static vs. Dynamic `src` When an `src` is a static string literal in your template, the build tool rewrites it into a runtime helper that resolves the final URL. A public path such as `/img/nuxt.png` is wrapped so that your [`app.baseURL`](https://nuxt.com/docs/5.x/api/nuxt-config#baseurl) is applied when the page renders, and a bundled path such as `~/assets/img/nuxt.png` additionally becomes an import that resolves to the hashed output file. ```vue <template> <!-- Static paths are rewritten: app.baseURL is applied at runtime, and the bundled file is hashed. --> <img src="/img/nuxt.png"> <img src="~/assets/img/nuxt.png"> </template> ``` Because `app.baseURL` is applied at runtime, a static public path works even when the base URL is only known at deploy time (for example set via `NUXT_APP_BASE_URL`), and it works whether or not the file is processed by the build. This resolution only happens for literal paths the build tool can see. A bound `:src` whose value is assembled at runtime is opaque to the build tool, so none of that rewriting happens. The string is used exactly as written: ```vue <template> <!-- This does not work: the path is built at runtime, so Vite never sees it as an import. --> <img :src="`~/assets/img/${name}.png`"> </template> ``` A runtime-built public path like `/img/${name}.png` is therefore **not** prefixed with [`app.baseURL`](https://nuxt.com/docs/5.x/api/nuxt-config#baseurl). If your application is deployed below the origin root, prefix it yourself with [`useRuntimeConfig().app.baseURL`](https://nuxt.com/docs/5.x/api/composables/use-runtime-config) (for example via [`joinURL`](https://github.com/unjs/ufo#joinurl)). The sections below cover how to handle each case when the path is only known at runtime. #### Public Assets If the files do not need to be processed or hashed, put them in the [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory and reference them by URL: ```vue [app/app.vue] <script setup lang="ts"> const props = defineProps<{ name: string }>() const imageUrl = computed(() => `/img/${props.name}.png`) </script> <template> <img :src="imageUrl" :alt="props.name" > </template> ``` Files in `public/` keep their original filenames. #### Bundled Assets with Vite The approaches below are specific to Vite, Nuxt's default builder. When the possible files are known, list their imports explicitly: ```vue [app/app.vue] <script setup lang="ts"> const props = defineProps<{ theme: 'light' | 'dark' }>() const logos = { light: () => import('./assets/img/logo-light.png?url'), dark: () => import('./assets/img/logo-dark.png?url'), } const logoUrl = (await logos[props.theme]()).default </script> <template> <img :src="logoUrl" alt="Nuxt" > </template> ``` Each import has a literal path, so Vite can find both files at build time while loading only the selected module at runtime. When many files share a directory and extension, use a [variable dynamic import](https://vite.dev/guide/features.html#dynamic-import) instead of listing every file: ```ts async function getImageUrl (name: string) { const image = await import(`./assets/img/${name}.png?url`) return image.default } ``` Only the filename can be dynamic in this example. Keeping the directory and extension in the import lets Vite find the possible files at build time. For a broader pattern or an explicit map of available files, use [`import.meta.glob`](https://vite.dev/guide/features.html#glob-import): ```ts const images = import.meta.glob<string>('./assets/img/*.{png,jpg,svg}', { query: '?url', import: 'default', }) async function getImageUrl (name: string) { const load = images[`./assets/img/${name}.png`] if (!load) { throw new Error(`Unknown image: ${name}`) } return await load() } ``` Glob imports are lazy by default. Add `eager: true` if the URLs must be available synchronously: ```ts const images = import.meta.glob<string>('./assets/img/*.{png,jpg,svg}', { query: '?url', import: 'default', eager: true, }) ``` Every matching asset is still included in the build output. Lazy imports load each match on demand, while an eager glob loads all matches up front and can increase the initial JavaScript size or inline small assets. <warning> Await a lazy import before using its URL in server-rendered markup. Vite's [`new URL(..., import.meta.url)` pattern](https://vite.dev/guide/assets.html#new-url-url-import-meta-url) does not work with SSR. </warning> # Configuration > Nuxt is configured with sensible defaults to make you productive. By default, Nuxt is configured to cover most use cases. The [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file can override or extend this default configuration. ## Nuxt Configuration The [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file is located at the root of a Nuxt project and can override or extend the application's behavior. A minimal configuration file exports the `defineNuxtConfig` function containing an object with your configuration. The `defineNuxtConfig` helper is globally available without import. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ // My Nuxt config }) ``` This file will often be mentioned in the documentation, for example to add custom scripts, register modules or change rendering modes. <read-more to="https://nuxt.com/docs/5.x/api/configuration/nuxt-config"> Every option is described in the **Configuration Reference**. </read-more> <note> You don't have to use TypeScript to build an application with Nuxt. However, it is strongly recommended to use the `.ts` extension for the `nuxt.config` file. This way you can benefit from hints in your IDE to avoid typos and mistakes while editing your configuration. </note> ### Environment Overrides You can configure fully typed, per-environment overrides in your nuxt.config ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ $production: { routeRules: { '/**': { isr: true }, }, }, $development: { // }, $env: { staging: { // }, }, }) ``` To select an environment when running a Nuxt CLI command, simply pass the name to the `--envName` flag, like so: `nuxt build --envName staging`. To learn more about the mechanism behind these overrides, please refer to the `c12` documentation on [environment-specific configuration](https://github.com/unjs/c12?tab=readme-ov-file#environment-specific-configuration). <video-accordion title="Watch a video from Alexander Lichter about the env-aware nuxt.config.ts" video-id="DFZI2iVCrNc"> </video-accordion> <note> If you're authoring layers, you can also use the `$meta` key to provide metadata that you or the consumers of your layer might use. </note> ### Environment Variables and Private Tokens The `runtimeConfig` API exposes values like environment variables to the rest of your application. By default, these keys are only available server-side. The keys within `runtimeConfig.public` and `runtimeConfig.app` (which is used by Nuxt internally) are also available client-side. Those values should be defined in `nuxt.config` and can be overridden using environment variables. <code-group> ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ runtimeConfig: { // The private keys which are only available server-side apiSecret: '123', // Keys within public are also exposed client-side public: { apiBase: '/api', }, }, }) ``` ```ini [.env] # This will override the value of apiSecret NUXT_API_SECRET=api_secret_token ``` </code-group> These variables are exposed to the rest of your application using the [`useRuntimeConfig()`](https://nuxt.com/docs/5.x/api/composables/use-runtime-config) composable. ```vue [app/pages/index.vue] <script setup lang="ts"> const runtimeConfig = useRuntimeConfig() </script> ``` <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> ## App Configuration The `app.config.ts` file, located in the source directory (by default `app/`), is used to expose public variables that can be determined at build time. Contrary to the `runtimeConfig` option, these cannot be overridden using environment variables. A minimal configuration file exports the `defineAppConfig` function containing an object with your configuration. The `defineAppConfig` helper is globally available without import. ```ts [app/app.config.ts] export default defineAppConfig({ title: 'Hello Nuxt', theme: { dark: true, colors: { primary: '#ff0000', }, }, }) ``` These variables are exposed to the rest of your application using the [`useAppConfig`](https://nuxt.com/docs/5.x/api/composables/use-app-config) composable. ```vue [app/pages/index.vue] <script setup lang="ts"> const appConfig = useAppConfig() </script> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/app-config"> </read-more> ## `runtimeConfig` vs. `app.config` As stated above, `runtimeConfig` and `app.config` are both used to expose variables to the rest of your application. To determine whether you should use one or the other, here are some guidelines: - `runtimeConfig`: Private or public tokens that need to be specified after build using environment variables. - `app.config`: Public tokens that are determined at build time, website configuration such as theme variant, title and any project config that are not sensitive. <table> <thead> <tr> <th> Feature </th> <th> <code> runtimeConfig </code> </th> <th> <code> app.config </code> </th> </tr> </thead> <tbody> <tr> <td> Client-side </td> <td> Hydrated </td> <td> Bundled </td> </tr> <tr> <td> Environment variables </td> <td> โœ… Yes </td> <td> โŒ No </td> </tr> <tr> <td> Reactive </td> <td> โœ… Yes </td> <td> โœ… Yes </td> </tr> <tr> <td> Types support </td> <td> โœ… Partial </td> <td> โœ… Yes </td> </tr> <tr> <td> Configuration per request </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> <tr> <td> Hot module replacement </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> <tr> <td> Non-primitive JS types </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> </tbody> </table> ## External Configuration Files Nuxt uses [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file as the single source of truth for configurations and skips reading external configuration files. During the course of building your project, you may have a need to configure those. The following table highlights common configurations and, where applicable, how they can be configured with Nuxt. <table> <thead> <tr> <th> Name </th> <th> Config File </th> <th> How To Configure </th> </tr> </thead> <tbody> <tr> <td> <a href="https://nitro.build" rel="nofollow"> Nitro </a> </td> <td> <del> <code> nitro.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/5.x/api/nuxt-config#nitro"> <code> nitro </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://postcss.org" rel="nofollow"> PostCSS </a> </td> <td> <del> <code> postcss.config.js </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/5.x/api/nuxt-config#postcss"> <code> postcss </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://vite.dev" rel="nofollow"> Vite </a> </td> <td> <del> <code> vite.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/5.x/api/nuxt-config#vite"> <code> vite </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://webpack.js.org" rel="nofollow"> webpack </a> </td> <td> <del> <code> webpack.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/5.x/api/nuxt-config#webpack-1"> <code> webpack </code> </a> key in <code> nuxt.config </code> </td> </tr> </tbody> </table> Here is a list of other common config files: <table> <thead> <tr> <th> Name </th> <th> Config File </th> <th> How To Configure </th> </tr> </thead> <tbody> <tr> <td> <a href="https://www.typescriptlang.org" rel="nofollow"> TypeScript </a> </td> <td> <code> tsconfig.json </code> </td> <td> <a href="https://nuxt.com/docs/5.x/directory-structure/tsconfig"> More Info </a> </td> </tr> <tr> <td> <a href="https://eslint.org" rel="nofollow"> ESLint </a> </td> <td> <code> eslint.config.js </code> </td> <td> <a href="https://eslint.org/docs/latest/use/configure/configuration-files" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://prettier.io" rel="nofollow"> Prettier </a> </td> <td> <code> prettier.config.js </code> </td> <td> <a href="https://prettier.io/docs/configuration.html" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://stylelint.io" rel="nofollow"> Stylelint </a> </td> <td> <code> stylelint.config.js </code> </td> <td> <a href="https://stylelint.io/user-guide/configure/" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://tailwindcss.com" rel="nofollow"> TailwindCSS </a> </td> <td> <code> tailwind.config.js </code> </td> <td> <a href="https://tailwindcss.nuxtjs.org/tailwindcss/configuration/" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://vitest.dev" rel="nofollow"> Vitest </a> </td> <td> <code> vitest.config.ts </code> </td> <td> <a href="https://vitest.dev/config/" rel="nofollow"> More Info </a> </td> </tr> </tbody> </table> ## Vue Configuration ### With Vite If you need to pass options to `@vitejs/plugin-vue` or `@vitejs/plugin-vue-jsx`, you can do this in your `nuxt.config` file. - `vite.vue` for `@vitejs/plugin-vue`. Check [available options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue). - `vite.vueJsx` for `@vitejs/plugin-vue-jsx`. Check [available options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ vite: { vue: { customElement: true, }, vueJsx: { mergeProps: true, }, }, }) ``` <read-more to="https://nuxt.com/docs/5.x/api/configuration/nuxt-config#vue"> </read-more> ### With webpack If you use webpack and need to configure `vue-loader`, you can do this using `webpack.loaders.vue` key inside your `nuxt.config` file. The available options are [defined here](https://github.com/vuejs/vue-loader/blob/main/src/index.ts#L32-L62). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ webpack: { loaders: { vue: { hotReload: true, }, }, }, }) ``` <read-more to="https://nuxt.com/docs/5.x/api/configuration/nuxt-config#loaders"> </read-more> ### Enabling Experimental Vue Features You may need to enable experimental features in Vue, such as `propsDestructure`. Nuxt provides an easy way to do that in `nuxt.config.ts`, no matter which builder you are using: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ vue: { propsDestructure: true, }, }) ``` #### experimental `reactivityTransform` migration from Vue 3.4 and Nuxt 3.9 Since Nuxt 3.9 and Vue 3.4, `reactivityTransform` has been moved from Vue to Vue Macros which has a [Nuxt integration](https://vue-macros.dev/guide/nuxt-integration.html). <read-more to="https://nuxt.com/docs/5.x/api/configuration/nuxt-config#vue-1"> </read-more> # Data Fetching > Nuxt provides composables to handle data fetching within your application. Nuxt comes with two composables and a built-in library to perform data-fetching in browser or server environments: `useFetch`, [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and `$fetch`. In a nutshell: - [`$fetch`](https://nuxt.com/docs/5.x/api/utils/dollarfetch) is the simplest way to make a network request. - [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) is a wrapper around `$fetch` that fetches data only once in [universal rendering](https://nuxt.com/docs/5.x/guide/concepts/rendering#universal-rendering). - [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) is similar to `useFetch` but offers more fine-grained control. Both `useFetch` and `useAsyncData` share a common set of options and patterns that we will detail in the last sections. ## The Need for `useFetch` and `useAsyncData` Nuxt is a framework which can run isomorphic (or universal) code in both server and client environments. If the [`$fetch` function](https://nuxt.com/docs/5.x/api/utils/dollarfetch) is used to perform data fetching in the setup function of a Vue component, this may cause data to be fetched twice, once on the server (to render the HTML) and once again on the client (when the HTML is hydrated). This can cause hydration issues, increase the time to interactivity and cause unpredictable behavior. The [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) composables solve this problem by ensuring that if an API call is made on the server, the data is forwarded to the client in the payload. The payload is a JavaScript object accessible through [`useNuxtApp().payload`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#payload). It is used on the client to avoid refetching the same data when the code is executed in the browser [during hydration](https://nuxt.com/docs/5.x/guide/concepts/rendering#universal-rendering). <tip> Use the [Nuxt DevTools](https://devtools.nuxt.com) to inspect this data in the **Payload tab**. </tip> ```vue [app/app.vue] <script setup lang="ts"> const { data } = await useFetch('/api/data') async function handleFormSubmit () { const res = await $fetch('/api/submit', { method: 'POST', body: { // My form data }, }) } </script> <template> <div v-if="data == undefined"> No data </div> <div v-else> <form @submit="handleFormSubmit"> <!-- form input tags --> </form> </div> </template> ``` In the example above, `useFetch` would make sure that the request would occur on the server and is properly forwarded to the browser. `$fetch` has no such mechanism and is a better option to use when the request is solely made from the browser. ### Suspense Nuxt uses Vue's [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense) component under the hood to prevent navigation before every async data is available to the view. The data fetching composables can help you leverage this feature and use what suits best on a per-call basis. <note> You can add the [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/5.x/api/components/nuxt-loading-indicator) to add a progress bar between page navigations. </note> ### A note on `await` Examples in this documentation usually `await` calls to `useFetch` and `useAsyncData`, but this is not always required. The `await` does **not** change the server-rendered HTML. During server rendering, Nuxt waits for the request to resolve before serializing the page either way (`<Suspense>`, and `onServerPrefetch` under the hood), so the fully populated result is always sent to the browser. What the `await` *does* change is what happens next in your own `<script setup>`, and how client-side navigation behaves: - **With await**, execution pauses until the data is ready, so any code after the call can rely on `data` already being populated. On client-side navigation, this blocks navigation until the data resolves: the user stays on the current page (optionally with a [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/5.x/api/components/nuxt-loading-indicator)) and then lands on a fully populated page. This is the default behaviour. - **Without await**, execution continues immediately while the request runs in the background, so `data` starts as its default value and fills in once the request resolves. On client-side navigation, this means navigation happens immediately and you are responsible for handling the loading and error states, typically via the returned `status` and `error` refs. Neither approach is universally better; the right choice depends on the experience you want for that route. Not awaiting has a similar user-visible effect to the [`lazy`](#lazy) option (navigation is not blocked and you handle loading state yourself), but the two are not identical: `lazy` is an explicit flag that defers the request until the component mounts, whereas simply not awaiting starts the request during setup. Prefer `lazy` (or [`useLazyFetch`](https://nuxt.com/docs/5.x/api/composables/use-lazy-fetch) / [`useLazyAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-lazy-async-data)) when you want non-blocking behaviour, since it makes the intent explicit. <warning> The `await` and `lazy` are independent, and on the client awaiting a `lazy` function won't have the effect you expect. If you `await` a `lazy` call (for example `await useLazyFetch(...)` or `await useFetch(..., { lazy: true })`), it still blocks server rendering as usual, but on **client-side navigation** the `await` resolves immediately without waiting for the request. `data` will still be at its default value right after the `await`, and you must handle the loading state via `status`. If you actually want the navigation to wait for the data, drop the `lazy` option rather than relying on `await`. </warning> ## `$fetch` Nuxt includes the [ofetch](https://github.com/unjs/ofetch) library, and is auto-imported as the `$fetch` alias globally across your application. ```vue [pages/todos.vue]twoslash <script setup lang="ts"> async function addTodo () { const todo = await $fetch('/api/todos', { method: 'POST', body: { // My todo data }, }) } </script> ``` <warning> Beware that using only `$fetch` will not provide [network calls de-duplication and navigation prevention](https://nuxt.com/docs/5.x/getting-started/data-fetching#the-need-for-usefetch-and-useasyncdata). <br /> It is recommended to use `$fetch` for client-side interactions (event-based) or combined with [`useAsyncData`](https://nuxt.com/docs/5.x/getting-started/data-fetching#useasyncdata) when fetching the initial component data. </warning> <read-more to="https://nuxt.com/docs/5.x/api/utils/dollarfetch"> Read more about `$fetch`. </read-more> ### Pass Client Headers to the API When calling `useFetch` on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/5.x/api/composables/use-request-fetch) to proxy client headers and cookies (with the exception of headers not meant to be forwarded, like `host`). ```vue <script setup lang="ts"> const { data } = await useFetch('/api/echo') </script> ``` ```ts // /api/echo.ts export default defineEventHandler(event => parseCookies(event)) ``` Alternatively, the example below shows how to use [`useRequestHeaders`](https://nuxt.com/docs/5.x/api/composables/use-request-headers) to access and send cookies to the API from a server-side request (originating on the client). Using an isomorphic `$fetch` call, we ensure that the API endpoint has access to the same `cookie` header originally sent by the user's browser. This is only necessary if you aren't using `useFetch`. ```vue <script setup lang="ts"> const headers = useRequestHeaders(['cookie']) async function getCurrentUser () { return await $fetch('/api/me', { headers }) } </script> ``` <tip> You can also use [`useRequestFetch`](https://nuxt.com/docs/5.x/api/composables/use-request-fetch) to proxy headers to the call automatically. </tip> <caution> Be very careful before proxying headers to an external API and just include headers that you need. Not all headers are safe to be bypassed and might introduce unwanted behavior. Here is a list of common headers that are NOT to be proxied: - `host`, `accept` - `content-length`, `content-md5`, `content-type` - `x-forwarded-host`, `x-forwarded-port`, `x-forwarded-proto` - `cf-connecting-ip`, `cf-ray` </caution> ## `useFetch` The [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) composable uses `$fetch` under-the-hood to make SSR-safe network calls in the setup function. ```vue [app/app.vue]twoslash <script setup lang="ts"> const { data: count } = await useFetch('/api/count') </script> <template> <p>Page visits: {{ count }}</p> </template> ``` This composable is a wrapper around the [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) composable and `$fetch` utility. <video-accordion title="Watch a video from Alexander Lichter to avoid using useFetch the wrong way" video-id="njsGVmcWviY"> </video-accordion> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-fetch"> </read-more> <link-example to="https://nuxt.com/docs/5.x/examples/features/data-fetching"> </link-example> ## `useAsyncData` The `useAsyncData` composable is responsible for wrapping async logic and returning the result once it is resolved. <tip> `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => event.$fetch(url))`. <br /> It's developer experience sugar for the most common use case. (You can find out more about `event.fetch` at [`useRequestFetch`](https://nuxt.com/docs/5.x/api/composables/use-request-fetch).) </tip> <video-accordion title="Watch a video from Alexander Lichter to dig deeper into the difference between useFetch and useAsyncData" video-id="0X-aOpSGabA"> </video-accordion> There are some cases when using the [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) composable is not appropriate, for example when a CMS or a third-party provides their own query layer. In this case, you can use [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) to wrap your calls and still keep the benefits provided by the composable. ```vue [app/pages/users.vue] <script setup lang="ts"> const { data, error } = await useAsyncData('users', () => myGetFunction('users')) // This is also possible: const { data, error } = await useAsyncData(() => myGetFunction('users')) </script> ``` <note> The first argument of [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) is a unique key used to cache the response of the second argument, the querying function. This key can be ignored by directly passing the querying function, the key will be auto-generated. <br /> <br /> Since the autogenerated key only takes into account the location where `useAsyncData` is invoked, it is recommended to always create your own key to avoid unwanted behavior, like when you are creating your own custom composable wrapping `useAsyncData`. <br /> <br /> Setting a key can be useful to share the same data between components using [`useNuxtData`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-data) or to [refresh specific data](https://nuxt.com/docs/5.x/api/utils/refresh-nuxt-data#refresh-specific-data). </note> ```vue [app/pages/users/[id].vue] <script setup lang="ts"> const { id } = useRoute().params const { data, error } = await useAsyncData(`user:${id}`, () => { return myGetFunction('users', { id }) }) </script> ``` The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results. ```vue <script setup lang="ts"> const { data: discounts, status } = await useAsyncData('cart-discount', async (_nuxtApp, { signal }) => { const [coupons, offers] = await Promise.all([ $fetch('/cart/coupons', { signal }), $fetch('/cart/offers', { signal }), ]) return { coupons, offers } }) // discounts.value.coupons // discounts.value.offers </script> ``` <note> `useAsyncData` is for fetching and caching data, not triggering side effects like calling Pinia actions, as this can cause unintended behavior such as repeated executions with nullish values. If you need to trigger side effects, use the [`callOnce`](https://nuxt.com/docs/5.x/api/utils/call-once) utility to do so. ```vue <script setup lang="ts"> const offersStore = useOffersStore() // you can't do this await useAsyncData(() => offersStore.getOffer(route.params.slug)) </script> ``` </note> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-async-data"> Read more about `useAsyncData`. </read-more> ## Return Values `useFetch` and `useAsyncData` have the same return values listed below. - `data`: the result of the asynchronous function that is passed in. - `refresh`/`execute`: a function that can be used to refresh the data returned by the `handler` function. - `clear`: a function that can be used to set `data` to `undefined` (or the value of `options.default()` if provided), set `error` to `undefined`, set `status` to `idle`, and mark any currently pending requests as cancelled. - `error`: an error object if the data fetching failed. - `status`: a string indicating the status of the data request (`"idle"`, `"pending"`, `"success"`, `"error"`). <note> `data`, `error` and `status` are Vue refs accessible with `.value` in `<script setup>` </note> By default, Nuxt waits until a `refresh` is finished before it can be executed again. <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain undefined within `<script setup>`. </note> ## Options [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) return the same object type and accept a common set of options as their last argument. They can help you control the composables behavior, such as navigation blocking, caching or execution. ### Lazy By default, data fetching composables will wait for the resolution of their asynchronous function before navigating to a new page by using Vue's Suspense. This feature can be ignored on client-side navigation with the `lazy` option. In that case, you will have to manually handle loading state using the `status` value. ```vue [app/app.vue]twoslash <script setup lang="ts"> const { status, data: posts } = useFetch('/api/posts', { lazy: true, }) </script> <template> <!-- you will need to handle a loading state --> <div v-if="status === 'pending'"> Loading ... </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` You can alternatively use [`useLazyFetch`](https://nuxt.com/docs/5.x/api/composables/use-lazy-fetch) and `useLazyAsyncData` as convenient methods to perform the same. ```vuetwoslash <script setup lang="ts"> const { status, data: posts } = useLazyFetch('/api/posts') </script> ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-lazy-fetch"> Read more about `useLazyFetch`. </read-more> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-lazy-async-data"> Read more about `useLazyAsyncData`. </read-more> <video-accordion title="Watch a video from Vue School on blocking vs. non-blocking (lazy) requests" video-id="1022000555" platform="vimeo"> </video-accordion> ### Client-only fetching By default, data fetching composables will perform their asynchronous function on both client and server environments. Set the `server` option to `false` to only perform the call on the client-side. On initial load, the data will not be fetched before hydration is complete so you have to handle a pending state, though on subsequent client-side navigation the data will be awaited before loading the page. Combined with the `lazy` option, this can be useful for data that is not needed on the first render (for example, non-SEO sensitive data). ```tstwoslash /* This call is performed before hydration */ const articles = await useFetch('/api/article') /* This call will only be performed on the client */ const { status, data: comments } = useFetch('/api/comments', { lazy: true, server: false, }) ``` The `useFetch` composable is meant to be invoked in setup method or called directly at the top level of a function in lifecycle hooks, otherwise you should use [`$fetch` method](https://nuxt.com/docs/5.x/getting-started/data-fetching#fetch). ### Minimize payload size The `pick` option helps you to minimize the payload size stored in your HTML document by only selecting the fields that you want returned from the composables. ```vue <script setup lang="ts"> /* only pick the fields used in your template */ const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'], }) </script> <template> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </template> ``` If you need more control or map over several objects, you can use the `transform` function to alter the result of the query. ```ts const { data: mountains } = await useFetch('/api/mountains', { transform: (mountains) => { return mountains.map(mountain => ({ title: mountain.title, description: mountain.description })) }, }) ``` <note> Both `pick` and `transform` don't prevent the unwanted data from being fetched initially. But they will prevent unwanted data from being added to the payload transferred from server to client. </note> <video-accordion title="Watch a video from Vue School on minimizing payload size" video-id="1026410430" platform="vimeo"> </video-accordion> ### Caching and refetching #### Keys [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) use keys to prevent refetching the same data. - [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) generates a key from the URL, the fetch options and the location of the call in your source code. This means two `useFetch` calls with the same URL in different components have **different** keys and will each perform their own request. To share the same data between multiple components, provide the same explicit `key` in the `options` object passed as a last argument. - [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) uses its first argument as a key if it is a string. If the first argument is the handler function that performs the query, then a key that is unique to the location of the `useAsyncData` call in your source code will be generated for you. <tip> To get the cached data by key, you can use [`useNuxtData`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-data) </tip> <video-accordion title="Watch a video from Vue School on caching data with the key option" video-id="1026410044" platform="vimeo"> </video-accordion> #### Shared State and Option Consistency When multiple components use the same key with `useAsyncData` or `useFetch`, they will share the same `data`, `error` and `status` refs. This ensures consistency across components but requires some options to be consistent. The following options **must be consistent** across all calls with the same key: - `handler` function - `deep` option - `transform` function - `pick` array - `getCachedData` function - `default` value ```ts // โŒ This will trigger a development warning const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true }) ``` The following options **can safely differ** without triggering warnings: - `server` - `lazy` - `immediate` - `dedupe` - `watch` ```ts // โœ… This is allowed const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false }) ``` If you need independent instances, use different keys: ```ts // These are completely independent instances const { data: users1 } = useAsyncData('users-1', (_nuxtApp, { signal }) => $fetch('/api/users', { signal })) const { data: users2 } = useAsyncData('users-2', (_nuxtApp, { signal }) => $fetch('/api/users', { signal })) ``` #### Reactive Keys You can use computed refs, plain refs or getter functions as keys, allowing for dynamic data fetching that automatically updates when dependencies change: ```ts // Using a computed property as a key const userId = ref('123') const { data: user } = useAsyncData( computed(() => `user-${userId.value}`), () => fetchUser(userId.value), ) // When userId changes, the data will be automatically refetched // and the old data will be cleaned up if no other components use it userId.value = '456' ``` #### Refresh and execute If you want to fetch or refresh data manually, use the `execute` or `refresh` function provided by the composables. ```vuetwoslash <script setup lang="ts"> const { data, error, execute, refresh } = await useFetch('/api/users') </script> <template> <div> <p>{{ data }}</p> <button @click="() => refresh()"> Refresh data </button> </div> </template> ``` The `execute` function is an alias for `refresh` that works in exactly the same way but is more semantic for cases when the fetch is [not immediate](https://nuxt.com/docs/5.x/getting-started/data-fetching#not-immediate). <tip> To globally refetch or invalidate cached data, see [`clearNuxtData`](https://nuxt.com/docs/5.x/api/utils/clear-nuxt-data) and [`refreshNuxtData`](https://nuxt.com/docs/5.x/api/utils/refresh-nuxt-data). </tip> #### Clear If you want to clear the data provided, for whatever reason, without needing to know the specific key to pass to `clearNuxtData`, you can use the `clear` function provided by the composables. ```vuetwoslash <script setup lang="ts"> const { data, clear } = await useFetch('/api/users') const route = useRoute() watch(() => route.path, (path) => { if (path === '/') { clear() } }) </script> ``` #### Watch To re-run your fetching function each time other reactive values in your application change, use the `watch` option. You can use it for one or multiple *watchable* elements. ```vuetwoslash <script setup lang="ts"> const id = ref(1) const { data, error, refresh } = await useFetch('/api/users', { /* Changing the id will trigger a refetch */ watch: [id], }) </script> ``` Note that **watching a reactive value won't change the URL fetched**. For example, this will keep fetching the same initial ID of the user because the URL is constructed at the moment the function is invoked. ```vue <script setup lang="ts"> const id = ref(1) const { data, error, refresh } = await useFetch(`/api/users/${id.value}`, { watch: [id], }) </script> ``` If you need to change the URL based on a reactive value, you may want to use a [computed URL](https://nuxt.com/docs/5.x/getting-started/data-fetching#computed-url) instead. When reactive fetch options are provided, they'll be automatically watched and trigger refetches. In some cases, it can be useful to opt-out of this behavior by specifying `watch: false`. ```ts const id = ref(1) // Won't automatically refetch when id changes const { data, execute } = await useFetch('/api/users', { query: { id }, // id is watched by default watch: false, // disables automatic watching of id }) // doesn't trigger refetch id.value = 2 ``` #### Computed URL Sometimes you may need to compute a URL from reactive values, and refresh the data each time these change. Instead of juggling your way around, you can attach each param as a reactive value. Nuxt will automatically use the reactive value and re-fetch each time it changes. ```vue <script setup lang="ts"> const id = ref(null) const { data, status } = useLazyFetch('/api/user', { query: { user_id: id, }, }) </script> ``` In the case of more complex URL construction, you may use a callback as a [computed getter](https://vuejs.org/guide/essentials/computed) that returns the URL string. Every time a dependency changes, the data will be fetched using the newly constructed URL. Combine this with [not-immediate](https://nuxt.com/docs/5.x/getting-started/data-fetching#not-immediate), and you can wait until the reactive element changes before fetching. ```vue <script setup lang="ts"> const id = ref(null) const { data, status } = useLazyFetch(() => `/api/users/${id.value}`, { immediate: false, }) </script> <template> <div> <!-- disable the input while fetching --> <input v-model="id" type="number" :disabled="status === 'pending'" > <div v-if="status === 'idle'"> Type a user ID </div> <div v-else-if="status === 'pending'"> Loading ... </div> <div v-else> {{ data }} </div> </div> </template> ``` If you need to force a refresh when other reactive values change, you can also [watch other values](https://nuxt.com/docs/5.x/getting-started/data-fetching#watch). ### Not immediate The `useFetch` composable will start fetching data the moment it is invoked. You may prevent this by setting `immediate: false`, for example, to wait for user interaction. With that, you will need both the `status` to handle the fetch lifecycle, and `execute` to start the data fetch. ```vue <script setup lang="ts"> const { data, error, execute, status } = await useLazyFetch('/api/comments', { immediate: false, }) </script> <template> <div v-if="status === 'idle'"> <button @click="execute"> Get data </button> </div> <div v-else-if="status === 'pending'"> Loading comments... </div> <div v-else> {{ data }} </div> </template> ``` For finer control, the `status` variable can be: - `idle` when the fetch hasn't started - `pending` when a fetch has started but not yet completed - `error` when the fetch fails - `success` when the fetch is completed successfully ## Passing Headers and Cookies When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. Normally, during server-side-rendering, due to security considerations, the `$fetch` wouldn't include the user's browser cookies, nor pass on cookies from the fetch response. However, when calling `useFetch` with a relative URL on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/5.x/api/composables/use-request-fetch) to proxy headers and cookies (with the exception of headers not meant to be forwarded, like `host`). ### Pass Cookies From Server-side API Calls on SSR Response If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself. ```ts [app/composables/fetch.ts] import type { H3Event } from 'h3' export const fetchWithCookie = async (event: H3Event, url: string) => { /* Get the response from the server endpoint */ const res = await $fetch.raw(url) /* Get the cookies from the response */ const cookies = res.headers.getSetCookie() /* Attach each cookie to our incoming Request */ for (const cookie of cookies) { event.res.headers.append('set-cookie', cookie) } /* Return the data of the response */ return res._data } ``` ```vue <script setup lang="ts"> // This composable will automatically pass cookies to the client const event = useRequestEvent() const { data: result } = await useAsyncData(() => fetchWithCookie(event!, '/api/with-cookie')) onMounted(() => console.log(document.cookie)) </script> ``` ## Options API Support Nuxt provides a way to perform `asyncData` fetching within the Options API. You must wrap your component definition within `defineNuxtComponent` for this to work. ```vue <script> export default defineNuxtComponent({ /* Use the fetchKey option to provide a unique key */ fetchKey: 'hello', async asyncData () { return { hello: await $fetch('/api/hello'), } }, }) </script> ``` <note> Using `<script setup>` or `<script setup lang="ts">` are the recommended way of declaring Vue components in Nuxt. </note> <read-more to="https://nuxt.com/docs/5.x/api/utils/define-nuxt-component"> </read-more> ## Typed Routes `$fetch` and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) are typed from the routes known to your server, so a response is automatically typed based on its handler's return type. ```ts [server/api/todos.get.ts] export default defineEventHandler(() => [{ id: '1', title: 'Buy milk' }]) ``` ```ts const todos = await $fetch('/api/todos') // ^? { id: string, title: string }[] ``` The method decides which handler responds, so `/api/todos` fetched with `POST` is typed by `server/api/todos.post.ts` rather than by the `GET` handler above. If a handler validates its request, this is typed for you when you fetch from that route. This works with any [Standard Schema](https://standardschema.dev) library: ```ts [server/api/todos.post.ts] import { z } from 'zod' export default defineValidatedHandler({ validate: { body: z.object({ title: z.string() }) }, handler: () => ({ id: '1' }), }) ``` ```ts await $fetch('/api/todos', { method: 'POST', body: { title: 'Buy milk' } }) await $fetch('/api/todos', { method: 'POST', body: { title: 42 } }) // ^ not assignable to string await $fetch('/api/todos', { method: 'POST' }) // ^ body is required ``` ### Requests Nuxt Cannot Type A path built at runtime, an absolute URL and a `Request` object all resolve to `unknown`, because there is nothing to match them against. In this case you can provide an explicit return type: ```ts const data = await $fetch<{ id: string }>(`/api/${resource}`) ``` By default a path that Nuxt does not handle is typed as `unknown`, since a nitro middleware, a [`routeRules`](https://nuxt.com/docs/5.x/guide/concepts/rendering#hybrid-rendering) proxy or a catch-all handler can answer it. Enable [`experimental.strictRouteTypes`](https://nuxt.com/docs/5.x/guide/going-further/experimental-features#strictroutetypes) to make an unrecognized path an error instead. ### Requests Made With a `baseURL` A `baseURL` is prepended to the path before the request is made, so it is part of the route being requested and Nuxt resolves it as such - whether it is set per call, on a `$fetch` instance, or on a composable built with `createUseFetch`: ```ts await $fetch('/todos', { baseURL: '/api' }) // ^? { id: string, title: string }[] - resolved as /api/todos const api = $fetch.create({ baseURL: '/api' }) await api('/todos') // ^? the same ``` Since the path is resolved against the base, passing a path that already carries it is an error naming the URL that would be requested: ```ts await $fetch('/api/todos', { baseURL: '/api' }) // ^ no GET route matches '/api/api/todos' ``` A base Nuxt cannot read - a runtime value, a `ref` or a getter - leaves the request typed as `unknown` rather than rejected, since there is nothing to resolve the path against. The same is true of a base pointing at another origin, so an external API is fetched the way it always was: ```ts const users = await $fetch('/users', { baseURL: 'https://api.example.com' }) // ^? unknown ``` ### Declaring Route Types A route Nuxt does not learn about from your server builder - one a nitro plugin registers at runtime, or an external API you want typed the same way - can be declared by augmenting `ServerRoutes`: ```ts [shared/server-routes.d.ts] import type { Endpoint } from 'nuxt/app' declare module '@nuxt/schema' { interface ServerRoutes { '/api/hello': { [Endpoint]: { GET: { response: { message: string } } } } } } ``` Declare it in a `.d.ts` file your app compiles - `shared/` is visible to both app and server code - and the route is resolved at the call site, though it does not appear in editor completions. <note> Modules that register handlers with [`addServerHandler`](https://nuxt.com/docs/5.x/api/kit/nitro#addserverhandler) need no augmentation: those routes are reported by the server builder like any other, and typed automatically. </note> ### Writing Your Own Wrapper To build a `useFetch` with different defaults, use [`createUseFetch`](https://nuxt.com/docs/5.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch), which keeps the route typing intact: ```ts [app/composables/useApiFetch.ts] export const useApiFetch = createUseFetch({ baseURL: '/api' }) ``` ```ts const { data } = useApiFetch('/todos') // ^? { id: string, title: string }[] - resolved as /api/todos ``` If you are wrapping `$fetch` by hand, constrain the path by `string` rather than by `TypedFetchRequest`, so that a route declared through augmentation is still accepted, and pass the request through to `$fetch` so it is typed there. ## Serializing Data From Server to Client When using `useAsyncData` and `useLazyAsyncData` to transfer data fetched on server to the client (as well as anything else that utilizes [the Nuxt payload](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#payload)), the payload is serialized with [`devalue`](https://github.com/sveltejs/devalue). This allows us to transfer not just basic JSON but also to serialize and revive/deserialize more advanced kinds of data, such as regular expressions, Dates, Map and Set, `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError` - and more. It is also possible to define your own serializer/deserializer for types that are not supported by Nuxt. You can read more in the [`useNuxtApp`](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#payload) docs. <note> Note that this *does not apply* to data passed from your server routes when fetched with `$fetch` or `useFetch` - see the next section for more information. </note> ## Serializing Data From API Routes When fetching data from the `server` directory, the response is serialized using `JSON.stringify`. However, since serialization is limited to only JavaScript primitive types, Nuxt does its best to convert the return type of `$fetch` and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) to match the actual value. <read-more to="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description" icon="i-simple-icons-mdnwebdocs" target="_blank"> Learn more about `JSON.stringify` limitations. </read-more> ### Example ```ts [server/api/foo.ts] export default defineEventHandler(() => { return new Date() }) ``` ```vue [app/app.vue] <script setup lang="ts"> // Type of `data` is inferred as string even though we returned a Date object const { data } = await useFetch('/api/foo') </script> ``` ### Custom serializer function To customize the serialization behavior, you can define a `toJSON` function on your returned object. If you define a `toJSON` method, Nuxt will respect the return type of the function and will not try to convert the types. ```ts [server/api/bar.ts] export default defineEventHandler(() => { const data = { createdAt: new Date(), toJSON () { return { createdAt: { year: this.createdAt.getFullYear(), month: this.createdAt.getMonth(), day: this.createdAt.getDate(), }, } }, } return data }) ``` ```vue [app/app.vue] <script setup lang="ts"> // Type of `data` is inferred as // { // createdAt: { // year: number // month: number // day: number // } // } const { data } = await useFetch('/api/bar') </script> ``` ### Using an alternative serializer Nuxt does not currently support an alternative serializer to `JSON.stringify`. However, you can return your payload as a normal string and utilize the `toJSON` method to maintain type safety. In the example below, we use [superjson](https://github.com/flightcontrolhq/superjson) as our serializer. ```ts [server/api/superjson.ts] import superjson from 'superjson' export default defineEventHandler(() => { const data = { createdAt: new Date(), // Workaround the type conversion toJSON () { return this }, } // Serialize the output to string, using superjson return superjson.stringify(data) as unknown as typeof data }) ``` ```vue [app/app.vue] <script setup lang="ts"> import superjson from 'superjson' // `date` is inferred as { createdAt: Date } and you can safely use the Date object methods const { data } = await useFetch('/api/superjson', { transform: (value) => { return superjson.parse(value as unknown as string) }, }) </script> ``` ## Recipes ### Consuming SSE (Server-Sent Events) via POST request <tip> If you're consuming SSE via GET request, you can use [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) or VueUse composable [`useEventSource`](https://vueuse.org/core/useeventsource/). </tip> When consuming SSE via POST request, you need to handle the connection manually. Here's how you can do it: ```ts // Make a POST request to the SSE endpoint const response = await $fetch<ReadableStream>('/chats/ask-ai', { method: 'POST', body: { query: 'Hello AI, how are you?', }, responseType: 'stream', }) // Create a new ReadableStream from the response with TextDecoderStream to get the data as text const reader = response.pipeThrough(new TextDecoderStream()).getReader() // Read the chunk of data as we get it while (true) { const { value, done } = await reader.read() if (done) { break } console.log('Received:', value) } ``` ### Making parallel requests When requests don't rely on each other, you can make them in parallel with `Promise.all()` to boost performance. ```ts const { data } = await useAsyncData((_nuxtApp, { signal }) => { return Promise.all([ $fetch('/api/comments/', { signal }), $fetch('/api/author/12', { signal }), ]) }) const comments = computed(() => data.value?.[0]) const author = computed(() => data.value?.[1]) ``` <video-accordion title="Watch a video from Vue School on parallel data fetching" video-id="1024262536" platform="vimeo"> </video-accordion> # Deployment > Learn how to deploy your Nuxt application to any hosting provider. A Nuxt application can be deployed on a Node.js server, pre-rendered for static hosting, or deployed to serverless or edge (CDN) environments. <tip> If you are looking for a list of cloud providers that support Nuxt, see the [Hosting providers](https://nuxt.com/deploy) section. </tip> ## Node.js Server Discover the Node.js server preset with Nitro to deploy on any Node hosting. - **Default output format** if none is specified or auto-detected <br /> - Loads only the required chunks to render the request for optimal cold start timing <br /> - Useful for deploying Nuxt apps to any Node.js hosting ### Entry Point When running `nuxt build` with the Node server preset, the result will be an entry point that launches a ready-to-run Node server. ```bash [Terminal] NODE_ENV=production node .output/server/index.mjs ``` This will launch your production Nuxt server that listens on port 3000 by default. <important> Set `NODE_ENV=production` when running the server. Some dependencies (notably Vue Router) only strip development-only warnings when this is set, so leaving it unset can flood your logs with messages like `[Vue Router warn]: No match found for location with path โ€ฆ` on unmatched routes. </important> It respects the following runtime environment variables: - `NITRO_PORT` or `PORT` (defaults to `3000`) - `NITRO_HOST` or `HOST` (defaults to `'0.0.0.0'`) - `NITRO_SSL_CERT` and `NITRO_SSL_KEY` - if both are present, this will launch the server in HTTPS mode. In the vast majority of cases, this should not be used other than for testing, and the Nitro server should be run behind a reverse proxy like nginx or Cloudflare which terminates SSL. ### Serving the Same Build at Multiple Paths For a normal subpath deployment, set [`app.baseURL`](https://nuxt.com/docs/5.x/api/nuxt-config#baseurl) or the `NUXT_APP_BASE_URL` environment variable. If a reverse proxy deliberately exposes the same rendered page at multiple public paths, Nuxt may replace the browser URL with the path used for server rendering during hydration. You can keep the browser URL by removing the rendered path from the payload in a server plugin: ```ts [app/plugins/preserve-proxy-url.server.ts] export default defineNuxtPlugin((nuxtApp) => { delete nuxtApp.payload.path }) ``` Use this only when the proxy already handles assets and routing for every public path. Without the rendered path, Nuxt cannot correct a genuine mismatch between the requested URL and the server-rendered route. ### PM2 [PM2](https://pm2.keymetrics.io/) (Process Manager 2) is a fast and easy solution for hosting your Nuxt application on your server or VM. To use `pm2`, use an `ecosystem.config.cjs`: ```ts [ecosystem.config.cjs] module.exports = { apps: [ { name: 'NuxtAppName', port: '3000', exec_mode: 'cluster', instances: 'max', script: './.output/server/index.mjs', env: { NODE_ENV: 'production', }, }, ], } ``` ### Cluster Mode You can use `NITRO_PRESET=node_cluster` in order to leverage multi-process performance using Node.js [cluster](https://nodejs.org/dist/latest/docs/api/cluster.html) module. By default, the workload gets distributed to the workers with the round robin strategy. ### Learn More <read-more to="https://nitro.build/deploy/runtimes/node" title="the Nitro documentation for node-server preset"> </read-more> <video-accordion title="Watch Daniel Roe's short video on the topic" video-id="0x1H6K5yOfs"> </video-accordion> ## Static Hosting There are two ways to deploy a Nuxt application to any static hosting services: - Static site generation (SSG) with `ssr: true` pre-renders routes of your application at build time. (This is the default behavior when running `nuxt generate`.) It will also generate `/200.html` and `/404.html` single-page app fallback pages, which can render dynamic routes or 404 errors on the client (though you may need to configure this on your static host). See [What are 200.html and 404.html?](https://nuxt.com/docs/5.x/guide/concepts/rendering#what-are-200html-and-404html). - Alternatively, you can prerender your site with `ssr: false` (static single-page app). This will produce HTML pages with an empty `<div id="__nuxt"></div>` where your Vue app would normally be rendered. You will lose many SEO benefits of prerendering your site, so it is suggested instead to use [`<ClientOnly>`](https://nuxt.com/docs/5.x/api/components/client-only) to wrap the portions of your site that cannot be server rendered (if any). Prerendered routes also emit `_payload.json` files with the data captured at build time, which Nuxt reuses during client-side navigation. Read more about [payload extraction](https://nuxt.com/docs/5.x/getting-started/prerendering#payload-extraction). ### Static Fallback Pages Nuxt can generate two fallback pages for static hosts: - `200.html` is the single-page app fallback. Configure your host to serve it for unmatched routes when you want client-side routing to handle the URL. - `404.html` is the not-found fallback. Configure your host to serve it for routes that should keep a 404 status. `nuxt generate` and `nuxt build --prerender` generate these files automatically. If you use `nuxt build` with route rules to prerender selected routes, add the fallback page explicitly: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { '/200.html': { prerender: true }, }, }) ``` By default both fallbacks are empty shells. Set [`experimental.prerenderErrorPages`](https://nuxt.com/docs/5.x/guide/concepts/rendering#server-rendering-the-error-page) to server-render your `error.vue` into `404.html` at build time. Some providers use `200.html`, some use `404.html`, and some let you configure both. Check your hosting provider's static fallback or rewrite settings after deployment. <read-more to="https://nuxt.com/docs/5.x/getting-started/prerendering" title="Nuxt prerendering"> </read-more> ### Client-side Only Rendering If you don't want to pre-render your routes, another way of using static hosting is to set the `ssr` property to `false` in the `nuxt.config` file. The `nuxt generate` command will then output an `.output/public/index.html` entrypoint and JavaScript bundles like a classic client-side Vue.js application. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ ssr: false, }) ``` ## Hosting Providers Nuxt can be deployed to several cloud providers with a minimal amount of configuration: <read-more to="https://nuxt.com/deploy"> </read-more> ## Presets In addition to Node.js servers and static hosting services, a Nuxt project can be deployed with several well-tested presets and a minimal amount of configuration. You can explicitly set the desired preset in the [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { preset: 'node-server', }, }) ``` ... or use the `NITRO_PRESET` environment variable when running `nuxt build`: ```bash [Terminal] NITRO_PRESET=node-server nuxt build ``` ๐Ÿ”Ž Check [the Nitro deployment](https://nitro.build/deploy) for all possible deployment presets and providers. ## CDN Proxy In most cases, Nuxt can work with third-party content that is not generated or created by Nuxt itself. But sometimes such content can cause problems, especially Cloudflare's "Minification and Security Options". Accordingly, you should make sure that the following options are unchecked / disabled in Cloudflare. Otherwise, unnecessary re-rendering or hydration errors could impact your production application. 1. Speed > Settings > Content Optimization > Disable "Rocket Loaderโ„ข" 2. Security > Settings > Disable "Email Address Obfuscation" With these settings, you can be sure that Cloudflare won't inject scripts into your Nuxt application that may cause unwanted side effects. <tip> Their location on the Cloudflare dashboard sometimes changes so don't hesitate to look around. </tip> # Error Handling > Learn how to catch and handle errors in Nuxt. Nuxt is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts: - Errors during the Vue rendering lifecycle (SSR & CSR) - Server and client startup errors (SSR + CSR) - Errors during Nitro server lifecycle ([`server/`](https://nuxt.com/docs/5.x/directory-structure/server) directory) - Errors downloading JS chunks <tip> **SSR** stands for **Server-Side Rendering** and **CSR** for **Client-Side Rendering**. </tip> ## Vue Errors You can hook into Vue errors using [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured). In addition, Nuxt provides a [`vue:error`](https://nuxt.com/docs/5.x/api/advanced/hooks#app-hooks-runtime) hook that will be called if any errors propagate up to the top level. If you are using an error reporting framework, you can provide a global handler through [`vueApp.config.errorHandler`](https://vuejs.org/api/application#app-config-errorhandler). It will receive all Vue errors, even if they are handled. ```ts [plugins/error-handler.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.config.errorHandler = (error, instance, info) => { // handle error, e.g. report to a service } // Also possible nuxtApp.hook('vue:error', (error, instance, info) => { // handle error, e.g. report to a service }) }) ``` <note> Note that the `vue:error` hook is based on [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) lifecycle hook. </note> ## Startup Errors Nuxt will call the `app:error` hook if there are any errors in starting your Nuxt application. This includes: - running [Nuxt plugins](https://nuxt.com/docs/5.x/directory-structure/app/plugins) - processing `app:created` and `app:beforeMount` hooks - rendering your Vue app to HTML (during SSR) - mounting the app (on client-side), though you should handle this case with `onErrorCaptured` or with `vue:error` - processing the `app:mounted` hook ## Nitro Server Errors You cannot currently define a server-side handler for these errors, but can render an error page, see the [Render an Error Page](https://nuxt.com/docs/5.x/getting-started/error-handling#error-page) section. ## Errors with JS Chunks You might encounter chunk loading errors due to a network connectivity failure or a new deployment (which invalidates your old, hashed JS chunk URLs). Nuxt provides built-in support for handling chunk loading errors by performing a hard reload when a chunk fails to load during route navigation. You can change this behavior by setting `experimental.emitRouteChunkError` to `false` (to disable hooking into these errors at all) or to `manual` if you want to handle them yourself. If you want to handle chunk loading errors manually, you can check out the [automatic implementation](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/plugins/chunk-reload.client.ts) for ideas. ## Error Page <note> When Nuxt encounters a fatal error (any unhandled error on the server, or an error created with `fatal: true` on the client) it will either render a JSON response (if requested with `Accept: application/json` header) or trigger a full-screen error page. </note> An error may occur during the server lifecycle when: - processing your Nuxt plugins - rendering your Vue app into HTML - a server API route throws an error It can also occur on the client side when: - processing your Nuxt plugins - before mounting the application (`app:beforeMount` hook) - mounting your app if the error was not handled with `onErrorCaptured` or `vue:error` hook - the Vue app is initialized and mounted in browser (`app:mounted`). <read-more to="https://nuxt.com/docs/5.x/api/advanced/hooks"> Discover all the Nuxt lifecycle hooks. </read-more> Customize the default error page by adding `~/error.vue` in the source directory of your application, alongside `app.vue`. ```vue [error.vue] <script setup lang="ts"> import type { NuxtError } from '#app' const props = defineProps({ error: Object as () => NuxtError, }) const handleError = () => clearError({ redirect: '/' }) </script> <template> <div> <h2>{{ error?.status }}</h2> <button @click="handleError"> Clear errors </button> </div> </template> ``` <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/error"> Read more about `error.vue` and its uses. </read-more> For custom errors we highly recommend using `onErrorCaptured` composable that can be called in a page/component setup function or `vue:error` runtime nuxt hook that can be configured in a nuxt plugin. ```ts [plugins/error-handler.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('vue:error', (err) => { // }) }) ``` When you are ready to remove the error page, you can call the [`clearError`](https://nuxt.com/docs/5.x/api/utils/clear-error) helper function, which takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page). <important> Make sure to check before using anything dependent on Nuxt plugins, such as `$route` or `useRouter`, as if a plugin threw an error, then it won't be re-run until you clear the error. </important> <note> Rendering an error page is an entirely separate page load, meaning any registered middleware will run again. You can use [`useError`](https://nuxt.com/docs/5.x/getting-started/error-handling#useerror) in middleware to check if an error is being handled. </note> <note> If you are running on Node 16 and you set any cookies when rendering your error page, they will [overwrite cookies previously set](https://github.com/nuxt/nuxt/pull/20585). We recommend using a newer version of Node as Node 16 reached end-of-life in September 2023. </note> ## Error Utils ### `useError` ```ts [TS Signature] function useError (): Ref<Error | { url, status, statusText, message, description, data }> ``` This function will return the global Nuxt error that is being handled. <read-more to="https://nuxt.com/docs/5.x/api/composables/use-error"> Read more about `useError` composable. </read-more> ### `createError` ```ts [TS Signature] function createError (err: string | { cause, data, message, name, stack, status, statusText, fatal }): Error ``` Create an error object with additional metadata. You can pass a string to be set as the error `message` or an object containing error properties. It is usable in both the Vue and Server portions of your app, and is meant to be thrown. If you throw an error created with `createError`: - on server-side, it will trigger a full-screen error page which you can clear with [`clearError`](https://nuxt.com/docs/5.x/getting-started/error-handling#clearerror). - on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`. In development, an error `cause` is preserved and exposed to your error page so you can trace the original error; in production, causes are never included in error responses or the error page payload. ```vue [pages/movies/[slug].vue]twoslash <script setup lang="ts"> const route = useRoute() const { data } = await useFetch(`/api/movies/${route.params.slug}`) if (!data.value) { throw createError({ status: 404, statusText: 'Page Not Found', }) } </script> ``` <tip> The `statusText` property is intended for short, HTTP-compliant status texts (e.g., "Not Found"). It should only contain horizontal tabs, spaces, and visible ASCII characters (`[\t\u0020-\u007E]`). For any detailed descriptions, multi-line messages, or content with non-ASCII characters, you should always use the `message` property instead. </tip> <read-more to="https://nuxt.com/docs/5.x/api/utils/create-error"> Read more about `createError` util. </read-more> ### `showError` ```ts [TS Signature] function showError (err: string | Error | { status, statusText }): Error ``` You can call this function at any point on client-side, or (on server side) directly within middleware, plugins or `setup()` functions. It will trigger a full-screen error page which you can clear with [`clearError`](https://nuxt.com/docs/5.x/getting-started/error-handling#clearerror). It is recommended instead to use `throw createError()`. <read-more to="https://nuxt.com/docs/5.x/api/utils/show-error"> Read more about `showError` util. </read-more> ### `clearError` ```ts [TS Signature] function clearError (options?: { redirect?: string }): Promise<void> ``` This function will clear the currently handled Nuxt error. It also takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page). <read-more to="https://nuxt.com/docs/5.x/api/utils/clear-error"> Read more about `clearError` util. </read-more> ## Render Error in Component Nuxt also provides a [`<NuxtErrorBoundary>`](https://nuxt.com/docs/5.x/api/components/nuxt-error-boundary) component that allows you to handle client-side errors within your app, without replacing your entire site with an error page. This component is responsible for handling errors that occur within its default slot. On client-side, it will prevent the error from bubbling up to the top level, and will render the `#error` slot instead. The `#error` slot will receive `error` as a prop. (If you set `error = null` it will trigger re-rendering the default slot; you'll need to ensure that the error is fully resolved first or the error slot will just be rendered a second time.) <tip> If you navigate to another route, the error will be cleared automatically. </tip> ```vue [app/pages/index.vue] <template> <!-- some content --> <NuxtErrorBoundary @error="someErrorLogger"> <!-- You use the default slot to render your content --> <template #error="{ error, clearError }"> You can display the error locally here: {{ error }} <button @click="clearError"> This will clear the error. </button> </template> </NuxtErrorBoundary> </template> ``` <link-example to="https://nuxt.com/docs/5.x/examples/advanced/error-handling"> </link-example> # Installation > Get started with Nuxt quickly with our online starters or start locally with your terminal. ## Play Online If you just want to play around with Nuxt in your browser without setting up a project, you can use this online sandbox: <card-group> <card color="info" icon="i-simple-icons-stackblitz" target="_blank" title="Open on StackBlitz" to="https://stackblitz.com/github/nuxt/starter?file=app%2Fapp.vue"> Online playground with code editor and terminal access. </card> </card-group> ## New Project <steps> ### Prerequisites - **Node.js** - [`22.x`](https://nodejs.org/en) or newer (but we recommend the [active LTS release](https://github.com/nodejs/release#release-schedule)) - **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box. If you use another editor, such as Neovim, you can configure [Vue Language Server](https://github.com/vuejs/language-tools) support by following the [Vue Language Tools setup guides](https://github.com/vuejs/language-tools/wiki). - **Terminal** - In order to run Nuxt commands <callout> <collapsible name="additional notes for an optimal setup"> - **Node.js**: Make sure to use an even numbered version (22, 24, etc.) - **Neovim**: When configuring the Vue TypeScript plugin, make sure `location` points to the `@vue/language-server` package directory, not its binary. See the [Neovim setup guide](https://github.com/vuejs/language-tools/wiki/Neovim) for a working configuration. - **WSL**: If you are using Windows and experience slow HMR, you may want to try using [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install) which may solve some performance issues. - **Windows slow DNS resolution**: Instead of using `localhost:3000` for local dev server on Windows, use `127.0.0.1` for much faster loading experience on browsers. </collapsible> </callout> ### Create a New Project Open a terminal (if you're using [Visual Studio Code](https://code.visualstudio.com), you can open an [integrated terminal](https://code.visualstudio.com/docs/terminal/basics)) and use the following command to create a new starter project: <code-group sync="pm"> ```bash [npm] npm create nuxt@latest <project-name> ``` ```bash [yarn] yarn create nuxt <project-name> ``` ```bash [pnpm] pnpm create nuxt@latest <project-name> ``` ```bash [bun] bun create nuxt@latest <project-name> ``` ```bash [deno] deno -A npm:create-nuxt@latest <project-name> ``` </code-group> Open your project folder in Visual Studio Code: ```bash [Terminal] code <project-name> ``` Or change directory into your new project from your terminal: ```bash cd <project-name> ``` ### Development Server Now you'll be able to start your Nuxt app in development mode: <code-group sync="pm"> ```bash [npm] npm run dev -- -o ``` ```bash [yarn] yarn dev --open ``` ```bash [pnpm] pnpm dev -o ``` ```bash [bun] bun run dev -o # To use the Bun runtime during development # bun --bun run dev -o ``` ```bash [deno] deno run dev -o ``` </code-group> <tip icon="i-lucide-circle-check"> Well done! A browser window should automatically open for [http://localhost:3000](http://localhost:3000). </tip> <tip icon="i-lucide-container"> If you're using Docker or want a consistent development environment across machines, consider using a dev container. [Learn more about dev containers](https://nuxt.com/docs/5.x/guide/best-practices/devcontainers) </tip> </steps> ## Next Steps Now that you've created your Nuxt project, you are ready to start building your application. <read-more title="Nuxt Concepts" to="https://nuxt.com/docs/5.x/guide/concepts"> </read-more> # Introduction > Nuxt's goal is to make web development intuitive and performant with a great Developer Experience in mind. Nuxt is a free and [open-source framework](https://github.com/nuxt/nuxt) with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with [Vue.js](https://vuejs.org). We made everything so you can start writing `.vue` files from the beginning while enjoying hot module replacement in development and a performant application in production with server-side rendering by default. Nuxt has no vendor lock-in, allowing you to deploy your application [**everywhere, even on the edge**](https://nuxt.com/blog/nuxt-on-the-edge). <tip> If you want to play around with Nuxt in your browser, you can [try it out in one of our online sandboxes](https://nuxt.com/docs/5.x/getting-started/installation#play-online). </tip> ## Automation and Conventions Nuxt uses conventions and an opinionated directory structure to automate repetitive tasks and allow developers to focus on pushing features. The configuration file can still customize and override its default behaviors. - **File-based routing:** define routes based on the structure of your [`app/pages/` directory](https://nuxt.com/docs/5.x/directory-structure/app/pages). This can make it easier to organize your application and avoid the need for manual route configuration. - **Code splitting:** Nuxt automatically splits your code into smaller chunks, which can help reduce the initial load time of your application. - **Server-side rendering out of the box:** Nuxt comes with built-in SSR capabilities, so you don't have to set up a separate server yourself. - **Auto-imports:** write Vue composables and components in their respective directories and use them without having to import them with the benefits of tree-shaking and optimized JS bundles. - **Data-fetching utilities:** Nuxt provides composables to handle SSR-compatible data fetching as well as different strategies. - **Zero-config TypeScript support:** write type-safe code without having to learn TypeScript with our auto-generated types and `tsconfig.json`. - **Configured build tools:** we use [Vite](https://vite.dev) by default to support hot module replacement (HMR) in development and bundling your code for production with best-practices baked-in. Nuxt takes care of these and provides both frontend and backend functionality so you can focus on what matters: **creating your web application**. ## Server-Side Rendering Nuxt comes with built-in server-side rendering (SSR) capabilities by default, without having to configure a server yourself, which has many benefits for web applications: - **Faster initial page load time:** Nuxt sends a fully rendered HTML page to the browser, which can be displayed immediately. This can provide a faster perceived page load time and a better user experience (UX), especially on slower networks or devices. - **Improved SEO:** search engines can better index SSR pages because the HTML content is available immediately, rather than requiring JavaScript to render the content on the client-side. - **Better performance on low-powered devices:** it reduces the amount of JavaScript that needs to be downloaded and executed on the client-side, which can be beneficial for low-powered devices that may struggle with processing heavy JavaScript applications. - **Better accessibility:** the content is immediately available on the initial page load, improving accessibility for users who rely on screen readers or other assistive technologies. - **Easier caching:** pages can be cached on the server-side, which can further improve performance by reducing the amount of time it takes to generate and send the content to the client. Overall, server-side rendering can provide a faster and more efficient user experience, as well as improve search engine optimization and accessibility. As Nuxt is a versatile framework, it gives you the possibility to statically render your whole application to a static hosting with `nuxt generate`, disable SSR globally with the `ssr: false` option or leverage hybrid rendering by setting up the `routeRules` option. <read-more title="Nuxt rendering modes" to="https://nuxt.com/docs/5.x/guide/concepts/rendering"> </read-more> ### Server engine The Nuxt server engine, [Nitro](https://nitro.build/), unlocks new full-stack capabilities. In development, it uses Rollup and Node.js workers for your server code and context isolation. It also generates your server API by reading files from `server/api/` and server middleware from `server/middleware/`. In production, Nitro builds your app and server into one universal `.output` directory. This output is light: minified and removed from any Node.js modules (except polyfills). You can deploy this output on any system supporting JavaScript, from Node.js, Serverless, Workers, Edge-side rendering or purely static. <read-more title="Nuxt server engine" to="https://nuxt.com/docs/5.x/guide/concepts/server-engine"> </read-more> ### Production-ready A Nuxt application can be deployed on a Node or Deno server, pre-rendered to be hosted in static environments, or deployed to serverless and edge providers. <read-more title="Deployment section" to="https://nuxt.com/docs/5.x/getting-started/deployment"> </read-more> ### Modular A module system allows you to extend Nuxt with custom features and integrations with third-party services. <read-more title="Nuxt Modules Concept" to="https://nuxt.com/docs/5.x/guide/concepts/modules"> </read-more> ### Architecture Nuxt is composed of different [core packages](https://github.com/nuxt/nuxt/tree/main/packages): - Core engine: [nuxt](https://github.com/nuxt/nuxt/tree/main/packages/nuxt) - Bundlers: [@nuxt/vite-builder](https://github.com/nuxt/nuxt/tree/main/packages/vite), [@nuxt/rspack-builder](https://github.com/nuxt/nuxt/tree/main/packages/rspack) and [@nuxt/webpack-builder](https://github.com/nuxt/nuxt/tree/main/packages/webpack) - Command line interface: [@nuxt/cli](https://github.com/nuxt/cli) - Server engine: [nitro](https://github.com/nitrojs/nitro) - Development kit: [@nuxt/kit](https://github.com/nuxt/nuxt/tree/main/packages/kit) We recommend reading each concept to have a full vision of Nuxt capabilities and the scope of each package. # Layers > Nuxt provides a powerful system that allows you to extend the default files, configs, and much more. One of the core features of Nuxt is the layers and extending support. You can extend a default Nuxt application to reuse components, utils, and configuration. The layers structure is almost identical to a standard Nuxt application which makes them easy to author and maintain. ## Use Cases - Share reusable configuration presets across projects using `nuxt.config` and `app.config` - Create a component library using [`app/components/`](https://nuxt.com/docs/5.x/directory-structure/app/components) directory - Create utility and composable library using [`app/composables/`](https://nuxt.com/docs/5.x/directory-structure/app/composables) and [`app/utils/`](https://nuxt.com/docs/5.x/directory-structure/app/utils) directories - Create Nuxt module presets - Share standard setup across projects - Create Nuxt themes - Enhance code organization by implementing a modular architecture and support Domain-Driven Design (DDD) pattern in large scale projects. ## Usage By default, any layers within your project in the `~~/layers` directory will be automatically registered as layers in your project. <note> Layer auto-registration was introduced in Nuxt v3.12.0. </note> In addition, named layer aliases to the `srcDir` of each of these layers will automatically be created. For example, you will be able to access the `~~/layers/test` layer via `#layers/test`. <note> Named layer aliases were introduced in Nuxt v3.16.0. </note> In addition, you can extend from a layer by adding the [extends](https://nuxt.com/docs/5.x/api/nuxt-config#extends) property to your [`nuxt.config`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ // Extend from a local layer '../base', // Extend from an installed npm package '@my-themes/awesome', // Extend from a git repository 'github:my-themes/awesome#v1', ], }) ``` You can also pass an authentication token if you are extending from a private GitHub repository: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ // per layer configuration ['github:my-themes/private-awesome', { auth: process.env.GITHUB_TOKEN }], ], }) ``` <note> If a branch is not specified, this will clone `main`. </note> <tip> You can override a layer's alias by specifying it in the options next to the layer source. ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ [ 'github:my-themes/awesome', { meta: { name: 'my-awesome-theme', }, }, ], ], }) ``` </tip> Nuxt uses [unjs/c12](https://github.com/unjs/c12) and [unjs/giget](https://github.com/unjs/giget) for extending remote layers. Check the documentation for more information and all available options. ## Layer Priority When using multiple layers, it's important to understand the override order. Layers with **higher priority** override layers with lower priority when they define the same files or components. ### Priority Order From highest to lowest priority: 1. **Your project files** - always have the highest priority 2. **Auto-scanned layers** from `~~/layers` directory - sorted alphabetically (Z has higher priority than A) 3. **Layers in extends** config - first entry has higher priority than second ### Practical Example Consider multiple layers defining the same component: ```bash [Directory structure] layers/ 1.base/ app/components/Button.vue # Base button style 2.theme/ app/components/Button.vue # Themed button (overrides base) app/ components/Button.vue # Project button (overrides all layers) ``` In this case: - If only layers exist, `2.theme/Button.vue` is used (higher alphabetically) - If `app/components/Button.vue` exists in your project, it overrides all layers ### Controlling Priority You can prefix layer directories with numbers to control the order: ```bash [Directory structure] layers/ 1.base/ # Lowest priority 2.features/ # Medium priority 3.admin/ # Highest priority (among layers) ``` <tip> This pattern is useful for creating base layers with defaults that can be progressively overridden by more specific layers. </tip> Alternatively, you can control the order of your `~~/layers` directories from `nuxt.config` by referencing them in [`extends`](https://nuxt.com/docs/5.x/api/nuxt-config#extends), without renaming your directories. The entries are ordered like any other `extends` layer, with the **first entry having the highest priority**: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ '~~/layers/admin', // highest priority '~~/layers/features', '~~/layers/base', // lowest priority (among the listed layers) ], }) ``` Both `~~/...` (recommended) and `~/...` alias forms as well as relative paths (`./layers/admin`) are supported. Any layer in `~~/layers` that you do not list keeps its alphabetical auto-scan order, ranked below the layers you list in `extends`. ### When to Use Each - **~~/layers directory** - Use for local layers that are part of your project - **extends** - Use for external dependencies (npm packages, remote repositories) or layers outside your project directory ### Full Example with `extends` ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ '../base', // Local layer outside project '@my-themes/awesome', // NPM package 'github:my-themes/awesome#v1', // Remote repository ], }) ``` If you also have `~~/layers/custom`, the priority order is: - Your project files (highest) - `~~/layers/custom` - `../base` - `@my-themes/awesome` - `github:my-themes/awesome#v1` (lowest) <read-more to="https://nuxt.com/docs/5.x/directory-structure/layers"> Learn about the **layers/ directory** to organize and share reusable code, components, composables, and configurations across your Nuxt application. </read-more> <read-more to="https://nuxt.com/docs/5.x/guide/going-further/layers"> Read more about layers in the **Layer Author Guide**. </read-more> <video-accordion title="Watch a video from Learn Vue about Nuxt Layers" video-id="lnFCM7c9f7I"> </video-accordion> <video-accordion title="Watch a video from Alexander Lichter about Nuxt Layers" video-id="fr5yo3aVkfA"> </video-accordion> ## Example <card-group> <card icon="i-simple-icons-github" target="_blank" title="Content Wind" to="https://github.com/Atinux/content-wind"> A lightweight Nuxt theme to build a Markdown driven website. Powered by Nuxt Content, TailwindCSS and Iconify. </card> </card-group> # Prerendering > Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics Nuxt allows for select pages from your application to be rendered at build time. Nuxt will serve the prebuilt pages when requested instead of generating them on the fly. <read-more to="https://nuxt.com/docs/5.x/guide/concepts/rendering" title="Nuxt rendering modes"> </read-more> ## Crawl-based Pre-rendering Use the [`nuxt generate` command](https://nuxt.com/docs/5.x/api/commands/generate) to build and pre-render your application using the [Nitro](https://nuxt.com/docs/5.x/guide/concepts/server-engine) crawler. This command is similar to `nuxt build` with the `nitro.static` option set to `true`, or running `nuxt build --prerender`. This will build your site, stand up a nuxt instance, and, by default, prerender the root page `/` along with any of your site's pages it links to, any of your site's pages they link to, and so on. <code-group sync="pm"> ```bash [npm] npx nuxt generate ``` ```bash [yarn] yarn nuxt generate ``` ```bash [pnpm] pnpm nuxt generate ``` ```bash [bun] bun x nuxt generate ``` ```bash [deno] deno x nuxt generate ``` </code-group> You can now deploy the `.output/public` directory to any static hosting service or preview it locally with `npx serve .output/public`. Static and prerender builds also emit `200.html` and `404.html` SPA fallbacks. See [What are 200.html and 404.html?](https://nuxt.com/docs/5.x/guide/concepts/rendering#what-are-200html-and-404html). How the Nitro crawler works: 1. Load the HTML of your application's root route (`/`), any non-dynamic pages in your `~/pages` directory, and any other routes in the `nitro.prerender.routes` array. 2. Save the HTML and `_payload.json` to the `~/.output/public/` directory to be served statically. 3. Find all anchor tags (`<a href="...">`) in the HTML to navigate to other routes. 4. Repeat steps 1-3 for each anchor tag found until there are no more anchor tags to crawl. This is important to understand since pages that are not linked to a discoverable page can't be pre-rendered automatically. <read-more to="https://nuxt.com/docs/5.x/api/commands/generate#nuxt-generate"> Read more about the `nuxt generate` command. </read-more> ### Selective Pre-rendering You can manually specify routes that [Nitro](https://nuxt.com/docs/5.x/guide/concepts/server-engine) will fetch and pre-render during the build or ignore routes that you don't want to pre-render like `/dynamic` in the `nuxt.config` file: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { prerender: { routes: ['/user/1', '/user/2'], ignore: ['/dynamic'], }, }, }) ``` You can combine this with the `crawlLinks` option to pre-render a set of routes that the crawler can't discover like your `/sitemap.xml` or `/robots.txt`: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { prerender: { crawlLinks: true, routes: ['/sitemap.xml', '/robots.txt'], }, }, }) ``` Setting `nitro.prerender` to `true` is similar to `nitro.prerender.crawlLinks` to `true`. <read-more to="https://nitro.build/config#prerender"> Read more about pre-rendering in the Nitro documentation. </read-more> Lastly, you can manually configure this using routeRules. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Set prerender to true to configure it to be prerendered '/rss.xml': { prerender: true }, // Set it to false to configure it to be skipped for prerendering '/this-DOES-NOT-get-prerendered': { prerender: false }, // Everything under /blog gets prerendered as long as it // is linked to from another page '/blog/**': { prerender: true }, }, }) ``` <read-more to="https://nitro.build/config#routerules"> Read more about Nitro's `routeRules` configuration. </read-more> As a shorthand, you can also configure this in a page file using [`defineRouteRules`](https://nuxt.com/docs/5.x/api/utils/define-route-rules). <read-more to="https://nuxt.com/docs/5.x/guide/going-further/experimental-features#inlinerouterules" icon="i-lucide-star"> This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`. </read-more> ```vue [app/pages/index.vue] <script setup> // Or set at the page level defineRouteRules({ prerender: true, }) </script> <template> <div> <h1>Homepage</h1> <p>Pre-rendered at build time</p> </div> </template> ``` This will be translated to: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, }) ``` ## Payload Extraction When Nuxt renders a page on the server, it serializes the results of your data fetching ([`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch)) and app state ([`useState`](https://nuxt.com/docs/5.x/api/composables/use-state)) into a payload so the client can hydrate without re-fetching. With payload extraction enabled, Nuxt also writes this payload to a `_payload.json` file alongside the route's HTML: - Prerendered routes generate their payload file at build time. - Routes using [ISR or SWR caching](https://nuxt.com/docs/5.x/guide/concepts/rendering#hybrid-rendering) generate their payload file when the route is first rendered, even on a hybrid (non-static) site. During client-side navigation, Nuxt fetches the `_payload.json` file for the destination route and reuses the extracted data instead of running the data fetching again in the browser. You can control this behavior with the [`experimental.payloadExtraction`](https://nuxt.com/docs/5.x/api/nuxt-config#payloadextraction) option: - `'client'` - The payload is inlined in the HTML for the initial render and extracted to `_payload.json` files for client-side navigation. There is no extra network request on first load. - `true` - The payload is extracted to a separate `_payload.json` file for both the initial render and client-side navigation. The HTML is smaller and the payload file can be cached by a CDN, at the cost of one extra request on first load. - `false` - Payload extraction is disabled. The payload is always inlined in the HTML and no `_payload.json` files are generated. The default is `true`, or `'client'` when `compatibilityVersion: 5` is set. It is forced to `false` when `ssr: false` is set. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { payloadExtraction: 'client', }, }) ``` A few practical consequences to be aware of: - On a fully static site, client-side navigation reuses the data captured at build time, so data can be stale until the next rebuild. - For ISR/SWR routes, CDNs can cache payload files alongside the HTML, improving client-side navigation performance for cached routes. Dynamic routes like `pages/[...slug].vue` can opt in with glob patterns such as `'/**': { isr: true }`. - Payloads are serialized with [devalue](https://github.com/Rich-Harris/devalue), so custom types (such as class instances) need payload plugins with custom reducers and revivers to survive the round trip. <read-more to="https://nuxt.com/docs/5.x/api/composables/use-nuxt-app#payload" title="Payload reducers and revivers"> </read-more> ## Runtime Prerender Configuration ### `prerenderRoutes` You can use this at runtime within a [Nuxt context](https://nuxt.com/docs/5.x/guide/going-further/nuxt-app#the-nuxt-context) to add more routes for Nitro to prerender. ```vue [app/pages/index.vue] <script setup> prerenderRoutes(['/some/other/url']) prerenderRoutes('/api/content/article/my-article') </script> <template> <div> <h1>This will register other routes for prerendering when prerendered</h1> </div> </template> ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/prerender-routes" title="prerenderRoutes"> </read-more> ### `prerender:routes` Nuxt hook This is called before prerendering for additional routes to be registered. ```ts [nuxt.config.ts] export default defineNuxtConfig({ hooks: { async 'prerender:routes' (ctx) { const { pages } = await fetch('https://api.some-cms.com/pages').then( res => res.json(), ) for (const page of pages) { ctx.routes.add(`/${page.name}`) } }, }, }) ``` ### `prerender:generate` Nitro hook This is called for each route during prerendering. You can use this for fine-grained handling of each route that gets prerendered. ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { hooks: { 'prerender:generate' (route) { if (route.route?.includes('private')) { route.skip = true } }, }, }, }) ``` # Routing > Nuxt file-system routing creates a route for every file in the pages/ directory. One core feature of Nuxt is the file system router. Every Vue file inside the [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) directory creates a corresponding URL (or route) that displays the contents of the file. By using dynamic imports for each page, Nuxt leverages code-splitting to ship the minimum amount of JavaScript for the requested route. <note> Code-splitting is enabled by default and is recommended for most apps. If you have a specific reason to ship a single bundle instead, you can disable it in your [`nuxt.config`](https://nuxt.com/docs/5.x/api/nuxt-config): ```ts [nuxt.config.ts] export default defineNuxtConfig({ vite: { $client: { build: { rolldownOptions: { output: { codeSplitting: false, }, }, }, }, }, }) ``` This ships all JavaScript in a single file. It is rarely beneficial โ€” it usually increases the initial download, even on slow connections โ€” so only disable code-splitting if you have measured that it helps your case. </note> ## Pages Nuxt routing is based on [vue-router](https://router.vuejs.org) and generates the routes from every component created in the [`app/pages/` directory](https://nuxt.com/docs/5.x/directory-structure/app/pages), based on their filename. This file system routing uses naming conventions to create dynamic and nested routes: <code-group> ```bash [Directory Structure] -| pages/ ---| about.vue ---| index.vue ---| posts/ -----| [id].vue ``` ```json [Generated Router File] { "routes": [ { "path": "/about", "component": "pages/about.vue" }, { "path": "/", "component": "pages/index.vue" }, { "path": "/posts/:id", "component": "pages/posts/[id].vue" } ] } ``` </code-group> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/pages"> </read-more> ## Navigation The [`<NuxtLink>`](https://nuxt.com/docs/5.x/api/components/nuxt-link) component links pages between them. It renders an `<a>` tag with the `href` attribute set to the route of the page. Once the application is hydrated, page transitions are performed in JavaScript by updating the browser URL. This prevents full-page refreshes and allows for animated transitions. When a [`<NuxtLink>`](https://nuxt.com/docs/5.x/api/components/nuxt-link) enters the viewport on the client side, Nuxt will automatically prefetch components and payload (generated pages) of the linked pages ahead of time, resulting in faster navigation. ```vue [app/pages/index.vue] <template> <header> <nav> <ul> <li><NuxtLink to="/about">About</NuxtLink></li> <li><NuxtLink to="/posts/1">Post 1</NuxtLink></li> <li><NuxtLink to="/posts/2">Post 2</NuxtLink></li> </ul> </nav> </header> </template> ``` <read-more to="https://nuxt.com/docs/5.x/api/components/nuxt-link"> </read-more> ## Route Parameters The [`useRoute()`](https://nuxt.com/docs/5.x/api/composables/use-route) composable can be used in a `<script setup>` block or a `setup()` method of a Vue component to access the current route details. ```vue [pages/posts/[id].vue]twoslash <script setup lang="ts"> const route = useRoute() // When accessing /posts/1, route.params.id will be 1 console.log(route.params.id) </script> ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-route"> </read-more> ## Route Middleware Nuxt provides a customizable route middleware framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route. <note> Route middleware runs within the Vue part of your Nuxt app. Despite the similar name, they are completely different from server middleware, which are run in the Nitro server part of your app. </note> <important> Route middleware does **not** run for server routes (e.g. `/api/*`) or other server requests. To apply middleware to these requests, use [server middleware](https://nuxt.com/docs/5.x/directory-structure/server#server-middleware) instead. </important> There are three kinds of route middleware: 1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used. 2. Named route middleware, which are placed in the [`app/middleware/`](https://nuxt.com/docs/5.x/directory-structure/app/middleware) directory and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.) 3. Global route middleware, which are placed in the [`app/middleware/`](https://nuxt.com/docs/5.x/directory-structure/app/middleware) directory (with a `.global` suffix) and will be automatically run on every route change. Example of an `auth` middleware protecting the `/dashboard` page: <code-group> ```ts [middleware/auth.ts]twoslash function isAuthenticated (): boolean { return false } // ---cut--- export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (isAuthenticated() === false) { return navigateTo('/login') } }) ``` ```vue [pages/dashboard.vue]twoslash <script setup lang="ts"> definePageMeta({ middleware: 'auth', }) </script> <template> <h1>Welcome to your dashboard</h1> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/middleware"> </read-more> ## Route Validation Nuxt offers route validation via the `validate` property in [`definePageMeta()`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) in each page you wish to validate. The `validate` property accepts the `route` as an argument. You can return a boolean value to determine whether or not this is a valid route to be rendered with this page. If you return `false`, this will cause a 404 error. You can also directly return an object with `status`/`statusText` to customize the error returned. If you have a more complex use case, then you can use anonymous route middleware instead. ```vue [pages/posts/[id].vue]twoslash <script setup lang="ts"> definePageMeta({ validate (route) { // Check if the id is made up of digits return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id) }, }) </script> ``` <read-more to="https://nuxt.com/docs/5.x/api/utils/define-page-meta"> </read-more> # SEO and Meta > Improve your Nuxt app's SEO with powerful head config, composables and components. Nuxt head tag management is powered by [Unhead](https://unhead.unjs.io). It provides sensible defaults, several powerful composables and numerous configuration options to manage your app's head and SEO meta tags. ## Nuxt Config Providing an [`app.head`](https://nuxt.com/docs/5.x/api/nuxt-config#head) property in your [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) allows you to statically customize the head for your entire app. <important> This method does not allow you to provide reactive data. We recommend using `useHead()` in `app.vue`. </important> It's good practice to set tags here that won't change such as your site title default, language and favicon. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { title: 'Nuxt', // default fallback title htmlAttrs: { lang: 'en', }, link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, ], }, }, }) ``` <note> When you set [`app.cdnURL`](https://nuxt.com/docs/5.x/api/nuxt-config#cdnurl), assets in your [`public/`](https://nuxt.com/docs/5.x/directory-structure/public) directory (including `favicon.ico`) are served from that CDN. Nuxt resolves public assets against `cdnURL`, falling back to `app.baseURL`. However, a static `app.head` link such as `href: '/favicon.ico'` above is a literal path and is **not** resolved against `cdnURL`. To point the favicon at the resolved location, build the `href` from runtime config with [`useHead()`](https://nuxt.com/docs/5.x/api/composables/use-head) in `app.vue`: ```vue [app/app.vue] <script setup lang="ts"> const { cdnURL, baseURL } = useRuntimeConfig().app useHead({ link: [ { rel: 'icon', type: 'image/x-icon', href: `${cdnURL || baseURL}favicon.ico` }, ], }) </script> ``` </note> You can also provide any of the keys listed below in [Types](https://nuxt.com/docs/5.x/getting-started/seo-meta#types). ### Default Tags Some tags are provided by Nuxt by default to ensure your website works well out of the box. - `viewport`: `width=device-width, initial-scale=1` - `charset`: `utf-8` While most sites won't need to override these defaults, you can update them using the keyed shortcuts. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { // update Nuxt defaults charset: 'utf-16', viewport: 'width=device-width, initial-scale=1, maximum-scale=1', }, }, }) ``` ## `useHead` The [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable function supports reactive input, allowing you to manage your head tags programmatically. ```vue [app/app.vue]twoslash <script setup lang="ts"> useHead({ title: 'My App', meta: [ { name: 'description', content: 'My amazing site.' }, ], bodyAttrs: { class: 'test', }, script: [{ innerHTML: 'console.log(\'Hello world\')' }], }) </script> ``` We recommend taking a look at the [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) and [`useHeadSafe`](https://nuxt.com/docs/5.x/api/composables/use-head-safe) composables. ## `useSeoMeta` The [`useSeoMeta`](https://nuxt.com/docs/5.x/api/composables/use-seo-meta) composable lets you define your site's SEO meta tags as an object with full type safety. This helps you avoid typos and common mistakes, such as using `name` instead of `property`. ```vue [app/app.vue]twoslash <script setup lang="ts"> useSeoMeta({ title: 'My Amazing Site', ogTitle: 'My Amazing Site', description: 'This is my amazing site, let me tell you all about it.', ogDescription: 'This is my amazing site, let me tell you all about it.', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script> ``` <read-more to="https://nuxt.com/docs/5.x/api/composables/use-seo-meta"> </read-more> ## Components While using [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) is recommended in all cases, you may have a personal preference for defining your head tags in your template using components. Nuxt provides the following components for this purpose: `<Title>`, `<Base>`, `<NoScript>`, `<Style>`, `<Meta>`, `<Link>`, `<Body>`, `<Html>` and `<Head>`. Note the capitalization of these components ensuring we don't use invalid native HTML tags. `<Head>` and `<Body>` can accept nested meta tags (for aesthetic reasons) but this does not affect *where* the nested meta tags are rendered in the final HTML. ```vue [app/app.vue] <script setup lang="ts"> const title = ref('Hello World') </script> <template> <div> <Head> <Title>{{ title }}

{{ title }}

``` It's suggested to wrap your components in either a `` or `` component as tags will be deduped more intuitively. If you need to duplicate tags across client-server boundaries, apply a `key` attribute on the `` component. ## Types Below are the non-reactive types used for [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head), [`app.head`](https://nuxt.com/docs/5.x/api/nuxt-config#head) and components. ```ts [Types] interface MetaObject { title?: string titleTemplate?: string | ((title?: string) => string) templateParams?: Record> base?: Base link?: Link[] meta?: Meta[] style?: Style[] script?: Script[] noscript?: Noscript[] htmlAttrs?: HtmlAttributes bodyAttrs?: BodyAttributes } ``` See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types. ## Features ### Reactivity Reactivity is supported on all properties, by providing a computed value, a getter, or a reactive object. ```vue [useHead]twoslash ``` ```vue [useSeoMeta]twoslash ``` ```vue [app/Components] ``` ### Title Template You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site. For example, you could add the name of your site to the title of every page. The `titleTemplate` can either be a string, where `%s` is replaced with the title, or a function. If you want to use a function (for full control), then this cannot be set in your `nuxt.config`. It is recommended instead to set it within your `app.vue` file where it will apply to all pages on your site: ```vue [useHead]twoslash ``` Now, if you set the title to `My Page` with [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to 'Site Title'. ### Template Parameters You can use `templateParams` to provide additional placeholders in your `titleTemplate` besides the default `%s`. This allows for more dynamic title generation. ```vue [useHead]twoslash ``` ### Body Tags You can use the `tagPosition: 'bodyClose'` option on applicable tags to append them to the end of the `` tag. For example: ```vuetwoslash ``` ## Example ### With `definePageMeta` Within your [`app/pages/` directory](https://nuxt.com/docs/5.x/directory-structure/app/pages), you can use `definePageMeta` along with [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) to set metadata based on the current route. For example, you can first set the current page title (this is extracted at build time via a macro, so it can't be set dynamically): ```vue [pages/some-page.vue]twoslash ``` And then in your layout file, you might use the route's metadata you have previously set: ```vue [layouts/default.vue]twoslash ``` ### Dynamic Title In the example below, `titleTemplate` is set either as a string with the `%s` placeholder or as a `function`, which allows greater flexibility in setting the page title dynamically for each route of your Nuxt app: ```vue [app/app.vue]twoslash ``` ```vue [app/app.vue]twoslash ``` `nuxt.config` is also used as an alternative way of setting the page title. However, `nuxt.config` does not allow the page title to be dynamic. Therefore, it is recommended to use `titleTemplate` in the `app.vue` file to add a dynamic title, which is then applied to all routes of your Nuxt app. ### External CSS The example below shows how you might enable Google Fonts using either the `link` property of the [`useHead`](https://nuxt.com/docs/5.x/api/composables/use-head) composable or using the `` component: ```vue [useHead]twoslash ``` ```vue [app/Components] ``` # Server > Build full-stack applications with Nuxt's server framework. You can fetch data from your database or another server, create APIs, or even generate static server-side content like a sitemap or a RSS feed - all from a single codebase. ## Powered by Nitro ![Server engine](https://nuxt.com/assets/docs/getting-started/server.svg) Nuxt's server is [Nitro](https://github.com/nitrojs/nitro). It was originally created for Nuxt but is now part of [UnJS](https://unjs.io) and open for other frameworks - and can even be used on its own. Using Nitro gives Nuxt superpowers: - Full control of the server-side part of your app - Universal deployment on any provider (many zero-config) - Hybrid rendering Nitro is internally using [h3](https://github.com/h3js/h3), a minimal H(TTP) framework built for high performance and portability. ## Server Endpoints & Middleware You can easily manage the server-only part of your Nuxt app, from API endpoints to middleware. Both endpoints and middleware can be defined like this: ```ts [server/api/test.ts]twoslash import { defineEventHandler } from 'nuxt/server' export default defineEventHandler(async (event) => { // ... Do whatever you want here }) ``` And you can directly return `text`, `json`, `html` or even a `stream`. Out-of-the-box, it supports **hot module replacement** and **auto-import** like the other parts of your Nuxt application. ## Universal Deployment Nitro offers the ability to deploy your Nuxt app anywhere, from a bare metal server to the edge network, with a start time of just a few milliseconds. That's fast! There are more than 15 presets to build your Nuxt app for different cloud providers and servers, including: - [Cloudflare Workers](https://workers.cloudflare.com) - [Netlify Functions](https://www.netlify.com/platform/core/functions/) - [Vercel Cloud](https://vercel.com/home) Or for other runtimes: ## Hybrid Rendering Nitro has a powerful feature called `routeRules` which allows you to define a set of rules to customize how each route of your Nuxt app is rendered (and more). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Generated at build time for SEO purpose '/': { prerender: true }, // Cached for 1 hour '/api/*': { cache: { maxAge: 60 * 60 } }, // Redirection to avoid 404 '/old-page': { redirect: { to: '/new-page', status: 302 }, }, // ... }, }) ``` Learn about all the route rules available to customize the rendering mode of your routes. In addition, there are some route rules (for example, `ssr`, `appMiddleware`, and `noScripts`) that are Nuxt specific to change the behavior when rendering your pages to HTML. Some route rules (`appMiddleware`, `redirect` and `prerender`) also affect client-side behavior. Nitro is used to build the app for server side rendering, as well as pre-rendering. # State Management > Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state. Nuxt provides the [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) composable to create a reactive and SSR-friendly shared state across components. [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) is an SSR-friendly [`ref`](https://vuejs.org/api/reactivity-core#ref) replacement. Its value will be preserved after server-side rendering (during client-side hydration) and shared across all components using a unique key. Because the data inside [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. Read more about `useState` composable. ## Best Practices Never define `const state = ref()` outside of ` ``` To globally invalidate cached state, see [`clearNuxtState`](https://nuxt.com/docs/5.x/api/utils/clear-nuxt-state) util. ### Initializing State Most of the time, you will want to initialize your state with data that resolves asynchronously. You can use the [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app) component with the [`callOnce`](https://nuxt.com/docs/5.x/api/utils/call-once) util to do so. ```vue [app/app.vue]twoslash ``` This is similar to the [`nuxtServerInit` action](https://v2.nuxt.com/docs/directory-structure/store/#the-nuxtserverinit-action) in Nuxt 2, which allows filling the initial state of your store server-side before rendering the page. ### Usage with Pinia In this example, we leverage the [Pinia module](https://nuxt.com/modules/pinia) to create a global store and use it across the app. Make sure to install the Pinia module with `npx nuxt module add pinia` or follow the [module's installation steps](https://pinia.vuejs.org/ssr/nuxt.html#Installation). ```ts [app/stores/website.ts] export const useWebsiteStore = defineStore('websiteStore', { state: () => ({ name: '', description: '', }), actions: { async fetch () { const infos = await $fetch('https://api.nuxt.com/modules/pinia') this.name = infos.name this.description = infos.description }, }, }) ``` ```vue [app/app.vue] ``` ## Advanced Usage ```ts [app/composables/locale.ts] import type { Ref } from 'vue' export const useLocale = () => { return useState('locale', () => useDefaultLocale().value) } export const useDefaultLocale = (fallback = 'en-US') => { const locale = ref(fallback) if (import.meta.server) { const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0] if (reqLocale) { locale.value = reqLocale } } else if (import.meta.client) { const navLang = navigator.language if (navLang) { locale.value = navLang } } return locale } export const useLocales = () => { const locale = useLocale() const locales = ref([ 'en-US', 'en-GB', // ..., 'ja-JP-u-ca-japanese', ]) if (!locales.value.includes(locale.value)) { locales.value.unshift(locale.value) } return locales } export const useLocaleDate = (date: Ref | Date, locale = useLocale()) => { return computed(() => new Intl.DateTimeFormat(locale.value, { dateStyle: 'full' }).format(unref(date))) } ``` ```vue [app/app.vue] ``` ## Shared State By using [auto-imported composables](https://nuxt.com/docs/5.x/directory-structure/app/composables) we can define global type-safe states and import them across the app. ```ts [composables/states.ts]twoslash export const useColor = () => useState('color', () => 'pink') ``` ```vue [app/app.vue] ``` ## Using Third-Party Libraries Nuxt **used to rely** on the Vuex library to provide global state management. If you are migrating from Nuxt 2, please head to [the migration guide](https://nuxt.com/docs/5.x/migration/configuration#vuex). Nuxt is not opinionated about state management, so feel free to choose the right solution for your needs. There are multiple integrations with the most popular state management libraries, including: - [Pinia](https://nuxt.com/modules/pinia) - the official Vue recommendation - [Harlem](https://nuxt.com/modules/harlem) - immutable global state management - [XState](https://nuxt.com/modules/xstate) - state machine approach with tools for visualizing and testing your state logic # Styling > Learn how to style your Nuxt application. Nuxt is highly flexible when it comes to styling. Write your own styles, or reference local and external stylesheets. You can use CSS preprocessors, CSS frameworks, UI libraries and Nuxt modules to style your application. ## Local Stylesheets If you're writing local stylesheets, the natural place to put them is the [`app/assets/` directory](https://nuxt.com/docs/5.x/directory-structure/app/assets). ### Importing Within Components You can import stylesheets in your pages, layouts and components directly. You can use a JavaScript import, or a CSS [`@import` statement](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@import). ```vue [app/pages/index.vue] ``` The stylesheets will be inlined in the HTML rendered by Nuxt. ### The CSS Property You can also use the `css` property in the Nuxt configuration. The natural place for your stylesheets is the [`app/assets/` directory](https://nuxt.com/docs/5.x/directory-structure/app/assets). You can then reference its path and Nuxt will include it to all the pages of your application. ```ts [nuxt.config.ts] export default defineNuxtConfig({ css: ['~/assets/css/main.css'], }) ``` The stylesheets will be inlined in the HTML rendered by Nuxt, injected globally and present in all pages. ### Working With Fonts Place your local fonts files in your `public/` directory, for example in `public/fonts`. You can then reference them in your stylesheets using `url()`. ```css [assets/css/main.css] @font-face { font-family: 'FarAwayGalaxy'; src: url('/fonts/FarAwayGalaxy.woff') format('woff'); font-weight: normal; font-style: normal; font-display: swap; } ``` Then reference your fonts by name in your stylesheets, pages or components: ```vue ``` ### Stylesheets Distributed Through NPM You can also reference stylesheets that are distributed through npm. Let's use the popular `animate.css` library as an example. ```bash [npm] npm install animate.css ``` ```bash [yarn] yarn add animate.css ``` ```bash [pnpm] pnpm install animate.css ``` ```bash [bun] bun install animate.css ``` ```bash [deno] deno install npm:animate.css ``` Then you can reference it directly in your pages, layouts and components: ```vue [app/app.vue] ``` The package can also be referenced as a string in the css property of your Nuxt configuration. ```ts [nuxt.config.ts] export default defineNuxtConfig({ css: ['animate.css'], }) ``` ## External Stylesheets You can include external stylesheets in your application by adding a link element in the head section of your nuxt.config file. You can achieve this result using different methods. Note that local stylesheets can also be included this way. You can manipulate the head with the [`app.head`](https://nuxt.com/docs/5.x/api/nuxt-config#head) property of your Nuxt configuration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }], }, }, }) ``` ### Dynamically Adding Stylesheets You can use the useHead composable to dynamically set a value in your head in your code. ```tstwoslash useHead({ link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }], }) ``` Nuxt uses `unhead` under the hood, and you can refer to [its full documentation](https://unhead.unjs.io). ### Modifying The Rendered Head With A Nitro Plugin If you need more advanced control, you can intercept the rendered html with a hook and modify the head programmatically. Create a plugin in `~~/server/plugins/my-plugin.ts` like this: ```ts [server/plugins/my-plugin.ts] import { definePlugin } from 'nitro' export default definePlugin((nitro) => { nitro.hooks.hook('render:html', (html) => { html.head.push('') }) }) ``` External stylesheets are render-blocking resources: they must be loaded and processed before the browser renders the page. Web pages that contain unnecessarily large styles take longer to render. You can read more about it on [web.dev](https://web.dev/articles/defer-non-critical-css). ## Using Preprocessors To use a preprocessor like SCSS, Sass, Less or Stylus, install it first. ```bash [Sass & SCSS] npm install -D sass ``` ```bash [Less] npm install -D less ``` ```bash [Stylus] npm install -D stylus ``` The natural place to write your stylesheets is the `app/assets` directory. You can then import your source files in your `app.vue` (or layouts files) using your preprocessor's syntax. ```vue [app/pages/app.vue] ``` Alternatively, you can use the `css` property of your Nuxt configuration. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ css: ['~/assets/scss/main.scss'], }) ``` In both cases, the compiled stylesheets will be inlined in the HTML rendered by Nuxt. If you need to inject code in pre-processed files, like a [Sass partial](https://sass-lang.com/documentation/at-rules/use/#partials) with color variables, you can do so with the Vite [preprocessors options](https://vite.dev/config/shared-options#css-preprocessoroptions). Create some partials in your `app/assets` directory: ```scss [assets/_colors.scss] $primary: #49240F; $secondary: #E4A79D; ``` ```sass [assets/_colors.sass] $primary: #49240F $secondary: #E4A79D ``` Then in your `nuxt.config` : ```ts [SCSS]twoslash export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { scss: { additionalData: '@use "~/assets/_colors.scss" as *;', }, }, }, }, }) ``` ```ts [SASS]twoslash export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { sass: { additionalData: '@use "~/assets/_colors.sass" as *\n', }, }, }, }, }) ``` Nuxt uses Vite by default. If you wish to use webpack instead, refer to each preprocessor loader [documentation](https://webpack.js.org/loaders/sass-loader/). ### Preprocessor Workers (Experimental) Vite has made available an [experimental option](https://vite.dev/config/shared-options#css-preprocessormaxworkers) which can speed up using preprocessors. You can enable this in your `nuxt.config`: ```ts export default defineNuxtConfig({ vite: { css: { preprocessorMaxWorkers: true, // number of CPUs minus 1 }, }, }) ``` This is an experimental option and you should refer to the Vite documentation and [provide feedback](https://github.com/vitejs/vite/discussions/15835). ## Single File Components (SFC) Styling One of the best things about Vue and SFC is how great it is at naturally dealing with styling. You can directly write CSS or preprocessor code in the style block of your components file, therefore you will have a fantastic developer experience without having to use something like CSS-in-JS. However if you wish to use CSS-in-JS, you can find 3rd party libraries and modules that support it, such as [pinceau](https://github.com/Tahul/pinceau). You can refer to the [Vue docs](https://vuejs.org/api/sfc-css-features) for a comprehensive reference about styling components in SFC. ### Class And Style Bindings You can leverage Vue SFC features to style your components with class and style attributes. ```vue [Ref and Reactive] ``` ```vue [Computed] ``` ```vue [Array] ``` ```vue [Style] ``` Refer to the [Vue docs](https://vuejs.org/guide/essentials/class-and-style) for more information. ### Dynamic Styles With `v-bind` You can reference JavaScript variables and expressions within your style blocks with the v-bind function. The binding will be dynamic, meaning that if the variable value changes, the style will be updated. ```vue ``` ### Scoped Styles The scoped attribute allows you to style components in isolation. The styles declared with this attribute will only apply to this component. ```vue ``` ### CSS Modules You can use [CSS Modules](https://github.com/css-modules/css-modules) with the module attribute. Access it with the injected `$style` variable. ```vue ``` ### Preprocessors Support SFC style blocks support preprocessor syntax. Vite comes with built-in support for .scss, .sass, .less, .styl and .stylus files without configuration. You just need to install them first, and they will be available directly in SFC with the lang attribute. ```vue [SCSS] ``` ```vue [Sass] ``` ```vue [LESS] ``` ```vue [Stylus] ``` You can refer to the [Vite CSS docs](https://vite.dev/guide/features#css) and the [@vitejs/plugin-vue docs](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue). For webpack users, refer to the [vue loader docs](https://vue-loader.vuejs.org). ## Using PostCSS Nuxt comes with postcss built-in. You can configure it in your `nuxt.config` file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ postcss: { plugins: { 'postcss-nested': {}, 'postcss-custom-media': {}, }, }, }) ``` For proper syntax highlighting in SFC, you can use the postcss lang attribute. ```vue ``` By default, Nuxt comes with the following plugins already pre-configured: - [postcss-import](https://github.com/postcss/postcss-import): Improves the `@import` rule - [postcss-url](https://github.com/postcss/postcss-url): Transforms `url()` statements - [autoprefixer](https://github.com/postcss/autoprefixer): Automatically adds vendor prefixes - [cssnano](https://cssnano.github.io/cssnano/): Minification and purge ## Leveraging Layouts For Multiple Styles If you need to style different parts of your application completely differently, you can use layouts. Use different styles for different layouts. ```vue ``` ## Third Party Libraries And Modules Nuxt isn't opinionated when it comes to styling and provides you with a wide variety of options. You can use any styling tool that you want, such as popular libraries like [UnoCSS](https://unocss.dev) or [Tailwind CSS](https://tailwindcss.com). The community and the Nuxt team have developed plenty of Nuxt modules to make the integration easier. You can discover them on the [modules section](https://nuxt.com/modules) of the website. Here are a few modules to help you get started: - [UnoCSS](https://nuxt.com/modules/unocss): Instant on-demand atomic CSS engine - [Tailwind CSS](https://nuxt.com/modules/tailwindcss): Utility-first CSS framework - [Fontaine](https://github.com/nuxt-modules/fontaine): Font metric fallback - [Pinceau](https://github.com/Tahul/pinceau): Adaptable styling framework - [Nuxt UI](https://ui.nuxt.com): A UI Library for Modern Web Apps - [Panda CSS](https://panda-css.com/docs/installation/nuxt): CSS-in-JS engine that generates atomic CSS at build time Nuxt modules provide you with a good developer experience out of the box, but remember that if your favorite tool doesn't have a module, it doesn't mean that you can't use it with Nuxt! You can configure it yourself for your own project. Depending on the tool, you might need to use a [Nuxt plugin](https://nuxt.com/docs/5.x/directory-structure/app/plugins) and/or [make your own module](https://nuxt.com/docs/5.x/guide/modules). Share them with the [community](https://nuxt.com/modules) if you do! ### Easily Load Webfonts You can use [the Nuxt Google Fonts module](https://github.com/nuxt-modules/google-fonts) to load Google Fonts. If you are using [UnoCSS](https://unocss.dev/integrations/nuxt), note that it comes with a [web fonts presets](https://unocss.dev/presets/web-fonts) to conveniently load fonts from common providers, including Google Fonts and more. ## Advanced ### Transitions Nuxt comes with the same `` element that Vue has, and also has support for the experimental [View Transitions API](https://nuxt.com/docs/5.x/getting-started/transitions#view-transitions-api-experimental). ### Font Advanced Optimization We would recommend using [Fontaine](https://github.com/nuxt-modules/fontaine) to reduce your [CLS](https://web.dev/articles/cls). If you need something more advanced, consider creating a Nuxt module to extend the build process or the Nuxt runtime. Always remember to take advantage of the various tools and techniques available in the Web ecosystem at large to make styling your application easier and more efficient. Whether you're using native CSS, a preprocessor, postcss, a UI library or a module, Nuxt has got you covered. Happy styling! ### LCP Advanced Optimizations You can do the following to speed-up the download of your global CSS files: - Use a CDN so the files are physically closer to your users - Compress your assets, ideally using Brotli - Use HTTP2/HTTP3 for delivery - Host your assets on the same domain (do not use a different subdomain) Most of these things should be done for you automatically if you're using modern platforms like Cloudflare, Netlify or Vercel. You can find an LCP optimization guide on [web.dev](https://web.dev/articles/optimize-lcp). If all of your CSS is inlined by Nuxt, you can (experimentally) completely stop external CSS files from being referenced in your rendered HTML. You can achieve that with a hook, that you can place in a module, or in your Nuxt configuration file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ hooks: { 'build:manifest': (manifest) => { // find the app entry, css list const css = Object.values(manifest).find(options => options.isEntry)?.css if (css) { // start from the end of the array and go to the beginning for (let i = css.length - 1; i >= 0; i--) { // if it starts with 'entry', remove it from the list if (css[i].startsWith('entry')) { css.splice(i, 1) } } } }, }, }) ``` # Testing > How to test your Nuxt application. If you are a module author, you can find more specific information in the [Module Author's guide](https://nuxt.com/docs/5.x/guide/modules/testing). Nuxt offers first-class support for end-to-end and unit testing of your Nuxt application via `@nuxt/test-utils`, a library of test utilities and configuration that currently powers the [tests we use on Nuxt itself](https://github.com/nuxt/nuxt/tree/main/test) and tests throughout the module ecosystem. ## Installation In order to allow you to manage your other testing dependencies, `@nuxt/test-utils` ships with various optional peer dependencies. For example: - you can choose between `happy-dom` and `jsdom` for a runtime Nuxt environment - you can choose between `vitest`, `cucumber`, `jest` and `playwright` for end-to-end test runners - `playwright-core` is only required if you wish to use the built-in browser testing utilities (and are not using `@playwright/test` as your test runner) ```bash [npm] npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [yarn] yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [pnpm] pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [bun] bun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ## Unit Testing We currently ship an environment for unit testing code that needs a [Nuxt](https://nuxt.com) runtime environment. It currently *only has support for vitest* (although contribution to add other runtimes would be welcome). ### Setup 1. Add `@nuxt/test-utils/module` to your `nuxt.config` file (optional). It adds a Vitest integration to your Nuxt DevTools which supports running your unit tests in development.```tstwoslash export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], }) ``` 2. Create a `vitest.config.ts` with the following content:```tstwoslash import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/unit/*.{test,spec}.ts'], environment: 'node', }, }, { test: { name: 'e2e', include: ['test/e2e/*.{test,spec}.ts'], environment: 'node', }, }, await defineVitestProject({ test: { name: 'nuxt', include: ['test/nuxt/*.{test,spec}.ts'], environment: 'nuxt', }, }), ], }, }) ``` `defineVitestProject` is only for Nuxt-environment tests. End-to-end tests should be configured as a regular `test.environment: 'node'` project. 3. If your Nuxt-environment tests live outside `test/nuxt/`, see [TypeScript Support in Tests](#typescript-support-in-tests) to add them to the TypeScript context. When importing `@nuxt/test-utils` in your vitest config, it is necessary to have `"type": "module"` specified in your `package.json` or rename your vitest config file appropriately. > i.e., `vitest.config.m{ts,js}`. It is possible to set environment variables for testing by using the `.env.test` file. ### Using a Nuxt Runtime Environment Using [Vitest projects](https://vitest.dev/guide/projects.html#test-projects), you have fine-grained control over which tests run in which environment: - **Unit tests**: Place regular unit tests in `test/unit/` - these run in a Node environment for speed - **Nuxt tests**: Place tests that rely on the Nuxt runtime environment in `test/nuxt/` - these will run within a Nuxt runtime environment #### Alternative: Simple Setup If you prefer a simpler setup and want all tests to run in the Nuxt environment, you can use the basic configuration: ```tstwoslash import { defineVitestConfig } from '@nuxt/test-utils/config' import { fileURLToPath } from 'node:url' export default defineVitestConfig({ test: { environment: 'nuxt', // you can optionally set Nuxt-specific environment options // environmentOptions: { // nuxt: { // rootDir: fileURLToPath(new URL('./playground', import.meta.url)), // domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom' // overrides: { // // other Nuxt config you want to pass // } // } // } }, }) ``` If you're using the simple setup with `environment: 'nuxt'` by default, you can opt *out* of the [Nuxt environment](https://vitest.dev/guide/environment.html#test-environment) per test file as needed. ```tstwoslash // @vitest-environment node import { test } from 'vitest' test('my test', () => { // ... test without Nuxt environment! }) ``` This approach is not recommended as it creates a hybrid environment where Nuxt Vite plugins run but the Nuxt entry and `nuxtApp` are not initialized. This can lead to hard-to-debug errors. ### Organizing Your Tests With the project-based setup, you might organize your tests as follows: ```bash [Directory structure] test/ โ”œโ”€โ”€ e2e/ โ”‚ โ””โ”€โ”€ ssr.test.ts โ”œโ”€โ”€ nuxt/ โ”‚ โ”œโ”€โ”€ components.test.ts โ”‚ โ””โ”€โ”€ composables.test.ts โ”œโ”€โ”€ unit/ โ”‚ โ””โ”€โ”€ utils.test.ts ``` You can of course opt for any test structure, but keeping the Nuxt runtime environment separated from Nuxt end-to-end tests is important for test stability. #### TypeScript Support in Tests By default, test files in `test/nuxt/` and `tests/nuxt/` directories are included in the [Nuxt app TypeScript context](https://nuxt.com/docs/5.x/guide/concepts/typescript#how-nuxt-uses-project-references). That means they will recognise Nuxt aliases (like `~/`, `@/`, `#imports`) and TypeScript will be aware of auto-imports that work in your Nuxt app. This matches the recommended structure where only tests that need the Nuxt runtime environment are placed in these directories. Unit tests in other directories like `test/unit/` can be added manually if needed. ##### Adding other test directories If you have tests in other directories that you will be running in the Nuxt Vitest environment, you can include them in the Nuxt app TypeScript context by adding them to your configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ typescript: { tsConfig: { include: [ // this path is relative to the generated .nuxt/tsconfig.json '../test/other-nuxt-context/**/*', ], }, }, }) ``` Unit tests should not depend on Nuxt runtime features like auto-imports or composables. Only add TypeScript path alias support if your tests import from your source files (e.g., `~/utils/helpers`), not for Nuxt-specific features. #### Running Tests With the project setup, you can run different test suites: ```bash # Run all tests npx vitest # Run only unit tests npx vitest --project unit # Run only Nuxt tests npx vitest --project nuxt # Run tests in watch mode npx vitest --watch ``` When you run your tests within the Nuxt environment, they will be running in a [`happy-dom`](https://github.com/capricorn86/happy-dom) or [`jsdom`](https://github.com/jsdom/jsdom) environment. Before your tests run, a global Nuxt app will be initialized (including, for example, running any plugins or code you've defined in your `app.vue`). This means you should take particular care not to mutate the global state in your tests (or, if you need to, to reset it afterwards). ### ๐ŸŽญ Built-In Mocks `@nuxt/test-utils` provides some built-in mocks for the DOM environment. #### `intersectionObserver` Default `true`, creates a dummy class without any functionality for the IntersectionObserver API #### `indexedDB` Default `false`, uses [`fake-indexeddb`](https://github.com/dumbmatter/fakeIndexedDB) to create a functional mock of the IndexedDB API These can be configured in the `environmentOptions` section of your `vitest.config.ts` file: ```tstwoslash import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ test: { environmentOptions: { nuxt: { mock: { intersectionObserver: true, indexedDb: true, }, }, }, }, }) ``` ### ๐Ÿ› ๏ธ Helpers `@nuxt/test-utils` provides a number of helpers to make testing Nuxt apps easier. #### `mountSuspended` `mountSuspended` allows you to mount any Vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins. Under the hood, `mountSuspended` wraps `mount` from `@vue/test-utils`, so you can check out [the Vue Test Utils documentation](https://test-utils.vuejs.org/guide/) for more on the options you can pass, and how to use this utility. For example: ```ts [tests/components/SomeComponents.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- import { expect, it } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' it('can mount some component', async () => { const component = await mountSuspended(SomeComponent) expect(component.text()).toMatchInlineSnapshot( '"This is an auto-imported component"', ) }) ``` ```ts [tests/App.nuxt.spec.ts]twoslash import { expect, it } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import App from '~/app.vue' it('can also mount an app', async () => { const component = await mountSuspended(App, { route: '/test' }) expect(component.html()).toMatchInlineSnapshot(` "
This is an auto-imported component
I am a global component
/
Test link " `) }) ``` If you need to spy on component setup state, you can set the `spy` option to `true` and access the return value of the setup via `setupState`. ```ts [tests/components/SomeComponents.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- import { expect, it, vi } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' it('can spy on setup state', async () => { const component = await mountSuspended(SomeComponent, { spy: true }) vi.mocked(component.setupState.someMethod).mockImplementation(() => 'mocked') }) ``` The options object accepts `@vue/test-utils` mount options and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). - `spy`: enable spy component setup state (default `false`). The return object includes the `@vue/test-utils` mount result and the following properties: - `setupState`: the return value of the component setup. #### `renderSuspended` `renderSuspended` allows you to render any Vue component within the Nuxt environment using `@testing-library/vue`, allowing async setup and access to injections from your Nuxt plugins. This should be used together with utilities from Testing Library, e.g. `screen` and `fireEvent`. Install [@testing-library/vue](https://testing-library.com/docs/vue-testing-library/intro/) in your project to use these. Additionally, Testing Library also relies on testing globals for cleanup. You should turn these on in your [Vitest config](https://vitest.dev/config/globals). The passed in component will be rendered inside a `
`. Examples: ```ts [tests/components/SomeComponents.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- import { expect, it } from 'vitest' import { renderSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' import { screen } from '@testing-library/vue' it('can render some component', async () => { await renderSuspended(SomeComponent) expect(screen.getByText('This is an auto-imported component')).toBeDefined() }) ``` ```ts [tests/App.nuxt.spec.ts]twoslash import { expect, it } from 'vitest' import { renderSuspended } from '@nuxt/test-utils/runtime' import App from '~/app.vue' it('can also render an app', async () => { const html = await renderSuspended(App, { route: '/test' }) expect(html).toMatchInlineSnapshot(` "
This is an auto-imported component
I am a global component
Index page
Test link
" `) }) ``` The options object accepts `@testing-library/vue` render options and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). - `spy`: enable spy component setup state (default `false`). See the [`mountSuspended`](#mountsuspended) example above. The return object includes the `@testing-library/vue` render result and the following properties: - `setupState`: the return value of the component setup. #### `mockNuxtImport` `mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useState`, you can do so like this: ```tstwoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', () => { return () => { return { value: 'mocked storage' } } }) // your tests here ``` You can explicitly type the mock for type safety, and use the original implementation passed to the factory function when mocking complex functionality. ```ts [test/nuxt/import.test.ts]twoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', (original) => { return (...args) => { return { ...original('some-key'), value: 'mocked state' } } }) // or specify the target to mock mockNuxtImport(useState, (original) => { return (...args) => { return { ...original('some-key'), value: 'mocked state' } } }) // your tests here ``` `mockNuxtImport` can only be used once per mocked import per test file. It is actually a macro that gets transformed to `vi.mock` and `vi.mock` is hoisted, as described [in the Vitest docs](https://vitest.dev/api/vi#vi-mock). If you need to mock a Nuxt import and provide different implementations between tests, you can do it by creating and exposing your mocks using [`vi.hoisted`](https://vitest.dev/api/vi#vi-hoisted), and then use those mocks in `mockNuxtImport`. You then have access to the mocked imports, and can change the implementation between tests. Be careful to [restore mocks](https://vitest.dev/api/mock#mockrestore) before or after each test to undo mock state changes between runs. ```tstwoslash import { vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' const { useStateMock } = vi.hoisted(() => { return { useStateMock: vi.fn(() => { return { value: 'mocked storage' } }), } }) mockNuxtImport('useState', () => { return useStateMock }) // Then, inside a test useStateMock.mockImplementation(() => { return { value: 'something else' } }) ``` If you need to mock behavior only inside a test, you can also use the following approach. ```tstwoslash import { beforeEach, vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport(useRoute, original => vi.fn(original)) beforeEach(() => { vi.resetAllMocks() }) // Then, inside a test const useRouteOriginal = vi.mocked(useRoute).getMockImplementation()! vi.mocked(useRoute).mockImplementation( (...args) => ({ ...useRouteOriginal(...args), path: '/mocked' }), ) ``` #### `mockComponent` `mockComponent` allows you to mock Nuxt's component. The first argument can be the component name in PascalCase, or the relative path of the component. The second argument is a factory function that returns the mocked component. For example, to mock `MyComponent`, you can: ```tstwoslash import { mockComponent } from '@nuxt/test-utils/runtime' mockComponent('MyComponent', { props: { value: String, }, setup (props) { // ... }, }) // relative path or alias also works mockComponent('~/components/my-component.vue', () => { // or a factory function return defineComponent({ setup (props) { // ... }, }) }) // or you can use SFC for redirecting to a mock component mockComponent('MyComponent', () => import('./MockComponent.vue')) // your tests here ``` > **Note**: You can't reference local variables in the factory function since they are hoisted. If you need to access Vue APIs or other variables, you need to import them in your factory function. ```tstwoslash import { mockComponent } from '@nuxt/test-utils/runtime' mockComponent('MyComponent', async () => { const { ref, h } = await import('vue') return defineComponent({ setup (props) { const counter = ref(0) return () => h('div', null, counter.value) }, }) }) ``` #### `registerEndpoint` `registerEndpoint` allows you create Nitro endpoint that returns mocked data. It can come in handy if you want to test a component that makes requests to API to display some data. The first argument is the endpoint name (e.g. `/test/`). The second argument is a factory function that returns the mocked data. For example, to mock `/test/` endpoint, you can do: ```tstwoslash import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', () => ({ test: 'test-field', })) ``` By default, your request will be made using the `GET` method. You may use another method by setting an object as the second argument instead of a function. ```tstwoslash import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', { method: 'POST', handler: () => ({ test: 'test-field' }), }) ``` This object accepts the following properties: - `handler`: the event handler function - `method`: (optional) HTTP method to match (e.g., 'GET', 'POST') - `once`: (optional) if true, the handler will only be used for the first matching request and then automatically removed > **Note**: If your requests in a component go to an external API, you can use `baseURL` and then make it empty using [Nuxt Environment Override Config](https://nuxt.com/docs/5.x/getting-started/configuration#environment-overrides) (`$test`) so all your requests will go to Nitro server. #### Conflict with End-To-End Testing `@nuxt/test-utils/runtime` and `@nuxt/test-utils/e2e` need to run in different testing environments and so can't be used in the same file. If you would like to use both the end-to-end and unit testing functionality of `@nuxt/test-utils`, you can split your tests into separate files. You then either specify a test environment per-file with the special `// @vitest-environment nuxt` comment, or name your runtime unit test files with the `.nuxt.spec.ts` extension. `app.nuxt.spec.ts` ```tstwoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', () => { return () => { return { value: 'mocked storage' } } }) ``` `app.e2e.spec.ts` ```tstwoslash import { $fetch, setup } from '@nuxt/test-utils/e2e' await setup({ setupTimeout: 10000, }) // ... ``` ### Using `@vue/test-utils` If you prefer to use `@vue/test-utils` on its own for unit testing in Nuxt, and you are only testing components which do not rely on Nuxt composables, auto-imports or context, you can follow these steps to set it up. 1. Install the needed dependencies ```bash [npm] npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [yarn] yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [pnpm] pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [bun] bun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` 2. Create a `vitest.config.ts` with the following content:```ts import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom', }, }) ``` 3. Add a new command for test in your `package.json````json "scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" }, ``` 4. Create a simple `` component `app/components/HelloWorld.vue` with the following content:```vue ``` 5. Create a simple unit test for this newly created component `~/components/HelloWorld.spec.ts````tstwoslash import { describe, expect, it } from 'vitest' import { mount } from '@vue/test-utils' import HelloWorld from './HelloWorld.vue' describe('HelloWorld', () => { it('component renders Hello world properly', () => { const wrapper = mount(HelloWorld) expect(wrapper.text()).toContain('Hello world') }) }) ``` 6. Run vitest command ```bash [npm] npm run test ``` ```bash [yarn] yarn test ``` ```bash [pnpm] pnpm run test ``` ```bash [bun] bun run test ``` Congratulations, you're all set to start unit testing with `@vue/test-utils` in Nuxt! Happy testing! ### Vitest Browser Mode `@nuxt/test-utils` provides helpers for testing in [Vitest Browser Mode](https://vitest.dev/guide/browser/) via `@nuxt/test-utils/browser`. #### Setup 1. Install Vitest browser packages and a browser provider: ```bash [npm] npm i --save-dev @vitest/browser-playwright ``` ```bash [yarn] yarn add --dev @vitest/browser-playwright ``` ```bash [pnpm] pnpm add -D @vitest/browser-playwright ``` ```bash [bun] bun add --dev @vitest/browser-playwright ``` 2. Configure browser mode in your `vitest.config.ts`:```tstwoslash // @errors: 2307 // ---cut--- import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { projects: [ await defineVitestProject({ test: { name: 'browser', include: ['test/browser/**/*.{test,spec}.ts'], browser: { enabled: true, provider: playwright(), instances: [{ browser: 'chromium' }], }, // If you want to enable `page.render` and automatic cleanup, add this setup file setupFiles: ['@nuxt/test-utils/browser'], }, }), ], }, }) ``` When adding `@nuxt/test-utils/browser` to `setupFiles`, if TypeScript does not automatically recognize the types for `page.render`, you can add `@nuxt/test-utils/browser` via `typescript.tsConfig.compilerOptions.types` in your `nuxt.config.ts`. If your Vitest browser mode tests live outside `test/nuxt/` (such as in `test/browser/`), see [Adding other test directories](#adding-other-test-directories) to add them to the TypeScript context. #### Usage You can use `page.render` from `vitest/browser`: ```ts [test/browser/components/MyCounter.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const MyCounter: Component } // ---cut--- import { expect, it } from 'vitest' import { page } from 'vitest/browser' // If you added the setup file, the following import is not needed import '@nuxt/test-utils/browser' import { MyCounter } from '#components' it('counter button increments the count', async () => { const screen = await page.render(MyCounter) await screen.getByRole('button', { name: 'Increment' }).click() await expect.element(screen.getByText('Count: 1')).toBeVisible() }) ``` You can also import `render` directly from `@nuxt/test-utils/browser`: ```tstwoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const MyCounter: Component } // ---cut--- import { expect, it } from 'vitest' import { render } from '@nuxt/test-utils/browser' import { MyCounter } from '#components' it('can render using the render helper', async () => { const screen = await render(MyCounter) await screen.getByRole('button', { name: 'Increment' }).click() await expect.element(screen.getByText('Count: 1')).toBeVisible() }) ``` The options object accepts `@vue/test-utils` mount options (use `container` instead of `attachTo`) and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). - `spy`: enable spy component setup state (default `false`). See the [`mountSuspended`](#mountsuspended) example above. - `container`: custom `HTMLElement` container to render into (use this option instead of `@vue/test-utils` `attachTo`). - `baseElement`: custom base `HTMLElement` (default `document.body`). The return object includes the following properties: - `container`: the container `HTMLElement` the component is rendered into. - `baseElement`: the base `HTMLElement` (default `document.body`). - `locator`: root element `Locator`. - `setupState`: the return value of the component setup, mocked when the `spy` option is enabled. - `debug()`: print formatted DOM to console. - `unmount()`: unmount the component. Also records a `nuxt.unmount` trace mark. - `emitted()`: get emitted events. - `rerender(props)`: re-render the component with new props. Also records a `nuxt.rerender` trace mark. ## End-To-End Testing For end-to-end testing, we support [Vitest](https://github.com/vitest-dev/vitest), [Jest](https://jestjs.io), [Cucumber](https://cucumber.io/) and [Playwright](https://playwright.dev/) as test runners. ### Setup In each `describe` block where you are taking advantage of the `@nuxt/test-utils/e2e` helper methods, you will need to set up the test context before beginning. ```ts [test/my-test.spec.ts]twoslash import { describe, test } from 'vitest' import { $fetch, setup } from '@nuxt/test-utils/e2e' describe('My test', async () => { await setup({ // test context options }) test('my test', () => { // ... }) }) ``` Behind the scenes, `setup` performs a number of tasks in `beforeAll`, `beforeEach`, `afterEach` and `afterAll` to set up the Nuxt test environment correctly. Please use the options below for the `setup` method. #### Nuxt Config - `rootDir`: Path to a directory with a Nuxt app to be put under test. - Type: `string` - Default: `'.'` - `configFile`: Name of the configuration file. - Type: `string` - Default: `'nuxt.config'` #### Timings - `setupTimeout`: The amount of time (in milliseconds) to allow for `setupTest` to complete its work (which could include building or generating files for a Nuxt application, depending on the options that are passed). - Type: `number` - Default: `120000` or `240000` on windows - `teardownTimeout`: The amount of time (in milliseconds) to allow tearing down the test environment, such as closing the browser. - Type: `number` - Default: `30000` #### Features - `build`: Whether to run a separate build step. - Type: `boolean` - Default: `true` (`false` if `browser` or `server` is disabled, or if a `host` is provided) - `server`: Whether to launch a server to respond to requests in the test suite. - Type: `boolean` - Default: `true` (`false` if a `host` is provided) - `port`: If provided, set the launched test server port to the value. - Type: `number | undefined` - Default: `undefined` - `host`: If provided, a URL to use as the test target instead of building and running a new server. Useful for running "real" end-to-end tests against a deployed version of your application, or against an already running local server (which may provide a significant reduction in test execution timings). See the [target host end-to-end example below](https://nuxt.com/docs/5.x/getting-started/testing#target-host-end-to-end-example). - Type: `string` - Default: `undefined` - `browser`: Under the hood, Nuxt test utils uses [`playwright`](https://playwright.dev) to carry out browser testing. If this option is set, a browser will be launched and can be controlled in the subsequent test suite. - Type: `boolean` - Default: `false` - `browserOptions` - Type: `object` with the following properties - `type`: The type of browser to launch - either `chromium`, `firefox` or `webkit` - `launch`: `object` of options that will be passed to playwright when launching the browser. See [full API reference](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). - `runner`: Specify the runner for the test suite. Currently, [Vitest](https://vitest.dev) is recommended. - Type: `'vitest' | 'jest' | 'cucumber'` - Default: `'vitest'` - `logLevel`: Overrides the consola log level for the server subprocess. (use NUXT_TEST_LOG_LEVEL environment variable to override) - Type: `number` - Default: `1` - `captureServerLogs`: Whether to capture server process output instead of inheriting stdio. When `true` (default), server stdout/stderr is suppressed from the console and accessible via `getServerLogs()`. Set to `false` to restore the old inherit-stdio behaviour (useful when debugging a test locally). - Type: `boolean` - Default: `true` ##### Target `host` end-to-end example A common use-case for end-to-end testing is running the tests against a deployed application running in the same environment typically used for Production. For local development or automated deploy pipelines, testing against a separate local server can be more efficient and is typically faster than allowing the test framework to rebuild between tests. To utilize a separate target host for end-to-end tests, simply provide the `host` property of the `setup` function with the desired URL. ```ts import { createPage, setup } from '@nuxt/test-utils/e2e' import { describe, expect, it } from 'vitest' describe('login page', async () => { await setup({ host: 'http://localhost:8787', }) it('displays the email and password fields', async () => { const page = await createPage('/login') expect(await page.getByTestId('email').isVisible()).toBe(true) expect(await page.getByTestId('password').isVisible()).toBe(true) }) }) ``` ### APIs #### `$fetch(url)` Get the HTML of a server-rendered page. ```tstwoslash import { $fetch } from '@nuxt/test-utils/e2e' const html = await $fetch('/') ``` #### `fetch(url)` Get the response of a server-rendered page. ```tstwoslash import { fetch } from '@nuxt/test-utils/e2e' const res = await fetch('/') const { body, headers } = res ``` #### `url(path)` Get the full URL for a given page (including the port the test server is running on.) ```tstwoslash import { url } from '@nuxt/test-utils/e2e' const pageUrl = url('/page') // 'http://localhost:6840/page' ``` #### `getServerLogs()` Returns the lines captured from the server subprocess's stdout/stderr since the last `startServer()` call (or `clearServerLogs()`). Only populated when `captureServerLogs` is `true` (the default). ```tstwoslash import { expect, it, vi } from 'vitest' import { $fetch, clearServerLogs, getServerLogs } from '@nuxt/test-utils/e2e' it('captures console.log output from a server route', async () => { clearServerLogs() await $fetch('/api/log-test') await vi.waitFor(() => { expect(getServerLogs().some(line => line.includes('[test] server-log-marker'))).toBe(true) }) }) ``` #### `clearServerLogs()` Clears the captured server log lines. Useful between requests when you want to assert only on the logs produced by a specific operation. ### Testing in a Browser We provide built-in support using Playwright within `@nuxt/test-utils`, either programmatically or via the Playwright test runner. #### `createPage(url)` Within `vitest`, `jest` or `cucumber`, you can create a configured Playwright browser instance with `createPage`, and (optionally) point it at a path from the running server. You can find out more about the API methods available in the [Playwright documentation](https://playwright.dev/docs/api/class-page). ```tstwoslash import { createPage } from '@nuxt/test-utils/e2e' const page = await createPage('/page') // you can access all the Playwright APIs from the `page` variable ``` #### Testing with Playwright Test Runner We also provide first-class support for testing Nuxt within [the Playwright test runner](https://playwright.dev/docs/intro). ```bash [npm] npm i --save-dev @playwright/test @nuxt/test-utils ``` ```bash [yarn] yarn add --dev @playwright/test @nuxt/test-utils ``` ```bash [pnpm] pnpm add -D @playwright/test @nuxt/test-utils ``` ```bash [bun] bun add --dev @playwright/test @nuxt/test-utils ``` ```bash [deno] deno add --dev npm:@playwright/test npm:@nuxt/test-utils ``` You can provide global Nuxt configuration, with the same configuration details as the `setup()` function mentioned earlier in this section. ```ts [playwright.config.ts] import { fileURLToPath } from 'node:url' import { defineConfig, devices } from '@playwright/test' import type { ConfigOptions } from '@nuxt/test-utils/playwright' export default defineConfig({ use: { nuxt: { rootDir: fileURLToPath(new URL('.', import.meta.url)), }, }, // ... }) ``` Your test file should then use `expect` and `test` directly from `@nuxt/test-utils/playwright`: ```ts [tests/example.test.ts] import { expect, test } from '@nuxt/test-utils/playwright' test('test', async ({ page, goto }) => { await goto('/', { waitUntil: 'hydration' }) await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!') }) ``` You can alternatively configure your Nuxt server directly within your test file: ```ts [tests/example.test.ts] import { expect, test } from '@nuxt/test-utils/playwright' test.use({ nuxt: { rootDir: fileURLToPath(new URL('..', import.meta.url)), }, }) test('test', async ({ page, goto }) => { await goto('/', { waitUntil: 'hydration' }) await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!') }) ``` # Transitions > Apply transitions between pages and layouts with Vue or native browser View Transitions. Nuxt leverages Vue's [``](https://vuejs.org/guide/built-ins/transition#the-transition-component) component to apply transitions between pages and layouts. Because Nuxt uses Vue's `` component, a page or layout you want to animate must have a **single root element**. A page or layout with multiple root elements (a fragment) cannot be animated, so the transition will not run and navigating between routes may error. Nuxt warns about this in development. Wrap the template in a single root element (for example a `
`). ## Page Transitions You can enable page transitions to apply an automatic transition for all your [pages](https://nuxt.com/docs/5.x/directory-structure/app/pages). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: { name: 'page', mode: 'out-in' }, }, }) ``` If you are changing layouts as well as pages, the page transition you set here will not run. Instead, you should set a [layout transition](https://nuxt.com/docs/5.x/getting-started/transitions#layout-transitions). To start adding transition between your pages, add the following CSS to your [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app): ```vue [app/app.vue] ``` ```vue [app/pages/index.vue] ``` ```vue [app/pages/about.vue] ``` This produces the following result when navigating between pages: To set a different transition for a page, set the `pageTransition` key in [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) of the page: ```vue [pages/about.vue]twoslash ``` ```vue [app/app.vue] ``` Moving to the about page will add the 3d rotation effect: ## Layout Transitions You can enable layout transitions to apply an automatic transition for all your [layouts](https://nuxt.com/docs/5.x/directory-structure/app/layouts). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { layoutTransition: { name: 'layout', mode: 'out-in' }, }, }) ``` To start adding transition between your pages and layouts, add the following CSS to your [`app.vue`](https://nuxt.com/docs/5.x/directory-structure/app/app): ```vue [app/app.vue] ``` ```vue [app/layouts/default.vue] ``` ```vue [app/layouts/orange.vue] ``` ```vue [app/pages/index.vue] ``` ```vue [app/pages/about.vue] ``` This produces the following result when navigating between pages: Similar to `pageTransition`, you can apply a custom `layoutTransition` to the page component using `definePageMeta`: ```vue [pages/about.vue]twoslash ``` ## Global Settings You can customize these default transition names globally using `nuxt.config`. Both `pageTransition` and `layoutTransition` keys accept [`TransitionProps`](https://vuejs.org/api/built-in-components#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: { name: 'fade', mode: 'out-in', // default }, layoutTransition: { name: 'slide', mode: 'out-in', // default }, }, }) ``` If you change the `name` property, you also have to rename the CSS classes accordingly. To override the global transition property, use the `definePageMeta` to define page or layout transitions for a single Nuxt page and override any page or layout transitions that are defined globally in `nuxt.config` file. ```vue [pages/some-page.vue]twoslash ``` ## Disable Transitions `pageTransition` and `layoutTransition` can be disabled for a specific route: ```vue [pages/some-page.vue]twoslash ``` Or globally in the `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: false, layoutTransition: false, }, }) ``` ## JavaScript Hooks For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt pages. This way presents perfect use-cases for JavaScript animation libraries such as [GSAP](https://gsap.com). ```vue [pages/some-page.vue]twoslash ``` Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition#javascript-hooks) available in the `Transition` component. ## Dynamic Transitions To apply dynamic transitions using conditional logic, you can leverage inline [middleware](https://nuxt.com/docs/5.x/directory-structure/app/middleware) to assign a different transition name to `to.meta.pageTransition`. ```vue [pages/[id].vue]twoslash ``` ```vue [app/layouts/default.vue] ``` The page now applies the `slide-left` transition when going to the next id and `slide-right` for the previous one: ## Transition with NuxtPage When `` is used in `app.vue`, transitions can be configured with the `transition` prop to activate transitions globally. ```vue [app/app.vue] ``` Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. ## View Transitions API (Experimental) Nuxt ships with an experimental implementation of the [**View Transitions API**](https://developer.chrome.com/docs/web-platform/view-transitions) (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API)). This is an exciting new way to implement native browser transitions which (among other things) have the ability to transition between unrelated elements on different pages. You can check a demo [on StackBlitz](https://stackblitz.com/edit/nuxt-view-transitions). The Nuxt integration can be enabled with the `experimental.viewTransition` option in your configuration file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { viewTransition: true, }, }) ``` The possible values are: `false`, `true`, or `'always'`. If set to true, Nuxt will not apply transitions if the user's browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition and it is up to you to respect the user's preference. By default, view transitions are enabled for all [pages](https://nuxt.com/docs/5.x/directory-structure/app/pages), but you can set a different global default. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { // Disable view transitions globally, and opt-in on a per page basis viewTransition: false, }, }) ``` It is possible to override the default `viewTransition` value for a page by setting the `viewTransition` key in [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) of the page: ```vue [pages/about.vue]twoslash ``` Overriding view transitions on a per-page basis will only have an effect if you have enabled the `experimental.viewTransition` option. ### View Transition Types v4.4 [View transition types](https://developer.chrome.com/blog/view-transitions-update-io24#view-transition-types) allow you to apply different CSS animations depending on the type of navigation. This is useful for creating asymmetric transitions (e.g., a different animation when navigating forward vs. backward). Types are set on the [`ViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) and can be targeted in CSS using the [`:active-view-transition-type()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:active-view-transition-type) pseudo-class selector. You can set default types globally in your `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { viewTransition: { enabled: true, types: ['slide'], }, }, }) ``` Or configure types per-page using `definePageMeta`. Per-page types support both static arrays and functions for dynamic behavior: ```vue [pages/detail.vue]twoslash ``` You can also use functions for `types`, `toTypes`, and `fromTypes` in `definePageMeta` to determine types dynamically based on the route: ```vue [pages/[id].vue]twoslash ``` Then target these types in your CSS: ```css /* Default crossfade */ ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.3s; } /* Slide left animation */ html:active-view-transition-type(slide-left) { &::view-transition-old(root) { animation: slide-out-left 0.3s ease-in-out; } &::view-transition-new(root) { animation: slide-in-right 0.3s ease-in-out; } } /* Slide right animation */ html:active-view-transition-type(slide-right) { &::view-transition-old(root) { animation: slide-out-right 0.3s ease-in-out; } &::view-transition-new(root) { animation: slide-in-left 0.3s ease-in-out; } } ``` Function values for `types`, `toTypes`, and `fromTypes` only work in `definePageMeta`, not in `nuxt.config.ts` (where only static `string[]` is supported). The `page:view-transition:start` hook provides access to the [`ViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) object, which includes a [`types`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition/types) property (`ViewTransitionTypeSet`) that can be read or modified at runtime: ```ts [plugins/view-transition.client.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:view-transition:start', (transition) => { // Read or modify types at runtime console.log([...transition.types]) }) }) ``` If you are also using Vue transitions like `pageTransition` and `layoutTransition` (see above) to achieve the same result as the new View Transitions API, then you may wish to *disable* Vue transitions if the user's browser supports the newer, native web API. You can do this by creating `~/middleware/disable-vue-transitions.global.ts` with the following contents: ```ts export default defineNuxtRouteMiddleware((to) => { if (import.meta.server || !document.startViewTransition) { return } // Disable built-in Vue transitions to.meta.pageTransition = false to.meta.layoutTransition = false }) ``` ### Known Issues - If you perform data fetching within your page setup functions, you may wish to reconsider using this feature for the moment. (By design, View Transitions completely freeze DOM updates whilst they are taking place.) We're looking at restricting the View Transition to the final moments before `` resolves, but in the interim you may want to consider carefully whether to adopt this feature if this describes you. # Upgrade Guide > Learn how to upgrade to the latest Nuxt version. ## Upgrading Nuxt ### Latest release To upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases), use the `nuxt upgrade` command. ```bash [npm] npx nuxt upgrade ``` ```bash [yarn] yarn nuxt upgrade ``` ```bash [pnpm] pnpm nuxt upgrade ``` ```bash [bun] bun x nuxt upgrade ``` ```bash [deno] deno x nuxt upgrade ``` ### Nightly Release Channel To use the latest Nuxt build and test features before their release, read about the [nightly release channel](https://nuxt.com/docs/5.x/guide/going-further/nightly-release-channel) guide. ## Testing Nuxt 5 Nuxt 5 is **currently in development**. Until the release, it is possible to test many of Nuxt 5's breaking changes from Nuxt version 4.2+. ### Opting in to Nuxt 5 First, upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases). Then you can set your `future.compatibilityVersion` to match Nuxt 5 behavior: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ future: { compatibilityVersion: 5, }, }) ``` When you set your `future.compatibilityVersion` to `5`, defaults throughout your Nuxt configuration will change to opt in to Nuxt v5 behavior, including: - **Vite Environment API**: Uses the new [Vite Environment API](https://nuxt.com/docs/5.x/getting-started/upgrade#migration-to-vite-environment-api) for improved build configuration - **Case-sensitive routing**: Page routes [match URL casing exactly](https://nuxt.com/docs/5.x/getting-started/upgrade#case-sensitive-routing), consistent with Nitro - **Normalized Page Names**: Page component names will [match their route names](https://nuxt.com/docs/5.x/getting-started/upgrade#normalized-page-component-names) for consistent `` behavior - **clearNuxtState resets to defaults**: `clearNuxtState` will [reset state to its initial value](https://nuxt.com/docs/5.x/getting-started/upgrade#respect-defaults-when-clearing-usestate) instead of setting it to `undefined` - **Non-async callHook**: [`callHook` may return `void`](https://nuxt.com/docs/5.x/getting-started/upgrade#non-async-callhook) instead of always returning a `Promise` - **Comment node placeholders**: Client-only components use [comment nodes instead of `
`](https://nuxt.com/docs/5.x/getting-started/upgrade#client-only-comment-placeholders) as SSR placeholders, fixing a scoped styles hydration issue - **Stricter side-effect imports**: The generated `tsconfig.json` enables [`noUncheckedSideEffectImports`](https://nuxt.com/docs/5.x/getting-started/upgrade#stricter-side-effect-imports) to match the TypeScript 7 default - **Vue Options API disabled**: The [Options API is compiled out of the client bundle](https://nuxt.com/docs/5.x/getting-started/upgrade#vue-options-api-disabled-by-default) to reduce its size - **process.* type augmentation removed**: TypeScript no longer exposes [deprecated `process.*` flags](https://nuxt.com/docs/5.x/getting-started/upgrade#process-type-augmentation-removed) on `NodeJS.Process` - **Typed pages**: [`experimental.typedPages`](https://nuxt.com/docs/5.x/getting-started/upgrade#typed-pages-enabled-by-default) is enabled by default for type-checked routing - **TypeScript baseUrl ignored**: Generated TypeScript configurations [no longer use `compilerOptions.baseUrl`](https://nuxt.com/docs/5.x/getting-started/upgrade#typescript-baseurl-is-ignored) to resolve Nuxt aliases - Other Nuxt 5 improvements and changes as they become available This section is subject to change until the final release, so please check back here regularly if you are testing Nuxt 5 using `future.compatibilityVersion: 5`. Breaking or significant changes will be noted below along with migration steps for backward/forward compatibility. ### `process.*` Type Augmentation Removed ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Nuxt no longer augments `NodeJS.Process` with `browser`, `client`, `dev`, `server`, and `test`. Build-time defines for those flags remain for compatibility, but TypeScript will not treat them as known properties. Prefer [`import.meta.*`](https://nuxt.com/docs/5.x/api/advanced/import-meta). Those flags are replaced at build time and stay tree-shakeable. #### Migration Steps Replace legacy checks in your app code, modules, and libraries: ```ts // Before // eslint-disable-next-line nuxt/prefer-import-meta if (process.server) { /* ... */ } // After if (import.meta.server) { /* ... */ } ``` The [`nuxt/prefer-import-meta`](https://eslint.nuxt.com/packages/plugin#nuxtprefer-import-meta) ESLint rule flags remaining `process.*` usage. ### Case-Sensitive Routing ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, page routes match URLs case-sensitively, consistent with Nitro. For example, `/About` no longer matches `pages/about.vue`. #### Migration Steps Update links to use the same casing as their page routes. To keep case-insensitive matching: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ router: { options: { sensitive: false, }, }, }) ``` ### `jiti` Is No Longer Bundled ๐Ÿšฆ **Impact Level**: Medium #### What Changed Nuxt no longer depends on [`jiti`](https://github.com/unjs/jiti). Files loaded outside the bundler (`nuxt.config.ts`, files in `modules/`, and layer configs) are now imported by the runtime itself. **You can still write your config in TypeScript.** Nuxt 5 requires Node `22.19` or later, where type stripping is on by default, so `nuxt.config.ts` and TypeScript modules load natively. Two things the runtime does not do, which `jiti` used to paper over, are guess file extensions and compile TypeScript syntax that emits code. Both would otherwise only surface when Nuxt loads the file, so the generated `node` tsconfig now describes the environment the way the runtime sees it (`module` and `moduleResolution` set to `nodenext`, plus [`erasableSyntaxOnly`](https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly)) and TypeScript reports both up front. That covers `nuxt.config`, `modules/` and layer configs only. Your app and `shared/` code goes through Vite and resolves the way it always has. If you need the previous behaviour, override it: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { nodeTsConfig: { compilerOptions: { module: 'preserve', moduleResolution: 'bundler', erasableSyntaxOnly: false, }, }, }, }) ``` #### Reasons for Change `jiti` was pulled into every Nuxt install to load a handful of files, most of which the runtime can now load unaided. Removing it makes a default install smaller. #### Migration Steps **1. Add file extensions to relative imports.** Relative imports in `nuxt.config.ts`, `modules/`, and layer configs need an explicit extension: ```diff [nuxt.config.ts] - import { myPlugin } from './build/my-plugin' + import { myPlugin } from './build/my-plugin.ts' ``` TypeScript reports a missing extension as `TS2835`. Note that its quick fix suggests `./build/my-plugin.js`; write the extension the file actually has (`.ts`), which Node resolves directly. Bare package imports (`import { defu } from 'defu'`) are unaffected. **2. Use erasable TypeScript syntax.** Type annotations are erased, but syntax that emits runtime code cannot be. In config and module files, replace: - `enum Foo {}` with a `const` object - `namespace` / `module` blocks with plain exports - constructor parameter properties (`constructor(private x: string) {}`) with an explicit assignment - experimental decorators TypeScript reports all of these for you as `TS1294`. **3. If you publish a layer or module, ship compiled JavaScript.** This one is specific to packages. The runtime refuses to strip types from any file inside `node_modules`, whatever the configuration, so a published entrypoint written in TypeScript cannot be loaded natively however new the Node version is. Build to JavaScript before publishing, and if your package ships a `nuxt.config`, emit it as `nuxt.config.mjs`. Otherwise every consuming project has to install `jiti`. This does not apply to layers inside your own project: `layers/*/nuxt.config.ts` loads natively. **4. Install jiti if you still need it.** `jiti` is now an optional peer dependency. Install it and Nuxt will pick it up automatically as a fallback whenever the runtime cannot load a file on its own: ```bash [npm] npm i -D jiti ``` ```bash [yarn] yarn add -D jiti ``` ```bash [pnpm] pnpm add -D jiti ``` ```bash [bun] bun add -D jiti ``` A `nuxt.schema` file always needs `jiti`, whatever Node version you are on: its JSDoc annotations are read by an import-time transform rather than by importing the file. One smaller change comes with this: PostCSS plugins named in `postcss.plugins` are now resolved by the runtime, so a plugin name that only resolves through a Nuxt `alias` entry no longer loads. Use the package name, or a path. ### Migration to Vite Environment API ๐Ÿšฆ **Impact Level**: Medium #### What Changed Nuxt 5 migrates to Vite 6's new [Environment API](https://vite.dev/guide/api-environment), which formalizes the concept of environments and provides better control over configuration per environment. Previously, Nuxt used separate client and server Vite configurations. Now, Nuxt uses a shared Vite configuration with environment-specific plugins that use the `applyToEnvironment()` method to target specific environments. The Vite Environment API is always enabled in Nuxt 5. The `experimental.viteEnvironmentApi` option has been removed. **Key changes:** 1. **Deprecated environment-specific extendViteConfig()**: The `server` and `client` options in `extendViteConfig()` are deprecated and will show warnings when used. 2. **Changed plugin registration**: Vite plugins registered with `addVitePlugin()` and only targeting one environment (by passing `server: false` or `client: false`) will not have their `config` or `configResolved` hooks called. 3. **Shared configuration**: The `vite:extendConfig` and `vite:configResolved` hooks now work with a shared configuration rather than separate client/server configs. #### Reasons for Change The Vite Environment API provides: - Better consistency between development and production builds - More granular control over environment-specific configuration - Improved performance and plugin architecture - Support for custom environments beyond just client and server #### Migration Steps ##### 1. Migrate to use Vite plugins We would recommend you use a Vite plugin instead of `extendViteConfig`, `vite:configResolved` and `vite:extendConfig`. ```ts // Before extendViteConfig((config) => { config.optimizeDeps.include.push('my-package') }, { server: false }) nuxt.hook('vite:extendConfig' /* or vite:configResolved */, (config, { isClient }) => { if (isClient) { config.optimizeDeps.include.push('my-package') } }) // After addVitePlugin(() => ({ name: 'my-plugin', config (config) { // you can set global vite configuration here }, configResolved (config) { // you can access the fully resolved vite configuration here }, configEnvironment (name, config) { // you can set environment-specific vite configuration here if (name === 'client') { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('my-package') } }, applyToEnvironment (environment) { return environment.name === 'client' }, })) ``` ##### 2. Migrate Vite plugins to use environments Instead of using `addVitePlugin` with `server: false` or `client: false`, you can instead use the new `applyToEnvironment` hook within your plugin. ```ts // Before addVitePlugin(() => ({ name: 'my-plugin', config (config) { config.optimizeDeps.include.push('my-package') }, }), { client: false }) // After addVitePlugin(() => ({ name: 'my-plugin', config (config) { // you can set global vite configuration here }, configResolved (config) { // you can access the fully resolved vite configuration here }, configEnvironment (name, config) { // you can set environment-specific vite configuration here if (name === 'client') { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('my-package') } }, applyToEnvironment (environment) { return environment.name === 'client' }, })) ``` Learn more about Vite's Environment API ### Migration to Vite 8 ๐Ÿšฆ **Impact Level**: Medium #### What Changed Nuxt 5 upgrades from Vite 7 to [Vite 8](https://main.vite.dev/guide/migration), which replaces esbuild and Rollup with [Rolldown](https://rolldown.rs) as the underlying bundler. This brings significantly faster builds but includes several breaking changes. Unlike the Vite Environment API migration, this change cannot be opted into early with `future.compatibilityVersion: 5`. If you want to test Vite 8 compatibility ahead of time, you can add a `"vite": "^8.0.0-beta.15"` resolution override in your `package.json`. Most of the migration is handled by Nuxt internally, but there are some user-facing changes to be aware of: - **vite.esbuild and vite.optimizeDeps.esbuildOptions** are deprecated in favour of `vite.oxc` and `vite.optimizeDeps.rolldownOptions`. Vite 8 converts these automatically for now, but they will be removed in the future. - **build.rollupOptions** is deprecated in favour of `build.rolldownOptions`. - **CommonJS interop behaviour** has changed. If you import CJS modules, review the [Vite 8 migration guide](https://main.vite.dev/guide/migration#consistent-commonjs-interop) for details. See the full Vite 8 migration guide for all breaking changes and migration steps. ### Server Imports Move to `nuxt/server` ๐Ÿšฆ **Impact Level**: Medium #### What Changed Nuxt 5 ships `nuxt/server`, an import surface for the server utilities server code reaches for most: `defineEventHandler`, `createError`, `getQuery`, `readBody`, the cookie and header helpers, `sendRedirect`, `getRouteRules` and `useRuntimeConfig`. It replaces `@nuxt/nitro-server/h3`, which is deprecated. Which server runtime is under your application depends on the configured [`server.builder`](https://nuxt.com/docs/5.x/guide/going-further/builders), and importing from `nitro/h3` pins your code to one of them and to its major version. `nuxt/server` does not, so one file can serve Nuxt 4.6 (running either `nitropack` v2 or Nitro v3) and Nuxt 5. ```diff [server/api/hello.ts] - import { defineEventHandler, getQuery } from 'nitro/h3' + import { defineEventHandler, getQuery } from 'nuxt/server' export default defineEventHandler((event) => { return getQuery(event) }) ``` Errors take the same shape as the ones the Vue part of your app constructs, and come from the same place: ```diff - import { HTTPError } from 'nitro/h3' + import { createError } from 'nuxt/server' export default defineEventHandler(() => { - throw new HTTPError({ status: 400, statusText: 'Bad request' }) + throw createError({ status: 400, statusText: 'Bad request' }) }) ``` Server auto-imports resolve to `nuxt/server` too, so a project that leaves them on needs no change. #### Migration Steps 1. Replace `nitro/h3` and `@nuxt/nitro-server/h3` imports with `nuxt/server`, for the utilities in [the surface](https://nuxt.com/docs/5.x/guide/going-further/server-imports#the-surface). 2. Leave the rest on `nitro/h3`. `nuxt/server` is not a re-export of h3, so helpers such as `readValidatedBody` and `handleCors` stay where they are. 3. Nothing you reach off `event` has to change: under the default Nitro builder it is still h3's `H3Event`. Learn what the surface covers, and what it means for module authors. ### Migration to Nitro v3 ๐Ÿšฆ **Impact Level**: Significant #### What Changed Nuxt 5 upgrades to [Nitro v3](https://nitro.build/blog/v3-beta), which is a major rewrite of the server engine. Nitro v3 is built on [srvx](https://srvx.h3.dev) and [h3 v2](https://h3.dev), adopting Web standard `Request`/`Response` APIs throughout. This brings performance improvements and a more consistent API, but includes several breaking changes to server-side code. We are still working on Nitro v3 integration so you should expect further changes, as well as additional work to make migration more straightforward. Read the Nitro v3 beta announcement for a full overview. See the full Nitro v3 migration guide for all breaking changes. The sections below highlight changes that are most relevant to Nuxt application developers and module authors. You don't have to make all of them before you upgrade: see [Nitro v2 Compatibility](#nitro-v2-compatibility) for the layer that keeps older server code running in the meantime. #### Package and Import Path Changes The `nitropack` package has been renamed to `nitro`. All import paths have changed:
Before After
nitropack nitro
nitropack/types nitro/types
nitropack/runtime nitro
h3 (for server utilities) nitro/h3
If you have explicit imports in server code, update them: ```diff - import { defineEventHandler, getQuery } from 'h3' + import { defineEventHandler, getQuery } from 'nitro/h3' ``` **For module authors**, type augmentations must target the new module path: ```diff - declare module 'nitropack/types' { + declare module 'nitro/types' { interface NitroRuntimeConfig { myModule?: { /* ... */ } } } ``` Route rules are augmented on a different module again. See [Route Rule Types Move to `h3/rules`](#route-rule-types-move-to-h3rules). #### Server Auto-Imports Are Now Opt-In Nitro v3 removed its auto-import support, so utilities such as `defineEventHandler`, `getQuery`, `readBody` and `useRuntimeConfig` are no longer global in server code. Nuxt still provides them, but in Nuxt 5 they are off by default. Add explicit imports to your server code. Prefer [`nuxt/server`](https://nuxt.com/docs/5.x/guide/going-further/server-imports), which is what the auto-imports resolve to: ```diff [server/api/hello.ts] + import { defineEventHandler, getQuery } from 'nuxt/server' + export default defineEventHandler((event) => { return getQuery(event) }) ``` Or keep the previous behaviour while you migrate: ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { nitroAutoImports: true, }, }) ``` This applies only to the utilities Nitro and h3 provide. Your own exports from `server/utils/` and `shared/utils/` are still auto-imported. #### `#imports` Is Deprecated in Server Code, in Favour of `#imports/server` Server code should import from `#imports/server`: ```diff [server/api/hello.ts] - import { defineEventHandler } from '#imports' + import { defineEventHandler } from '#imports/server' export default defineEventHandler(() => ({ hello: true })) ``` `#imports` still resolves when your server code runs, so an unmigrated project keeps working, but it is no longer typed: TypeScript reports it as unresolved until you move to `#imports/server`. #### Error Handling: `status`/`statusText` replace `statusCode`/`statusMessage` h3 v2 renames the error properties to align with Web standards: ```diff createError({ - statusCode: 404, - statusMessage: 'Not Found', + status: 404, + statusText: 'Not Found', }) ``` In server routes, the error class is now `HTTPError` (replacing `createError` from `h3`): ```diff - import { createError } from 'h3' + import { HTTPError } from 'nitro/h3' export default defineEventHandler(() => { - throw createError({ statusCode: 400, statusMessage: 'Bad request' }) + throw new HTTPError({ status: 400, statusText: 'Bad request' }) }) ``` In the Vue part of your app (the `app/` directory), Nuxt's `createError` composable continues to work and is the recommended way to throw errors. #### `createError` No Longer Returns an `HTTPError` Instance `NuxtError` is now its own class rather than a subclass of h3's `HTTPError`, so `instanceof HTTPError` no longer matches an error created with Nuxt's `createError`. Everything else is unchanged: the error keeps the same properties, serialises the same way, and is still mapped to the right HTTP response during SSR. If you narrow errors by class, use one of the predicates instead: ```diff - if (error instanceof HTTPError) { + if (HTTPError.isError(error)) { // handles both `new HTTPError()` and Nuxt's `createError()` } ``` ```diff + import { isNuxtError } from '#app' + + if (isNuxtError(error)) { + // narrows to errors created with Nuxt's `createError` + } ``` #### Server Event API Changes (h3 v2) The `H3Event` object now uses Web standard APIs: **Request properties:** ```diff - event.path // string + event.url.pathname // URL object - use .pathname, .search, .hash - event.method // string + event.req.method // via Web Request object - event.node.req.headers // Node.js IncomingHttpHeaders + event.req.headers // Web Headers API (.get(), .set(), .has()) ``` **Response properties:** ```diff - event.node.res.statusCode = 200 + event.res.status = 200 - event.node.res.statusMessage = 'OK' + event.res.statusText = 'OK' - setResponseHeader(event, 'x-custom', 'value') + event.res.headers.set('x-custom', 'value') - appendResponseHeader(event, 'set-cookie', cookie) + event.res.headers.append('set-cookie', cookie) ``` #### `useRuntimeConfig()` No Longer Accepts `event` In Nitro v3, `useRuntimeConfig()` no longer requires (or accepts) an `event` argument in server routes: ```diff export default defineEventHandler((event) => { - const config = useRuntimeConfig(event) + const config = useRuntimeConfig() }) ``` #### Route Rules: `statusCode` Renamed to `status` If you define redirect route rules, the property name has changed: ```diff export default defineNuxtConfig({ routeRules: { '/old-page': { - redirect: { to: '/new-page', statusCode: 302 }, + redirect: { to: '/new-page', status: 302 }, }, }, }) ``` Nuxt applies `statusCode` as `status` for now and warns, so an unmigrated rule keeps its status rather than silently falling back to the default. The fallback will be removed. #### Cached Route Rules Ignore Query Parameters Cached routes (`cache`, `swr`, `isr`) now key on the path only, and the query string is dropped before the handler runs. Set `allowQuery` to keep it, either as `true` or as a list of parameter names: ```ts export default defineNuxtConfig({ routeRules: { '/products': { cache: { swr: true, maxAge: 60, allowQuery: ['page'] } }, }, }) ``` #### Route Rule Types Move to `h3/rules` Nitro v3 builds route rules on h3, so custom route rules are declared there rather than on `nitro/types`. `NitroRouteConfig` and `NitroRouteRules` are still exported as deprecated aliases, but they are now type aliases rather than interfaces, so augmenting them fails with `TS2300: Duplicate identifier`. There are two interfaces to declare, and they are separate on purpose. `RouteRuleConfig` is what a rule looks like in `nuxt.config`, and `RouteRules` is what a matched rule looks like at runtime: ```diff - declare module 'nitropack/types' { - interface NitroRouteConfig { + declare module 'h3/rules' { + interface RouteRuleConfig { myModule?: { enabled: boolean } } - interface NitroRouteRules { + interface RouteRules { myModule?: { enabled: boolean } } } ``` A rule that nothing declares now reads back as `unknown` rather than `any`, so it needs a cast at the point of use: ```diff - const enabled = rules.myUndeclaredRule + const enabled = rules.myUndeclaredRule as boolean | undefined ``` #### The Server `tsconfig.json` Is Generated by Nuxt Nuxt now generates `.nuxt/tsconfig.server.json` itself, as one of the tsconfigs it writes per environment, rather than delegating it to the server builder. If you extended it through Nitro, use the Nuxt option instead: ```diff export default defineNuxtConfig({ - nitro: { - typescript: { - tsConfig: { compilerOptions: { /* ... */ } }, - }, - }, + typescript: { + serverTsConfig: { compilerOptions: { /* ... */ } }, + }, }) ``` `typescript.serverTsConfig` already existed in Nuxt 4 and was kept in sync with `nitro.typescript.tsConfig`, so this is a no-op if you were already using it. #### For Module Authors: Additional Changes - **Nitro plugin imports**: Use `import { definePlugin } from 'nitro'`, which is now required by default. See [Server Auto-Imports Are Now Opt-In](#server-auto-imports-are-now-opt-in). - **Route rule helpers**: `basicAuth` route rules are replaced by middleware, and a new `cors` rule replaces manual CORS wiring. See the [Nitro migration guide](https://nitro.build/docs/migration) for the runtime details. - **Runtime hooks**: `nitroApp.hooks.hook('beforeResponse', ...)` and `nitroApp.hooks.hook('afterResponse', ...)` have been replaced by `nitroApp.hooks.hook('response', ...)`. - **getRouteRules() from nitro/app**: On the server, the Nitro helper changed from `getRouteRules(event)` to `getRouteRules(method, pathname)`, which returns `{ routeRules }`. ### Removal of `experimental.externalVue` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The `experimental.externalVue` option has been removed. Vue compiler dependencies (`@babel/parser`, `@vue/compiler-core`, `@vue/compiler-dom`, `@vue/compiler-ssr`, `estree-walker`) are now always replaced with mock proxies in the server bundle when `vue.runtimeCompiler` is not enabled. #### Reasons for Change With the migration to Nitro v3, all dependencies are bundled into the server output by default (unlike Nitro v2, which externalized `node_modules`). The `externalVue` option was originally designed to keep Vue as an external dependency, which was needed to avoid multiple copies of Vue from being bundled, but since Nitro v3 bundles everything regardless, the option became a no-op. Vue's server builds include the full compiler toolchain, pulling `@babel/parser` (465KB) and other compiler packages into the server bundle unnecessarily. These compiler packages are only needed when `vue.runtimeCompiler` is enabled for runtime template compilation. By always mocking these compiler dependencies, the default server bundle size is reduced by approximately 860KB (~59%). #### Migration Steps If you previously set `experimental.externalVue` explicitly, you should now remove it. ```diff export default defineNuxtConfig({ experimental: { - externalVue: false, }, }) ``` If you use `vue.runtimeCompiler: true`, the real compiler packages are still included as before. ### `experimental.parseErrorData` Is No Longer Configurable ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The `experimental.parseErrorData` option is deprecated, and on Nuxt 5 it is forced on. Setting it to `false` logs a warning and is otherwise ignored, so `error.data` on the error page is always the value you passed to `createError`. On `compatibilityVersion: 4` the option still works and `false` still gives you a stringified `error.data`, so the behaviour only changes when you opt in to Nuxt 5. #### Reasons for Change When Nuxt renders an error page it fetches `/__nuxt_error` internally, passing the error along with the request. That used to spread the error across one query parameter per field, and because query values are always strings, `error.data` arrived as a string and had to be parsed back. `parseErrorData` existed to opt out of that parsing. The error is now sent as a single JSON-encoded parameter, so `error.data` keeps its original shape and is never stringified. Values also keep their types, so `status` is a number and booleans are booleans rather than the strings `'true'` and `'false'`. With nothing stringifying `error.data`, the option only survives to re-stringify it for apps that still expect a string. #### Migration Steps Remove the option: ```diff export default defineNuxtConfig({ experimental: { - parseErrorData: false, }, }) ``` If you set it to `false` in order to keep parsing `error.data` yourself, drop that parsing too, as `error.data` now keeps whatever value you passed to `createError`: ```diff ``` ### `@vitejs/plugin-vue-jsx` Is Now Optional ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `@vitejs/plugin-vue-jsx` is no longer installed by default with `@nuxt/vite-builder`. It is now an optional peer dependency that is loaded on demand only when a `.jsx` or `.tsx` file is encountered during the build. If your project uses JSX/TSX components, Nuxt will automatically detect this and prompt you to install the package. #### Reasons for Change The `@vitejs/plugin-vue-jsx` plugin pulls in a significant dependency tree (Babel, `@vue/babel-plugin-jsx`, etc.) that is unnecessary for projects that don't use JSX. Making it optional reduces the default install size and speeds up dependency resolution for the majority of Nuxt projects. #### Migration Steps If your project uses `.jsx` or `.tsx` files, add `@vitejs/plugin-vue-jsx` as a dev dependency: ```bash [npm] npm install -D @vitejs/plugin-vue-jsx ``` ```bash [yarn] yarn add -D @vitejs/plugin-vue-jsx ``` ```bash [pnpm] pnpm add -D @vitejs/plugin-vue-jsx ``` ```bash [bun] bun add -D @vitejs/plugin-vue-jsx ``` Alternatively, Nuxt will prompt you to install it automatically the first time a JSX/TSX file is processed during development. If your project does not use JSX, no changes are needed. ### `giget` Is Now Optional (Remote Layers) ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `giget` is no longer installed by default. It is now an optional peer dependency of `@nuxt/kit`, needed only to download a layer that `extends` names by remote URL: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: ['github:my-org/my-theme'], }) ``` Local layers, layers in `~~/layers/`, and layers installed as packages are unaffected. #### Reasons for Change Most projects never extend from a remote source, so the downloader was being installed for everyone to serve a small minority. Downloading a layer at config-resolution time is also the least reproducible way to consume one: the fetch happens outside your package manager, so it is not in your lockfile and, unless you pin it yourself, not pinned to a revision. #### Migration Steps **Preferred: move the layer into package.json.** Every major package manager understands git URLs, so a remote layer can be a normal dependency. This puts it in your lockfile, pins it to an exact commit, and installs it alongside everything else: ```json [package.json] { "devDependencies": { "my-theme": "github:my-org/my-theme#4a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b" } } ``` Then extend from it by package name: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: ['my-theme'], }) ``` The part after `#` is any commit-ish, so a tag (`#v1.2.0`) or `#semver:^1.2.0` works too; a full commit SHA is the only form that is genuinely immutable. **Otherwise, install giget** and keep using a remote `extends` entry: ```bash [npm] npm install -D giget ``` ```bash [yarn] yarn add -D giget ``` ```bash [pnpm] pnpm add -D giget ``` ```bash [bun] bun add -D giget ``` If a remote layer is resolved without `giget` present, Nuxt reports which `extends` entry needs it. ### Removal of Legacy `_renderResponse` Support ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `ssrContext._renderResponse` is no longer checked as a fallback. Only the internal `ssrContext['~renderResponse']` (set by Nuxt's own router composable) is used. #### Reasons for Change The `_renderResponse` property on `ssrContext` was kept as a backward-compatibility fallback after [#33896](https://github.com/nuxt/nuxt/pull/33896) migrated the internal API to `~renderResponse`. The TODO comments indicated it should be removed in Nuxt v5. #### Migration Steps If you were setting `ssrContext._renderResponse` directly (which was never a public API), use `ssrContext['~renderResponse']` instead. The Nuxt router composable already uses the new property, so no changes are needed if you're going through `navigateTo` or route middleware. ### Non-Async `callHook` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With the upgrade to [hookable v6](https://github.com/unjs/hookable), `callHook` may now return `void` instead of always returning `Promise`. This is a significant performance improvement that avoids unnecessary `Promise` allocations when there are no registered hooks or all hooks are synchronous. By default (with `compatibilityVersion: 4`), Nuxt wraps `callHook` with `Promise.resolve()` so that existing `.then()` and `.catch()` chaining continues to work. With `compatibilityVersion: 5`, this wrapper is removed. This affects both build-time Nuxt hooks (used by Nuxt modules) and runtime Nuxt hooks (which you might use in your application code). #### Reasons for Change Hookable v6's `callHook` is 20-40x faster because it avoids creating a `Promise` when one is not needed. This benefits applications with many hook call sites. #### Migration Steps If you or your modules use `callHook` with `.then()` or `.catch()` chaining, switch to `await`: ```diff - nuxtApp.callHook('my:hook', data).then(() => { ... }) + await nuxtApp.callHook('my:hook', data) ``` ```diff - nuxtApp.hooks.callHook('my:hook', data).catch(err => { ... }) + try { await nuxtApp.hooks.callHook('my:hook', data) } catch (err) { ... } ``` You can test this feature early by setting `future.compatibilityVersion: 5` (see [Testing Nuxt 5](https://nuxt.com/docs/5.x/getting-started/upgrade#testing-nuxt-5)) or by enabling it explicitly with `experimental.asyncCallHook: false`. Alternatively, you can ensure `callHook` always returns a `Promise` with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { asyncCallHook: true, }, }) ``` ### Client-Only Comment Placeholders ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, client-only components (`.client.vue` files and `createClientOnly()` wrappers) now render an HTML comment (``) on the server instead of an empty `
` element. #### Reasons for Change When the placeholder `
` and the actual component root share the same tag name, Vue's runtime skips re-applying `setScopeId` during hydration. This causes scoped styles to be missing after the component mounts. Using a comment node avoids the tag name collision entirely. #### Migration Steps If you rely on the placeholder `
` to inherit attributes (`class`, `style`, etc.) for layout purposes (e.g., reserving space to prevent layout shift), wrap the component in `` with a `#fallback` slot instead: ```diff - + + + + ``` You can test this feature early by setting `future.compatibilityVersion: 5` (see [Testing Nuxt 5](https://nuxt.com/docs/5.x/getting-started/upgrade#testing-nuxt-5)) or by enabling it explicitly with `experimental.clientNodePlaceholder: true`. Alternatively, you can revert to the previous `
` placeholder behavior with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { clientNodePlaceholder: false, }, }) ``` ### Stricter Side-Effect Imports ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, Nuxt's generated `tsconfig.json` enables [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports). This is a default in TypeScript 7, so adopting it early keeps your project aligned ahead of that upgrade. With this option on, a side-effect-only import (`import './setup'`) that TypeScript cannot resolve to a module is now a type error, whereas it was previously ignored. This only affects type-checking (`nuxt typecheck` and your editor), not runtime behavior. #### Reasons for Change Unresolved side-effect imports were silently ignored, so a typo or a deleted file could pass type-checking. Flagging them catches these mistakes and matches the TypeScript 7 default. #### Migration Steps If type-checking now errors on a side-effect import of a non-code asset (for example `import '~/assets/styles.css'`), add an ambient module declaration so TypeScript knows the import is valid: ```ts [types.d.ts] declare module '*.css' {} ``` You can revert to the previous behavior by disabling the option in your `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedSideEffectImports: false, }, }, }, }) ``` ### Vue Options API Disabled by Default ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, Nuxt sets Vue's [`__VUE_OPTIONS_API__`](https://vuejs.org/api/compile-time-flags#VUE_OPTIONS_API) feature flag to `false`, which compiles Vue's Options API runtime out of the client bundle. #### Reasons for Change The Options API runtime ships in every client bundle even though most Nuxt applications are written with the Composition API and ` ``` For in-page updates that are not navigations, such as form validation or toasts, use [``](https://nuxt.com/docs/5.x/api/components/nuxt-announcer) with [`useAnnouncer`](https://nuxt.com/docs/5.x/api/composables/use-announcer) instead. ## Page Titles Because the route announcer follows the document title, giving every route a distinct title is the single most valuable thing you can do. Set a global template in `app.vue` and let each page fill in its own part: ```vue [app.vue] ``` ```vue [app/pages/about.vue] ``` If your titles come from route metadata rather than from the page itself, you can read [`definePageMeta`](https://nuxt.com/docs/5.x/directory-structure/app/pages#page-metadata) values from [`useRoute`](https://nuxt.com/docs/5.x/api/composables/use-route) in a layout. ## Links Use [``](https://nuxt.com/docs/5.x/api/components/nuxt-link) for in-app navigation. It renders a real ``, which means it is focusable, appears in the tab order, and works with middle-click and "open in new tab", all of which you would have to reimplement on a `
` with a `@click` handler calling `navigateTo`. ```vue ``` In a menu or a set of breadcrumbs, the link matching the current route already exposes `aria-current="page"`, so assistive technology can tell which item you are on. Where a different token describes the relationship better, such as a step in a multi-page form, set [`ariaCurrentValue`](https://nuxt.com/docs/5.x/api/components/nuxt-link#routerlink): ```vue ``` Links to files in your `public/` directory, or to another app on the same origin, are not routes that Vue Router knows about. Mark them as [`external`](https://nuxt.com/docs/5.x/api/components/nuxt-link#handling-static-file-and-cross-app-links) so the browser performs a real navigation instead of failing to match a route. ## Focus Management After a client-side navigation, focus stays where it was, which is usually the link the user just activated. Vue Router does not move it and neither does Nuxt, so a keyboard user can end up tabbing through the whole header again to reach the content that just changed. A skip link as the first tab stop of your app is the conventional fix, and it helps on the initial page load too: ```vue [app.vue] ``` `
` is not focusable on its own, so it needs `tabindex="-1"` to accept focus from the skip link or from a script. Use `-1` rather than a positive value, which would move the element in the tab order and surprise everyone else. If it suits your app, you can go further and move focus to the main region after every navigation from a plugin: ```ts [app/plugins/focus-main.client.ts] export default defineNuxtPlugin(() => { useRouter().afterEach((to, from) => { if (to.path === from.path) { return } nextTick(() => document.getElementById('main')?.focus()) }) }) ``` Navigate around your app with the keyboard alone. Tabbing from the skip link into `
` after a couple of navigations will surface most focus problems quickly. ## Scroll Behavior Nuxt scrolls to the top on a new route, restores the previous position when the user goes back, and scrolls to hash targets. If you need something different, such as smooth scrolling or a different offset, configure [`scrollBehaviorType`](https://nuxt.com/docs/5.x/guide/recipes/custom-routing#scroll-behavior-for-hash-links) or write your own `scrollBehavior` in [`router.options.ts`](https://nuxt.com/docs/5.x/guide/recipes/custom-routing#router-options). Bear in mind that smooth scrolling should respect the user's `prefers-reduced-motion` setting. ## Useful Resources - [Web Accessibility Initiative (WAI)](https://www.w3.org/WAI/) - [MDN: Accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility) - [Understanding WCAG 2.1](https://www.w3.org/WAI/WCAG21/Understanding/) # Dev Containers > Set up or open a Nuxt project in a dev container for a consistent development environment. ## Setting Up a Dev Container If you're starting a new Nuxt project and want to develop inside a dev container, you can add the configuration yourself. Read more about dev containers ### Prerequisites - [Visual Studio Code](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) - [Docker Desktop](https://www.docker.com/products/docker-desktop/) or [Docker Engine](https://docs.docker.com/engine/) ### Create the Configuration Create a `.devcontainer/` folder in your project root with these two files: ```json [devcontainer.json] { "name": "nuxt-devcontainer", "build": { "dockerfile": "Dockerfile", "context": "../" }, "forwardPorts": [3000], "portsAttributes": { "3000": { "label": "Application", "onAutoForward": "openPreview" } }, "mounts": [ "type=volume,target=${containerWorkspaceFolder}/node_modules" ], "postStartCommand": "pnpm install && pnpm dev:prepare" } ``` ```dockerfile [Dockerfile] FROM node:lts WORKDIR /app RUN npm i -g corepack && corepack enable COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ RUN pnpm install --frozen-lockfile COPY . . ``` This configuration uses Node.js LTS and enables pnpm via corepack. It forwards port 3000 for the Nuxt dev server and persists `node_modules` in a Docker volume to avoid reinstallation on container restarts. To use a different package manager, replace `corepack enable` with your preferred manager (for example, `npm install -g yarn`) and update the `postStartCommand` accordingly. ## Opening an Existing Dev Container If a project already includes a dev container configuration, you can open it using any of these methods: ### 1. VS Code Prompt When you open the project in VS Code, you should see a notification in the bottom right corner: > "Reopen in Dev Containers" Click this button to build and open the project in a dev container. ### 2. Command Palette If you dismiss the prompt or want to manually trigger it: 1. Open the Command Palette (`Cmd+Shift+P` on Mac, `Ctrl+Shift+P` on Windows/Linux) 2. Search for **"Dev Containers: Reopen in Container"** 3. Select it VS Code will build the container and reopen your project. ### 3. Dev Containers CLI For advanced users or CI workflows, you can use the Dev Containers CLI directly: ```bash # Install the CLI (if not already installed) npm install -g @devcontainers/cli # Build and open the project in a container devcontainer up --workspace-folder . # After making changes to .devcontainer, rebuild devcontainer build ``` ## Next Steps Once the container is running: ```bash pnpm dev ``` Your Nuxt app will be available at [http://localhost:3000](http://localhost:3000). # Nuxt and Hydration > Why fixing hydration issues is important When developing, you may face hydration issues. Don't ignore those warnings. ## Why Is It Important to Fix Them? Hydration mismatches are not just warnings - they are indicators of serious problems that can break your application: ### Performance Impact - **Increased time to interactive**: Hydration errors force Vue to re-render the entire component tree, which will increase the time for your Nuxt app to become interactive - **Poor user experience**: Users may see content flashing or unexpected layout shifts ### Functionality Issues - **Broken interactivity**: Event listeners may not attach properly, leaving buttons and forms non-functional - **State inconsistencies**: Application state can become out of sync between what the user sees and what the application thinks is rendered - **SEO problems**: Search engines may index different content than what users actually see ## How to Detect Them ### Development Console Warnings Vue will log hydration mismatch warnings in the browser console during development: ![Screenshot of Vue hydration mismatch warning in the browser console](https://nuxt.com/assets/docs/best-practices/vue-console-hydration.png) ## Common Reasons ### Browser-only APIs in Server Context **Problem**: Using browser-specific APIs during server-side rendering. ```html ``` **Solution**: You can use [`useCookie`](https://nuxt.com/docs/5.x/api/composables/use-cookie): ```html ``` ### Inconsistent Data **Problem**: Different data between server and client. ```html ``` **Solution**: Use SSR-friendly state: ```html ``` ### Conditional Rendering Based on Client State **Problem**: Using client-only conditions during SSR. ```html ``` **Solution**: Use media queries or handle it client-side: ```html ``` ### Third-party Libraries with Side Effects **Problem**: Libraries that modify the DOM or have browser dependencies (this happens a LOT with tag managers). ```html ``` **Solution**: Initialise libraries after hydration has completed: ```html ``` ### Dynamic Content Based on Time **Problem**: Content that changes based on current time. ```html ``` **Solution**: Use [`NuxtTime`](https://nuxt.com/docs/5.x/api/components/nuxt-time) component or handle it client-side: ```html ``` ```html ``` ## In Summary 1. **Use SSR-friendly composables**: [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch), [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data), [`useState`](https://nuxt.com/docs/5.x/api/composables/use-state) 2. **Wrap client-only code**: Use [`ClientOnly`](https://nuxt.com/docs/5.x/api/components/client-only) component for browser-specific content 3. **Consistent data sources**: Ensure server and client uses the same data 4. **Avoid side effects in setup**: Move browser-dependent code to `onMounted` You can read the [Vue documentation on SSR hydration mismatch](https://vuejs.org/guide/scaling-up/ssr#hydration-mismatch) for a better understanding of hydration. # Nuxt performance > Best practices for improving performance of Nuxt apps. Nuxt comes with built-in features designed to improve your application's performance and contribute to better [Core Web Vitals](https://web.dev/articles/vitals). There are also multiple Nuxt core modules that assist in improving performance in specific areas. This guide outlines best practices to optimize performance of your Nuxt application. ## Built-in Features Nuxt offers several built-in features that help you optimize performance of your website. Understanding how these features work is crucial for achieving blazingly-fast performance. ### Links [``](https://nuxt.com/docs/5.x/api/components/nuxt-link) is a drop-in replacement for both Vue Router's `` component and HTML's `` tag. It intelligently determines whether the link is internal or external and renders it accordingly with available optimizations (prefetching, default attributes, etc.) ```html About page ``` Nuxt automatically includes smart prefetching. That means it detects when a link is visible (by default), either in the viewport or when scrolling and prefetches the JavaScript for those pages so that they are ready when the user clicks the link. You can also opt for prefetching on interaction instead: ```ts export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { prefetchOn: { interaction: true, visibility: false, }, }, }, }, }) ``` ### Hybrid Rendering In more complex applications, we may need a full control over how our application is rendered to support cases where some pages could be generated at build time, while others should be client-side rendered Hybrid rendering allows different caching rules per route using Route Rules and decides how the server should respond to a new request on a given URL: ```ts export default defineNuxtConfig({ routeRules: { '/': { prerender: true, }, '/products/**': { swr: 3600, }, '/blog': { isr: 3600, }, '/admin/**': { ssr: false, }, }, }) ``` Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using Nitro caching layer. ### Lazy Loading Components To dynamically import a component (also known as lazy-loading a component) all you need to do is add the Lazy prefix to the component's name. This is useful if the component is not always needed. ```html ``` By using the Lazy prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size. ### Lazy Hydration It is not always necessary to hydrate (or make interactive) all the components of your site on the initial load. Using lazy hydration, you can control when components can have their code loaded, which can improve the time-to-interactive metric for your app. Nuxt allows you to control when components become interactive with lazy hydration (added in Nuxt v3.16). ```html ``` To optimize your app, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks. For content and marketing sites that need little or no client-side interactivity, you can go further and combine prerendering, the `noScripts` route rule, [server components](https://nuxt.com/docs/5.x/guide/concepts/server-components) and lazy hydration to ship near-zero JavaScript. ### Fetching data To avoid fetching same data twice (once on the server and once on client) Nuxt provides [`useFetch`](https://nuxt.com/docs/5.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/5.x/api/composables/use-async-data). They ensure that if an API call is made on the server, the data is forwarded to the client in the payload instead of being fetched again. ## Core Nuxt Modules Apart from Nuxt's built-in features, there are also core modules maintained by the Nuxt team which help improve performance even further. These modules help handle assets such as images, custom fonts, or third party scripts. ### Images Unoptimized images can have a significant negative impact on your website performance, specifically the [Largest Contentful Paint (LCP)](https://web.dev/articles/lcp) score. In Nuxt we can use [Nuxt Image](https://image.nuxt.com/) module that is a plug-and-play image optimization for Nuxt apps. It allows resizing and transforming your images using built-in optimizer or your favorite images CDN. [``](https://nuxt.com/docs/5.x/api/components/nuxt-img) is a drop-in replacement for the native `` tag that comes with following enhancements: - Uses built-in provider to optimize local and remote images - Converts `src` to provider optimized URLs with modern formats such as WebP or Avif - Automatically resizes images based on `width` and `height` - Generates responsive `sizes` when providing sizes option - Supports native `lazy loading` as well as other `` attributes Images in your website can usually be separated by importance; the ones that are needed to be delivered first at initial load (i.e. `Largest Contentful Paint`), and the ones that can be loaded later or when specifically needed. For that, we could use the following optimizations: ```html ``` ### Fonts [Nuxt Fonts](https://fonts.nuxt.com/) will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance. It includes built-in automatic self-hosting for any font file which means you can optimally load web fonts with reduced layout shift, thanks to the underlying package [fontaine](https://github.com/unjs/fontaine). Nuxt Fonts processes all your CSS and does the following things automatically when it encounters a font-family declaration. 1. **Resolves fonts** โ€“ Looks for font files in public/, then checks web providers like Google, Bunny, and Fontshare. 2. **Generates @font-face rules** โ€“ Injects CSS rules to load fonts from the correct sources. 3. **Proxies & caches fonts** โ€“ Rewrites URLs to `/_fonts`, downloads and caches fonts locally. 4. **Creates fallback metrics** โ€“ Adjusts local system fonts to match web fonts, reducing layout shift ([CLS](https://web.dev/articles/cls)). 5. **Includes fonts in build** โ€“ Bundles fonts with your project, hashing file names and setting long-lived cache headers. It supports multiple providers that are designed to be pluggable and extensible, so no matter your setup you should be able to use an existing provider or write your own. ### Scripts Third-party resources like analytics tools, video embeds, maps, and social media integrations enhance website functionality but can significantly degrade user experience and negatively impact [Interaction to Next Paint (INP)](https://web.dev/articles/inp) and Largest Contentful Paint (LCP) scores. [Nuxt Scripts](https://scripts.nuxt.com/) lets you load third-party scripts with better performance, privacy, security and DX. Nuxt Scripts provides an abstraction layer on top of third-party scripts, providing SSR support and type-safety and while still giving you full low-level control over how a script is loaded. ```ts const { onLoaded, proxy } = useScriptGoogleAnalytics( { id: 'G-1234567', scriptOptions: { trigger: 'manual', }, }, ) // queue events to be sent when ga loads proxy.gtag('config', 'UA-123456789-1') // or wait until ga is loaded onLoaded((gtag) => { // script loaded }) ``` ## Profiling Tools To improve performance, we need to first know how to measure it, starting with measuring performance during development - on local environment, and then moving to auditing application that are deployed on production. ### Nuxi Analyze [This](https://nuxt.com/docs/5.x/api/commands/analyze) command of `nuxt` allows you to analyze the production bundle of your Nuxt application. It leverages `vite-bundle-visualizer` (similar to `webpack-bundle-analyzer`) to generate a visual representation of your application's bundle, making it easier to identify which components take up the most space. When you see a large block in the visualization, it often signals an opportunity for optimizationโ€”whether by splitting it into smaller parts, implementing lazy loading, or replacing it with a more efficient alternative, especially for third-party libraries. Large blocks containing multiple elements can often be reduced by importing only the necessary components rather than entire modules while large standalone blocks may be better suited for lazy loading rather than being included in the main bundle. ### Nuxt DevTools The [Nuxt DevTools](https://devtools.nuxt.com/) gives you insights and transparency about your Nuxt App to identify performance gaps and seamlessly manage your app configurations. ![Nuxt DevTools example](https://user-images.githubusercontent.com/11247099/217670806-fb39aeff-3881-44e5-b9c8-6c757f5925fc.png) It comes with several features we can use to measure performance of Nuxt apps: 1. **Timeline** โ€“ Tracks time spent on rendering, updating, and initializing components to identify performance bottlenecks. 2. **Assets** โ€“ Displays file sizes (e.g., images) without transformations. 3. **Render Tree** โ€“ Shows connections between Vue components, scripts, and styles to optimize dynamic loading. 4. **Inspect** โ€“ Lists all files used in the Vue app with their size and evaluation time. ### Chrome DevTools Chrome DevTools come with two useful tabs for measuring performance; `Performance` and `Lighthouse`. When you open the [Performance](https://developer.chrome.com/docs/devtools/performance/overview) panel, it instantly shows your local **Largest Contentful Paint (LCP)** and **Cumulative Layout Shift (CLS)** scores (good, needs improvement, or bad). If you interact with the page, it also captures **Interaction to Next Paint (INP)**, giving you a full view of your Core Web Vitals based on your device and network. ![Chrome DevTools Performance Panel](https://developer.chrome.com/static/docs/devtools/performance/image/cpu-throttling_856.png) [Lighthouse](https://developer.chrome.com/docs/devtools/lighthouse) audits performance, accessibility, SEO, progressive web apps, and best practices. It runs tests on your page and generates a report. Use failing audits as a guide to improve your site. ![Lighthouse](https://developer.chrome.com/static/docs/lighthouse/images/lighthouse-overview_720.png) Each audit has a reference document explaining why the audit is important, as well as how to fix it. ### PageSpeed Insights [PageSpeed Insights (PSI)](https://developers.google.com/speed/docs/insights/v5/about) reports on the user experience of a page on both mobile and desktop devices, and provides suggestions on how that page may be improved. It provides both lab and field data about a page. Lab data is useful for debugging issues, as it is collected in a controlled environment while field data is useful for capturing true, real-world user experience. ### Web Page Test [WebPageTest](https://www.webpagetest.org/) is a web performance tool providing deep diagnostic information about how a page performs under a variety of conditions. Each test can be run from different locations around the world, on real browsers, over any number of customizable network conditions. ## Common Problems When building more complex Nuxt applications, you will probably encounter some of the problems listed below. Understanding these problems and fixing them will help you improve performance of your website. ### Overusing plugins **Problem**: A large number of plugins can cause performance issues, especially if they require expensive computations or take too long to initialize. Since plugins run during the hydration phase, inefficient setups can block rendering and degrade the user experience. **Solution**: Inspect your plugins and see if some of them could be implemented rather as a composable or utility function instead. ### Unused code / dependencies **Problem**: With the development of the project, there can be a case where there will be some unused code or a dependency. This additional functionality may not be used or needed while it will be increase the bundle size of our project. **Solution**: Inspect your `package.json` for unused dependencies and analyze your code for unused utils/composables/functions. ### Not using Vue Performance tips **Problem**: [Vue documentation](https://vuejs.org/guide/best-practices/performance) lists several Performance improvements we can use in our Nuxt projects as well but as they are part of Vue documentation, developers tend to forget about it and focus on Nuxt specific improvements only - while Nuxt application is still a Vue project. **Solution**: Use concepts such as `shallowRef`, `v-memo`, `v-once`, etc to improve performance. ### Not following patterns **Problem**: The more people are currently working on the project, the more difficult it will be to maintain the stable codebase. Developers have a tendency to introduce new concepts they've seen in another project which can cause conflicts and problems with performance. **Solution**: Establish rules and patterns in the project such as [Good practices and Design Patterns for Vue Composables](https://dev.to/jacobandrewsky/good-practices-and-design-patterns-for-vue-composables-24lk) ### Trying to load everything at the same time **Problem**: When a page is loaded and it is not correctly instructed about the order of loading elements it will result in fetching everything at the same time - which can be slow and result in bad User Experience. **Solution**: Use concepts such as Progressive Enhancement where core webpage content is set first, then more nuanced and technically rigorous layers of presentation and features are added on top as the browser/internet connection allow. ## Useful Resources To learn more about various techniques for improving performance, take a look at the following resources: 1. [Apply instant loading with the PRPL pattern](https://web.dev/articles/apply-instant-loading-with-prpl) 2. [Perceived performance](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance) 3. [Understanding Critical Rendering Path](https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Critical_rendering_path) # Nuxt Plugins > Best practices when using Nuxt plugins. Plugins in Nuxt allow you to extend your application with additional functionality. However, improper use can lead to performance bottlenecks. This guide outlines best practices to optimize your Nuxt plugins. ## Avoid Costly Plugin Setup A large number of plugins can cause performance issues, especially if they require expensive computations or take too long to initialize. Since plugins run during the hydration phase, inefficient setups can block rendering and degrade the user experience. ## Use Composition Whenever Possible Whenever possible, favor composition over plugins. Just like in Vue, many utilities and composables can be used directly without the need for a plugin. This keeps your project lightweight and improves maintainability. ## If `async`, Enable `parallel` By default, all plugins loads synchronously. When defining asynchronous plugins, setting `parallel: true` allows multiple plugins to load concurrently, improving performance by preventing blocking operations. # Auto-imports > Nuxt auto-imports components, composables, helper functions and Vue APIs. Nuxt auto-imports components, composables and [Vue.js APIs](https://vuejs.org/api/) to use across your application without explicitly importing them. ```vue [app/app.vue]twoslash ``` Thanks to its opinionated directory structure, Nuxt can auto-import your [`app/components/`](https://nuxt.com/docs/5.x/directory-structure/app/components), [`app/composables/`](https://nuxt.com/docs/5.x/directory-structure/app/composables) and [`app/utils/`](https://nuxt.com/docs/5.x/directory-structure/app/utils). Contrary to a classic global declaration, Nuxt preserves typings, IDEs completions and hints, and **only includes what is used in your production code**. In the docs, every function that is not explicitly imported is auto-imported by Nuxt and can be used as-is in your code. You can find a reference for auto-imported components, composables and utilities in the [API section](https://nuxt.com/docs/5.x/api). In the [`server`](https://nuxt.com/docs/5.x/directory-structure/server) directory, Nuxt auto-imports exported functions and variables from `server/utils/`. You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports`](https://nuxt.com/docs/5.x/api/nuxt-config#imports) section of your `nuxt.config` file. ## Built-in Auto-imports Nuxt auto-imports functions and composables to perform [data fetching](https://nuxt.com/docs/5.x/getting-started/data-fetching), get access to the [app context](https://nuxt.com/docs/5.x/api/composables/use-nuxt-app) and [runtime config](https://nuxt.com/docs/5.x/guide/going-further/runtime-config), manage [state](https://nuxt.com/docs/5.x/getting-started/state-management) or define components and plugins. ```vuetwoslash ``` Vue exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt. ```vuetwoslash ``` ### Vue and Nuxt Composables When you are using the built-in Composition API composables provided by Vue and Nuxt, be aware that many of them rely on being called in the right *context*. During a component lifecycle, Vue tracks the temporary instance of the current component (and similarly, Nuxt tracks a temporary instance of `nuxtApp`) via a global variable, and then unsets it in the same tick. This is essential when server rendering, both to avoid cross-request state pollution (leaking a shared reference between two users) and to avoid leakage between different components. That means that (with very few exceptions) you cannot use them outside a Nuxt plugin, Nuxt route middleware or Vue setup function. On top of that, you must use them synchronously - that is, you cannot use `await` before calling a composable, except within ` ``` ### Disabling Auto-imports If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { autoImport: false, }, }) ``` This will disable auto-imports completely but it's still possible to use [explicit imports](https://nuxt.com/docs/5.x/guide/concepts/auto-imports#explicit-imports) from `#imports`. ### Partially Disabling Auto-imports If you want framework-specific functions like `ref` to remain auto-imported but wish to disable auto-imports for your own code (e.g., custom composables), you can set the `imports.scan` option to `false` in your `nuxt.config.ts` file: ```ts export default defineNuxtConfig({ imports: { scan: false, }, }) ``` With this configuration: - Framework functions like `ref`, `computed`, or `watch` will still work without needing manual imports. - Custom code, such as composables, will need to be manually imported in your files. **Caution:** This setup has certain limitations: - If you structure your project with layers, you will need to explicitly import the composables from each layer, rather than relying on auto-imports. - This breaks the layer systemโ€™s override feature. If you use `imports.scan: false`, ensure you understand this side-effect and adjust your architecture accordingly. ## Auto-imported Components Nuxt also automatically imports components from your `~/components` directory, although this is configured separately from auto-importing composables and utility functions. To disable auto-importing components from your own `~/components` directory, you can set `components.dirs` to an empty array (though note that this will not affect components added by modules). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: { dirs: [], }, }) ``` ## Auto-Import from Third-Party Packages Nuxt also allows auto-importing from third-party packages. If you are using the Nuxt module for that package, it is likely that the module has already configured auto-imports for that package. For example, you could enable the auto-import of the `useI18n` composable from the `vue-i18n` package like this: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { presets: [ { from: 'vue-i18n', imports: ['useI18n'], }, ], }, }) ``` # Code Style > Nuxt supports ESLint out of the box ## ESLint The recommended approach for Nuxt is to enable ESLint support using the [`@nuxt/eslint`](https://eslint.nuxt.com/packages/module) module, that will setup project-aware ESLint configuration for you. The module is designed for the [new ESLint flat config format](https://eslint.org/docs/latest/use/configure/configuration-files) which is the [default format since ESLint v9](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/). If you are using the legacy `.eslintrc` config, you will need to [configure manually with `@nuxt/eslint-config`](https://eslint.nuxt.com/packages/config#customizing-the-config). We highly recommend you to migrate over the flat config to be future-proof. ## Quick Setup ```bash npx nuxt module add eslint ``` Start your Nuxt app, a `eslint.config.mjs` file will be generated under your project root. You can customize it as needed. You can learn more about the module and customizations in [Nuxt ESLint's documentation](https://eslint.nuxt.com/packages/module). # ES Modules > Nuxt uses native ES modules. This guide helps explain what ES Modules are and how to make a Nuxt app (or upstream library) compatible with ESM. ## Background ### CommonJS Modules CommonJS (CJS) is a format introduced by Node.js that allows sharing functionality between isolated JavaScript modules ([read more](https://nodejs.org/api/modules.html)). You might be already familiar with this syntax: ```js const a = require('./a') module.exports.a = a ``` Bundlers like webpack and Rollup support this syntax and allow you to use modules written in CommonJS in the browser. ### ESM Syntax Most of the time, when people talk about ESM vs. CJS, they are talking about a different syntax for writing [modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ```js import a from './a' export { a } ``` Before ECMAScript Modules (ESM) became a standard (it took more than 10 years!), tooling like [webpack](https://webpack.js.org/guides/ecma-script-modules/) and even languages like TypeScript started supporting so-called **ESM syntax**. However, there are some key differences with actual spec; here's [a helpful explainer](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/). ### What is 'Native' ESM? You may have been writing your app using ESM syntax for a long time. After all, it's natively supported by the browser, and in Nuxt 2 we compiled all the code you wrote to the appropriate format (CJS for server, ESM for browser). When adding modules to your package, things were a little different. A sample library might expose both CJS and ESM versions, and let us pick which one we wanted: ```json { "name": "sample-library", "main": "dist/sample-library.cjs.js", "module": "dist/sample-library.esm.js" } ``` So in Nuxt 2, the bundler (webpack) would pull in the CJS file ('main') for the server build and use the ESM file ('module') for the client build. The `module` field is a convention used by bundlers like webpack and Rollup, but is not recognized by Node.js itself. Node.js only uses the [`exports`](https://nodejs.org/api/packages.html#exports) and [`main`](https://nodejs.org/api/packages.html#main) fields for module resolution. However, in recent Node.js LTS releases, it is now possible to [use native ESM module](https://nodejs.org/api/esm.html) within Node.js. That means that Node.js itself can process JavaScript using ESM syntax, although it doesn't do it by default. The two most common ways to enable ESM syntax are: - set `"type": "module"` within your `package.json` and keep using `.js` extension - use the `.mjs` file extensions (recommended) This is what we do for Nuxt Nitro; we output a `.output/server/index.mjs` file. That tells Node.js to treat this file as a native ES module. ### What Are Valid Imports in a Node.js Context? When you `import` a module rather than `require` it, Node.js resolves it differently. For example, when you import `sample-library`, Node.js will look for the `exports` entry in that library's `package.json`, or fall back to the `main` entry if `exports` is not defined. This is also true of dynamic imports, like `const b = await import('sample-library')`. Node supports the following kinds of imports (see [docs](https://nodejs.org/api/packages.html#determining-module-system)): 1. files ending in `.mjs` - these are expected to use ESM syntax 2. files ending in `.cjs` - these are expected to use CJS syntax 3. files ending in `.js` - these are expected to use CJS syntax unless their `package.json` has `"type": "module"` ### What Kinds of Problems Can There Be? For a long time module authors have been producing ESM-syntax builds but using conventions like `.esm.js` or `.es.js`, which they have added to the `module` field in their `package.json`. This hasn't been a problem until now because they have only been used by bundlers like webpack, which don't especially care about the file extension. However, if you try to import a package with an `.esm.js` file in a Node.js ESM context, it won't work, and you'll get an error like: ```bash [Terminal] (node:22145) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. /path/to/index.js:1 export default {} ^^^^^^ SyntaxError: Unexpected token 'export' at wrapSafe (internal/modules/cjs/loader.js:1001:16) at Module._compile (internal/modules/cjs/loader.js:1049:27) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10) .... at async Object.loadESM (internal/process/esm_loader.js:68:5) ``` You might also get this error if you have a named import from an ESM-syntax build that Node.js thinks is CJS: ```bash [Terminal] file:///path/to/index.mjs:5 import { named } from 'sample-library' ^^^^^ SyntaxError: Named export 'named' not found. The requested module 'sample-library' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using: import pkg from 'sample-library'; const { named } = pkg; at ModuleJob._instantiate (internal/modules/esm/module_job.js:120:21) at async ModuleJob.run (internal/modules/esm/module_job.js:165:5) at async Loader.import (internal/modules/esm/loader.js:177:24) at async Object.loadESM (internal/process/esm_loader.js:68:5) ``` ## Troubleshooting ESM Issues If you encounter these errors, the issue is almost certainly with the upstream library. They need to [fix their library](https://nuxt.com/docs/5.x/guide/concepts/esm#library-author-guide) to support being imported by Node. ### Transpiling Libraries In the meantime, you can tell Nuxt not to try to import these libraries by adding them to `build.transpile`: ```tstwoslash export default defineNuxtConfig({ build: { transpile: ['sample-library'], }, }) ``` You may find that you *also* need to add other packages that are being imported by these libraries. ### Aliasing Libraries In some cases, you may also need to manually alias the library to the CJS version, for example: ```tstwoslash export default defineNuxtConfig({ alias: { 'sample-library': 'sample-library/dist/sample-library.cjs.js', }, }) ``` ### Default Exports A dependency with CommonJS format, can use `module.exports` or `exports` to provide a default export: ```js [node_modules/cjs-pkg/index.js] module.exports = { test: 123 } // or exports.test = 123 ``` This normally works well if we `require` such dependency: ```js [test.cjs] const pkg = require('cjs-pkg') console.log(pkg) // { test: 123 } ``` [Node.js in native ESM mode](https://nodejs.org/api/esm.html#interoperability-with-commonjs), [typescript with `esModuleInterop` enabled](https://www.typescriptlang.org/tsconfig/#esModuleInterop) and bundlers such as webpack, provide a compatibility mechanism so that we can default import such library. This mechanism is often referred to as "interop require default": ```js import pkg from 'cjs-pkg' console.log(pkg) // { test: 123 } ``` However, because of the complexities of syntax detection and different bundle formats, there is always a chance that the interop default fails and we end up with something like this: ```js import pkg from 'cjs-pkg' console.log(pkg) // { default: { test: 123 } } ``` Also when using dynamic import syntax (in both CJS and ESM files), we always have this situation: ```js import('cjs-pkg').then(console.log) // [Module: null prototype] { default: { test: '123' } } ``` In this case, we need to manually interop the default export: ```js // Static import import { default as pkg } from 'cjs-pkg' // Dynamic import import('cjs-pkg').then(m => m.default || m).then(console.log) ``` For handling more complex situations and more safety, we recommend [mlly](https://github.com/unjs/mlly), which can preserve named exports. ```js import { interopDefault } from 'mlly' // Assuming the shape is { default: { foo: 'bar' }, baz: 'qux' } import myModule from 'my-module' console.log(interopDefault(myModule)) // { foo: 'bar', baz: 'qux' } ``` ## Library Author Guide The good news is that it's relatively simple to fix issues of ESM compatibility. There are two main options: 1. **You can rename your ESM files to end with .mjs.**
*This is the recommended and simplest approach.* You may have to sort out issues with your library's dependencies and possibly with your build system, but in most cases, this should fix the problem for you. It's also recommended to rename your CJS files to end with `.cjs`, for the greatest explicitness. 2. **You can opt to make your entire library ESM-only**.
This would mean setting `"type": "module"` in your `package.json` and ensuring that your built library uses ESM syntax. However, you may face issues with your dependencies - and this approach means your library can *only* be consumed in an ESM context. ### Migration The initial step from CJS to ESM is updating any usage of `require` to use `import` instead: ```ts [Before] module.exports = function () { /* ... */ } exports.hello = 'world' ``` ```ts [After] export default function () { /* ... */ } export const hello = 'world' ``` ```js [Before] const myLib = require('my-lib') ``` ```js [After] import myLib from 'my-lib' // or const dynamicMyLib = await import('my-lib').then(lib => lib.default || lib) ``` In ESM Modules, unlike CJS, `require`, `require.resolve`, `__filename` and `__dirname` globals are not available and should be replaced with `import()` and `import.meta.filename`. ```js [Before] const { join } = require('node:path') const newDir = join(__dirname, 'new-dir') ``` ```js [After] import { fileURLToPath } from 'node:url' const newDir = fileURLToPath(new URL('./new-dir', import.meta.url)) ``` ```js [Before] const someFile = require.resolve('./lib/foo.js') ``` ```js [After] import { resolveModulePath } from 'exsolve' const someFile = resolveModulePath('my-lib', { from: import.meta.url }) ``` ### Best Practices - Prefer named exports rather than default export. This helps reduce CJS conflicts. (see [Default exports](https://nuxt.com/docs/5.x/guide/concepts/esm#default-exports) section) - Avoid depending on Node.js built-ins and CommonJS or Node.js-only dependencies as much as possible to make your library usable in Browsers and Edge Workers without needing Nitro polyfills. - Use new `exports` field with conditional exports. ([read more](https://nodejs.org/api/packages.html#conditional-exports)). ```json { "exports": { ".": { "import": "./dist/mymodule.mjs" } } } ``` # Modules > Nuxt provides a module system to extend the framework core and simplify integrations. ## Exploring Nuxt Modules When developing production-grade applications with Nuxt you might find that the framework's core functionality is not enough. Nuxt can be extended with configuration options and plugins, but maintaining these customizations across multiple projects can be tedious, repetitive and time-consuming. On the other hand, supporting every project's needs out of the box would make Nuxt very complex and hard to use. This is one of the reasons why Nuxt provides a module system that makes it possible to extend the core. Nuxt modules are async functions that sequentially run when starting Nuxt in development mode using [`nuxt dev`](https://nuxt.com/docs/5.x/api/commands/dev) or building a project for production with [`nuxt build`](https://nuxt.com/docs/5.x/api/commands/build). They can override templates, configure webpack loaders, add CSS libraries, and perform many other useful tasks. Best of all, Nuxt modules can be distributed in npm packages. This makes it possible for them to be reused across projects and shared with the community, helping create an ecosystem of high-quality add-ons. Explore Nuxt Modules ## Add Nuxt Modules Once you have installed the modules you can add them to your [`nuxt.config.ts`](https://nuxt.com/docs/5.x/directory-structure/nuxt-config) file under the `modules` property. Module developers usually provide additional steps and details for usage. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ modules: [ // Using package name (recommended usage) '@nuxtjs/example', // Load a local module './modules/example', // Add module with inline-options ['./modules/example', { token: '123' }], // Inline module definition async (inlineOptions, nuxt) => { }, ], }) ``` Nuxt modules are now build-time-only, and the `buildModules` property used in Nuxt 2 is deprecated in favor of `modules`. ## Disabling Modules v4.3 You can disable a module by setting its config key to `false` in your Nuxt config. This is particularly useful when you want to disable modules inherited from layers. ```ts [nuxt.config.ts] export default defineNuxtConfig({ // Disable `@nuxt/image` module image: false, }) ``` ## Create a Nuxt Module Everyone has the opportunity to develop modules and we cannot wait to see what you will build. # Nuxt Lifecycle > Understanding the lifecycle of Nuxt applications can help you gain deeper insights into how the framework operates, especially for both server-side and client-side rendering. The goal of this chapter is to provide a high-level overview of the different parts of the framework, their execution order, and how they work together. ## Server Lifecycle On the server, the following steps are executed for every initial request to your application: ### Server plugins once Nuxt is powered by [Nitro](https://nitro.build/), a modern server engine. When Nitro starts, it initializes and executes the plugins under the [`/server/plugins`](https://nuxt.com/docs/5.x/directory-structure/server#server-plugins) directory. These plugins can: - Capture and handle application-wide errors. - Register hooks that execute when Nitro shuts down. - Register hooks for request lifecycle events, such as modifying responses. Nitro plugins are executed only once when the server starts. In a serverless environment, the server boots on each incoming request, and so do the Nitro plugins. However, they are not awaited. ### Server middleware After initializing the Nitro server, middleware under `server/middleware/` is executed for every request. Middleware can be used for tasks such as authentication, logging, or request transformation. Returning a value from middleware will terminate the request and send the returned value as the response. This behavior should generally be avoided to ensure proper request handling! ### App plugins The Vue and Nuxt instances are created first. Afterward, Nuxt executes its app plugins. This includes: - Built-in plugins, such as Vue Router and `unhead`. - Custom plugins located in the `app/plugins/` directory, including those without a suffix (e.g., `myPlugin.ts`) and those with the `.server` suffix (e.g., `myServerPlugin.server.ts`). Plugins execute in a specific order and may have dependencies on one another. For more details, including execution order and parallelism, refer to the [Plugins documentation](https://nuxt.com/docs/5.x/directory-structure/app/plugins). After this step, Nuxt calls the [`app:created`](https://nuxt.com/docs/5.x/api/advanced/hooks#app-hooks-runtime) hook, which can be used to execute additional logic. ### Route validation After initializing plugins and before executing middleware, Nuxt calls the `validate` method if it is defined in the `definePageMeta` function. The `validate` method, which can be synchronous or asynchronous, is often used to validate dynamic route parameters. - The `validate` function should return `true` if the parameters are valid. - If validation fails, it should return `false` or an object containing a `status` and/or `statusText` to terminate the request. For more information, see the [Route Validation documentation](https://nuxt.com/docs/5.x/getting-started/routing#route-validation). ### App middleware Middleware allows you to run code before navigating to a particular route. It is often used for tasks such as authentication, redirection, or logging. In Nuxt, there are three types of middleware: - **Global route middleware** - **Named route middleware** - **Anonymous (or inline) route middleware** Nuxt executes all global middleware on the initial page load (both on server and client) and then again before any client-side navigation. Named and anonymous middleware are executed only on the routes specified in the middleware property of the page(route) meta defined in the corresponding page components. For details about each type and examples, see the [Middleware documentation](https://nuxt.com/docs/5.x/directory-structure/app/middleware). Any redirection on the server will result in a `Location:` header being sent to the browser; the browser then makes a fresh request to this new location. All application state will be reset when this happens, unless persisted in a cookie. ### Page and components Nuxt renders the page and its components and fetches any required data with `useFetch` and `useAsyncData` during this step. Since there are no dynamic updates and no DOM operations occur on the server, Vue lifecycle hooks such as `onBeforeMount`, `onMounted`, and subsequent hooks are **NOT** executed during SSR. By default, Vue pauses dependency tracking during SSR for better performance. There is no reactivity on the server side because Vue SSR renders the app top-down as static HTML, making it impossible to go back and modify content that has already been rendered. You should avoid code that produces side effects that need cleanup in root scope of ` ``` On the initial request, the `counter` ref is initialized in the server since it is rendered inside the `

` tag. The contents of `handleClick` is never executed here. During hydration in the browser, the `counter` ref is re-initialized. The `handleClick` finally binds itself to the button; Therefore it is reasonable to deduce that the body of `handleClick` will always run in a browser environment. [Middlewares](https://nuxt.com/docs/5.x/directory-structure/app/middleware) and [pages](https://nuxt.com/docs/5.x/directory-structure/app/pages) run in the server and on the client during hydration. [Plugins](https://nuxt.com/docs/5.x/directory-structure/app/plugins) can be rendered on the server or client or both. [Components](https://nuxt.com/docs/5.x/directory-structure/app/components) can be forced to run on the client only as well. [Composables](https://nuxt.com/docs/5.x/directory-structure/app/composables) and [utilities](https://nuxt.com/docs/5.x/directory-structure/app/utils) are rendered based on the context of their usage. **Benefits of server-side rendering:** - **Performance**: Users can get immediate access to the page's content because browsers can display static content much faster than JavaScript-generated content. At the same time, Nuxt preserves the interactivity of a web application during the hydration process. - **Search Engine Optimization**: Universal rendering delivers the entire HTML content of the page to the browser as a classic server application. Web crawlers can directly index the page's content, which makes Universal rendering a great choice for any content that you want to index quickly. **Downsides of server-side rendering:** - **Development constraints:** Server and browser environments don't provide the same APIs, and it can be tricky to write code that can run on both sides seamlessly. Fortunately, Nuxt provides guidelines and specific variables to help you determine where a piece of code is executed. - **Cost:** A server needs to be running in order to render pages on the fly. This adds a monthly cost like any traditional server. However, the server calls are highly reduced thanks to universal rendering with the browser taking over on client-side navigation. A cost reduction is possible by leveraging [edge-side-rendering](https://nuxt.com/docs/5.x/guide/concepts/rendering#edge-side-rendering). Universal rendering is very versatile and can fit almost any use case, and is especially appropriate for any content-oriented websites: **blogs, marketing websites, portfolios, e-commerce sites, and marketplaces.** For more examples about writing Vue code without hydration mismatch, see [the Vue docs](https://vuejs.org/guide/scaling-up/ssr#hydration-mismatch). When importing a library that relies on browser APIs and has side effects, make sure the component importing it is only called client-side. Bundlers do not treeshake imports of modules containing side effects. ## Client-Side Rendering Out of the box, a traditional Vue.js application is rendered in the browser (or **client**). Then, Vue.js generates HTML elements after the browser downloads and parses all the JavaScript code containing the instructions to create the current interface. ![Users have to wait for the browser to download, parse and execute the JavaScript before seeing the page's content](https://nuxt.com/assets/docs/concepts/rendering/csr.svg) **Benefits of client-side rendering:** - **Development speed**: When working entirely on the client-side, we don't have to worry about the server compatibility of the code, for example, by using browser-only APIs like the `window` object. - **Cheaper:** Running a server adds a cost of infrastructure as you would need to run on a platform that supports JavaScript. We can host client-only applications on any static server with HTML, CSS, and JavaScript files. - **Offline:** Because code entirely runs in the browser, it can nicely keep working while the internet is unavailable. **Downsides of client-side rendering:** - **Performance**: The user has to wait for the browser to download, parse and run JavaScript files. Depending on the network for the download part and the user's device for the parsing and execution, this can take some time and impact the user's experience. - **Search Engine Optimization**: Indexing and updating the content delivered via client-side rendering takes more time than with a server-rendered HTML document. This is related to the performance drawback we discussed, as search engine crawlers won't wait for the interface to be fully rendered on their first try to index the page. Your content will take more time to show and update in search results pages with pure client-side rendering. Client-side rendering is a good choice for heavily interactive **web applications** that don't need indexing or whose users visit frequently. It can leverage browser caching to skip the download phase on subsequent visits, such as **SaaS, back-office applications, or online games**. You can enable client-side only rendering with Nuxt in your `nuxt.config.ts`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ ssr: false, }) ``` If you do use `ssr: false`, you should also place an HTML file in `~/spa-loading-template.html` with some HTML you would like to use to render a loading screen that will be rendered until your app is hydrated. ### Deploying a Static Client-Rendered App If you deploy your app to [static hosting](https://nuxt.com/docs/5.x/getting-started/deployment#static-hosting) with the `nuxt generate` or `nuxt build --prerender` commands, then by default, Nuxt will render every page as a separate static HTML file. If you prerender your app with the `nuxt generate` or `nuxt build --prerender` commands, then you will not be able to use any server endpoints as no server will be included in your output folder. If you need server functionality, use `nuxt build` instead. If you are using purely client-side rendering, then this might be unnecessary. You might only need a single `index.html` file, plus `200.html` and `404.html` fallbacks, which you can tell your static web host to serve up for all requests. In order to achieve this we can change how the routes are prerendered. Just add this to [your hooks](https://nuxt.com/docs/5.x/api/advanced/hooks#nuxt-hooks-build-time) in your `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ hooks: { 'prerender:routes' ({ routes }) { routes.clear() // Do not generate any routes (except the defaults) }, }, }) ``` This will produce three files: - `index.html` - `200.html` - `404.html` #### What are 200.html and 404.html? Static hosts need an HTML shell for client-side routes and missing paths. Nuxt emits two SPA fallbacks for that: - **200.html**. Serve this for unmatched paths when you want the client router to handle the URL. - **404.html**. Serve this when the host should keep a 404 status and still load your app. `nuxt generate` and `nuxt build --prerender` write these into `.output/public/`. A plain `nuxt build` without prerender does not. With hybrid route rules, add the fallbacks with route rules or run a prerender build if you need them. Point your host at the file your provider expects. #### Server-rendering the Error Page By default `404.html` is an empty shell, so your `error.vue` (and its layout and data) only appear once the client app has booted. You can prerender it instead: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { prerenderErrorPages: true, }, }) ``` Nuxt then renders `error.vue` at build time with a synthetic 404 error and writes the result to `404.html`, which hydrates in place at whatever URL your host served it from. Pass an array of status codes between 400 and 599 (`[404, 500]`) to emit additional pages, if your host can serve them. Because a single file is served for every missing path, the error page cannot depend on the request: `useRoute()`, `useRequestURL()` and data fetched with the current path will hold the build-time values in the prerendered HTML and be corrected on hydration. Wrap request-specific markup in [``](https://nuxt.com/docs/5.x/api/components/client-only), and skip request-specific data fetching with `import.meta.prerender`: ```vue [error.vue] ``` `import.meta.prerender` is only `true` while the page is being generated, so the same `error.vue` still server-renders its data when the app is deployed with a server. #### Skipping Client Fallback Generation When prerendering a client-rendered app, Nuxt will generate `index.html`, `200.html` and `404.html` files by default. However, if you need to prevent any (or all) of these files from being generated in your build, you can use the `'prerender:generate'` hook from [Nitro](https://nuxt.com/docs/5.x/getting-started/prerendering#prerendergenerate-nitro-hook). ```ts [nuxt.config.ts]twoslash // @errors: 2353 7006 export default defineNuxtConfig({ ssr: false, nitro: { hooks: { 'prerender:generate' (route) { const routesToSkip = ['/index.html', '/200.html', '/404.html'] if (routesToSkip.includes(route.route)) { route.skip = true } }, }, }, }) ``` ## Hybrid Rendering Hybrid rendering allows different caching rules per route using **Route Rules** and decides how the server should respond to a new request on a given URL. Previously every route/page of a Nuxt application and server must use the same rendering mode, universal or client-side. In various cases, some pages could be generated at build time, while others should be client-side rendered. For example, think of a content website with an admin section. Every content page should be primarily static and generated once, but the admin section requires registration and behaves more like a dynamic application. Nuxt includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route! Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using [Nitro caching layer](https://nitro.build/guide/cache). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Homepage pre-rendered at build time '/': { prerender: true }, // Products page generated on demand, revalidates in background, cached until API response changes '/products': { swr: true }, // Product pages generated on demand, revalidates in background, cached for 1 hour (3600 seconds) '/products/**': { swr: 3600 }, // Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds) '/blog': { isr: 3600 }, // Blog post page generated on demand once until next deployment, cached on CDN '/blog/**': { isr: true }, // Admin dashboard renders only on client-side '/admin/**': { ssr: false }, // Add cors headers on API routes '/api/**': { cors: true }, // Redirects legacy urls '/old-page': { redirect: '/new-page' }, }, }) ``` ### Route Rules The different properties you can use are the following: - `redirect: string` - Define server-side redirects. - `ssr: boolean` - Disables server-side rendering of the HTML for sections of your app and make them render only in the browser with `ssr: false` - `cors: boolean` - Automatically adds cors headers with `cors: true` - you can customize the output by overriding with `headers` - `headers: object` - Add specific headers to sections of your site - for example, your assets - `swr: number | boolean` - Add cache headers to the server response and cache it on the server or reverse proxy for a configurable TTL (time to live). The `node-server` preset of Nitro is able to cache the full response. When the TTL expired, the cached response will be sent while the page will be regenerated in the background. If true is used, a `stale-while-revalidate` header is added without a MaxAge. - `isr: number | boolean` - The behavior is the same as `swr` except that we are able to add the response to the CDN cache on platforms that support this (currently Netlify or Vercel). If `true` is used, the content persists until the next deploy inside the CDN. - `prerender: boolean` - Prerenders routes at build time and includes them in your build as static assets - `noScripts: boolean` - Disables rendering of Nuxt scripts and JS resource hints for sections of your site. Read more about [`noScripts`](https://nuxt.com/docs/5.x/guide/going-further/features#noscripts). - `appMiddleware: string | string[] | Record` - Allows you to define middleware that should or should not run for page paths within the Vue app part of your application (that is, not your Nitro routes) Routes using `isr` or `swr` also generate `_payload.json` files alongside HTML. Client-side navigation loads these cached payloads instead of re-fetching data. Read more about [payload extraction](https://nuxt.com/docs/5.x/getting-started/prerendering#payload-extraction). ### Server Bundle Size with `ssr: false` A route covered by `ssr: false` is only ever rendered in the browser, so Nuxt excludes its page component from the server bundle. This applies whenever the rules covering every path that reaches the page can be resolved at build time, including dynamic routes such as `pages/products/[id].vue` under a `/products/**` rule. A page is kept in the server bundle when any path that reaches it might still be rendered on the server: - a more specific rule re-enables SSR somewhere below the client-only one (`'/admin/**': { ssr: false }` with `'/admin/report': { ssr: true }`) - the page has an alias, or a child declared with an absolute path, that falls outside the client-only region - the page is a parent shell rendering a child that is still server-rendered This is a build-time optimization only; it does not change what the server sends to the browser. Whenever possible, route rules will be automatically applied to the deployment platform's native rules for optimal performances (Netlify and Vercel are currently supported). Note that Hybrid Rendering is not available when using [`nuxt generate`](https://nuxt.com/docs/5.x/api/commands/generate). **Examples:** Example of a Nuxt application with hybrid rendering deployed on Vercel. ## Edge-Side Rendering Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience. With ESR, the rendering process is pushed to the 'edge' of the network - the CDN's edge servers. Note that ESR is more a deployment target than an actual rendering mode. When a request for a page is made, instead of going all the way to the original server, it's intercepted by the nearest edge server. This server generates the HTML for the page and sends it back to the user. This process minimizes the physical distance the data has to travel, **reducing latency and loading the page faster**. Edge-side rendering is possible thanks to [Nitro](https://nitro.build/), the [server engine](https://nuxt.com/docs/5.x/guide/concepts/server-engine) that powers Nuxt. It offers cross-platform support for Node.js, Deno, Cloudflare Workers, and more. The current platforms where you can leverage ESR are: - [Cloudflare Pages](https://pages.cloudflare.com) with zero configuration using the git integration and the `nuxt build` command - [Vercel Cloud](https://vercel.com/home) using the `nuxt build` command and `NITRO_PRESET=vercel-edge` environment variable - [Netlify Edge Functions](https://www.netlify.com/platform/#netlify-edge-functions) using the `nuxt build` command and `NITRO_PRESET=netlify-edge` environment variable Note that **Hybrid Rendering** can be used when using Edge-Side Rendering with route rules. # Server Components > Render individual components on the server only, keeping their JavaScript out of your client bundle. Nuxt renders your app on the server by default, but then it ships the JavaScript for every component to the browser and hydrates the whole page. For content-heavy components (markdown rendering, syntax highlighting, CMS output) that never change on the client, this is wasted work: the user downloads, parses and executes code whose only job is to reproduce HTML that is already on the page. Server components (also called island components) invert this. A server component is rendered on the server, its HTML is embedded in the page, and none of its JavaScript is sent to the client. Its dependencies (a markdown parser, a highlighting library) stay on the server too. Read Daniel Roe's guide to Nuxt Server Components. ## Enabling Server Components Component islands are controlled by [`experimental.componentIslands`](https://nuxt.com/docs/5.x/guide/going-further/experimental-features#componentislands). The default value is `'auto'`, which enables the feature automatically as soon as your app contains a server component or island, so in most cases you do not need any configuration. Set the option explicitly if you want remote islands or selective client hydration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { componentIslands: { selectiveClient: true, // or 'deep', to enable `nuxt-client` remoteIsland: false, // allow rendering islands from a remote source }, }, }) ``` Server components are still marked experimental. You can follow the roadmap on GitHub. ## `.server.vue` Components Add the `.server` suffix to a component to make it a standalone server component: ```bash [Directory Structure] -| app/ ---| components/ -----| HighlightedMarkdown.server.vue ``` Use it like any other component: ```vue [app/pages/example.vue] ``` Components inside `~/components/islands/` are also registered as islands and can be rendered with [``](https://nuxt.com/docs/5.x/api/components/nuxt-island) directly, for example `` for `~/components/islands/MyIsland.vue`. You can also pair a `.server.vue` component with a `.client.vue` component of the same name for [separate server and client implementations](https://nuxt.com/docs/5.x/directory-structure/app/components#paired-with-a-client-component). In that case the component is not an island: the client half hydrates normally. Server components (and islands) must have a single root element. (HTML comments are considered elements as well.) ## How Islands Are Rendered Server components use [``](https://nuxt.com/docs/5.x/api/components/nuxt-island) under the hood. Rendering an island issues a request to a dedicated island endpoint, which: - creates a **new, isolated Vue app** on the server to render just that component - creates an 'island context' that you can access via `nuxtApp.ssrContext.islandContext` inside the island - runs your plugins again, unless they set `env: { islands: false }` (object-syntax plugins) Because the island is isolated from the rest of your app: - you cannot share state (provide/inject, Pinia, `useState`) between the page and the island; pass data via props instead - [`useRoute()`](https://nuxt.com/docs/5.x/api/composables/use-route) inside an island reflects the island's own request, not the page the user is on. If an island needs route information, pass it in explicitly, either as props or via the `context` prop on `` (read inside the island from `nuxtApp.ssrContext.islandContext`) - route middleware does not run when rendering islands Props are serialized and sent as **GET query parameters**. This makes island responses cacheable, but it also means: - props must be JSON-serializable - props are limited by URL length, so avoid passing large amounts of data - props may be visible in server access logs, CDN caches and `Referer` headers Because props come from the request (URL query or body), treat them as untrusted input. Nuxt rejects the props most likely to leak through unintentionally: a top-level `as` that the island does not declare (an undeclared prop falls through as an attribute onto the island's root), and, with `vue.runtimeCompiler` enabled, a `template` anywhere in the props. Beyond that, avoid feeding props you have not validated into dynamic component resolution (``, `h()`, `resolveDynamicComponent()`, or a polymorphic `as` / `asChild` prop), since a string can resolve to any registered component or HTML element. Props a component does not declare fall through as attributes onto its single root element, so an island whose root is a polymorphic component (e.g. from `reka-ui` / `@nuxt/ui`) can receive attributes you did not bind. Set `defineOptions({ inheritAttrs: false })` on such islands, or declare the props you accept. To switch components based on caller input, map a discriminator through an allowlist of imported components rather than passing the raw prop: ```vue ``` Changing an island's props triggers a network request that re-renders the component on the server and updates its HTML in place. Read the full `` API documentation, including props, slots, events and known limitations. ## Selective Hydration with `nuxt-client` An island is static by default, but you can hydrate individual components inside it by adding the `nuxt-client` attribute. This requires `experimental.componentIslands.selectiveClient` to be enabled. ```vue [app/components/ServerWithClient.server.vue] ``` The component marked with `nuxt-client` is server-rendered as part of the island, then hydrated by the main client app. Only its chunk is shipped to the client; the rest of the island remains static. Setting `selectiveClient: 'deep'` additionally allows passing slots to `nuxt-client` components. Those slots are rendered on the server and are **not interactive** on the client. Use `nuxt-client` only on local `.vue` SFCs. Built-ins like [``](https://nuxt.com/docs/5.x/api/components/nuxt-link) skip the islands transform. After client navigation you may see `Failed to locate Teleport target`, or the link disappears with no error. Wrap the built-in in your own `.vue` file and put `nuxt-client` on that wrapper. See [#29251](https://github.com/nuxt/nuxt/issues/29251) and [#26002](https://github.com/nuxt/nuxt/issues/26002). ## Slots Slots can be passed to an island component if declared in the island. Slot content is provided by the parent, so it belongs to the main client app and **is** interactive (it is wrapped in a `

` with `display: contents;`). `` reserves the `#fallback` slot to specify content rendered before the island loads (when `lazy` is set) or when fetching the island fails. ## The Client Navigation Round Trip On the initial server-rendered page load, islands are rendered inline and there is no extra request. On **client-side navigation**, however, each island on the destination page must be fetched from the server (you can see these requests in the network tab). This has real costs: - islands block on a network round trip during navigation, unless you pass the `lazy` prop (with a `#fallback` slot) to render them non-blockingly - an app with many islands per page makes many requests per navigation Islands work best on pages that are reached by full page loads (content and marketing pages) or when their number per page is small. If a component needs to update frequently on the client, an island is probably the wrong tool. ## Prerendering and Caching Islands play well with static and cached rendering: - during prerendering (`nuxt generate` or `prerender` route rules), island responses are cached, so identical islands (same name, props and context) are rendered once and reused - because props travel as GET query parameters, island responses can also be cached by your server or CDN at the island endpoint level - two instances of the same island with the same props share a single server render and payload entry Note that island responses being keyed only on name, props and context is exactly what keeps them cacheable independently of the page they appear on; this is also why they cannot see the current route (see above). If you are building a mostly-static site, islands combine well with `prerender` and `noScripts` route rules. See the mostly-static site recipe for combining prerendering, `noScripts`, islands and lazy hydration. One interaction to be aware of: island slots and `nuxt-client` components rely on a small inline script to relocate teleported content into place before hydration. On routes rendered with [`noScripts`](https://nuxt.com/docs/5.x/guide/going-further/features#noscripts), that script is omitted, so fully interactive `nuxt-client` components will not hydrate there. Plain static islands are unaffected. ## Current Limitations Server components are experimental, and some rough edges are tracked in open issues: - Most features for server-only and island components, such as slots and `nuxt-client` components, are only available for single file components. - Using islands can significantly increase the number of chunks generated at build time ([#34855](https://github.com/nuxt/nuxt/issues/34855)). - With webpack and Rspack, scoped `:slotted()` styles in server component slots can fail because server and client builds may generate different scope IDs ([#31510](https://github.com/nuxt/nuxt/issues/31510)). - Template refs cannot reference elements inside a server component from the parent ([#31512](https://github.com/nuxt/nuxt/issues/31512)). - `inject`/`provide` does not cross the island boundary, so injecting from the page into a standalone server component does not work ([#22751](https://github.com/nuxt/nuxt/issues/22751)). - Server components rendered via the auto-generated wrapper do not expose load and error events; use `` directly if you need its `error` event and `refresh()` method ([#25744](https://github.com/nuxt/nuxt/issues/25744)). - [`useId`](https://vuejs.org/api/composition-api-helpers#useid) has known limitations inside islands; see the [`` documentation](https://nuxt.com/docs/5.x/api/components/nuxt-island#known-limitations). - Each nested island adds extra overhead, so be careful when nesting islands within other islands. Read more about server component file conventions in the components directory documentation. # Server Engine > Nuxt is powered by a new server engine: Nitro. While building Nuxt, we created a new server engine: [Nitro](https://nitro.build/). It is shipped with many features: - Cross-platform support for Node.js, browsers, service workers and more. - Serverless support out-of-the-box. - API routes support. - Automatic code-splitting and async-loaded chunks. - Hybrid mode for static + serverless sites. - Development server with hot module reloading. ## API Layer Server [API endpoints](https://nuxt.com/docs/5.x/directory-structure/server#server-routes) and [Middleware](https://nuxt.com/docs/5.x/directory-structure/server#server-middleware) are added by Nitro that internally uses [h3](https://github.com/h3js/h3). Key features include: - Handlers can directly return objects/arrays for an automatically-handled JSON response - Handlers can return promises, which will be awaited (`res.end()` and `next()` are also supported) - Helper functions for body parsing, cookie handling, redirects, headers and more Check out [the h3 docs](https://github.com/h3js/h3) for more information. Learn more about the API layer in the `server/` directory. ## Direct API Calls Nitro allows 'direct' calling of routes via the globally-available [`$fetch`](https://nuxt.com/docs/5.x/api/utils/dollarfetch) helper. This will make an API call to the server if run on the browser, but will directly call the relevant function if run on the server, **saving an additional API call**. [`$fetch`](https://nuxt.com/docs/5.x/api/utils/dollarfetch) API is using [ofetch](https://github.com/unjs/ofetch), with key features including: - Automatic parsing of JSON responses (with access to raw response if needed) - Request body and params are automatically handled, with correct `Content-Type` headers For more information on `$fetch` features, check out [ofetch](https://github.com/unjs/ofetch). ## Typed API Routes When using API routes (or middleware), Nitro will generate typings for these routes as long as you are returning a value instead of using `res.end()` to send a response. You can access these types when using [`$fetch()`](https://nuxt.com/docs/5.x/api/utils/dollarfetch) or [`useFetch()`](https://nuxt.com/docs/5.x/api/composables/use-fetch). ## Standalone Server Nitro produces a standalone server dist that is independent of `node_modules`. The server in Nuxt 2 is not standalone and requires part of Nuxt core to be involved by running `nuxt start` (with the [`nuxt-start`](https://www.npmjs.com/package/nuxt-start) or [`nuxt`](https://www.npmjs.com/package/nuxt) distributions) or custom programmatic usage, which is fragile and prone to breakage and not suitable for serverless and service worker environments. Nuxt generates this dist when running `nuxt build` into a [`.output`](https://nuxt.com/docs/5.x/directory-structure/output) directory. The output contains runtime code to run your Nuxt server in any environment (including experimental browser service workers!) and serve your static files, making it a true hybrid framework for the JAMstack. In addition, Nuxt implements a native storage layer, supporting multi-source drivers and local assets. Read more about Nitro engine on GitHub. # TypeScript > Nuxt is fully typed and provides helpful shortcuts to ensure you have access to accurate type information when you are coding. ## Type-checking By default, Nuxt doesn't check types when you run [`nuxt dev`](https://nuxt.com/docs/5.x/api/commands/dev) or [`nuxt build`](https://nuxt.com/docs/5.x/api/commands/build), for performance reasons. To enable type-checking at build or development time, install `vue-tsc` and `typescript` as development dependency: ```bash [npm] npm install --save-dev vue-tsc typescript ``` ```bash [yarn] yarn add --dev vue-tsc typescript ``` ```bash [pnpm] pnpm add -D vue-tsc typescript ``` ```bash [bun] bun add -D vue-tsc typescript ``` ```bash [deno] deno add -D npm:vue-tsc npm:typescript ``` Then, run [`nuxt typecheck`](https://nuxt.com/docs/5.x/api/commands/typecheck) command to check your types: ```bash [Terminal] npx nuxt typecheck ``` To enable type-checking at build or development time, you can also use the [`typescript.typeCheck`](https://nuxt.com/docs/5.x/api/nuxt-config#typecheck) option in your `nuxt.config` file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { typeCheck: true, }, }) ``` ## Auto-generated Types Nuxt projects rely on auto-generated types to work properly. These types are stored in the [`.nuxt`](https://nuxt.com/docs/5.x/directory-structure/nuxt) directory and are generated when you run the dev server or build your application. You can also generate these files manually by running `nuxt prepare`. The generated `tsconfig.json` files inside the [`.nuxt`](https://nuxt.com/docs/5.x/directory-structure/nuxt) directory include **recommended basic TypeScript configuration** for your project, references to [auto-imports](https://nuxt.com/docs/5.x/guide/concepts/auto-imports), [API route types](https://nuxt.com/docs/5.x/guide/concepts/server-engine#typed-api-routes), path aliases like `#imports`, `~/file`, or `#build/file`, and more. Nuxt relies on this configuration, and [Nuxt modules](https://nuxt.com/docs/5.x/guide/modules) can extend it as well. For this reason, it is not recommended to modify your `tsconfig.json` file directly, as doing so could overwrite important settings. Instead, extend it via `nuxt.config.ts`. [Learn more about extending the configuration here](https://nuxt.com/docs/5.x/directory-structure/tsconfig). Watch a video from Daniel Roe explaining built-in Nuxt aliases. ## Project References Nuxt uses [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html) to improve type-checking performance and provide better IDE support. This feature allows TypeScript to break up your codebase into smaller, more manageable pieces. ### How Nuxt Uses Project References When you run `nuxt dev`, `nuxt build` or `nuxt prepare`, Nuxt will generate multiple `tsconfig.json` files for different parts of your application. - **.nuxt/tsconfig.app.json** - Configuration for your application code within the `app/` directory - **.nuxt/tsconfig.node.json** - Configuration for your `nuxt.config.ts` and files outside the other contexts - **.nuxt/tsconfig.server.json** - Configuration for server-side code (when applicable) - **.nuxt/tsconfig.shared.json** - For code shared between app and server contexts (like types and non-environment specific utilities) Each of these files is configured to reference the appropriate dependencies and provide optimal type-checking for their specific context. For backward compatibility, Nuxt still generates `.nuxt/tsconfig.json`. However, we recommend using [TypeScript project references](https://nuxt.com/docs/5.x/directory-structure/tsconfig) with the new configuration files (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, etc.) for better type safety and performance. This legacy file will be removed in a future version of Nuxt. ### Benefits of Project References - **Faster builds**: TypeScript can skip rebuilding unchanged projects - **Better IDE performance**: Your IDE can provide faster IntelliSense and error checking - **Isolated compilation**: Errors in one part of your application don't prevent compilation of other parts - **Clearer dependency management**: Each project explicitly declares its dependencies ### Augmenting Types with Project References Since the project is divided into **multiple type contexts**, it's important to **augment types within the correct context** to ensure they're properly recognized. TypeScript will not recognize augmentations placed outside these directories unless they are explicitly included in the appropriate context. For example, if you want to augment types for the `app` context, the augmentation file should be placed in the `app/` directory. Similarly: - For the `server` context, place the augmentation file in the `server/` directory. - For types that are **shared between the app and server**, place the file in the `shared/` directory. Read more about augmenting specific type contexts from **files outside those contexts** in the Module Author Guide. ## Strict Checks TypeScript comes with certain checks to give you more safety and analysis of your program. [Strict checks](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) are enabled by default in Nuxt when the [`typescript.typeCheck`](https://nuxt.com/docs/5.x/guide/concepts/typescript#type-checking) option is enabled to give you greater type safety. If you are currently converting your codebase to TypeScript, you may want to temporarily disable strict checks by setting `strict` to `false` in your `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { strict: false, }, }) ``` # Vue.js Development > Nuxt uses Vue.js and adds features such as component auto-imports, file-based routing and composables for an SSR-friendly usage. Nuxt integrates Vue 3, the new major release of Vue that enables new patterns for Nuxt users. While an in-depth knowledge of Vue is not required to use Nuxt, we recommend that you read the documentation and go through some of the examples on [vuejs.org](https://vuejs.org). Nuxt has always used Vue as a frontend framework. We chose to build Nuxt on top of Vue for these reasons: - The reactivity model of Vue, where a change in data automatically triggers a change in the interface. - The component-based templating, while keeping HTML as the common language of the web, enables intuitive patterns to keep your interface consistent, yet powerful. - From small projects to large web applications, Vue keeps performing well at scale to ensure that your application keeps delivering value to your users. ## Vue with Nuxt ### Single File Components [Vueโ€™s single-file components](https://vuejs.org/guide/scaling-up/sfc) (SFC or `*.vue` files) encapsulate the markup (` ``` 1. Make sure you use capital letters for these component names to distinguish them from native HTML elements (`` rather than `<title>`). 2. You can place these components anywhere in your template for your page. </important> ### Options API ```vue [Nuxt 3 (Options API)] <script> // if using options API `head` method you must use `defineNuxtComponent` export default defineNuxtComponent({ head (nuxtApp) { // `head` receives the nuxt app but cannot access the component instance return { meta: [{ name: 'description', content: 'This is my page description.', }], } }, }) </script> ``` # Modules > Learn how to migrate from Nuxt 2 to Nuxt 3 modules. ## Module Compatibility Nuxt 3 has a basic backward compatibility layer for Nuxt 2 modules using `@nuxt/kit` auto wrappers. But there are usually steps to follow to make modules compatible with Nuxt 3 and sometimes, using Nuxt Bridge is required for cross-version compatibility. We have prepared a [Dedicated Guide](https://nuxt.com/docs/5.x/guide/modules) for authoring Nuxt 3 ready modules using `@nuxt/kit`. Currently best migration path is to follow it and rewrite your modules. Rest of this guide includes preparation steps if you prefer to avoid a full rewrite yet making modules compatible with Nuxt 3. <tip icon="i-lucide-puzzle" to="https://nuxt.com/modules"> Explore Nuxt 3 compatible modules. </tip> ### Plugin Compatibility Nuxt 3 plugins are **not** fully backward compatible with Nuxt 2. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/plugins"> </read-more> ### Vue Compatibility Plugins or components using the Composition API need exclusive Vue 2 or Vue 3 support. By using [vue-demi](https://github.com/vueuse/vue-demi) they should be compatible with both Nuxt 2 and 3. ## Module Migration When Nuxt 3 users add your module, you will not have access to the module container (`this.*`) so you will need to use utilities from `@nuxt/kit` to access the container functionality. ### Test with `@nuxt/bridge` Migrating to `@nuxt/bridge` is the first and most important step for supporting Nuxt 3. If you have a fixture or example in your module, add `@nuxt/bridge` package to its config (see [example](https://nuxt.com/docs/5.x/bridge/overview#update-nuxtconfig)) ### Migrate from CommonJS to ESM Nuxt 3 natively supports TypeScript and ECMAScript Modules. Please check [Native ES Modules](https://nuxt.com/docs/5.x/guide/concepts/esm) for more info and upgrading. ### Ensure Plugins Default Export If you inject a Nuxt plugin that does not have `export default` (such as global Vue plugins), ensure you add `export default () => { }` to the end of it. <code-group> ```js [Before] // ~/plugins/vuelidate.js import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate) ``` ```js [After] // ~/plugins/vuelidate.js import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate) export default () => { } ``` </code-group> ### Avoid Runtime Modules With Nuxt 3, Nuxt is now a build-time-only dependency, which means that modules shouldn't attempt to hook into the Nuxt runtime. Your module should work even if it's only added to [`buildModules`](https://nuxt.com/docs/5.x/api/nuxt-config#runtimeconfig) (instead of `modules`). For example: - Avoid updating `process.env` within a Nuxt module and reading by a Nuxt plugin; use [`runtimeConfig`](https://nuxt.com/docs/5.x/api/nuxt-config#runtimeconfig) instead. - (*) Avoid depending on runtime hooks like `vue-renderer:*` for production - (*) Avoid adding `serverMiddleware` by importing them inside the module. Instead, add them by referencing a file path so that they are independent of the module's context (*) Unless it is for `nuxt dev` purpose only and guarded with `if (nuxt.options.dev) { }`. <tip> Continue reading about Nuxt 3 modules in the [Modules Author Guide](https://nuxt.com/docs/5.x/guide/modules). </tip> ### Use TypeScript (Optional) While it is not essential, most of the Nuxt ecosystem is shifting to use TypeScript, so it is highly recommended to consider migration. <tip> You can start migration by renaming `.js` files, to `.ts`. TypeScript is designed to be progressive! </tip> <tip> You can use TypeScript syntax for Nuxt 2 and 3 modules and plugins without any extra dependencies. </tip> # Overview > Nuxt 3 is a complete rewrite of Nuxt 2, and also based on a new set of underlying technologies. There are significant changes when migrating a Nuxt 2 app to Nuxt 3, although you can expect migration to become more straightforward as we move toward a stable release. <note> This migration guide is under progress to align with the development of Nuxt 3. </note> Some of these significant changes include: 1. Moving from Vue 2 to Vue 3, including defaulting to the Composition API and script setup. 2. Moving from webpack 4 and Babel to Vite or webpack 5 and esbuild. 3. Moving from a runtime Nuxt dependency to a minimal, standalone server compiled with nitropack. <tip> If you need to remain on Nuxt 2, but want to benefit from Nuxt 3 features in Nuxt 2, you can alternatively check out [how to get started with Bridge](https://nuxt.com/docs/5.x/bridge/overview). </tip> ## Next Steps - Learn about differences in [configuration](https://nuxt.com/docs/5.x/migration/configuration) # Pages and Layouts > Learn how to migrate from Nuxt 2 to Nuxt 3 pages and layouts. ## `app.vue` Nuxt 3 provides a central entry point to your app via `~/app.vue`. <note> If you don't have an `app.vue` file in your source directory, Nuxt will use its own default version. </note> This file is a great place to put any custom code that needs to be run once when your app starts up, as well as any components that are present on every page of your app. For example, if you only have one layout, you can move this to `app.vue` instead. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/app"> </read-more> <link-example to="https://nuxt.com/docs/5.x/examples/hello-world"> </link-example> ### Migration Consider creating an `app.vue` file and including any logic that needs to run once at the top-level of your app. You can check out [an example here](https://nuxt.com/docs/5.x/directory-structure/app/app). ## Layouts If you are using layouts in your app for multiple pages, there is only a slight change required. In Nuxt 2, the `<Nuxt>` component is used within a layout to render the current page. In Nuxt 3, layouts use slots instead, so you will have to replace that component with a `<slot />`. This also allows advanced use cases with named and scoped slots. [Read more about layouts](https://nuxt.com/docs/5.x/directory-structure/app/layouts). You will also need to change how you define the layout used by a page using the `definePageMeta` compiler macro. Layouts will be kebab-cased. So `app/layouts/customLayout.vue` becomes `custom-layout` when referenced in your page. ### Migration 1. Replace `<Nuxt />` with `<slot />````diff [app/layouts/custom.vue] <template> <div id="app-layout"> <main> - <Nuxt /> + <slot /> </main> </div> </template> ``` 2. Use [`definePageMeta`](https://nuxt.com/docs/5.x/api/utils/define-page-meta) to select the layout used by your page. ```diff [app/pages/index.vue] + <script setup> + definePageMeta({ + layout: 'custom' + }) - <script> - export default { - layout: 'custom' - } </script> ``` 3. Move `~/layouts/_error.vue` to `~/error.vue`. See [the error handling docs](https://nuxt.com/docs/5.x/getting-started/error-handling). If you want to ensure that this page uses a layout, you can use [`<NuxtLayout>`](https://nuxt.com/docs/5.x/directory-structure/app/layouts) directly within `error.vue`: ```vue [error.vue] <template> <div> <NuxtLayout name="default"> <!-- --> </NuxtLayout> </div> </template> ``` ## Pages Nuxt 3 ships with an optional `vue-router` integration triggered by the existence of a [`app/pages/`](https://nuxt.com/docs/5.x/directory-structure/app/pages) directory in your source directory. If you only have a single page, you may consider instead moving it to `app.vue` for a lighter build. ### Dynamic Routes The format for defining dynamic routes in Nuxt 3 is slightly different from Nuxt 2, so you may need to rename some of the files within `app/pages/`. 1. Where you previously used `_id` to define a dynamic route parameter you now use `[id]`. 2. Where you previously used `_.vue` to define a catch-all route, you now use `[...slug].vue`. ### Nested Routes In Nuxt 2, you will have defined any nested routes (with parent and child components) using `<Nuxt>` and `<NuxtChild>`. In Nuxt 3, these have been replaced with a single `<NuxtPage>` component. ### Page Keys and Keep-alive Props If you were passing a custom page key or keep-alive props to `<Nuxt>`, you will now use `definePageMeta` to set these options. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/pages#special-metadata"> </read-more> ### Page and Layout Transitions If you have been defining transitions for your page or layout directly in your component options, you will now need to use `definePageMeta` to set the transition. Since Vue 3, [-enter and -leave CSS classes have been renamed](https://v3-migration.vuejs.org/breaking-changes/transition.html). The `style` prop from `<Nuxt>` no longer applies to transition when used on `<slot>`, so move the styles to your `-active` class. <read-more to="https://nuxt.com/docs/5.x/getting-started/transitions"> </read-more> ### Migration 1. Rename any pages with dynamic parameters to match the new format. 2. Update `<Nuxt>` and `<NuxtChild>` to be `<NuxtPage>`. 3. If you're using the Composition API, you can also migrate `this.$route` and `this.$router` to use [`useRoute`](https://nuxt.com/docs/5.x/api/composables/use-route) and [`useRouter`](https://nuxt.com/docs/5.x/api/composables/use-router) composables. #### Example: Dynamic Routes <code-group> ```text [Nuxt 2] - URL: /users - Page: /pages/users/index.vue - URL: /users/some-user-name - Page: /pages/users/_user.vue - Usage: params.user - URL: /users/some-user-name/edit - Page: /pages/users/_user/edit.vue - Usage: params.user - URL: /users/anything-else - Page: /pages/users/_.vue - Usage: params.pathMatch ``` ```text [Nuxt 3] - URL: /users - Page: /pages/users/index.vue - URL: /users/some-user-name - Page: /pages/users/[user].vue - Usage: params.user - URL: /users/some-user-name/edit - Page: /pages/users/[user]/edit.vue - Usage: params.user - URL: /users/anything-else - Page: /pages/users/[...slug].vue - Usage: params.slug ``` </code-group> #### Example: Nested Routes and `definePageMeta` <code-group> ```vue [Nuxt 2] <template> <div> <NuxtChild keep-alive :keep-alive-props="{ exclude: ['modal'] }" :nuxt-child-key="$route.slug" /> </div> </template> <script> export default { transition: 'page', // or { name: 'page' } } </script> ``` ```vue [Nuxt 3] <template> <div> <NuxtPage /> </div> </template> <script setup lang="ts"> // This compiler macro works in both <script> and <script setup> definePageMeta({ // you can also pass a string or a computed property key: route => route.slug, transition: { name: 'page', }, keepalive: { exclude: ['modal'], }, }) </script> ``` </code-group> ## `<NuxtLink>` Component Most of the syntax and functionality are the same for the global [NuxtLink](https://nuxt.com/docs/5.x/api/components/nuxt-link) component. If you have been using the shortcut `<NLink>` format, you should update this to use `<NuxtLink>`. `<NuxtLink>` is now a drop-in replacement for *all* links, even external ones. You can read more about it, and how to extend it to provide your own link component. <read-more to="https://nuxt.com/docs/5.x/api/components/nuxt-link"> </read-more> ## Programmatic Navigation When migrating from Nuxt 2 to Nuxt 3, you will have to update how you programmatically navigate your users. In Nuxt 2, you had access to the underlying Vue Router with `this.$router`. In Nuxt 3, you can use the `navigateTo()` utility method which allows you to pass a route and parameters to Vue Router. <warning> Make sure to always `await` on [`navigateTo`](https://nuxt.com/docs/5.x/api/utils/navigate-to) or chain its result by returning from functions. </warning> <code-group> ```vue [Nuxt 2] <script> export default { methods: { navigate () { this.$router.push({ path: '/search', query: { name: 'first name', type: '1', }, }) }, }, } </script> ``` ```vue [Nuxt 3] <script setup lang="ts"> function navigate () { return navigateTo({ path: '/search', query: { name: 'first name', type: '1', }, }) } </script> ``` </code-group> # Plugins and Middleware > Learn how to migrate from Nuxt 2 to Nuxt 3 plugins and middleware. ## Plugins Plugins now have a different format, and take only one argument (`nuxtApp`). <code-group> ```ts [Nuxt 2] export default (ctx, inject) => { inject('injected', () => 'my injected function') } ``` ```ts [Nuxt 3] export default defineNuxtPlugin((nuxtApp) => { // now available on `nuxtApp.$injected` nuxtApp.provide('injected', () => 'my injected function') // You can alternatively use this format, which comes with automatic type support return { provide: { injected: () => 'my injected function', }, } }) ``` </code-group> <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/plugins"> </read-more> <read-more to="https://nuxt.com/docs/5.x/api/composables/use-nuxt-app"> Read more about the format of `nuxtApp`. </read-more> ### Migration 1. Migrate your plugins to use the `defineNuxtPlugin` helper function. 2. Remove any entries in your `nuxt.config` plugins array that are located in your `app/plugins/` folder. All files in this directory at the top level (and any index files in any subdirectories) will be automatically registered. Instead of setting `mode` to `client` or `server`, you can indicate this in the file name. For example, `~/plugins/my-plugin.client.ts` will only be loaded on client-side. ## Route Middleware Route middleware has a different format. <code-group> ```js [Nuxt 2] export default function ({ store, redirect }) { // If the user is not authenticated if (!store.state.authenticated) { return redirect('/login') } } ``` ```ts [Nuxt 3] export default defineNuxtRouteMiddleware((to, from) => { const auth = useState('auth') if (!auth.value.authenticated) { return navigateTo('/login') } }) ``` </code-group> Much like Nuxt 2, route middleware placed in your `~/middleware` folder is automatically registered. You can then specify it by name in a component. However, this is done with `definePageMeta` rather than as a component option. `navigateTo` is one of a number of route helper functions. <read-more to="https://nuxt.com/docs/5.x/directory-structure/app/middleware"> </read-more> ### Migration 1. Migrate your route middleware to use the `defineNuxtRouteMiddleware` helper function. 2. Any global middleware (such as in your `nuxt.config`) can be placed in your `~/middleware` folder with a `.global` extension, for example `~/middleware/auth.global.ts`. # Runtime Config > Learn how to migrate from Nuxt 2 to Nuxt 3 runtime config. If you wish to reference environment variables within your Nuxt 3 app, you will need to use runtime config. When referencing these variables within your components, you will have to use the [`useRuntimeConfig`](https://nuxt.com/docs/5.x/api/composables/use-runtime-config) composable in your setup method (or Nuxt plugin). In the `server/` portion of your app, you can use [`useRuntimeConfig`](https://nuxt.com/docs/5.x/api/composables/use-runtime-config) without any import. <read-more to="https://nuxt.com/docs/5.x/guide/going-further/runtime-config"> </read-more> ## Migration 1. Add any environment variables that you use in your app to the `runtimeConfig` property of the `nuxt.config` file. 2. Migrate `process.env` to [`useRuntimeConfig`](https://nuxt.com/docs/5.x/api/composables/use-runtime-config) throughout the Vue part of your app. <code-group> ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { // Private config that is only available on the server apiSecret: '123', // Config within public will be also exposed to the client public: { apiBase: '/api', }, }, }) ``` ```vue [app/pages/index.vue] <script setup lang="ts"> const config = useRuntimeConfig() // instead of process.env you will now access config.public.apiBase console.log(config.public.apiBase) </script> ``` ```ts [server/api/hello.ts] export default defineEventhandler((event) => { const config = useRuntimeConfig() // In server, you can now access config.apiSecret, in addition to config.public console.log(config.apiSecret) console.log(config.public.apiBase) }) ``` ```ini [.env] # Runtime config values are automatically replaced by matching environment variables at runtime NUXT_API_SECRET=api_secret_token NUXT_PUBLIC_API_BASE=https://nuxtjs.org ``` </code-group> # Server > Learn how to migrate from Nuxt 2 to Nuxt 3 server. In a built Nuxt 3 application, there is no runtime Nuxt dependency. That means your site will be highly performant, and ultra-slim. But it also means you can no longer hook into runtime Nuxt server hooks. <read-more to="https://nuxt.com/docs/5.x/guide/concepts/server-engine"> </read-more> ## Steps 1. Remove the `render` key in your `nuxt.config`. 2. Any files in `~~/server/api` and `~~/server/middleware` will be automatically registered; you can remove them from your `serverMiddleware` array. 3. Update any other items in your `serverMiddleware` array to point to files or npm packages directly, rather than using inline functions. <read-more to="https://nuxt.com/docs/5.x/directory-structure/server"> </read-more> <read-more to="https://nuxt.com/docs/5.x/guide/going-further/hooks#server-hooks-runtime"> </read-more> # Nuxt Docs This repository contains the documentation of Nuxt, hosted on [https://nuxt.com/docs](https://nuxt.com/docs) ## Contributing Have a look at [https://github.com/nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) to run the website locally. # Nuxt API Reference > Explore all Nuxt Internals: Components, Composables, Utils, Commands and more. <card-group> <card icon="i-lucide-box" title="Components" to="https://nuxt.com/docs/4.x/api/components/client-only"> Explore Nuxt built-in components for pages, layouts, head, and more. </card> <card icon="i-lucide-arrow-left-right" title="Composables" to="https://nuxt.com/docs/4.x/api/composables/use-app-config"> Discover Nuxt composable functions for data-fetching, head management and more. </card> <card icon="i-lucide-square-function" title="Utils" to="https://nuxt.com/docs/4.x/api/utils/dollarfetch"> Learn about Nuxt utility functions for navigation, error handling and more. </card> <card icon="i-lucide-square-terminal" title="Commands" to="https://nuxt.com/docs/4.x/api/commands/add"> List of Nuxt CLI commands to init, analyze, build, and preview your application. </card> <card icon="i-lucide-package" title="Nuxt Kit" to="https://nuxt.com/docs/4.x/api/kit/modules"> Understand Nuxt Kit utilities to create modules and control Nuxt. </card> <card icon="i-lucide-brain" title="Advanced" to="https://nuxt.com/docs/4.x/api/advanced/hooks"> Go deep in Nuxt internals with Nuxt lifecycle hooks. </card> <card icon="i-lucide-cog" title="Nuxt Configuration" to="https://nuxt.com/docs/4.x/api/nuxt-config"> Explore all Nuxt configuration options to customize your application. </card> </card-group> # Lifecycle Hooks > Nuxt provides a powerful hooking system to expand almost every aspect using hooks. <read-more to="https://nuxt.com/docs/4.x/guide/going-further/hooks"> </read-more> ## App Hooks (Runtime) Check the [app source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts#L37) for all available hooks. <table> <thead> <tr> <th> Hook </th> <th> Arguments </th> <th> Environment </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> app:created </code> </td> <td> <code> vueApp </code> </td> <td> Server & Client </td> <td> Called when initial <code> vueApp </code> instance is created. </td> </tr> <tr> <td> <code> app:error </code> </td> <td> <code> err </code> </td> <td> Server & Client </td> <td> Called when a fatal error occurs. </td> </tr> <tr> <td> <code> app:error:cleared </code> </td> <td> <code> { redirect? } </code> </td> <td> Server & Client </td> <td> Called when a fatal error occurs. </td> </tr> <tr> <td> <code> vue:setup </code> </td> <td> - </td> <td> Server & Client </td> <td> Called when the setup of Nuxt root is initialized. This callback must be synchronous. </td> </tr> <tr> <td> <code> vue:error </code> </td> <td> <code> err, target, info </code> </td> <td> Server & Client </td> <td> Called when a vue error propagates to the root component. <a href="https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured" rel="nofollow"> Learn More </a> . </td> </tr> <tr> <td> <code> app:rendered </code> </td> <td> <code> renderContext </code> </td> <td> Server </td> <td> Called when SSR rendering is done. </td> </tr> <tr> <td> <code> app:redirected </code> </td> <td> - </td> <td> Server </td> <td> Called before SSR redirection. </td> </tr> <tr> <td> <code> app:beforeMount </code> </td> <td> <code> vueApp </code> </td> <td> Client </td> <td> Called before mounting the app, called only on client side. </td> </tr> <tr> <td> <code> app:mounted </code> </td> <td> <code> vueApp </code> </td> <td> Client </td> <td> Called when Vue app is initialized and mounted in browser. </td> </tr> <tr> <td> <code> app:suspense:resolve </code> </td> <td> <code> appComponent </code> </td> <td> Client </td> <td> On <a href="https://vuejs.org/guide/built-ins/suspense#suspense" rel="nofollow"> Suspense </a> resolved event. </td> </tr> <tr> <td> <code> app:manifest:update </code> </td> <td> <code> { id, timestamp } </code> </td> <td> Client </td> <td> Called when there is a newer version of your app detected. </td> </tr> <tr> <td> <code> app:data:refresh </code> </td> <td> <code> keys? </code> </td> <td> Client </td> <td> Called when <code> refreshNuxtData </code> is called. </td> </tr> <tr> <td> <code> link:prefetch </code> </td> <td> <code> to </code> </td> <td> Client </td> <td> Called when a <code> <NuxtLink> </code> is observed to be prefetched. </td> </tr> <tr> <td> <code> page:start </code> </td> <td> <code> pageComponent? </code> </td> <td> Client </td> <td> Called on <a href="https://vuejs.org/guide/built-ins/suspense#suspense" rel="nofollow"> Suspense </a> inside of <code> NuxtPage </code> pending event. </td> </tr> <tr> <td> <code> page:finish </code> </td> <td> <code> pageComponent? </code> </td> <td> Client </td> <td> Called on <a href="https://vuejs.org/guide/built-ins/suspense#suspense" rel="nofollow"> Suspense </a> inside of <code> NuxtPage </code> resolved event. </td> </tr> <tr> <td> <code> page:loading:start </code> </td> <td> - </td> <td> Client </td> <td> Called when a route navigation begins (before resolution) or when the page key changes. May fire without the page component's <code> setup() </code> re-running if the page is reused (e.g. with a static <code> key </code> in <code> definePageMeta </code> ). </td> </tr> <tr> <td> <code> page:loading:end </code> </td> <td> - </td> <td> Client </td> <td> Called after <code> page:finish </code> </td> </tr> <tr> <td> <code> page:transition:finish </code> </td> <td> <code> pageComponent? </code> </td> <td> Client </td> <td> After page transition <a href="https://vuejs.org/guide/built-ins/transition#javascript-hooks" rel="nofollow"> onAfterLeave </a> event. </td> </tr> <tr> <td> <code> dev:ssr-logs </code> </td> <td> <code> logs </code> </td> <td> Client </td> <td> Called with an array of server-side logs that have been passed to the client (if <code> features.devLogs </code> is enabled). </td> </tr> <tr> <td> <code> page:view-transition:start </code> </td> <td> <code> transition </code> </td> <td> Client </td> <td> Called after <code> document.startViewTransition </code> is called when <a href="https://nuxt.com/docs/4.x/getting-started/transitions#view-transitions-api-experimental"> experimental viewTransition support is enabled </a> . The <code> transition </code> argument is a <a href="https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition" rel="nofollow"> <code> ViewTransition </code> </a> object with a <code> types </code> property (<a href="https://developer.mozilla.org/en-US/docs/Web/API/ViewTransitionTypeSet" rel="nofollow"> <code> ViewTransitionTypeSet </code> </a> ) that can be read or modified. </td> </tr> </tbody> </table> ## Nuxt Hooks (Build Time) Check the [schema source code](https://github.com/nuxt/nuxt/blob/main/packages/schema/src/types/hooks.ts#L83) for all available hooks. <table> <thead> <tr> <th> Hook </th> <th> Arguments </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> kit:compatibility </code> </td> <td> <code> compatibility, issues </code> </td> <td> Allows extending compatibility checks. </td> </tr> <tr> <td> <code> ready </code> </td> <td> <code> nuxt </code> </td> <td> Called after Nuxt initialization, when the Nuxt instance is ready to work. </td> </tr> <tr> <td> <code> close </code> </td> <td> <code> nuxt </code> </td> <td> Called when Nuxt instance is gracefully closing. </td> </tr> <tr> <td> <code> restart </code> </td> <td> <code> { hard?: boolean } </code> </td> <td> To be called to restart the current Nuxt instance. </td> </tr> <tr> <td> <code> modules:before </code> </td> <td> - </td> <td> Called during Nuxt initialization, before installing user modules. </td> </tr> <tr> <td> <code> modules:done </code> </td> <td> - </td> <td> Called during Nuxt initialization, after installing user modules. </td> </tr> <tr> <td> <code> module:before </code> </td> <td> <code> module </code> </td> <td> Called immediately before each individual module is set up. </td> </tr> <tr> <td> <code> module:done </code> </td> <td> <code> module </code> </td> <td> Called immediately after each individual module has been set up, including how long it took. </td> </tr> <tr> <td> <code> app:resolve </code> </td> <td> <code> app </code> </td> <td> Called after resolving the <code> app </code> instance. </td> </tr> <tr> <td> <code> app:templates </code> </td> <td> <code> app </code> </td> <td> Called during <code> NuxtApp </code> generation, to allow customizing, modifying or adding new files to the build directory (either virtually or to written to <code> .nuxt </code> ). </td> </tr> <tr> <td> <code> app:templatesGenerated </code> </td> <td> <code> app </code> </td> <td> Called after templates are compiled into the <a href="https://nuxt.com/docs/4.x/directory-structure/nuxt"> virtual file system </a> (vfs). </td> </tr> <tr> <td> <code> build:before </code> </td> <td> - </td> <td> Called before Nuxt bundle builder. </td> </tr> <tr> <td> <code> build:done </code> </td> <td> - </td> <td> Called after Nuxt bundle builder is complete. </td> </tr> <tr> <td> <code> build:manifest </code> </td> <td> <code> manifest </code> </td> <td> Called during the manifest build by Vite and webpack. This allows customizing the manifest that Nitro will use to render <code> <script> </code> and <code> <link> </code> tags in the final HTML. </td> </tr> <tr> <td> <code> builder:generateApp </code> </td> <td> <code> options </code> </td> <td> Called before generating the app. </td> </tr> <tr> <td> <code> builder:watch </code> </td> <td> <code> event, path </code> </td> <td> Called at build time in development when the watcher spots a change to a file or directory in the project. </td> </tr> <tr> <td> <code> pages:extend </code> </td> <td> <code> pages </code> </td> <td> Called after page routes are scanned from the file system. </td> </tr> <tr> <td> <code> pages:resolved </code> </td> <td> <code> pages </code> </td> <td> Called after page routes have been augmented with scanned metadata. </td> </tr> <tr> <td> <code> pages:routerOptions </code> </td> <td> <code> { files: Array<{ path: string, optional?: boolean }> } </code> </td> <td> Called when resolving <code> router.options </code> files. Later items in the array override earlier ones. </td> </tr> <tr> <td> <code> server:routes </code> </td> <td> <code> routes </code> , <code> context </code> </td> <td> Called when Nuxt needs the full set of route handlers the server will serve, so that it can type <code> $fetch </code> and <code> useFetch </code> against them. </td> </tr> <tr> <td> <code> server:devHandler </code> </td> <td> <code> handler </code> </td> <td> Called when the dev middleware is being registered on the Nitro dev server. </td> </tr> <tr> <td> <code> imports:sources </code> </td> <td> <code> presets </code> </td> <td> Called at setup allowing modules to extend sources. </td> </tr> <tr> <td> <code> imports:extend </code> </td> <td> <code> imports </code> </td> <td> Called at setup allowing modules to extend imports. </td> </tr> <tr> <td> <code> imports:context </code> </td> <td> <code> context </code> </td> <td> Called when the <a href="https://github.com/unjs/unimport" rel="nofollow"> unimport </a> context is created. </td> </tr> <tr> <td> <code> imports:dirs </code> </td> <td> <code> dirs </code> </td> <td> Allows extending import directories. </td> </tr> <tr> <td> <code> components:dirs </code> </td> <td> <code> dirs </code> </td> <td> Called within <code> app:resolve </code> allowing to extend the directories that are scanned for auto-importable components. </td> </tr> <tr> <td> <code> components:extend </code> </td> <td> <code> components </code> </td> <td> Allows extending new components. </td> </tr> <tr> <td> <code> nitro:config </code> </td> <td> <code> nitroConfig </code> </td> <td> Called before initializing Nitro, allowing customization of Nitro's configuration. </td> </tr> <tr> <td> <code> nitro:init </code> </td> <td> <code> nitro </code> </td> <td> Called after Nitro is initialized, which allows registering Nitro hooks and interacting directly with Nitro. </td> </tr> <tr> <td> <code> nitro:build:before </code> </td> <td> <code> nitro </code> </td> <td> Called before building the Nitro instance. </td> </tr> <tr> <td> <code> nitro:build:public-assets </code> </td> <td> <code> nitro </code> </td> <td> Called after copying public assets. Allows modifying public assets before Nitro server is built. </td> </tr> <tr> <td> <code> prerender:routes </code> </td> <td> <code> ctx </code> </td> <td> Allows extending the routes to be pre-rendered. </td> </tr> <tr> <td> <code> build:error </code> </td> <td> <code> error </code> </td> <td> Called when an error occurs at build time. </td> </tr> <tr> <td> <code> prepare:types </code> </td> <td> <code> options </code> </td> <td> Called before <code> @nuxt/cli </code> writes TypeScript configuration files (<code> .nuxt/tsconfig.app.json </code> , <code> .nuxt/tsconfig.server.json </code> , etc.) and <code> .nuxt/nuxt.d.ts </code> , allowing addition of custom references and declarations in <code> nuxt.d.ts </code> , or directly modifying the options in generated configurations </td> </tr> <tr> <td> <code> listen </code> </td> <td> <code> listenerServer, listener </code> </td> <td> Called when the dev server is loading. </td> </tr> <tr> <td> <code> schema:extend </code> </td> <td> <code> schemas </code> </td> <td> Allows extending default schemas. </td> </tr> <tr> <td> <code> schema:resolved </code> </td> <td> <code> schema </code> </td> <td> Allows extending resolved schema. </td> </tr> <tr> <td> <code> schema:beforeWrite </code> </td> <td> <code> schema </code> </td> <td> Called before writing the given schema. </td> </tr> <tr> <td> <code> schema:written </code> </td> <td> - </td> <td> Called after the schema is written. </td> </tr> <tr> <td> <code> vite:extend </code> </td> <td> <code> viteBuildContext </code> </td> <td> Allows extending Vite default context. </td> </tr> <tr> <td> <code> vite:extendConfig </code> </td> <td> <code> viteInlineConfig, env </code> </td> <td> Allows extending Vite default config. <strong> Deprecated in Nuxt 5+. </strong> In Nuxt 5, this operates on a shared configuration rather than separate client/server configs. </td> </tr> <tr> <td> <code> vite:configResolved </code> </td> <td> <code> viteInlineConfig, env </code> </td> <td> Allows reading the resolved Vite config. <strong> Deprecated in Nuxt 5+. </strong> In Nuxt 5, this operates on a shared configuration rather than separate client/server configs. </td> </tr> <tr> <td> <code> vite:serverCreated </code> </td> <td> <code> viteServer, env </code> </td> <td> Called when the Vite server is created. </td> </tr> <tr> <td> <code> vite:compiled </code> </td> <td> - </td> <td> Called after Vite server is compiled. </td> </tr> <tr> <td> <code> webpack:config </code> </td> <td> <code> webpackConfigs </code> </td> <td> Called before configuring the webpack compiler. </td> </tr> <tr> <td> <code> webpack:configResolved </code> </td> <td> <code> webpackConfigs </code> </td> <td> Allows reading the resolved webpack config. </td> </tr> <tr> <td> <code> webpack:compile </code> </td> <td> <code> options </code> </td> <td> Called right before compilation. </td> </tr> <tr> <td> <code> webpack:compiled </code> </td> <td> <code> options </code> </td> <td> Called after resources are loaded. </td> </tr> <tr> <td> <code> webpack:change </code> </td> <td> <code> shortPath </code> </td> <td> Called on <code> change </code> on WebpackBar. </td> </tr> <tr> <td> <code> webpack:error </code> </td> <td> - </td> <td> Called on <code> done </code> if has errors on WebpackBar. </td> </tr> <tr> <td> <code> webpack:done </code> </td> <td> - </td> <td> Called on <code> allDone </code> on WebpackBar. </td> </tr> <tr> <td> <code> webpack:progress </code> </td> <td> <code> statesArray </code> </td> <td> Called on <code> progress </code> on WebpackBar. </td> </tr> </tbody> </table> ## Nitro App Hooks (Runtime, Server-Side) See [Nitro](https://nitro.build/guide/plugins#available-hooks) for all available hooks. <table> <thead> <tr> <th> Hook </th> <th> Arguments </th> <th> Description </th> <th> Types </th> </tr> </thead> <tbody> <tr> <td> <code> dev:ssr-logs </code> </td> <td> <code> { path, logs } </code> </td> <td> Server </td> <td> Called at the end of a request cycle with an array of server-side logs. </td> </tr> <tr> <td> <code> render:response </code> </td> <td> <code> response, { event } </code> </td> <td> Called before sending the response. </td> <td> <a href="https://github.com/nuxt/nuxt/blob/71ef8bd3ff207fd51c2ca18d5a8c7140476780c7/packages/nuxt/src/core/runtime/nitro/renderer.ts#L24" rel="nofollow"> response </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> render:html </code> </td> <td> <code> html, { event } </code> </td> <td> Called before constructing the HTML. </td> <td> <a href="https://github.com/nuxt/nuxt/blob/71ef8bd3ff207fd51c2ca18d5a8c7140476780c7/packages/nuxt/src/core/runtime/nitro/renderer.ts#L15" rel="nofollow"> html </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> render:island </code> </td> <td> <code> islandResponse, { event, islandContext } </code> </td> <td> Called before constructing the island HTML. </td> <td> <a href="https://github.com/nuxt/nuxt/blob/e50cabfed1984c341af0d0c056a325a8aec26980/packages/nuxt/src/core/runtime/nitro/renderer.ts#L28" rel="nofollow"> islandResponse </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> , <a href="https://github.com/nuxt/nuxt/blob/e50cabfed1984c341af0d0c056a325a8aec26980/packages/nuxt/src/core/runtime/nitro/renderer.ts#L38" rel="nofollow"> islandContext </a> </td> </tr> <tr> <td> <code> close </code> </td> <td> - </td> <td> Called when Nitro is closed. </td> <td> - </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> error, { event? } </code> </td> <td> Called when an error occurs. </td> <td> <a href="https://github.com/nitrojs/nitro/blob/d20ffcbd16fc4003b774445e1a01e698c2bb078a/src/types/runtime/nitro.ts#L48" rel="nofollow"> error </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> request </code> </td> <td> <code> event </code> </td> <td> Called when a request is received. </td> <td> <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> beforeResponse </code> </td> <td> <code> event, { body } </code> </td> <td> Called before sending the response. </td> <td> <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> , unknown </td> </tr> <tr> <td> <code> afterResponse </code> </td> <td> <code> event, { body } </code> </td> <td> Called after sending the response. </td> <td> <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> , unknown </td> </tr> </tbody> </table> # Import meta > Understand where your code is running using `import.meta`. ## The `import.meta` Object With ES modules you can obtain some metadata from the code that imports or compiles your ES-module. This is done through `import.meta`, which is an object that provides your code with this information. Throughout the Nuxt documentation you may see snippets that use this already to figure out whether the code is currently running on the client or server side. <read-more to="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta"> Read more about `import.meta`. </read-more> ## Runtime (App) Properties These values are statically injected and can be used for tree-shaking your runtime code. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> import.meta.client </code> </td> <td> boolean </td> <td> True when evaluated on the client side. </td> </tr> <tr> <td> <code> import.meta.browser </code> </td> <td> boolean </td> <td> True when evaluated on the client side. </td> </tr> <tr> <td> <code> import.meta.server </code> </td> <td> boolean </td> <td> True when evaluated on the server side. </td> </tr> <tr> <td> <code> import.meta.nitro </code> </td> <td> boolean </td> <td> True when evaluated on the server side. </td> </tr> <tr> <td> <code> import.meta.dev </code> </td> <td> boolean </td> <td> True when running the Nuxt dev server. </td> </tr> <tr> <td> <code> import.meta.envName </code> <badge className="align-middle" color="info" size="xs"> v4.5 </badge> </td> <td> string </td> <td> The current Nuxt environment name, including custom values passed via <code> --envName </code> . </td> </tr> <tr> <td> <code> import.meta.test </code> </td> <td> boolean </td> <td> True when running in a test context. </td> </tr> <tr> <td> <code> import.meta.prerender </code> </td> <td> boolean </td> <td> True when rendering HTML on the server in the prerender stage of your build. </td> </tr> </tbody> </table> ## Builder Properties These values are available both in modules and in your `nuxt.config`. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> import.meta.env </code> </td> <td> object </td> <td> Equals <code> process.env </code> </td> </tr> <tr> <td> <code> import.meta.url </code> </td> <td> string </td> <td> Resolvable path for the current file. </td> </tr> </tbody> </table> ## Example ### Using `import.meta.url` to Resolve Files within Modules ```ts [modules/my-module/index.ts] import { createResolver } from 'nuxt/kit' // Resolve relative from the current file const resolver = createResolver(import.meta.url) export default defineNuxtModule({ meta: { name: 'myModule' }, setup () { addComponent({ name: 'MyModuleComponent', // Resolves to '/modules/my-module/components/MyModuleComponent.vue' filePath: resolver.resolve('./components/MyModuleComponent.vue'), }) }, }) ``` # nuxt add > Add modules to your Nuxt application with the command line. ```bash [Terminal] npx nuxt add <MODULENAME> [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--skipInstall] [--skipConfig] [--dev] ``` ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> MODULENAME </code> </td> <td> Specify one or more modules to install by name, separated by spaces </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --skipInstall </code> </td> <td> </td> <td> Skip npm install </td> </tr> <tr> <td> <code> --skipConfig </code> </td> <td> </td> <td> Skip nuxt.config.ts update </td> </tr> <tr> <td> <code> --dev </code> </td> <td> </td> <td> Install modules as dev dependencies </td> </tr> </tbody> </table> The command lets you install [Nuxt modules](https://nuxt.com/modules) in your application with no manual work. When running the command, it will: - install the module as a dependency using your package manager (unless `--skipInstall` is set) - add it to your [package.json](https://nuxt.com/docs/4.x/directory-structure/package) file (unless `--skipInstall` is set) - update your [`nuxt.config`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file (unless `--skipConfig` is set) If no module name is passed, you will be prompted to search for and select modules to add. **Example:** Installing the [`Pinia`](https://nuxt.com/modules/pinia) module ```bash [Terminal] npx nuxt add pinia ``` <note> `nuxt module add` is an alias for `nuxt add`. </note> <read-more to="https://nuxt.com/docs/4.x/api/commands/module"> Read more about the other `nuxt module` commands. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/module/add.ts) # nuxt add-template > Scaffold an entity into your Nuxt application. ```bash [Terminal] npx nuxt add-template <TEMPLATE> <NAME> [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--force] ``` <note> `nuxt add <TEMPLATE> <NAME>` still works but is deprecated in favour of `nuxt add-template`. </note> <read-more to="https://nuxt.com/docs/4.x/api/commands/add"> Read more about `nuxt add`, which adds Nuxt modules to your application. </read-more> ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> TEMPLATE </code> </td> <td> Specify which template to generate (options: <api|app|app-config|component|composable|error|layer|layout|middleware|module|page|plugin|server-middleware|server-plugin|server-route|server-util>) </td> </tr> <tr> <td> <code> NAME </code> </td> <td> Specify name of the generated file </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --force </code> </td> <td> <code> false </code> </td> <td> Force override file if it already exists </td> </tr> </tbody> </table> **Modifiers:** Some templates support additional modifier flags to add a suffix (like `.client` or `.get`) to their name. Generated files are written relative to your [`srcDir`](https://nuxt.com/docs/4.x/api/nuxt-config#srcdir), which defaults to the root of your project. The paths below assume that default. ```bash [Terminal] # Generates `/plugins/sockets.client.ts` npx nuxt add-template plugin sockets --client ``` ## `nuxt add-template component` - Modifier flags: `--mode client|server` or `--client` or `--server` ```bash [Terminal] # Generates `components/TheHeader.vue` npx nuxt add-template component TheHeader ``` ## `nuxt add-template composable` ```bash [Terminal] # Generates `composables/foo.ts` npx nuxt add-template composable foo ``` ## `nuxt add-template layout` ```bash [Terminal] # Generates `layouts/custom.vue` npx nuxt add-template layout custom ``` ## `nuxt add-template plugin` - Modifier flags: `--mode client|server` or `--client` or `--server` ```bash [Terminal] # Generates `plugins/analytics.ts` npx nuxt add-template plugin analytics ``` ## `nuxt add-template page` ```bash [Terminal] # Generates `pages/about.vue` npx nuxt add-template page about ``` ```bash [Terminal] # Generates `pages/category/[id].vue` npx nuxt add-template page "category/[id]" ``` ## `nuxt add-template middleware` - Modifier flags: `--global` ```bash [Terminal] # Generates `middleware/auth.ts` npx nuxt add-template middleware auth ``` ## `nuxt add-template api` - Modifier flags: `--method` (can accept `connect`, `delete`, `get`, `head`, `options`, `patch`, `post`, `put` or `trace`) or alternatively you can directly use `--get`, `--post`, etc. ```bash [Terminal] # Generates `server/api/hello.ts` npx nuxt add-template api hello ``` ## `nuxt add-template layer` ```bash [Terminal] # Generates `layers/subscribe/nuxt.config.ts` npx nuxt add-template layer subscribe ``` --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/add-template.ts) # nuxt analyze > Analyze the production bundle or your Nuxt application. ```bash [Terminal] npx nuxt analyze [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dotenv] [-e, --extends=<layer-name>] [--name=<name>] [--no-serve] ``` The `analyze` command builds Nuxt and analyzes the production bundle (experimental). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --name=<name> </code> </td> <td> <code> default </code> </td> <td> Name of the analysis </td> </tr> <tr> <td> <code> --no-serve </code> </td> <td> </td> <td> Skip serving the analysis results </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/analyze.ts) # nuxt build > Build your Nuxt application. ```bash [Terminal] npx nuxt build [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--prerender] [--preset] [--dotenv] [--envName] [-e, --extends=<layer-name>] [--profile[=verbose]] ``` The `build` command creates a `.output` directory with all your application, server and dependencies ready for production. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --prerender </code> </td> <td> </td> <td> Build Nuxt and prerender static routes </td> </tr> <tr> <td> <code> --preset </code> </td> <td> </td> <td> Nitro server preset </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --profile[=verbose] </code> </td> <td> </td> <td> Profile performance. Use <code> --profile </code> for CPU only, <code> --profile=verbose </code> for full report. </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. </note> <note> `--prerender` will always set the `preset` to `static` </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/build.ts) # nuxt build-module > Nuxt command to build your Nuxt module before publishing. ```bash [Terminal] npx nuxt build-module [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--build] [--stub] [--sourcemap] [--prepare] ``` The `build-module` command runs `@nuxt/module-builder` to generate `dist` directory within your `rootDir` that contains the full build for your **nuxt-module**. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --build </code> </td> <td> <code> false </code> </td> <td> Build module for distribution </td> </tr> <tr> <td> <code> --stub </code> </td> <td> <code> false </code> </td> <td> Stub dist instead of actually building it for development </td> </tr> <tr> <td> <code> --sourcemap </code> </td> <td> <code> false </code> </td> <td> Generate sourcemaps </td> </tr> <tr> <td> <code> --prepare </code> </td> <td> <code> false </code> </td> <td> Prepare module for local development </td> </tr> </tbody> </table> <read-more icon="i-simple-icons-github" target="\_blank" to="https://github.com/nuxt/module-builder"> Read more about `@nuxt/module-builder`. </read-more> --- - [Source](https://github.com/nuxt/module-builder/blob/main/src/cli.ts) # nuxt cleanup > Remove common generated Nuxt files and caches. ```bash [Terminal] npx nuxt cleanup [ROOTDIR] [--cwd=<directory>] ``` The `cleanup` command removes common generated Nuxt files and caches, including: - `.nuxt` - `.output` - `dist` - `node_modules/.vite` - `node_modules/.cache` ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/cleanup.ts) # nuxt dev > The dev command starts a development server with hot module replacement at http://localhost:3000 ```bash [Terminal] npx nuxt dev [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dotenv] [--envName] [-e, --extends=<layer-name>] [--clear] [--no-f, --no-fork] [-p, --port] [-h, --host] [--clipboard] [-o, --open] [--https] [--publicURL] [--qr] [--public] [--tunnel] [--profile[=verbose]] [--sslCert] [--sslKey] ``` The `dev` command starts a development server with hot module replacement at [http://localhost:3000](https://localhost:3000) ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --clear </code> </td> <td> <code> false </code> </td> <td> Clear console on restart </td> </tr> <tr> <td> <code> --no-f, --no-fork </code> </td> <td> </td> <td> Disable forked mode </td> </tr> <tr> <td> <code> -p, --port </code> </td> <td> </td> <td> Port to listen on (default: <code> NUXT_PORT || NITRO_PORT || PORT || nuxtOptions.devServer.port </code> ) </td> </tr> <tr> <td> <code> -h, --host </code> </td> <td> </td> <td> Host to listen on (default: <code> NUXT_HOST || NITRO_HOST || HOST || nuxtOptions.devServer?.host </code> ) </td> </tr> <tr> <td> <code> --clipboard </code> </td> <td> <code> false </code> </td> <td> Copy the URL to the clipboard </td> </tr> <tr> <td> <code> -o, --open </code> </td> <td> <code> false </code> </td> <td> Open the URL in the browser </td> </tr> <tr> <td> <code> --https </code> </td> <td> </td> <td> Enable HTTPS </td> </tr> <tr> <td> <code> --publicURL </code> </td> <td> </td> <td> Displayed public URL (used for QR code) </td> </tr> <tr> <td> <code> --qr </code> </td> <td> </td> <td> Display The QR code of public URL when available </td> </tr> <tr> <td> <code> --public </code> </td> <td> </td> <td> Listen to all network interfaces </td> </tr> <tr> <td> <code> --tunnel </code> </td> <td> </td> <td> Open a tunnel using <a href="https://github.com/unjs/untun" rel="nofollow"> https://github.com/unjs/untun </a> </td> </tr> <tr> <td> <code> --profile[=verbose] </code> </td> <td> </td> <td> Profile performance. Use <code> --profile </code> for CPU only, <code> --profile=verbose </code> for full report. </td> </tr> <tr> <td> <code> --sslCert </code> </td> <td> </td> <td> (DEPRECATED) Use <code> --https.cert </code> instead. </td> </tr> <tr> <td> <code> --sslKey </code> </td> <td> </td> <td> (DEPRECATED) Use <code> --https.key </code> instead. </td> </tr> </tbody> </table> The port and host can also be set via NUXT_PORT, PORT, NUXT_HOST or HOST environment variables. Additionally to the above options, `@nuxt/cli` can pass options through to `listhen`, e.g. `--no-qr` to turn off the dev server QR code. You can find the list of `listhen` options in the [unjs/listhen](https://github.com/unjs/listhen) docs. This command sets `process.env.NODE_ENV` to `development`. <note> If you are using a self-signed certificate in development, you will need to set `NODE_TLS_REJECT_UNAUTHORIZED=0` in your environment. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/dev.ts) # nuxt devtools > The devtools command allows you to enable or disable Nuxt DevTools on a per-project basis. ```bash [Terminal] npx nuxt devtools <COMMAND> [ROOTDIR] [--cwd=<directory>] ``` Running `nuxt devtools enable` will install the Nuxt DevTools globally, and also enable it within the particular project you are using. It is saved as a preference in your user-level `.nuxtrc`. If you want to remove devtools support for a particular project, you can run `nuxt devtools disable`. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> COMMAND </code> </td> <td> Command to run (options: <enable|disable>) </td> </tr> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> </tbody> </table> <read-more icon="i-simple-icons-nuxtdotjs" target="\_blank" to="https://devtools.nuxt.com"> Read more about the **Nuxt DevTools**. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/devtools.ts) # nuxt generate > Pre-renders every route of the application and stores the result in plain HTML files. ```bash [Terminal] npx nuxt generate [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--preset] [--dotenv] [--envName] [-e, --extends=<layer-name>] [--profile[=verbose]] ``` The `generate` command pre-renders every route of your application and stores the result in plain HTML files that you can deploy on any static hosting services. The command triggers the `nuxt build` command with the `prerender` argument set to `true` ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --preset </code> </td> <td> </td> <td> Nitro server preset </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --profile[=verbose] </code> </td> <td> </td> <td> Profile performance. Use <code> --profile </code> for CPU only, <code> --profile=verbose </code> for full report. </td> </tr> </tbody> </table> <read-more to="https://nuxt.com/docs/4.x/getting-started/deployment#static-hosting"> Read more about pre-rendering and static hosting. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/generate.ts) # nuxt info > The info command logs information about the current or specified Nuxt project. ```bash [Terminal] npx nuxt info [ROOTDIR] [--cwd=<directory>] ``` The `info` command logs information about the current or specified Nuxt project. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/info.ts) # create nuxt > The init command initializes a fresh Nuxt project. ```bash [Terminal] npm create nuxt@latest [DIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [-t, --template] [-f, --force] [--offline] [--preferOffline] [--no-install] [--gitInit] [--shell] [--packageManager] [-M, --modules] [--no-modules] [--nightly] ``` The `create-nuxt` command initializes a fresh Nuxt project using [unjs/giget](https://github.com/unjs/giget). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> DIR="" </code> </td> <td> Project directory </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> -t, --template </code> </td> <td> </td> <td> Template name </td> </tr> <tr> <td> <code> -f, --force </code> </td> <td> </td> <td> Override existing directory </td> </tr> <tr> <td> <code> --offline </code> </td> <td> </td> <td> Force offline mode </td> </tr> <tr> <td> <code> --preferOffline </code> </td> <td> </td> <td> Prefer offline mode </td> </tr> <tr> <td> <code> --no-install </code> </td> <td> </td> <td> Skip installing dependencies </td> </tr> <tr> <td> <code> --gitInit </code> </td> <td> </td> <td> Initialize git repository </td> </tr> <tr> <td> <code> --shell </code> </td> <td> </td> <td> Start shell after installation in project directory </td> </tr> <tr> <td> <code> --packageManager </code> </td> <td> </td> <td> Package manager choice (npm, pnpm, yarn, bun) </td> </tr> <tr> <td> <code> -M, --modules </code> </td> <td> </td> <td> Nuxt modules to install (comma separated without spaces) </td> </tr> <tr> <td> <code> --no-modules </code> </td> <td> </td> <td> Skip module installation prompt </td> </tr> <tr> <td> <code> --nightly </code> </td> <td> </td> <td> Use Nuxt nightly release channel (3x or latest) </td> </tr> </tbody> </table> ## Environment Variables - `NUXI_INIT_REGISTRY`: Set to a custom template registry. ([learn more](https://github.com/unjs/giget#custom-registry)). - Default registry is loaded from [nuxt/starter/templates](https://github.com/nuxt/starter/tree/templates/templates) --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/init.ts) # nuxt module > Search and remove modules in your Nuxt application with the command line. Nuxt provides a few utilities to work with [Nuxt modules](https://nuxt.com/modules) seamlessly. <read-more to="https://nuxt.com/docs/4.x/api/commands/add"> Read more about `nuxt add`, which installs modules into your application. </read-more> ## `nuxt module remove` ```bash [Terminal] npx nuxt module remove [MODULENAME] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--skipInstall] [--skipConfig] ``` ### Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> MODULENAME </code> </td> <td> Specify one or more modules to remove by name, separated by spaces </td> </tr> </tbody> </table> ### Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --skipInstall </code> </td> <td> </td> <td> Skip dependency uninstall </td> </tr> <tr> <td> <code> --skipConfig </code> </td> <td> </td> <td> Skip nuxt.config.ts update </td> </tr> </tbody> </table> The command uninstalls the module (unless `--skipInstall` is set) and removes it from your [`nuxt.config`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file (unless `--skipConfig` is set). If no module name is passed, you will be prompted to select from the modules registered in your `nuxt.config`. A module name is required when `--skipConfig` is set. **Example:** ```bash [Terminal] npx nuxt module remove pinia ``` ## `nuxt module search` ```bash [Terminal] npx nuxt module search <QUERY> [--cwd=<directory>] [--nuxtVersion=<2|3>] ``` ### Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> QUERY </code> </td> <td> keywords to search for </td> </tr> </tbody> </table> ### Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --nuxtVersion=<2|3> </code> </td> <td> </td> <td> Filter by Nuxt version and list compatible modules only (auto detected by default) </td> </tr> </tbody> </table> The command searches for Nuxt modules matching your query that are compatible with your Nuxt version. **Example:** ```bash [Terminal] npx nuxt module search pinia ``` --- - [Source](https://github.com/nuxt/cli/tree/3.x/packages/nuxi/src/commands/module) # Nuxt CLI > The Nuxt CLI runs, builds and inspects your Nuxt application from the command line. `@nuxt/cli` is the `nuxt` command: it runs the dev server, builds your application for production, scaffolds files, manages modules and answers questions about your project. It is a dependency of `nuxt`, so a Nuxt project already has it. ```bash [Terminal] npx nuxt dev ``` The binary is installed as `nuxt`, and also as `nuxi`, `nuxi-ng` and `nuxt-cli` for compatibility with older setups. Two other packages ship the same commands for different situations. `nuxi` is a standalone build with no runtime dependencies, for running commands outside a project or installing globally. Scaffolding a new project is [`create-nuxt`](https://nuxt.com/docs/4.x/api/commands/init), a separate package so that it can be run without a project to install into. ## Running commands Inside a project, your package manager runs the version the project depends on: ```bash [Terminal] pnpm nuxt dev npm exec nuxt dev yarn nuxt dev bun nuxt dev ``` Outside a project, `npx nuxi` runs the same commands from its own bundled copy. ## Global options `--cwd` may be passed before the command name as well as after it, which is useful in a monorepo: ```bash [Terminal] npx nuxt --cwd apps/web dev ``` Commands that take a `ROOTDIR` positional treat an explicit `--cwd` as an override of it. `--help` on any command prints its arguments and options, and `--version` prints the CLI version. Node.js 18 or newer is required. Older versions still run, with a warning that they are unsupported. ## Project commands A command the CLI does not provide is looked up as a `nuxt-<command>` binary in your project, so a dependency can add a command of its own. This is how [`nuxt build-module`](https://nuxt.com/docs/4.x/api/commands/build-module) works: it runs the `nuxt-build-module` binary that `@nuxt/module-builder` installs. ## Shell completions `nuxt complete <shell>` prints a completion script, powered by [`@bomb.sh/tab`](https://github.com/bombshell-dev/tab). It completes commands, flags and some flag values: ports and hosts for `nuxt dev`, Nitro presets for `nuxt build --preset`, starter templates for `nuxt init --template`, and log levels. <code-group> ```bash [zsh] npx nuxt complete zsh > "${fpath[1]}/_nuxt" ``` ```bash [bash] npx nuxt complete bash > /etc/bash_completion.d/nuxt ``` ```bash [fish] npx nuxt complete fish > ~/.config/fish/completions/nuxt.fish ``` </code-group> `powershell` is also supported, and `create-nuxt complete <shell>` has its own script which completes starter template names. <note> Completions work through your package manager too (`pnpm nuxt <Tab>`), if you install [tab's package manager completions](https://github.com/bombshell-dev/tab?tab=readme-ov-file#package-manager-completions). </note> ## Debugging the CLI Set `DEBUG=nuxi` for extra diagnostics from the CLI itself, such as dev server startup timings and the paths it removes during cleanup. ## Prereleases Every commit is published to the nightly channel: ```bash [Terminal] npm install -D @nuxt/cli-nightly npx @nuxt/cli-nightly dev ``` `create-nuxt-nightly` scaffolds with it, and `npm create nuxt@latest --nightly` scaffolds a project against the Nuxt nightly channel. Builds for an individual pull request are published by [pkg.pr.new](https://pkg.pr.new) and linked from the pull request itself, which is the quickest way to check whether a fix works before it is released. --- - [Source](https://github.com/nuxt/cli) # nuxt prepare > The prepare command creates a .nuxt directory in your application and generates types. ```bash [Terminal] npx nuxt prepare [ROOTDIR] [--dotenv] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--envName] [-e, --extends=<layer-name>] ``` The `prepare` command creates a [`.nuxt`](https://nuxt.com/docs/4.x/directory-structure/nuxt) directory in your application and generates types. This can be useful in a CI environment or as a `postinstall` command in your [`package.json`](https://nuxt.com/docs/4.x/directory-structure/package). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/prepare.ts) # nuxt preview > The preview command starts a server to preview your application after the build command. ```bash [Terminal] npx nuxt preview [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--envName] [-e, --extends=<layer-name>] [-p, --port] [--dotenv] ``` The `preview` command starts a server to preview your Nuxt application after running the `build` command. The `start` command is an alias for `preview`. When running your application in production refer to the [Deployment section](https://nuxt.com/docs/4.x/getting-started/deployment). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> -p, --port </code> </td> <td> </td> <td> Port to listen on </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> </tbody> </table> If `--port` is not provided, the `NUXT_PORT`, `NITRO_PORT` and `PORT` environment variables are used, in that order. This command sets `process.env.NODE_ENV` to `production`. To override, define `NODE_ENV` in a `.env` file or as command-line argument. <note> For convenience, in preview mode, your [`.env`](https://nuxt.com/docs/4.x/directory-structure/env) file will be loaded into `process.env`. (However, in production you will need to ensure your environment variables are set yourself. For example, with Node.js 20+ you could do this by running `NODE_ENV=production node --env-file .env .output/server/index.mjs` to start your server.) </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/preview.ts) # nuxt test > The test command runs tests using @nuxt/test-utils. ```bash [Terminal] npx nuxt test [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dev] [--watch] ``` The `test` command runs tests using [`@nuxt/test-utils`](https://nuxt.com/docs/4.x/getting-started/testing). This command sets `process.env.NODE_ENV` to `test` if not already set. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dev </code> </td> <td> </td> <td> Run in dev mode </td> </tr> <tr> <td> <code> --watch </code> </td> <td> </td> <td> Watch mode </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `test`. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/test.ts) # nuxt typecheck > The typecheck command runs vue-tsc or Golar to check types throughout your app. ```bash [Terminal] npx nuxt typecheck [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dotenv] [-e, --extends=<layer-name>] [--checker] ``` The `typecheck` command runs [`vue-tsc`](https://github.com/vuejs/language-tools/tree/master/packages/tsc) or [Golar](https://golar.dev/languages/vue/) to check types throughout your app. If neither is installed, you will be prompted to install one, or shown installation instructions when running in a non-interactive terminal. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --checker </code> </td> <td> </td> <td> Type checker to use (<code> vue-tsc </code> or <code> golar </code> ) </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. To override, define `NODE_ENV` in a [`.env`](https://nuxt.com/docs/4.x/directory-structure/env) file or as a command-line argument. </note> <read-more to="https://nuxt.com/docs/4.x/guide/concepts/typescript#type-checking"> Read more on how to enable type-checking at build or development time. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/typecheck.ts) # nuxt upgrade > The upgrade command upgrades Nuxt to the latest version. ```bash [Terminal] npx nuxt upgrade [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dedupe] [-f, --force] [-ch, --channel=<stable|nightly|v3|v4|v4-nightly|v3-nightly>] ``` The `upgrade` command upgrades Nuxt to the latest version. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dedupe </code> </td> <td> </td> <td> Dedupe dependencies after upgrading </td> </tr> <tr> <td> <code> -f, --force </code> </td> <td> </td> <td> Force upgrade to recreate lockfile and node_modules </td> </tr> <tr> <td> <code> -ch, --channel=<stable|nightly|v3|v4|v4-nightly|v3-nightly> </code> </td> <td> <code> stable </code> </td> <td> Specify a channel to install from (default: stable) </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/upgrade.ts) # <ClientOnly> > Render components only in client-side with the <ClientOnly> component. The `<ClientOnly>` component is used for purposely rendering a component only on client side. <note> The content of the default slot will be tree-shaken out of the server build. (This does mean that any CSS used by components within it may not be inlined when rendering the initial HTML.) </note> ## Props - `placeholderTag` | `fallbackTag`: specify a tag to be rendered server-side. - `placeholder` | `fallback`: specify a content to be rendered server-side. ```vue [app/pages/example.vue] <template> <div> <Sidebar /> <!-- The <Comment> component will only be rendered on client-side --> <ClientOnly fallback-tag="span" fallback="Loading comments..." > <Comment /> </ClientOnly> </div> </template> ``` ## Slots - `#fallback`: specify a content to be rendered on the server and displayed until `<ClientOnly>` is mounted in the browser. ```vue [app/pages/example.vue] <template> <div> <Sidebar /> <!-- This renders the "span" element on the server side --> <ClientOnly fallback-tag="span"> <!-- this component will only be rendered on client side --> <Comments /> <template #fallback> <!-- this will be rendered on server side --> <p>Loading comments...</p> </template> </ClientOnly> </div> </template> ``` ## Example ### Accessing HTML Elements Components inside `<ClientOnly>` are rendered only after being mounted. To access the rendered elements in the DOM, you can watch a template ref: ```vue [app/pages/example.vue] <script setup lang="ts"> const nuxtWelcomeRef = useTemplateRef('nuxtWelcomeRef') // The watch will be triggered when the component is available watch(nuxtWelcomeRef, () => { console.log('<NuxtWelcome /> mounted') }, { once: true }) </script> <template> <ClientOnly> <NuxtWelcome ref="nuxtWelcomeRef" /> </ClientOnly> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-only.ts) # <DevOnly> > Render components only during development with the <DevOnly> component. Nuxt provides the `<DevOnly>` component to render a component only during development. The content will not be included in production builds. ```vue [app/pages/example.vue] <template> <div> <Sidebar /> <DevOnly> <!-- this component will only be rendered during development --> <LazyDebugBar /> <!-- if you ever require to have a replacement during production --> <!-- be sure to test these using `nuxt preview` --> <template #fallback> <div><!-- empty div for flex.justify-between --></div> </template> </DevOnly> </div> </template> ``` ## Slots - `#fallback`: if you ever require to have a replacement during production. ```vue <template> <div> <Sidebar /> <DevOnly> <!-- this component will only be rendered during development --> <LazyDebugBar /> <!-- be sure to test these using `nuxt preview` --> <template #fallback> <div><!-- empty div for flex.justify-between --></div> </template> </DevOnly> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/dev-only.ts) # <NuxtAnnouncer> > The <NuxtAnnouncer> component adds a hidden element to announce dynamic content changes to assistive technologies. <important> This component is available in Nuxt v4.4.2+. </important> ## Usage Add `<NuxtAnnouncer/>` in your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) or [`app/layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts) to enable announcing dynamic content changes to screen readers. This is useful for form validation, toast notifications, loading states, and other in-page updates. ```vue [app/app.vue] <template> <NuxtAnnouncer /> <NuxtRouteAnnouncer /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` Then use the [`useAnnouncer`](https://nuxt.com/docs/4.x/api/composables/use-announcer) composable anywhere in your app to announce messages: ```vue [app/pages/contact.vue] <script setup lang="ts"> const { polite, assertive } = useAnnouncer() async function submitForm () { try { await $fetch('/api/contact', { method: 'POST', body: formData }) polite('Message sent successfully') } catch (error) { assertive('Error: Failed to send message') } } </script> ``` ## Slots You can pass custom HTML or components through the announcer's default slot. ```vue <template> <NuxtAnnouncer> <template #default="{ message }"> <p>{{ message }}</p> </template> </NuxtAnnouncer> </template> ``` ## Props - `atomic`: Controls if screen readers announce only changes or the entire content. Set to true for full content readouts on updates, false for changes only. (default `true`) - `politeness`: Sets the default urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) ## Differences from `<NuxtRouteAnnouncer>` <table> <thead> <tr> <th> Aspect </th> <th> <code> <NuxtRouteAnnouncer> </code> </th> <th> <code> <NuxtAnnouncer> </code> </th> </tr> </thead> <tbody> <tr> <td> <strong> Purpose </strong> </td> <td> Announces route/page changes </td> <td> Announces any dynamic content </td> </tr> <tr> <td> <strong> Trigger </strong> </td> <td> Automatic on navigation </td> <td> Manual via <code> polite() </code> /<code> assertive() </code> </td> </tr> <tr> <td> <strong> Message source </strong> </td> <td> Page <code> <title> </code> </td> <td> Developer-provided </td> </tr> <tr> <td> <strong> atomic default </strong> </td> <td> <code> false </code> </td> <td> <code> true </code> </td> </tr> </tbody> </table> <callout> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-announcer.ts). </callout> <callout> You can hook into the underlying announcer instance using [the `useAnnouncer` composable](https://nuxt.com/docs/4.x/api/composables/use-announcer), which allows you to set custom announcement messages. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-announcer.ts) # <NuxtClientFallback> > Nuxt provides the <NuxtClientFallback> component to render its content on the client if any of its children trigger an error in SSR Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR. <note to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#clientfallback"> This component is experimental and in order to use it you must enable the `experimental.clientFallback` option in your `nuxt.config`. </note> ```vue [app/pages/example.vue] <template> <div> <Sidebar /> <!-- this component will be rendered on client-side --> <NuxtClientFallback fallback-tag="span"> <Comments /> <BrokeInSSR /> </NuxtClientFallback> </div> </template> ``` ## Events - `@ssr-error`: Event emitted when a child triggers an error in SSR. Note that this will only be triggered on the server.```vue <template> <NuxtClientFallback @ssr-error="logSomeError"> <!-- ... --> </NuxtClientFallback> </template> ``` ## Props - `placeholderTag` | `fallbackTag`: Specify a fallback tag to be rendered if the slot fails to render on the server. - **type**: `string` - **default**: `div` - `placeholder` | `fallback`: Specify fallback content to be rendered if the slot fails to render. - **type**: `string` - `keepFallback`: Keep the fallback content if it failed to render server-side. - **type**: `boolean` - **default**: `false` <warning icon="i-ph-warning-duotone"> The `placeholder` and `fallback` props render content as raw HTML. Do not pass untrusted user input to these props as it may lead to XSS vulnerabilities. Use the `#fallback` or `#placeholder` slots instead for dynamic content that needs proper escaping. </warning> ```vue <template> <!-- render <span>Hello world</span> server-side if the default slot fails to render --> <NuxtClientFallback fallback-tag="span" fallback="Hello world" > <BrokeInSSR /> </NuxtClientFallback> </template> ``` ## Slots - `#fallback`: specify content to be displayed server-side if the slot fails to render. ```vue <template> <NuxtClientFallback> <!-- ... --> <template #fallback> <!-- this will be rendered on server side if the default slot fails to render in ssr --> <p>Hello world</p> </template> </NuxtClientFallback> </template> ``` --- - [Source (client)](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.client.ts) - [Source (server)](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.server.ts) # <NuxtErrorBoundary> > The <NuxtErrorBoundary> component handles client-side errors happening in its default slot. <tip> The `<NuxtErrorBoundary>` uses Vue's [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) hook under the hood. </tip> ## Events - `@error`: Event emitted when the default slot of the component throws an error.```vue [app/app.vue] <template> <NuxtErrorBoundary @error="logSomeError"> <!-- ... --> </NuxtErrorBoundary> </template> ``` ## Slots - `#error`: Specify a fallback content to display in case of error.```vue [app/app.vue] <template> <NuxtErrorBoundary> <!-- ... --> <template #error="{ error, clearError }"> <p>An error occurred: {{ error }}</p> <button @click="clearError"> Clear error </button> </template> </NuxtErrorBoundary> </template> ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> ## Example ### Accessing `error` and `clearError` in Script You can access `error` and `clearError` properties within the component's script as below: ```vue [app/app.vue] <template> <NuxtErrorBoundary ref="errorBoundary"> <!-- ... --> </NuxtErrorBoundary> </template> <script setup lang="ts"> const errorBoundary = useTemplateRef('errorBoundary') // errorBoundary.value?.error // errorBoundary.value?.clearError() </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-error-boundary.vue) # <NuxtImg> > Nuxt provides a <NuxtImg> component to handle automatic image optimization. `<NuxtImg>` is a drop-in replacement for the native `<img>` tag. - Uses built-in provider to optimize local and remote images - Converts `src` to provider-optimized URLs - Automatically resizes images based on `width` and `height` - Generates responsive sizes when providing `sizes` option - Supports native lazy loading as well as other `<img>` attributes ## Setup In order to use `<NuxtImg>` you should install and enable the Nuxt Image module: ```bash [Terminal] npx nuxt module add image ``` ## Usage `<NuxtImg>` outputs a native `img` tag directly (without any wrapper around it). Use it like you would use the `<img>` tag: ```html <NuxtImg src="/nuxt-icon.png" /> ``` Will result in: ```html <img src="/nuxt-icon.png" /> ``` <read-more target="_blank" to="https://image.nuxt.com/usage/nuxt-img"> Read more about the `<NuxtImg>` component. </read-more> --- - [Source](https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtImg.vue) # <NuxtIsland> > Nuxt provides the <NuxtIsland> component to render a non-interactive component without any client JS. When rendering an island component, the content of the island component is static, thus no JS is downloaded client-side. Changing the island component props triggers a refetch of the island component to re-render it again. <tip> Server only components use `<NuxtIsland>` under the hood </tip> <read-more to="https://nuxt.com/docs/4.x/guide/concepts/server-components"> Read the dedicated guide to server components and islands. </read-more> ## Props - `name` : Name of the component to render. - **type**: `string` - **required** - `lazy`: Make the component non-blocking. - **type**: `boolean` - **default**: `false` - `props`: Props to send to the component to render. - **type**: `Record<string, any>` - `source`: Remote source to call the island to render. - **type**: `string` - **dangerouslyLoadClientComponents**: Required to load client components from a remote source. - **type**: `boolean` - **default**: `false` <note> Remote islands need `experimental.componentIslands` to be `'local+remote'` in your `nuxt.config`. </note> <warning icon="i-ph-warning-duotone"> Using the `source` prop to render content from a remote server is inherently dangerous. When you specify a remote `source`, you are fully trusting that server to provide safe HTML content that will be rendered directly in your application. This is similar to using `v-html` with external content - the remote server can inject any HTML, including potentially malicious content. **Only use source with servers you fully trust and control.** The `dangerouslyLoadClientComponents` prop controls an additional layer of risk: whether to also download and execute client components from the remote source. Even with `dangerouslyLoadClientComponents` disabled (the default), you are still trusting the remote server's HTML output. </warning> <note> Component props and context are sent as GET query parameters to enable caching. Query parameters may be visible in server access logs, CDN caches, and HTTP `Referer` headers. </note> <note> By default, component islands are scanned from the `~/components/islands/` directory. So the `~/components/islands/MyIsland.vue` component could be rendered with `<NuxtIsland name="MyIsland" />`. </note> ## Known Limitations ### `useId` in island and server components Each island is rendered in its own Vue app on the server, so Vue's [`useId`](https://vuejs.org/api/composition-api-helpers#useid) counter restarts for every island. Ids generated inside an island can therefore collide with ids generated by other islands on the same page, or by the rest of your app. **Workaround**: set a distinct [`idPrefix`](https://vuejs.org/api/application#app-config-idprefix) on the island's Vue app from a server plugin, based on the island context id: ```ts [plugins/island-id-prefix.server.ts] export default defineNuxtPlugin((nuxtApp) => { const islandContext = nuxtApp.ssrContext?.islandContext if (islandContext) { nuxtApp.vueApp.config.idPrefix = `${islandContext.id}-v` } }) ``` - **Identical islands still share the same ids.** Two instances of the same island rendered with the same name, props and context share a single server render (and payload entry), so their HTML โ€” including any `useId`-generated ids โ€” is identical, and the island context id used as prefix is the same. This results in duplicated `id` attributes in the DOM, which can break `aria-*` references and `<label for>` associations between the two instances. There is currently no workaround for this case. - **useId does not work in interactive components inside islands.** A component loaded with the [`nuxt-client` attribute](https://nuxt.com/docs/4.x/guide/concepts/server-components#selective-hydration-with-nuxt-client) is server-rendered inside the island's app but hydrated by the main client app, so `useId` returns different values on the server and on the client, causing a hydration mismatch. ## Slots Slots can be passed to an island component if declared. Every slot is interactive since the parent component is the one providing it. Some slots are reserved to `NuxtIsland` for special cases. - `#fallback`: Specify the content to be rendered before the island loads (if the component is lazy) or if `NuxtIsland` fails to fetch the component. ## Ref - `refresh()` - **type**: `() => Promise<void>` - **description**: force refetch the server component by refetching it. ## Events - `error` - **parameters**: - **error**: - **type**: `unknown` - **description**: emitted when `NuxtIsland` fails to fetch the new island. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-island.ts) # <NuxtLayout> > Nuxt provides the <NuxtLayout> component to show layouts on pages and error pages. You can use `<NuxtLayout />` component to activate the `default` layout on `app.vue` or `error.vue`. ```vue [app/app.vue] <template> <NuxtLayout> some page content </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/layouts"> </read-more> ## Props - `name`: Specify a layout name to be rendered, can be a string, reactive reference or a computed property. It **must** match the name of the corresponding layout file in the [`app/layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts) directory, or `false` to disable the layout. - **type**: `string | false` - **default**: `default` ```vue [app/pages/index.vue] <script setup lang="ts"> // layouts/custom.vue const layout = 'custom' </script> <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> ``` <note> Please note the layout name is normalized to kebab-case, so if your layout file is named `errorLayout.vue`, it will become `error-layout` when passed as a `name` property to `<NuxtLayout />`. </note> ```vue [error.vue] <template> <NuxtLayout name="error-layout"> <NuxtPage /> </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/layouts"> Read more about dynamic layouts. </read-more> - `fallback`: If an invalid layout is passed to the `name` prop, no layout will be rendered. Specify a `fallback` layout to be rendered in this scenario. It **must** match the name of the corresponding layout file in the [`app/layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts) directory. - **type**: `string` - **default**: `null` ## Additional Props `NuxtLayout` also accepts any additional props that you may need to pass to the layout. These custom props are then made accessible as attributes. ```vue [app/pages/some-page.vue] <template> <div> <NuxtLayout name="custom" title="I am a custom layout" > <!-- ... --> </NuxtLayout> </div> </template> ``` In the above example, the value of `title` will be available using `$attrs.title` in the template or `useAttrs().title` in `<script setup>` at custom.vue. ```vue [app/layouts/custom.vue] <script setup lang="ts"> const layoutCustomProps = useAttrs() console.log(layoutCustomProps.title) // I am a custom layout </script> ``` ## Layout Props from Page Meta When using [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) with the object syntax for `layout`, props are automatically passed to the layout component. The layout can receive them with `defineProps`: ```vue [app/pages/dashboard.vue] <script setup lang="ts"> definePageMeta({ layout: { name: 'admin', props: { sidebar: true, }, }, }) </script> ``` ```vue [app/layouts/admin.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean }>() </script> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/layouts#passing-props-to-layouts"> Read more about passing props to layouts. </read-more> ## Transitions `<NuxtLayout />` renders incoming content via `<slot />`, which is then wrapped around Vueโ€™s `<Transition />` component to activate layout transition. For this to work as expected, it is recommended that `<NuxtLayout />` is **not** the root element of the page component. <code-group> ```vue [app/pages/index.vue] <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> </NuxtLayout> </div> </template> ``` ```vue [app/layouts/custom.vue] <template> <div> <!-- named slot --> <slot name="header" /> <slot /> </div> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/4.x/getting-started/transitions"> </read-more> ## Layout's Ref To get the ref of a layout component, access it through `ref.value.layoutRef`. <code-group> ```vue [app/app.vue] <script setup lang="ts"> const layout = ref() function logFoo () { layout.value.layoutRef.foo() } </script> <template> <NuxtLayout ref="layout"> default layout </NuxtLayout> </template> ``` ```vue [app/layouts/default.vue] <script setup lang="ts"> const foo = () => console.log('foo') defineExpose({ foo, }) </script> <template> <div> default layout <slot /> </div> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/layouts"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-layout.ts) # <NuxtLink> > Nuxt provides <NuxtLink> component to handle any kind of links within your application. <note> `<NuxtLink>` is a drop-in replacement for both Vue Router's `<RouterLink>` component and HTML's `<a>` tag. It intelligently determines whether the link is *internal* or *external* and renders it accordingly with available optimizations (prefetching, default attributes, etc.) </note> <read-more title="Nuxt accessibility" to="https://nuxt.com/docs/4.x/guide/best-practices/accessibility#links"> </read-more> ## Internal Routing In this example, we use `<NuxtLink>` component to link to another page of the application. <code-group> ```vue [app/pages/index.vue] <template> <NuxtLink to="/about">About page</NuxtLink> </template> ``` ```html [(Renders as) index.html] <!-- (Vue Router & Smart Prefetching) --> <a href="/about">About page</a> ``` </code-group> ### Passing Params to Dynamic Routes In this example, we pass the `id` param to link to the route `~/pages/posts/[id].vue`. <code-group> ```vue [app/pages/index.vue] <template> <NuxtLink :to="{ name: 'posts-id', params: { id: 123 } }"> Post 123 </NuxtLink> </template> ``` ```html [(Renders as) index.html] <a href="/posts/123">Post 123</a> ``` </code-group> <tip> Check out the Pages panel in Nuxt DevTools to see the route name and the params it might take. </tip> <tip> When you pass an object into the `to` prop, `<NuxtLink>` will inherit Vue Routerโ€™s handling of query parameters. Keys and values will be automatically encoded, so you donโ€™t need to call `encodeURI` or `encodeURIComponent` manually. </tip> ### Handling Static File and Cross-App Links By default, `<NuxtLink>` uses Vue Router's client side navigation for relative route. When linking to static files in the `/public` directory or to another application hosted on the same domain, it might result in unexpected 404 errors because they are not part of the client routes. In such cases, you can use the `external` prop with `<NuxtLink>` to bypass Vue Router's internal routing mechanism. The `external` prop explicitly indicates that the link is external. `<NuxtLink>` will render the link as a standard HTML `<a>` tag. This ensures the link behaves correctly, bypassing Vue Routerโ€™s logic and directly pointing to the resource. #### Linking to Static Files For static files in the `/public` directory, such as PDFs or images, use the `external` prop to ensure the link resolves correctly. ```vue [app/pages/index.vue] <template> <NuxtLink to="/example-report.pdf" external > Download Report </NuxtLink> </template> ``` #### Linking to a Cross-App URL When pointing to a different application on the same domain, using the `external` prop ensures the correct behavior. ```vue [app/pages/index.vue] <template> <NuxtLink to="/another-app" external > Go to Another App </NuxtLink> </template> ``` Using the `external` prop or relying on automatic handling ensures proper navigation, avoids unexpected routing issues, and improves compatibility with static resources or cross-application scenarios. ## External Routing In this example, we use `<NuxtLink>` component to link to a website. ```vue [app/app.vue] <template> <NuxtLink to="https://nuxtjs.org"> Nuxt website </NuxtLink> <!-- <a href="https://nuxtjs.org" rel="noopener noreferrer">...</a> --> </template> ``` ## `rel` and `noRel` Attributes A `rel` attribute of `noopener noreferrer` is applied by default to links with a `target` attribute or to absolute links (e.g., links starting with `http://`, `https://`, or `//`). - `noopener` solves a [security bug](https://mathiasbynens.github.io/rel-noopener/) in older browsers. - `noreferrer` improves privacy for your users by not sending the `Referer` header to the linked site. These defaults have no negative impact on SEO and are considered [best practice](https://developer.chrome.com/docs/lighthouse/best-practices/external-anchors-use-rel-noopener). When you need to overwrite this behavior you can use the `rel` or `noRel` props. ```vue [app/app.vue] <template> <NuxtLink to="https://twitter.com/nuxt_js"> Nuxt Twitter </NuxtLink> <!-- <a href="https://twitter.com/nuxt_js" rel="noopener noreferrer">...</a> --> <NuxtLink to="https://discord.nuxtjs.org" rel="noopener" > Nuxt Discord </NuxtLink> <!-- <a href="https://discord.nuxtjs.org" rel="noopener">...</a> --> <NuxtLink to="/about" target="_blank" >About page</NuxtLink> <!-- <a href="/about" target="_blank" rel="noopener noreferrer">...</a> --> </template> ``` A `noRel` prop can be used to prevent the default `rel` attribute from being added to the absolute links. ```vue [app/app.vue] <template> <NuxtLink to="https://github.com/nuxt" no-rel > Nuxt GitHub </NuxtLink> <!-- <a href="https://github.com/nuxt">...</a> --> </template> ``` <note> `noRel` and `rel` cannot be used together. `rel` will be ignored. </note> ## Prefetch Links Nuxt automatically includes smart prefetching. That means it detects when a link is visible (by default), either in the viewport or when scrolling and prefetches the JavaScript for those pages so that they are ready when the user clicks the link. Nuxt only loads the resources when the browser isn't busy and skips prefetching if your connection is offline or if you only have 2g connection. When using the `custom` prop, `<NuxtLink>` does not automatically attach prefetch handlers. You can call `prefetch` from the custom slot yourself. ```vue [app/pages/index.vue] <NuxtLink to="/about" no-prefetch> About page not pre-fetched </NuxtLink> <NuxtLink to="/about" :prefetch="false"> About page not pre-fetched </NuxtLink> ``` ### Custom Prefetch Triggers We now support custom prefetch triggers for `<NuxtLink>` after `v3.13.0`. You can use the `prefetchOn` prop to control when to prefetch links. ```vue <template> <NuxtLink prefetch-on="visibility"> This will prefetch when it becomes visible (default) </NuxtLink> <NuxtLink prefetch-on="interaction"> This will prefetch when hovered or when it gains focus </NuxtLink> </template> ``` - `visibility`: Prefetches when the link becomes visible in the viewport. Monitors the element's intersection with the viewport using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Prefetching is triggered when the element is scrolled into view. - `interaction`: Prefetches when the link is hovered or focused. This approach listens for `pointerenter` and `focus` events, proactively prefetching resources when the user indicates intent to interact. You can also use an object to configure `prefetchOn`: ```vue <template> <NuxtLink :prefetch-on="{ interaction: true }"> This will prefetch when hovered or when it gains focus </NuxtLink> </template> ``` That you probably don't want both enabled! ```vue <template> <NuxtLink :prefetch-on="{ visibility: true, interaction: true }"> This will prefetch when hovered/focus - or when it becomes visible </NuxtLink> </template> ``` This configuration will observe when the element enters the viewport and also listen for `pointerenter` and `focus` events. This may result in unnecessary resource usage or redundant prefetching, as both triggers can prefetch the same resource under different conditions. When using `custom`, prefetching is controlled by your slot implementation <badge className="align-middle" color="info" size="xs"> v4.5 </badge> : ```vue <template> <NuxtLink v-slot="{ href, navigate, prefetch, shouldPrefetch }" to="/about" custom > <a :href="href" @click="navigate" @pointerenter="shouldPrefetch('interaction') && prefetch()" @focus="shouldPrefetch('interaction') && prefetch()" > About page </a> </NuxtLink> </template> ``` ### Enable Cross-origin Prefetch To enable cross-origin prefetching, you can set the `crossOriginPrefetch` option in your `nuxt.config`. This will enable cross-origin prefetching using the [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API). ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { crossOriginPrefetch: true, }, }) ``` ### Disable prefetch globally It's also possible to enable/disable prefetching all links globally for your app. ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { prefetch: false, }, }, }, }) ``` ## Props ### RouterLink When not using `external`, `<NuxtLink>` supports all Vue Router's [`RouterLink` props](https://router.vuejs.org/api/interfaces/routerlinkprops) - `to`: Any URL or a [route location object](https://router.vuejs.org/api/type-aliases/routelocation) from Vue Router - `custom`: Whether `<NuxtLink>` should wrap its content in an `<a>` element. It allows taking full control of how a link is rendered and how navigation works when it is clicked. Works the same as [Vue Router's `custom` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#custom-) - `exactActiveClass`: A class to apply on exact active links. Works the same as [Vue Router's `exactActiveClass` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#exactActiveClass-) on internal links. Defaults to Vue Router's default (`"router-link-exact-active"`) - `activeClass`: A class to apply on active links. Works the same as [Vue Router's `activeClass` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#activeClass-) on internal links. Defaults to Vue Router's default (`"router-link-active"`) - `replace`: Works the same as [Vue Router's `replace` prop](https://router.vuejs.org/api/interfaces/routelocationoptions#replace-) on internal links - `ariaCurrentValue`: An `aria-current` attribute value to apply on exact active links. Works the same as [Vue Router's `ariaCurrentValue` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#ariaCurrentValue-) on internal links ### NuxtLink - `href`: An alias for `to`. If used with `to`, `href` will be ignored - `noRel`: If set to `true`, no `rel` attribute will be added to the external link - `external`: Forces the link to be rendered as an `<a>` tag instead of a Vue Router `RouterLink`. - `prefetch`: When enabled will prefetch middleware, layouts and payloads (when using [payloadExtraction](https://nuxt.com/docs/4.x/guide/going-further/experimental-features#payloadextraction)) of links in the viewport. Used by the experimental [crossOriginPrefetch](https://nuxt.com/docs/4.x/guide/going-further/experimental-features#crossoriginprefetch) config. - `prefetchOn`: Allows custom control of when to prefetch links. Possible options are `interaction` and `visibility` (default). You can also pass an object for full control, for example: `{ interaction: true, visibility: true }`. This prop is only used when `prefetch` is enabled (default) and `noPrefetch` is not set. - `noPrefetch`: Disables prefetching. - `prefetchedClass`: A class to apply to links that have been prefetched. <note> With the `custom` prop, `prefetch`, `prefetchOn` and `prefetchedClass` do not attach handlers or classes automatically. Use the custom slot's `prefetch`, `prefetched` and `shouldPrefetch` values to implement this behavior. </note> ### Anchor - `target`: A `target` attribute value to apply on the link - `rel`: A `rel` attribute value to apply on the link. Defaults to `"noopener noreferrer"` for external links. <tip> Defaults can be overwritten, see [overwriting defaults](https://nuxt.com/docs/4.x/api/components/nuxt-link#overwriting-defaults) if you want to change them. </tip> ## Overwriting Defaults ### In Nuxt Config You can overwrite some `<NuxtLink>` defaults in your [`nuxt.config`](https://nuxt.com/docs/4.x/guide/going-further/experimental-features#defaults) <important> These options will likely be moved elsewhere in the future, such as into `app.config` or into the `app/` directory. </important> ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { // default values componentName: 'NuxtLink', externalRelAttribute: 'noopener noreferrer', activeClass: 'router-link-active', exactActiveClass: 'router-link-exact-active', prefetchedClass: undefined, // can be any valid string class name trailingSlash: undefined, // can be 'append' or 'remove' prefetch: true, prefetchOn: { visibility: true }, }, }, }, }) ``` ### Custom Link Component You can overwrite `<NuxtLink>` defaults by creating your own link component using `defineNuxtLink`. ```ts [app/components/MyNuxtLink.ts] export default defineNuxtLink({ componentName: 'MyNuxtLink', /* see signature below for more */ }) ``` The component is auto-imported by its file name, so you can use `<MyNuxtLink />` as usual with your new defaults. `componentName` only sets the component's internal name (as shown in Vue DevTools); it does not change how the component is used in templates. ### `defineNuxtLink` Signature ```ts interface NuxtLinkOptions { componentName?: string externalRelAttribute?: string activeClass?: string exactActiveClass?: string trailingSlash?: 'append' | 'remove' prefetch?: boolean prefetchedClass?: string prefetchOn?: Partial<{ visibility: boolean interaction: boolean }> } function defineNuxtLink (options: NuxtLinkOptions): Component {} ``` - `componentName`: The component's internal name, as shown in Vue DevTools. It does not change the name used in templates (that comes from the component's file name). Default is `NuxtLink`. - `externalRelAttribute`: A default `rel` attribute value applied on external links. Defaults to `"noopener noreferrer"`. Set it to `""` to disable - `activeClass`: A default class to apply on active links. Works the same as [Vue Router's `linkActiveClass` option](https://router.vuejs.org/api/interfaces/routeroptions#linkActiveClass-). Defaults to Vue Router's default (`"router-link-active"`) - `exactActiveClass`: A default class to apply on exact active links. Works the same as [Vue Router's `linkExactActiveClass` option](https://router.vuejs.org/api/interfaces/routeroptions#linkExactActiveClass-). Defaults to Vue Router's default (`"router-link-exact-active"`) - `trailingSlash`: An option to either add or remove trailing slashes in the `href`. If unset or not matching the valid values `append` or `remove`, it will be ignored. - `prefetch`: Whether or not to prefetch links by default. - `prefetchOn`: Granular control of which prefetch strategies to apply by default. - `prefetchedClass`: A default class to apply to links that have been prefetched. <link-example to="https://nuxt.com/docs/4.x/examples/routing/pages"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-link.ts) # <NuxtLoadingIndicator> > Display a progress bar between page navigations. ## Usage Add `<NuxtLoadingIndicator/>` in your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) or [`app/layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts). ```vue [app/app.vue] <template> <NuxtLoadingIndicator /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` <link-example to="https://nuxt.com/docs/4.x/examples/routing/pages"> </link-example> ## Slots You can pass custom HTML or components through the loading indicator's default slot. ## Props - `color`: The color of the loading bar. It can be set to `false` to turn off explicit color styling. - `errorColor`: The color of the loading bar when `error` is set to `true`. - `height`: Height of the loading bar, in pixels (default `3`). - `duration`: Duration of the loading bar, in milliseconds (default `2000`). - `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`). - `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100. <note> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts). </note> <note> You can hook into the underlying indicator instance using [the `useLoadingIndicator` composable](https://nuxt.com/docs/4.x/api/composables/use-loading-indicator), which will allow you to trigger start/finish events yourself. </note> <tip> The loading indicator's speed gradually decreases after reaching a specific point controlled by `estimatedProgress`. This adjustment provides a more accurate reflection of longer page loading times and prevents the indicator from prematurely showing 100% completion. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts) # <NuxtPage> > The <NuxtPage> component is required to display pages located in the pages/ directory. `<NuxtPage>` is a built-in component that comes with Nuxt. It lets you display top-level or nested pages located in the [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory. <note> `<NuxtPage>` is a wrapper around [`<RouterView>`](https://router.vuejs.org/api/interfaces/routerviewprops) from Vue Router. It should be used instead of `<RouterView>` because the former takes additional care of internal states. Otherwise, `useRoute()` may return incorrect paths. </note> `<NuxtPage>` includes the following components: ```vue <template> <RouterView v-slot="{ Component }"> <!-- Optional, when using transitions --> <Transition> <!-- Optional, when using keep-alive --> <KeepAlive> <Suspense> <component :is="Component" /> </Suspense> </KeepAlive> </Transition> </RouterView> </template> ``` By default, Nuxt does not enable `<Transition>` and `<KeepAlive>`. You can enable them in the nuxt.config file or by setting the `transition` and `keepalive` properties on `<NuxtPage>`. If you want to define a specific page, you can set it in `definePageMeta` in the page component. <warning> If you enable `<Transition>` in your page component, ensure that the page has a single root element. </warning> Since `<NuxtPage>` uses `<Suspense>` under the hood, the component lifecycle behavior during page changes differs from that of a typical Vue application. In a typical Vue application, a new page component is mounted **only after** the previous one has been fully unmounted. However, in Nuxt, due to how Vue `<Suspense>` is implemented, the new page component is mounted **before** the previous one is unmounted. ## Props - `name`: tells `<RouterView>` to render the component with the corresponding name in the matched route record's components option. See [Named Views](https://nuxt.com/docs/4.x/directory-structure/app/pages#named-views) for the `name@view.vue` filename convention. - type: `string` - `route`: route location that has all of its components resolved. - type: `RouteLocationNormalized` - `pageKey`: control when the `NuxtPage` component is re-rendered. - type: `string` or `function` - `transition`: define global transitions for all pages rendered with the `NuxtPage` component. - type: `boolean` or [`TransitionProps`](https://vuejs.org/api/built-in-components#transition) - `keepalive`: control state preservation of pages rendered with the `NuxtPage` component. - type: `boolean` or [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive) <tip> Nuxt automatically resolves the `name` and `route` by scanning and rendering all Vue component files found in the `/pages` directory. </tip> ## Example For example, if you pass a key that never changes, the `<NuxtPage>` component will be rendered only once - when it is first mounted. ```vue [app/app.vue] <template> <NuxtPage page-key="static" /> </template> ``` You can also use a dynamic key based on the current route: ```html <NuxtPage :page-key="route => route.fullPath" /> ``` <warning> Don't use `$route` object here as it can cause problems with how `<NuxtPage>` renders pages with `<Suspense>`. </warning> Alternatively, `pageKey` can be passed as a `key` value via [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) from the `<script>` section of your Vue component in the `/pages` directory. ```vue [app/pages/my-page.vue] <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, }) </script> ``` <link-example to="https://nuxt.com/docs/4.x/examples/routing/pages"> </link-example> ## Page's Ref To get the `ref` of a page component, access it through `ref.value.pageRef` ```vue [app/app.vue] <script setup lang="ts"> const page = ref() function logFoo () { page.value.pageRef.foo() } </script> <template> <NuxtPage ref="page" /> </template> ``` ```vue [my-page.vue] <script setup lang="ts"> const foo = () => { console.log('foo method called') } defineExpose({ foo, }) </script> ``` ## Custom Props `<NuxtPage>` also accepts custom props that you may need to pass further down the hierarchy. For example, in the below example, the value of `foobar` will be passed to the `NuxtPage` component and then to the page components. ```vue [app/app.vue] <template> <NuxtPage :foobar="123" /> </template> ``` We can access the `foobar` prop in the page component: ```vue [app/pages/page.vue] <script setup lang="ts"> const props = defineProps<{ foobar: number }>() console.log(props.foobar) // Outputs: 123 ``` If you have not defined the prop with `defineProps`, any props passed down to `NuxtPage` can still be accessed directly from the page `attrs`: ```vue [app/pages/page.vue] <script setup lang="ts"> const attrs = useAttrs() console.log(attrs.foobar) // Outputs: 123 </script> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/pages"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/page.ts) # <NuxtPicture> > Nuxt provides a <NuxtPicture> component to handle automatic image optimization. `<NuxtPicture>` is a drop-in replacement for the native `<picture>` tag. Usage of `<NuxtPicture>` is almost identical to [`<NuxtImg>`](https://nuxt.com/docs/4.x/api/components/nuxt-img) but it also allows serving modern formats like `webp` when possible. Learn more about the [`<picture>` tag on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture). ## Setup In order to use `<NuxtPicture>` you should install and enable the Nuxt Image module: ```bash [Terminal] npx nuxt module add image ``` <read-more target="_blank" to="https://image.nuxt.com/usage/nuxt-picture"> Read more about the `<NuxtPicture>` component. </read-more> --- - [Source](https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtPicture.vue) # <NuxtRouteAnnouncer> > The <NuxtRouteAnnouncer> component adds a hidden element with the page title to announce route changes to assistive technologies. <important> This component is available in Nuxt v3.12+. </important> <read-more title="Nuxt accessibility" to="https://nuxt.com/docs/4.x/guide/best-practices/accessibility#route-announcements"> </read-more> ## Usage Add `<NuxtRouteAnnouncer/>` in your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) or [`app/layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts) to enhance accessibility by informing assistive technologies about page title changes. This ensures that navigational changes are announced to users relying on screen readers. ```vue [app/app.vue] <template> <NuxtRouteAnnouncer /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` ## Slots You can pass custom HTML or components through the route announcer's default slot. ```vue <template> <NuxtRouteAnnouncer> <template #default="{ message }"> <p>{{ message }} was loaded.</p> </template> </NuxtRouteAnnouncer> </template> ``` ## Props - `atomic`: Controls if screen readers only announce changes or the entire content. Set to true for full content readouts on updates, false for changes only. (default `false`) - `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) <callout> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts). </callout> <callout> You can hook into the underlying announcer instance using [the `useRouteAnnouncer` composable](https://nuxt.com/docs/4.x/api/composables/use-route-announcer), which allows you to set a custom announcement message. </callout> <callout> For announcing in-page content changes (form validation, toast notifications, loading states, etc.), use the [`<NuxtAnnouncer>`](https://nuxt.com/docs/4.x/api/components/nuxt-announcer) component with the [`useAnnouncer`](https://nuxt.com/docs/4.x/api/composables/use-announcer) composable instead. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts) # <NuxtTime> > The <NuxtTime> component displays time in a locale-friendly format with server-client consistency. <important> This component is available in Nuxt v3.17+. </important> The `<NuxtTime>` component lets you display dates and times in a locale-friendly format with proper `<time>` HTML semantics. It ensures consistent rendering between server and client without hydration mismatches. ## Usage You can use the `<NuxtTime>` component anywhere in your app: ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" /> </template> ``` ## Props ### `datetime` - Type: `Date | number | string` - Required: `true` The date and time value to display. You can provide: - A `Date` object - A timestamp (number) - An ISO-formatted date string ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" /> <NuxtTime :datetime="new Date()" /> <NuxtTime datetime="2023-06-15T09:30:00.000Z" /> </template> ``` ### `locale` - Type: `string` - Required: `false` - Default: Uses the browser or server's default locale The [BCP 47 language tag](https://datatracker.ietf.org/doc/html/rfc5646) for formatting (e.g., 'en-US', 'fr-FR', 'ja-JP'): ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" locale="fr-FR" /> </template> ``` ### Formatting Props The component accepts any property from the [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) options: ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" year="numeric" month="long" day="numeric" hour="2-digit" minute="2-digit" /> </template> ``` This would output something like: "April 22, 2025, 08:30 AM" ### `relative` - Type: `boolean` - Required: `false` - Default: `false` Enables relative time formatting using the Intl.RelativeTimeFormat API: ```vue [app/app.vue] <template> <!-- Shows something like "5 minutes ago" --> <NuxtTime :datetime="Date.now() - 5 * 60 * 1000" relative /> </template> ``` ### Relative Time Formatting Props When `relative` is set to `true`, the component also accepts properties from [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat): <warning> Due to `style` being a reserved prop, `relativeStyle` prop is used instead. </warning> ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now() - 3 * 24 * 60 * 60 * 1000" relative numeric="auto" relative-style="long" /> </template> ``` This would output something like: "3 days ago" or "last Friday" depending on the `numeric` setting. ## Example ### Basic Usage ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" /> </template> ``` ### Custom Formatting ```vue [app/app.vue] <template> <NuxtTime :datetime="Date.now()" weekday="long" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" time-zone-name="short" /> </template> ``` ### Relative Time ```vue [app/app.vue] <template> <div> <p> <NuxtTime :datetime="Date.now() - 30 * 1000" relative /> <!-- 30 seconds ago --> </p> <p> <NuxtTime :datetime="Date.now() - 45 * 60 * 1000" relative /> <!-- 45 minutes ago --> </p> <p> <NuxtTime :datetime="Date.now() + 2 * 24 * 60 * 60 * 1000" relative /> <!-- in 2 days --> </p> </div> </template> ``` ### With Custom Locale ```vue [app/app.vue] <template> <div> <NuxtTime :datetime="Date.now()" locale="en-US" weekday="long" /> <NuxtTime :datetime="Date.now()" locale="fr-FR" weekday="long" /> <NuxtTime :datetime="Date.now()" locale="ja-JP" weekday="long" /> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-time.vue) # <NuxtWelcome> > The <NuxtWelcome> component greets users in new projects made from the starter template. It includes links to the Nuxt documentation, source code, and social media accounts. ```vue [app/app.vue] <template> <NuxtWelcome /> </template> ``` <read-more target="_blank" to="https://templates.ui.nuxtjs.org/templates/welcome"> Preview the `<NuxtWelcome />` component. </read-more> <tip> This component is part of [`@nuxt/ui-templates`](https://github.com/nuxt/nuxt/tree/main/packages/ui-templates) package. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/ui-templates/templates/welcome/index.html) # <Teleport> > The <Teleport> component teleports a component to a different location in the DOM. <warning> The `to` target of [`<Teleport>`](https://vuejs.org/guide/built-ins/teleport) expects a CSS selector string or an actual DOM node. Nuxt currently has SSR support for teleports to `#teleports` only, with client-side support for other targets using a `<ClientOnly>` wrapper. </warning> ## Body Teleport ```vue <template> <button @click="open = true"> Open Modal </button> <Teleport to="#teleports"> <div v-if="open" class="modal" > <p>Hello from the modal!</p> <button @click="open = false"> Close </button> </div> </Teleport> </template> ``` ## Client-side Teleport ```vue <template> <ClientOnly> <Teleport to="#some-selector"> <!-- content --> </Teleport> </ClientOnly> </template> ``` <link-example to="https://nuxt.com/docs/4.x/examples/advanced/teleport"> </link-example> # createUseAsyncData > A factory function to create a custom useAsyncData composable with pre-defined default options. `createUseAsyncData` creates a custom [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) composable with pre-defined options. The resulting composable is fully typed and works exactly like `useAsyncData`, but with your defaults baked in. <note> `createUseAsyncData` is a compiler macro. It must be used as an **exported** declaration in the `composables/` directory (or any directory scanned by the Nuxt compiler). Nuxt automatically injects de-duplication keys at build time. </note> ## Usage ```ts [app/composables/useCachedData.ts] export const useCachedData = createUseAsyncData({ getCachedData (key, nuxtApp) { return nuxtApp.payload.data[key] ?? nuxtApp.static.data[key] }, }) ``` ```vue [app/pages/index.vue] <script setup lang="ts"> const { data: mountains } = await useCachedData( 'mountains', () => $fetch('https://api.nuxtjs.dev/mountains'), ) </script> ``` The resulting composable has the same signature and return type as [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data), with all options available for the caller to use or override. ## Type ```ts [Signature] function createUseAsyncData ( options?: Partial<AsyncDataOptions>, ): typeof useAsyncData function createUseAsyncData ( options: (callerOptions: AsyncDataOptions) => Partial<AsyncDataOptions>, ): typeof useAsyncData ``` ## Options `createUseAsyncData` accepts all the same options as [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data#parameters), including `server`, `lazy`, `immediate`, `default`, `transform`, `pick`, `getCachedData`, `deep`, `dedupe`, `timeout`, and `watch`. See the full list of options in the [`useAsyncData` documentation](https://nuxt.com/docs/4.x/api/composables/use-async-data#parameters). ## Default vs Override Mode ### Default Mode (plain object) When you pass a plain object, the factory options act as **defaults**. Callers can override any option: ```ts [app/composables/useLazyData.ts] export const useLazyData = createUseAsyncData({ lazy: true, server: false, }) ``` ```ts // Uses the defaults (lazy: true, server: false) const { data } = await useLazyData('key', () => fetchSomeData()) // Caller overrides server to true const { data } = await useLazyData('key', () => fetchSomeData(), { server: true }) ``` ### Override Mode (function) When you pass a function, the factory options **override** the caller's options. The function receives the caller's options as its argument: ```ts [app/composables/useStrictData.ts] // deep is always enforced as false export const useStrictData = createUseAsyncData(callerOptions => ({ deep: false, })) ``` <read-more to="https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch"> </read-more> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-async-data"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # createUseFetch > A factory function to create a custom useFetch composable with pre-defined default options. `createUseFetch` creates a custom [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) composable with pre-defined options. The resulting composable is fully typed and works exactly like `useFetch`, but with your defaults baked in. <note> `createUseFetch` is a compiler macro. It must be used as an **exported** declaration in the `composables/` directory (or any directory scanned by the Nuxt compiler). Nuxt automatically injects de-duplication keys at build time. </note> ## Usage ```ts [app/composables/useAPI.ts] export const useAPI = createUseFetch({ baseURL: 'https://api.nuxt.com', }) ``` ```vue [app/pages/modules.vue] <script setup lang="ts"> const { data: modules } = await useAPI('/modules') </script> ``` The resulting `useAPI` composable has the same signature and return type as [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch), with all options available for the caller to use or override. ## Type ```ts [Signature] function createUseFetch ( options?: Partial<UseFetchOptions>, ): typeof useFetch function createUseFetch ( options: (callerOptions: UseFetchOptions) => Partial<UseFetchOptions>, ): typeof useFetch ``` ## Options `createUseFetch` accepts all the same options as [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch#parameters), including `baseURL`, `headers`, `query`, `onRequest`, `onResponse`, `server`, `lazy`, `transform`, `getCachedData`, and more. See the full list of options in the [`useFetch` documentation](https://nuxt.com/docs/4.x/api/composables/use-fetch#parameters). ## Default vs Override Mode ### Default Mode (plain object) When you pass a plain object, the factory options act as **defaults**. Callers can override any option: ```ts [app/composables/useAPI.ts] export const useAPI = createUseFetch({ baseURL: 'https://api.nuxt.com', lazy: true, }) ``` ```ts // Uses the default baseURL const { data } = await useAPI('/modules') // Caller overrides the baseURL const { data } = await useAPI('/modules', { baseURL: 'https://other-api.com' }) ``` ### Override Mode (function) When you pass a function, the factory options **override** the caller's options. The function receives the caller's options as its argument, so you can read them to compute your overrides: ```ts [app/composables/useAPI.ts] // baseURL is always enforced, regardless of what the caller passes export const useAPI = createUseFetch(callerOptions => ({ baseURL: 'https://api.nuxt.com', })) ``` This is useful for enforcing settings like authentication headers or a specific base URL that should not be changed by the caller. ## Combining with a Custom `$fetch` You can pass a custom `$fetch` instance to `createUseFetch`: ```ts [app/composables/useAPI.ts] export const useAPI = createUseFetch(callerOptions => ({ $fetch: useNuxtApp().$api as typeof $fetch, ...callerOptions, })) ``` <important> The **function signature** (override mode) is required here so that [`useNuxtApp()`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) is called in the setup context (at the composable call site) rather than in the module scope, where no Nuxt instance is available. </important> <read-more to="https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch"> </read-more> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-fetch"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # onPrehydrate > Use onPrehydrate to run a callback on the client immediately before Nuxt hydrates the page. <important> This composable is available in Nuxt v3.12+. </important> `onPrehydrate` is a composable lifecycle hook that allows you to run a callback on the client immediately before Nuxt hydrates the page. <note> This is an advanced utility and should be used with care. For example, [`nuxt-time`](https://github.com/danielroe/nuxt-time/pull/251) and [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode/blob/main/src/script.js) manipulate the DOM to avoid hydration mismatches. </note> ## Usage Call `onPrehydrate` in the setup function of a Vue component (e.g., in `<script setup>`) or in a plugin. The call itself only has an effect when made on the server and is stripped from your client build. The callback you pass, however, is serialized and inlined into the HTML, so it runs in the **browser** immediately before Nuxt hydrates. This means it can access browser globals like `window` and the DOM. ## Type ```ts [Signature] export function onPrehydrate (callback: (el: HTMLElement) => void): void export function onPrehydrate (callback: string | ((el: HTMLElement) => void), key?: string): undefined | string ``` ## Parameters <table> <thead> <tr> <th> Parameter </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> callback </code> </td> <td> <code> ((el: HTMLElement) => void) | string </code> </td> <td> Yes </td> <td> A function (or stringified function) to run before Nuxt hydrates. It will be stringified and inlined in the HTML. Should not have external dependencies or reference variables outside the callback. Runs before Nuxt runtime initializes, so it should not rely on Nuxt or Vue context. </td> </tr> <tr> <td> <code> key </code> </td> <td> <code> string </code> </td> <td> No </td> <td> (Advanced) A unique key to identify the prehydrate script, useful for advanced scenarios like multiple root nodes. </td> </tr> </tbody> </table> ## Return Values - Returns `undefined` when called with only a callback function. - Returns a string (the prehydrate id) when called with a callback and a key, which can be used to set or access the `data-prehydrate-id` attribute for advanced use cases. ## Example ```vue [app/app.vue]twoslash <script setup lang="ts"> declare const window: Window // ---cut--- onPrehydrate(() => { // Runs in the browser, right before Nuxt hydrates console.log(window) }) // Access the root element onPrehydrate((el) => { console.log(el.outerHTML) // <div data-v-inspector="app.vue:15:3" data-prehydrate-id=":b3qlvSiBeH:"> Hi there </div> }) // Advanced: access/set `data-prehydrate-id` yourself const prehydrateId = onPrehydrate((el) => {}) </script> <template> <div> Hi there </div> </template> ``` Under the hood, the callback is stringified and minified at build time, then inlined as a `<script>` tag in the server-rendered HTML, just before the closing `</body>` tag. For the example above, the rendered HTML includes something like: ```html <div data-prehydrate-id=":b3qlvSiBeH:"> Hi there </div> <script>(()=>{console.log(window)})()</script> <script>document.querySelectorAll('[data-prehydrate-id*=":b3qlvSiBeH:"]').forEach(el=>{console.log(el.outerHTML)})</script> ``` When the callback accepts an `el` parameter, the component's root element is tagged with a `data-prehydrate-id` attribute so the inlined script can find it. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useAnnouncer > A composable for announcing messages to screen readers. <important> This composable is available in Nuxt v4.4.2+. </important> ## Description A composable for announcing dynamic content changes to screen readers. Unlike [`useRouteAnnouncer`](https://nuxt.com/docs/4.x/api/composables/use-route-announcer) which automatically announces route changes, `useAnnouncer` gives you manual control over what and when to announce. Use this for in-page updates like form validation, async operations, toast notifications, and live content changes. ## Parameters - `politeness`: Sets the default urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) ## Properties ### `message` - **type**: `Ref<string>` - **description**: The current message to announce ### `politeness` - **type**: `Ref<'polite' | 'assertive' | 'off'>` - **description**: Screen reader announcement urgency level ## Methods ### `set(message, politeness = "polite")` Sets the message to announce with its urgency level. ### `polite(message)` Sets the message with `politeness = "polite"`. Use for non-urgent updates that can wait for the screen reader to finish its current task. ### `assertive(message)` Sets the message with `politeness = "assertive"`. Use for urgent updates that should interrupt the screen reader immediately. ## Example ```vue [app/pages/contact.vue] <script setup lang="ts"> const { polite, assertive } = useAnnouncer() async function submitForm () { try { await $fetch('/api/contact', { method: 'POST', body: formData }) polite('Message sent successfully') } catch (error) { assertive('Error: Failed to send message') } } </script> ``` ## Use Cases ### Form Validation ```vue [app/components/LoginForm.vue] <script setup lang="ts"> const { assertive } = useAnnouncer() function validateForm () { const errors = [] if (!email.value) { errors.push('Email is required') } if (!password.value) { errors.push('Password is required') } if (errors.length) { assertive(`Form has ${errors.length} errors: ${errors.join(', ')}`) return false } return true } </script> ``` ### Loading States ```vue [app/pages/dashboard.vue] <script setup lang="ts"> const { polite } = useAnnouncer() const { data, status } = await useFetch('/api/data') watch(status, (newStatus) => { if (newStatus === 'pending') { polite('Loading data...') } else if (newStatus === 'success') { polite('Data loaded successfully') } }) </script> ``` ### Search Results ```vue [app/components/Search.vue] <script setup lang="ts"> const { polite } = useAnnouncer() const results = ref([]) watch(results, (newResults) => { polite(`Found ${newResults.length} results`) }) </script> ``` <callout> You need to add the [`<NuxtAnnouncer>`](https://nuxt.com/docs/4.x/api/components/nuxt-announcer) component to your app for the announcements to be rendered in the DOM. </callout> <callout> For automatic announcements of route/page changes, use [`useRouteAnnouncer`](https://nuxt.com/docs/4.x/api/composables/use-route-announcer) with the [`<NuxtRouteAnnouncer>`](https://nuxt.com/docs/4.x/api/components/nuxt-route-announcer) component instead. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/announcer.ts) # useAppConfig > Access the reactive app config defined in the project. ## Usage ```ts const appConfig = useAppConfig() console.log(appConfig) ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/app-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/config.ts) # useAsyncData > useAsyncData provides access to data that resolves asynchronously in an SSR-friendly composable. Within your pages, components, and plugins you can use useAsyncData to get access to data that resolves asynchronously. <note> [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) is a composable meant to be called directly in the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context). It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client **without re-fetching the data on client side** when the page hydrates. </note> ## Usage ```vue [app/pages/index.vue] <script setup lang="ts"> const { data, status, pending, error, refresh, clear } = await useAsyncData( 'mountains', (_nuxtApp, { signal }) => $fetch('https://api.nuxtjs.dev/mountains', { signal }), ) </script> ``` <tip to="https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch"> Need a custom `useAsyncData` with pre-defined defaults? Use `createUseAsyncData` to create a fully typed custom composable. See the [custom useFetch recipe](https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch) for details. </tip> <note> You do not need to `await` `useAsyncData`. On the server, Nuxt waits for the promise to resolve before rendering in either case, so the returned HTML always contains the data. The `await` affects what happens after the call: with it, execution pauses until `data` is populated, and client-side navigation is blocked until the data is ready; without it, execution continues immediately, `data` starts as its default value until the request resolves, and on client-side navigation you handle the loading and error states yourself using the returned `status` and `error` refs. This has a similar effect to the [`lazy`](#parameters) option, though `lazy` is the explicit way to opt into non-blocking navigation. </note> <note> `data`, `status`, `pending`, and `error` are Vue refs. Access their values with `.value` in `<script setup>`. `refresh`/`execute` and `clear` are plain functions. </note> ### Watch Parameters The built-in `watch` option allows automatically rerunning the fetcher function when any changes are detected. ```vue [app/pages/index.vue] <script setup lang="ts"> const page = ref(1) const { data: posts } = await useAsyncData( 'posts', (_nuxtApp, { signal }) => $fetch('https://fakeApi.com/posts', { params: { page: page.value, }, signal, }), { watch: [page], }, ) </script> ``` ### Reactive Keys You can use a computed ref, plain ref or a getter function as the key, allowing for dynamic data fetching that automatically updates when the key changes: ```vue [app/pages/[id].vue] <script setup lang="ts"> const route = useRoute() const userId = computed(() => `user-${route.params.id}`) // When the route changes and userId updates, the data will be automatically refetched const { data: user } = useAsyncData( userId, () => fetchUserById(route.params.id), ) </script> ``` ### Make Your `handler` Abortable You can make your `handler` function abortable by using the `signal` provided in the second argument. This is useful for cancelling requests when they are no longer needed, such as when a user navigates away from a page. `$fetch` natively supports abort signals. ```ts [app/pages/index.vue] const { data, error } = await useAsyncData( 'users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), ) refresh() // will actually cancel the $fetch request (if dedupe: cancel) refresh() // will actually cancel the $fetch request (if dedupe: cancel) refresh() clear() // will cancel the latest pending handler ``` You can also pass an `AbortSignal` to the `refresh`/`execute` function to cancel individual requests manually. ```ts [app/pages/index.vue] const { refresh } = await useAsyncData( 'users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), ) let abortController: AbortController | undefined function handleUserAction () { abortController = new AbortController() refresh({ signal: abortController.signal }) } function handleCancel () { abortController?.abort() // aborts the ongoing refresh request } ``` If your `handler` function does not support abort signals, you can implement your own abort logic using the `signal` provided. ```ts [app/pages/index.vue] const { data, error } = await useAsyncData( 'users', (_nuxtApp, { signal }) => { return new Promise((resolve, reject) => { signal?.addEventListener('abort', () => { reject(new Error('Request aborted')) }) return Promise.resolve(callback.call(this, yourHandler)).then(resolve, reject) }) }, ) ``` The handler signal will be aborted when: - A new request is made with `dedupe: 'cancel'` - The `clear` function is called - The `options.timeout` duration is exceeded <warning> [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) is a reserved function name transformed by the compiler, so you should not name your own function [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data). </warning> <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching#useasyncdata"> </read-more> ## Type ```ts [Signature] export type AsyncDataHandler<ResT> = (nuxtApp: NuxtApp, options: { signal: AbortSignal }) => Promise<ResT> export function useAsyncData<ResT, DataE = unknown, DataT = ResT> ( handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> export function useAsyncData<ResT, DataE = unknown, DataT = ResT> ( key: MaybeRefOrGetter<string>, handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> type AsyncDataOptions<ResT, DataT = ResT> = { server?: boolean lazy?: boolean immediate?: boolean deep?: boolean dedupe?: 'cancel' | 'defer' default?: () => DataT | Ref<DataT> transform?: (input: ResT) => DataT | Promise<DataT> pick?: string[] watch?: MultiWatchSources getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined timeout?: number enabled?: MaybeRefOrGetter<boolean> serialize?: boolean } type AsyncDataRequestContext = { /** The reason for this data request */ cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch' } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | undefined> refresh: (opts?: AsyncDataExecuteOptions) => Promise<void> execute: (opts?: AsyncDataExecuteOptions) => Promise<void> clear: () => void error: Ref<ErrorT | undefined> status: Ref<AsyncDataRequestStatus> pending: Ref<boolean> } interface AsyncDataExecuteOptions { dedupe?: 'cancel' | 'defer' timeout?: number signal?: AbortSignal } type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> ## Parameters - `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you. - `handler`: an asynchronous function that must return a truthy value (for example, it should not be `undefined` or `null`) or the request may be duplicated on the client side. <warning> The `handler` function should be **side-effect free** to ensure predictable behavior during SSR and CSR hydration. If you need to trigger side effects, use the [`callOnce`](https://nuxt.com/docs/4.x/api/utils/call-once) utility to do so. </warning> - `options` (object): Configuration for the asynchronous function call. All options can be a static value, a `ref`, or a computed value. <table> <thead> <tr> <th> Option </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to call the function on the server. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If true, resolves after route loads (does not block navigation). </td> </tr> <tr> <td> <code> immediate </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If false, prevents function from being called immediately. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => DataT </code> </td> <td> - </td> <td> Factory for default value of <code> data </code> before async resolves. </td> </tr> <tr> <td> <code> timeout </code> <badge className="align-middle" color="info" size="xs"> v4.2 </badge> </td> <td> <code> number </code> </td> <td> - </td> <td> A number in milliseconds to wait before timing out the call (defaults to <code> undefined </code> , which means no timeout) </td> </tr> <tr> <td> <code> transform </code> </td> <td> <code> (input: DataT) => DataT | Promise<DataT> </code> </td> <td> - </td> <td> Function to transform the result after resolving. </td> </tr> <tr> <td> <code> getCachedData </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> (key, nuxtApp, ctx) => DataT | undefined </code> </td> <td> - </td> <td> Function to return cached data. See below for default. </td> </tr> <tr> <td> <code> pick </code> </td> <td> <code> string[] </code> </td> <td> - </td> <td> Only pick specified keys from the result. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> MultiWatchSources </code> </td> <td> - </td> <td> Array of reactive sources to watch and auto-refresh. </td> </tr> <tr> <td> <code> deep </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Return data in a deep ref object. Defaults to <code> false </code> for improved performance (shallow ref object). </td> </tr> <tr> <td> <code> dedupe </code> <badge className="align-middle" color="info" size="xs"> v3.9 </badge> </td> <td> <code> 'cancel' | 'defer' </code> </td> <td> <code> 'cancel' </code> </td> <td> Policy when triggering an execution more than once at a time. </td> </tr> <tr> <td> <code> enabled </code> <badge className="align-middle" color="info" size="xs"> v4.5 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Barrier that gates whether the <code> handler </code> may run. While <code> false </code> , every execution is blocked (initial fetch, <code> execute </code> /<code> refresh </code> , and watch triggers), and switching <code> true </code> โ†’ <code> false </code> cancels any in-flight request without clearing <code> data </code> . Re-enabling does not refetch on its own. </td> </tr> <tr> <td> <code> serialize </code> <badge className="align-middle" color="info" size="xs"> v4.6 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to store resolved data in the Nuxt payload (<code> __NUXT_DATA__ </code> ). When <code> false </code> , server-fetched data is kept out of the payload and the client will refetch after hydration if a component renders it. Pair with <a href="https://nuxt.com/docs/4.x/guide/best-practices/performance#lazy-hydration"> lazy hydration </a> to avoid hydration mismatches and unnecessary client fetches. </td> </tr> </tbody> </table> <note> All options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated. </note> **getCachedData default:** ```ts [Default getCachedData Implementation] const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key] ``` This only caches data when `experimental.payloadExtraction` in `nuxt.config` is enabled. <note> Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience. </note> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-lazy-async-data"> You can use `useLazyAsyncData` to have the same behavior as `lazy: true` with `useAsyncData`. </read-more> <video-accordion title="Watch a video from Alexander Lichter about client-side caching with getCachedData" video-id="aQPR0xn-MMk"> </video-accordion> ### Shared State and Option Consistency When multiple `useAsyncData` calls use the same key, they share the same `data`, `error`, `status`, and `pending` refs. Keep the options listed below consistent across these calls. The following options **must be consistent** across all calls with the same key: - `handler` function - `deep` option - `transform` function - `pick` array - `getCachedData` function - `default` value The following options **can differ** without triggering warnings: - `server` - `lazy` - `immediate` - `dedupe` - `watch` - `enabled` - `serialize` ```ts [app/pages/index.vue] // โŒ This will trigger a development warning const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true }) // โœ… This is allowed const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false }) ``` <tip> Keyed state created using `useAsyncData` can be retrieved across your Nuxt application using [`useNuxtData`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-data). </tip> ## Return Values This composable returns a `Promise` that can be awaited, which makes it possible to use `data` directly within the `<script setup>` (i.e. a value will be present, instead of being undefined). You can also directly pull the values without awaiting the return value, in which case `data` can be undefined within `<script setup>` until the fetch completes. <tip> Even if you do not await the return value, during SSR Nuxt will wait for the request to finish and send the resolved data to the client. </tip> <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) on the client side, `data` will remain `undefined` within `<script setup>`. </note> <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous function that is passed in. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. By default, Nuxt waits until a <code> refresh </code> is finished before it can be executed again. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the asynchronous function threw an error. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the asynchronous function call. Use it to distinguish <code> idle </code> , <code> pending </code> , <code> success </code> , and <code> error </code> . </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> <code> true </code> while a request is in flight. With <a href="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#pendingwhenidle"> <code> experimental.pendingWhenIdle </code> </a> , it is also <code> true </code> when <code> status </code> is <code> idle </code> and no cached data is available. </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> (or the value of <code> options.default() </code> if provided), <code> error </code> to <code> undefined </code> , set <code> status </code> to <code> idle </code> , and cancels any pending calls. </td> </tr> </tbody> </table> <tip> Functions from the `Promise` (`then`, `catch`, and `finally`) can safely be destructured, if you did not await the return value. </tip> ### Status Values - `idle`: Function has not been called yet (e.g. `{ immediate: false }` or `{ server: false }` on server render) - `pending`: Function has been called and the promise is pending - `success`: Function returned a value - `error`: Function threw an error --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # useCookie > useCookie is an SSR-friendly composable to read and write cookies. ## Usage Within your pages, components, and plugins, you can use `useCookie` to read and write cookies in an SSR-friendly way. ```ts [Usage] const cookie = useCookie(name, options) ``` <note> `useCookie` only works in the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context). </note> <tip> The returned ref will automatically serialize and deserialize cookie values to JSON. </tip> ## Type ```ts [Signature] import type { Ref } from 'vue' import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es' export interface CookieOptions<T = any> extends Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'> { decode?(value: string): T encode?(value: T): string default?: () => T | Ref<T> watch?: boolean | 'shallow' readonly?: boolean refresh?: boolean } export interface CookieRef<T> extends Ref<T> {} export function useCookie<T = string | null | undefined> ( name: string, options?: CookieOptions<T>, ): CookieRef<T> ``` ## Parameters `name`: The name of the cookie. `options`: Options to control cookie behavior. The object can have the following properties: Most of the options will be directly passed to the [cookie](https://github.com/jshttp/cookie) package. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> decode </code> </td> <td> <code> (value: string) => T </code> </td> <td> <code> decodeURIComponent </code> + <a href="https://github.com/unjs/destr" rel="nofollow"> destr </a> . </td> <td> Custom function to decode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode a previously encoded cookie value into a JavaScript string or other object. <br /> <strong> Note: </strong> If an error is thrown from this function, the original, non-decoded cookie value will be returned as the cookie's value. </td> </tr> <tr> <td> <code> encode </code> </td> <td> <code> (value: T) => string </code> </td> <td> <code> JSON.stringify </code> + <code> encodeURIComponent </code> </td> <td> Custom function to encode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to encode a value into a string suited for a cookie's value. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => T | Ref<T> </code> </td> <td> <code> undefined </code> </td> <td> Function returning the default value if the cookie does not exist. The function can also return a <code> Ref </code> . </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> boolean | 'shallow' </code> </td> <td> <code> true </code> </td> <td> Whether to watch for changes and update the cookie. <code> true </code> for deep watch, <code> 'shallow' </code> for shallow watch, i.e. data changes for only top level properties, <code> false </code> to disable. <br /> <strong> Note: </strong> Refresh <code> useCookie </code> values manually when a cookie has changed with <a href="https://nuxt.com/docs/4.x/api/utils/refresh-cookie"> <code> refreshCookie </code> </a> . </td> </tr> <tr> <td> <code> refresh </code> <badge className="align-middle" color="info" size="xs"> v4.4 </badge> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the cookie expiration will be refreshed on every explicit write (e.g. <code> cookie.value = cookie.value </code> ), even if the value itself hasnโ€™t changed. Note: the expiration is not refreshed automatically โ€” you must assign to <code> .value </code> to trigger it. </td> </tr> <tr> <td> <code> readonly </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , disables writing to the cookie, on both server and client. A <code> default </code> value is still returned by the composable but is never persisted to the browser. </td> </tr> <tr> <td> <code> maxAge </code> </td> <td> <code> number </code> </td> <td> <code> undefined </code> </td> <td> Max age in seconds for the cookie, i.e. the value for the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.2" rel="nofollow"> <code> Max-Age </code> <code> Set-Cookie </code> attribute </a> . The given number will be converted to an integer by rounding down. By default, no maximum age is set. </td> </tr> <tr> <td> <code> expires </code> </td> <td> <code> Date | (() => Date | undefined) </code> </td> <td> <code> undefined </code> </td> <td> Expiration date for the cookie, or a getter that returns one. When a function is provided, it is evaluated on every cookie write, so the expiration can be refreshed when the value is re-set. Returning <code> undefined </code> creates a session cookie. The getter should be pure (no side effects). By default, no expiration is set. Most clients will consider this a "non-persistent cookie" and will delete it on a condition like exiting a web browser application. <br /> <strong> Note: </strong> The <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.3" rel="nofollow"> cookie storage model specification </a> states that if both <code> expires </code> and <code> maxAge </code> is set, then <code> maxAge </code> takes precedence, but not all clients may obey this, so if both are set, they should point to the same date and time! <br /> If neither of <code> expires </code> and <code> maxAge </code> is set, the cookie will be session-only and removed when the user closes their browser. </td> </tr> <tr> <td> <code> httpOnly </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the HttpOnly attribute. <br /> <strong> Note: </strong> Be careful when setting this to <code> true </code> , as compliant clients will not allow client-side JavaScript to see the cookie in <code> document.cookie </code> . </td> </tr> <tr> <td> <code> secure </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.5" rel="nofollow"> <code> Secure </code> <code> Set-Cookie </code> attribute </a> . <br /> <strong> Note: </strong> Be careful when setting this to <code> true </code> , as compliant clients will not send the cookie back to the server in the future if the browser does not have an HTTPS connection. This can lead to hydration errors. </td> </tr> <tr> <td> <code> partitioned </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1" rel="nofollow"> <code> Partitioned </code> <code> Set-Cookie </code> attribute </a> . <br /> <strong> Note: </strong> This is an attribute that has not yet been fully standardized, and may change in the future. <br /> This also means many clients may ignore this attribute until they understand it.<br /> More information can be found in the <a href="https://github.com/privacycg/CHIPS" rel="nofollow"> proposal </a> . </td> </tr> <tr> <td> <code> domain </code> </td> <td> <code> string </code> </td> <td> <code> undefined </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3" rel="nofollow"> <code> Domain </code> <code> Set-Cookie </code> attribute </a> . By default, no domain is set, and most clients will consider applying the cookie only to the current domain. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> '/' </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.4" rel="nofollow"> <code> Path </code> <code> Set-Cookie </code> attribute </a> . By default, the path is considered the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4" rel="nofollow"> "default path" </a> . </td> </tr> <tr> <td> <code> sameSite </code> </td> <td> <code> boolean | string </code> </td> <td> <code> undefined </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7" rel="nofollow"> <code> SameSite </code> <code> Set-Cookie </code> attribute </a> . <br /> - <code> true </code> will set the <code> SameSite </code> attribute to <code> Strict </code> for strict same-site enforcement.<br /> - <code> false </code> will not set the <code> SameSite </code> attribute.<br /> - <code> 'lax' </code> will set the <code> SameSite </code> attribute to <code> Lax </code> for lax same-site enforcement.<br /> - <code> 'none' </code> will set the <code> SameSite </code> attribute to <code> None </code> for an explicit cross-site cookie.<br /> - <code> 'strict' </code> will set the <code> SameSite </code> attribute to <code> Strict </code> for strict same-site enforcement. </td> </tr> </tbody> </table> ## Return Values Returns a Vue `Ref<T>` representing the cookie value. Updating the ref will update the cookie (unless `readonly` is set). The ref is SSR-friendly and will work on both client and server. ## Example ### Basic Usage The example below creates a cookie called `counter`. If the cookie doesn't exist, it is initially set to a random value. Whenever we update the `counter` variable, the cookie will be updated accordingly. ```vue [app/app.vue] <script setup lang="ts"> const counter = useCookie('counter') counter.value ||= Math.round(Math.random() * 1000) </script> <template> <div> <h1>Counter: {{ counter || '-' }}</h1> <button @click="counter = null"> reset </button> <button @click="counter--"> - </button> <button @click="counter++"> + </button> </div> </template> ``` ### Readonly Cookies ```vue [app/app.vue] <script setup lang="ts"> const user = useCookie( 'userInfo', { default: () => ({ score: -1 }), watch: false, }, ) if (user.value) { // the actual `userInfo` cookie will not be updated user.value.score++ } </script> <template> <div>User score: {{ user?.score }}</div> </template> ``` ### Writable Cookies ```vue [app/app.vue] <script setup lang="ts"> const list = useCookie( 'list', { default: () => [], watch: 'shallow', }, ) function add () { list.value?.push(Math.round(Math.random() * 1000)) // list cookie won't be updated with this change } function save () { // the actual `list` cookie will be updated list.value &&= [...list.value] } </script> <template> <div> <h1>List</h1> <pre>{{ list }}</pre> <button @click="add"> Add </button> <button @click="save"> Save </button> </div> </template> ``` ### Refreshing Cookies ```vue [app/app.vue] <script setup lang="ts"> const session = useCookie( 'session', { maxAge: 60 * 60, // 1 hour refresh: true, default: () => 'active', }) // Even if the value does not change, // the cookie expiration will be refreshed // every time the setter is called session.value = 'active' </script> <template> <div>Session: {{ session }}</div> </template> ``` ### Dynamic Expiration with a Getter Use a function for `expires` when you want a fresh expiration date every time the cookie is written (for example, sliding sessions or tokens): ```vue <script setup lang="ts"> const token = useCookie('token', { // Re-evaluated on every write โ€” keep this getter pure expires: () => new Date(Date.now() + 60 * 60 * 1000), // 1 hour from now }) // Assigning a new value also refreshes the cookie expiration token.value = 'new-token' </script> ``` ### Cookies in API Routes You can use `getCookie` and `setCookie` from [`h3`](https://github.com/h3js/h3) package to set cookies in server API routes. ```ts [server/api/counter.ts] export default defineEventHandler((event) => { // Read counter cookie let counter = getCookie(event, 'counter') || 0 // Increase counter cookie by 1 setCookie(event, 'counter', ++counter) // Send JSON response return { counter } }) ``` <link-example to="https://nuxt.com/docs/4.x/examples/advanced/use-cookie"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts) # useError > useError composable returns the global Nuxt error that is being handled. ## Usage The `useError` composable returns the global Nuxt error that is being handled and is available on both client and server. It provides a reactive, SSR-friendly error state across your app. ```ts const error = useError() ``` You can use this composable in your components, pages, or plugins to access or react to the current Nuxt error. ## Type ```ts interface NuxtError<DataT = unknown> { status: number statusText?: string message: string data?: DataT cause?: unknown fatal: boolean } export const useError: () => Ref<NuxtError | undefined> ``` ## Parameters This composable does not take any parameters. ## Return Values Returns a `Ref` containing the current Nuxt error (or `undefined` if there is no error). The error object is reactive and will update automatically when the error state changes. ## Example ```vue <script setup lang="ts"> const error = useError() if (error.value) { console.error('Nuxt error:', error.value) } </script> ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # useFetch > Fetch data from an API endpoint with an SSR-friendly composable. This composable provides a convenient wrapper around [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`$fetch`](https://nuxt.com/docs/4.x/api/utils/dollarfetch). It automatically generates a key for the request, provides type hints for request url based on server routes, and infers API response type. <note> `useFetch` is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates. </note> ## Usage ```vue [app/pages/modules.vue] <script setup lang="ts"> const { data, status, error, refresh, clear } = await useFetch('/api/modules', { pick: ['title'], }) </script> ``` <tip to="https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch"> Need a custom `useFetch` with pre-defined defaults (like `baseURL` or auth headers)? Use `createUseFetch` to create a fully typed custom composable. </tip> <note> You do not need to `await` `useFetch`. On the server, Nuxt waits for the promise to resolve before rendering in either case, so the returned HTML always contains the data. The `await` affects what happens after the call: with it, execution pauses until `data` is populated, and client-side navigation is blocked until the data is ready; without it, execution continues immediately, `data` starts as its default value until the request resolves, and on client-side navigation you handle the loading and error states yourself using the returned `status` and `error` refs. This has a similar effect to the [`lazy`](#parameters) option, though `lazy` is the explicit way to opt into non-blocking navigation. </note> <note> `data`, `status`, and `error` are Vue refs, and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions. </note> Using the `query` option, you can add search parameters to your query. This option is extended from [unjs/ofetch](https://github.com/unjs/ofetch) and is using [unjs/ufo](https://github.com/unjs/ufo) to create the URL. Objects are automatically stringified. ```ts [app/pages/index.vue] const param1 = ref('value1') const { data, status, error, refresh } = await useFetch('/api/modules', { query: { param1, param2: 'value2' }, }) ``` The above example results in `https://api.nuxt.com/modules?param1=value1¶m2=value2`. You can also use [interceptors](https://github.com/unjs/ofetch#%EF%B8%8F-interceptors): ```ts [app/pages/index.vue] const { data, status, error, refresh, clear } = await useFetch('/api/auth/login', { onRequest ({ request, options }) { // Set the request headers // note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile options.headers.set('Authorization', '...') }, onRequestError ({ request, options, error }) { // Handle the request errors }, onResponse ({ request, response, options }) { // Process the response data localStorage.setItem('token', response._data.token) }, onResponseError ({ request, response, options }) { // Handle the response errors }, }) ``` ### Reactive Keys and Shared State You can use a computed ref or a plain ref as the URL, allowing for dynamic data fetching that automatically updates when the URL changes: ```vue [app/pages/[id].vue] <script setup lang="ts"> const route = useRoute() const id = computed(() => route.params.id) // When the route changes and id updates, the data will be automatically refetched const { data: post } = await useFetch(() => `/api/posts/${id.value}`) </script> ``` The auto-generated key is unique to each call site, so calling `useFetch` with the same URL and options in different components will **not** share state and each call performs its own request. Multiple instances of the same component do share state, since they use the same call site. To share the same `data`, `error` and `status` refs across different components, provide the same explicit `key` to each call: <code-group> ```vue [app/components/ComponentA.vue] <script setup lang="ts"> // shares the data with ComponentB - only one request is made const { data } = await useFetch('/api/random', { key: 'random' }) </script> ``` ```vue [app/components/ComponentB.vue] <script setup lang="ts"> // shares the data with ComponentA - only one request is made const { data } = await useFetch('/api/random', { key: 'random' }) </script> ``` </code-group> <tip> Keyed state created using `useFetch` can be retrieved across your Nuxt application using [`useNuxtData`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-data). </tip> <warning> `useFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`. To create a custom variant with pre-defined options, use [`createUseFetch`](https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch#custom-usefetch-with-createusefetch) instead. </warning> <warning> If you encounter the `data` variable destructured from a `useFetch` returns a string and not a JSON parsed object then make sure your component doesn't include an import statement like `import { useFetch } from '@vueuse/core`. </warning> <video-accordion title="Watch the video from Alexander Lichter to avoid using useFetch the wrong way" video-id="njsGVmcWviY"> </video-accordion> <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> ### Reactive Fetch Options Fetch options can be provided as reactive, supporting `computed`, `ref` and [computed getters](https://vuejs.org/guide/essentials/computed). When a reactive fetch option is updated it will trigger a refetch using the updated resolved reactive value. ```ts [app/pages/index.vue] const searchQuery = ref('initial') const { data } = await useFetch('/api/search', { query: { q: searchQuery }, }) // triggers a refetch: /api/search?q=new%20search searchQuery.value = 'new search' ``` If needed, you can opt out of this behavior using `watch: false`: ```ts [app/pages/index.vue] const searchQuery = ref('initial') const { data } = await useFetch('/api/search', { query: { q: searchQuery }, watch: false, }) // does not trigger a refetch searchQuery.value = 'new search' ``` ## Type ```ts [Signature] export function useFetch<ResT, ErrorT = NuxtError<unknown>, DataT = ResT> ( url: string | Request | Ref<string | Request> | (() => string | Request), options?: UseFetchOptions<ResT, DataT>, ): AsyncData<DataT, ErrorT> & Promise<AsyncData<DataT, ErrorT>> type UseFetchOptions<ResT, DataT = ResT> = { key?: MaybeRefOrGetter<string> method?: MaybeRefOrGetter<string> query?: MaybeRefOrGetter<SearchParams> params?: MaybeRefOrGetter<SearchParams> body?: MaybeRefOrGetter<RequestInit['body'] | Record<string, any>> headers?: MaybeRefOrGetter<Record<string, string> | [key: string, value: string][] | Headers> baseURL?: MaybeRefOrGetter<string> cache?: false | 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload' server?: boolean lazy?: boolean immediate?: boolean getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined deep?: boolean dedupe?: 'cancel' | 'defer' timeout?: number enabled?: MaybeRefOrGetter<boolean> serialize?: boolean default?: () => DataT | Ref<DataT> transform?: (input: ResT) => DataT | Promise<DataT> pick?: string[] $fetch?: typeof globalThis.$fetch watch?: MultiWatchSources | false } type AsyncDataRequestContext = { /** The reason for this data request */ cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch' } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | undefined> pending: Ref<boolean> refresh: (opts?: AsyncDataExecuteOptions) => Promise<void> execute: (opts?: AsyncDataExecuteOptions) => Promise<void> clear: () => void error: Ref<ErrorT | undefined> status: Ref<AsyncDataRequestStatus> } interface AsyncDataExecuteOptions { dedupe?: 'cancel' | 'defer' timeout?: number signal?: AbortSignal } type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' ``` ## Parameters - `URL` (`string | Request | Ref<string | Request> | () => string | Request`): The URL or request to fetch. Can be a string, a Request object, a Vue ref, or a function returning a string/Request. Supports reactivity for dynamic endpoints. - `options` (object): Configuration for the fetch request. Extends [unjs/ofetch](https://github.com/unjs/ofetch) options and [`AsyncDataOptions`](https://nuxt.com/docs/4.x/api/composables/use-async-data#parameters). All options can be a static value, a `ref`, or a computed value. <table> <thead> <tr> <th> Option </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> key </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> auto-gen </td> <td> Unique key for de-duplication. If not provided, generated from the URL, options and call site location in the source code. </td> </tr> <tr> <td> <code> method </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> <code> 'GET' </code> </td> <td> HTTP request method. </td> </tr> <tr> <td> <code> query </code> </td> <td> <code> MaybeRefOrGetter<SearchParams> </code> </td> <td> - </td> <td> Query/search params to append to the URL. Alias: <code> params </code> . </td> </tr> <tr> <td> <code> params </code> </td> <td> <code> MaybeRefOrGetter<SearchParams> </code> </td> <td> - </td> <td> Alias for <code> query </code> . </td> </tr> <tr> <td> <code> body </code> </td> <td> <code> MaybeRefOrGetter<RequestInit['body'] | Record<string, any>> </code> </td> <td> - </td> <td> Request body. Objects are automatically stringified. </td> </tr> <tr> <td> <code> headers </code> </td> <td> <code> MaybeRefOrGetter<Record<string, string> | [key, value][] | Headers> </code> </td> <td> - </td> <td> Request headers. </td> </tr> <tr> <td> <code> baseURL </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> - </td> <td> Base URL for the request. </td> </tr> <tr> <td> <code> cache </code> </td> <td> <code> false | string </code> </td> <td> - </td> <td> Cache control. Boolean disables cache, or use Fetch API values: <code> default </code> , <code> no-store </code> , etc. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to fetch on the server. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If true, resolves after route loads (does not block navigation). </td> </tr> <tr> <td> <code> immediate </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If false, prevents request from firing immediately. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => DataT </code> </td> <td> - </td> <td> Factory for default value of <code> data </code> before async resolves. </td> </tr> <tr> <td> <code> timeout </code> <badge className="align-middle" color="info" size="xs"> v4.2 </badge> </td> <td> <code> number </code> </td> <td> - </td> <td> A number in milliseconds to wait before timing out the request (defaults to <code> undefined </code> , which means no timeout) </td> </tr> <tr> <td> <code> transform </code> </td> <td> <code> (input: DataT) => DataT | Promise<DataT> </code> </td> <td> - </td> <td> Function to transform the result after resolving. </td> </tr> <tr> <td> <code> getCachedData </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> (key, nuxtApp, ctx) => DataT | undefined </code> </td> <td> - </td> <td> Function to return cached data. See below for default. </td> </tr> <tr> <td> <code> pick </code> </td> <td> <code> string[] </code> </td> <td> - </td> <td> Only pick specified keys from the result. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> MultiWatchSources | false </code> </td> <td> - </td> <td> Array of reactive sources to watch and auto-refresh. <code> false </code> disables watching. </td> </tr> <tr> <td> <code> deep </code> <badge className="align-middle" color="info" size="xs"> v3.8 </badge> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Return data in a deep ref object. Defaults to <code> false </code> for improved performance (shallow ref object). </td> </tr> <tr> <td> <code> dedupe </code> <badge className="align-middle" color="info" size="xs"> v3.9 </badge> </td> <td> <code> 'cancel' | 'defer' </code> </td> <td> <code> 'cancel' </code> </td> <td> Avoid fetching same key more than once at a time. </td> </tr> <tr> <td> <code> enabled </code> <badge className="align-middle" color="info" size="xs"> v4.5 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Barrier that gates whether the request may run. While <code> false </code> , every execution is blocked (initial fetch, <code> execute </code> /<code> refresh </code> , and watch triggers), and switching <code> true </code> โ†’ <code> false </code> cancels any in-flight request without clearing <code> data </code> . Re-enabling does not refetch on its own. </td> </tr> <tr> <td> <code> serialize </code> <badge className="align-middle" color="info" size="xs"> v4.6 </badge> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to store resolved data in the Nuxt payload (<code> __NUXT_DATA__ </code> ). When <code> false </code> , server-fetched data is kept out of the payload and the client will refetch after hydration if a component renders it. Pair with <a href="https://nuxt.com/docs/4.x/guide/best-practices/performance#lazy-hydration"> lazy hydration </a> to avoid hydration mismatches and unnecessary client fetches. </td> </tr> <tr> <td> <code> $fetch </code> <badge className="align-middle" color="info" size="xs"> v3.2 </badge> </td> <td> <code> typeof globalThis.$fetch </code> </td> <td> - </td> <td> Custom $fetch implementation. See <a href="https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch"> Custom useFetch in Nuxt </a> </td> </tr> </tbody> </table> <note> All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated (unless `watch` is set to `false`). </note> **getCachedData default:** ```ts [Default getCachedData Implementation] const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key] ``` This only caches data when `experimental.payloadExtraction` in `nuxt.config` is enabled. ## Return Values This composable returns a `Promise` that can be awaited, which makes it possible to use `data` directly within the `<script setup>` (i.e. a value will be present, instead of being undefined). You can also directly pull the values without awaiting the return value, in which case `data` can be undefined within `<script setup>` until the fetch completes. <tip> Even if you do not await the return value, during SSR Nuxt will wait for the request to finish and send the resolved data to the client. </tip> <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain undefined within `<script setup>`. </note> <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous fetch. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. By default, Nuxt waits until a <code> refresh </code> is finished before it can be executed again. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the data fetching failed. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the data request. Use it to distinguish <code> idle </code> , <code> pending </code> , <code> success </code> , and <code> error </code> . </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> <code> true </code> while a request is in flight. With <a href="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#pendingwhenidle"> <code> experimental.pendingWhenIdle </code> </a> , it is also <code> true </code> when <code> status </code> is <code> idle </code> and no cached data is available. </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> (or the value of <code> options.default() </code> if provided), <code> error </code> to <code> undefined </code> , set <code> status </code> to <code> idle </code> , and cancels any pending requests. </td> </tr> </tbody> </table> <tip> Functions from the `Promise` (`then`, `catch`, and `finally`) can safely be destructured, if you did not await the return value. </tip> ### Status Values - `idle`: Request has not started (e.g. `{ immediate: false }` or `{ server: false }` on server render) - `pending`: Request is in progress - `success`: Request completed successfully - `error`: Request failed ### Example <link-example to="https://nuxt.com/docs/4.x/examples/advanced/use-custom-fetch-composable"> </link-example> <link-example to="https://nuxt.com/docs/4.x/examples/features/data-fetching"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # useHead > useHead customizes the head properties of individual pages of your Nuxt app. ## Usage The `useHead` composable allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.unjs.io). It lets you customize the meta tags, links, scripts, and other elements in the `<head>` section of your HTML document. ```vue [app/app.vue] <script setup lang="ts"> useHead({ title: 'My App', meta: [ { name: 'description', content: 'My amazing site.' }, ], bodyAttrs: { class: 'test', }, script: [{ innerHTML: 'console.log(\'Hello world\')' }], }) </script> ``` <warning> If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](https://nuxt.com/docs/4.x/api/composables/use-head-safe). </warning> <note> The properties of `useHead` can be dynamic, accepting `ref`, `computed` and `reactive` properties. The `meta` parameter can also accept a function returning an object to make the entire object reactive. </note> ## Type ```ts [Signature] export function useHead (meta: MaybeComputedRef<MetaObject>): ActiveHeadEntry<UseHeadInput> interface MetaObject { title?: string titleTemplate?: string | ((title?: string) => string) base?: Base link?: Link[] meta?: Meta[] style?: Style[] script?: Script[] noscript?: Noscript[] htmlAttrs?: HtmlAttributes bodyAttrs?: BodyAttributes } interface ActiveHeadEntry<Input> { /** * Updates the entry with new input. * * Will first clear any side effects for previous input. */ patch: (input: Input) => void /** * Dispose the entry, removing it from the active head. * * Will queue side effects for removal. */ dispose: () => void } ``` See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types. ## Parameters `meta`: An object accepting head metadata properties to customize the page's `<head>` section. All properties support reactive values (`ref`, `computed`, `reactive`) or can be a function returning the metadata object. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> title </code> </td> <td> <code> string </code> </td> <td> Sets the page title. </td> </tr> <tr> <td> <code> titleTemplate </code> </td> <td> <code> string | ((title?: string) => string) </code> </td> <td> Configures a dynamic template to customize the page title. Can be a string with <code> %s </code> placeholder or a function. </td> </tr> <tr> <td> <code> base </code> </td> <td> <code> Base </code> </td> <td> Sets the <code> <base> </code> tag for the document. </td> </tr> <tr> <td> <code> link </code> </td> <td> <code> Link[] </code> </td> <td> Array of link objects. Each element is mapped to a <code> <link> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Meta[] </code> </td> <td> Array of meta objects. Each element is mapped to a <code> <meta> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> style </code> </td> <td> <code> Style[] </code> </td> <td> Array of style objects. Each element is mapped to a <code> <style> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> script </code> </td> <td> <code> Script[] </code> </td> <td> Array of script objects. Each element is mapped to a <code> <script> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> noscript </code> </td> <td> <code> Noscript[] </code> </td> <td> Array of noscript objects. Each element is mapped to a <code> <noscript> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> htmlAttrs </code> </td> <td> <code> HtmlAttributes </code> </td> <td> Sets attributes of the <code> <html> </code> tag. Each object property is mapped to the corresponding attribute. </td> </tr> <tr> <td> <code> bodyAttrs </code> </td> <td> <code> BodyAttributes </code> </td> <td> Sets attributes of the <code> <body> </code> tag. Each object property is mapped to the corresponding attribute. </td> </tr> </tbody> </table> ## Return Values This composable does not return any value. It registers the head metadata with Unhead, which manages the actual DOM updates. ## Example ### Basic Meta Tags ```vue [app/pages/about.vue] <script setup lang="ts"> useHead({ title: 'About Us', meta: [ { name: 'description', content: 'Learn more about our company' }, { property: 'og:title', content: 'About Us' }, { property: 'og:description', content: 'Learn more about our company' }, ], }) </script> ``` ### Reactive Meta Tags ```vue [app/pages/profile.vue] <script setup lang="ts"> const profile = ref({ name: 'John Doe' }) useHead({ title: computed(() => profile.value.name), meta: [ { name: 'description', content: computed(() => `Profile page for ${profile.value.name}`), }, ], }) </script> ``` ### Using a Function for Full Reactivity ```vue [app/pages/dynamic.vue] <script setup lang="ts"> const count = ref(0) useHead(() => ({ title: `Count: ${count.value}`, meta: [ { name: 'description', content: `Current count is ${count.value}` }, ], })) </script> ``` ### Adding External Scripts and Styles ```vue [app/pages/external.vue] <script setup lang="ts"> useHead({ link: [ { rel: 'stylesheet', href: 'https://cdn.example.com/styles.css', }, ], script: [ { src: 'https://cdn.example.com/script.js', async: true, }, ], }) </script> ``` ### Body and HTML Attributes ```vue [app/pages/themed.vue] <script setup lang="ts"> const isDark = ref(true) useHead({ htmlAttrs: { lang: 'en', class: computed(() => isDark.value ? 'dark' : 'light'), }, bodyAttrs: { class: 'themed-page', }, }) </script> ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useHeadSafe > The recommended way to provide head data with user input. ## Usage The `useHeadSafe` composable is a wrapper around the [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable that restricts the input to only allow safe values. This is the recommended way to manage head data when working with user input, as it prevents XSS attacks by sanitizing potentially dangerous attributes. <warning> When using `useHeadSafe`, potentially dangerous attributes like `innerHTML` in scripts or `http-equiv` in meta tags are automatically stripped out to prevent XSS attacks. Use this composable whenever you're working with user-generated content. </warning> ## Type ```ts [Signature] export function useHeadSafe (input: MaybeComputedRef<HeadSafe>): void ``` ### Allowed Attributes The following attributes are whitelisted for each head element type: ```ts const WhitelistAttributes = { htmlAttrs: ['class', 'style', 'lang', 'dir'], bodyAttrs: ['class', 'style'], meta: ['name', 'property', 'charset', 'content', 'media'], noscript: ['textContent'], style: ['media', 'textContent', 'nonce', 'title', 'blocking'], script: ['type', 'textContent', 'nonce', 'blocking'], link: ['color', 'crossorigin', 'fetchpriority', 'href', 'hreflang', 'imagesrcset', 'imagesizes', 'integrity', 'media', 'referrerpolicy', 'rel', 'sizes', 'type'], } ``` See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/safeSchema.ts) for more detailed types. ## Parameters `input`: A `MaybeComputedRef<HeadSafe>` object containing head data. You can pass all the same values as [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head), but only safe attributes will be rendered. ## Return Values This composable does not return any value. ## Example ```vue [app/pages/user-profile.vue] <script setup lang="ts"> // User-generated content that might contain malicious code const userBio = ref('<script>alert("xss")<' + '/script>') useHeadSafe({ title: `User Profile`, meta: [ { name: 'description', content: userBio.value, // Safely sanitized }, ], }) </script> ``` <read-more target="_blank" to="https://unhead.unjs.io/docs/typescript/head/api/composables/use-head-safe"> Read more on the `Unhead` documentation. </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useHydration > Allows full control of the hydration cycle to set and receive data from the server. `useHydration` is a built-in composable that provides a way to set data on the server side every time a new HTTP request is made and receive that data on the client side. This way `useHydration` allows you to take full control of the hydration cycle. <note> This is an advanced composable, primarily designed for use within plugins, mostly used by Nuxt modules. </note> <note> `useHydration` is designed to **ensure state synchronization and restoration during SSR**. If you need to create a globally reactive state that is SSR-friendly in Nuxt, [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) is the recommended choice. </note> ## Usage The data returned from the `get` function on the server is stored in `nuxtApp.payload` under the unique key provided as the first parameter to `useHydration`. During hydration, this data is then retrieved on the client, preventing redundant computations or API calls. <code-group> ```ts [With useHydration] export default defineNuxtPlugin((nuxtApp) => { const myStore = new MyStore() useHydration( 'myStoreState', () => myStore.getState(), data => myStore.setState(data), ) }) ``` ```ts [Without useHydration] export default defineNuxtPlugin((nuxtApp) => { const myStore = new MyStore() if (import.meta.server) { nuxt.hooks.hook('app:rendered', () => { nuxtApp.payload.myStoreState = myStore.getState() }) } if (import.meta.client) { nuxt.hooks.hook('app:created', () => { myStore.setState(nuxtApp.payload.myStoreState) }) } }) ``` </code-group> ## Type ```ts [Signature] export function useHydration<T> (key: string, get: () => T, set: (value: T) => void): void ``` ## Parameters <table> <thead> <tr> <th> Parameter </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> key </code> </td> <td> <code> string </code> </td> <td> A unique key that identifies the data in your Nuxt application. </td> </tr> <tr> <td> <code> get </code> </td> <td> <code> () => T </code> </td> <td> A function executed <strong> only on the server </strong> (called when SSR rendering is done) to set the initial value. </td> </tr> <tr> <td> <code> set </code> </td> <td> <code> (value: T) => void </code> </td> <td> A function executed <strong> only on the client </strong> (called when initial Vue instance is created) to receive the data. </td> </tr> </tbody> </table> ## Return Values This composable does not return any value. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/hydrate.ts) # useLayout > useLayout returns the layout resolved for the current route. ## Description `useLayout` returns a computed ref with the layout resolved for the current route, using the same chain as [`<NuxtLayout>`](https://nuxt.com/docs/4.x/api/components/nuxt-layout): the page's `layout` meta first, then the `appLayout` set via [route rules](https://nuxt.com/docs/4.x/guide/concepts/rendering#hybrid-rendering), then `'default'`. Within a rendered `<NuxtLayout>` it reflects the enclosing layout; outside of one (for example in `app.vue`) it returns the layout that would be resolved for the current route. Unlike reading `route.meta.layout` directly, this accounts for a layout set through route rules and stays in sync as the route changes. ## Return Values A read-only computed ref resolving to the layout name (a `string`), or `false` when the layout is disabled. ## Example ```vue [app.vue] <script setup lang="ts"> const layout = useLayout() </script> <template> <div> <CommandPalette v-if="layout !== 'minimal'" /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/layout.ts) # useLazyAsyncData > This wrapper around useAsyncData triggers navigation immediately. `useLazyAsyncData` provides a wrapper around [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. <note> By default, [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) blocks navigation until its async handler is resolved. `useLazyAsyncData` allows navigation to occur immediately while data fetching continues in the background. </note> ## Usage ```vue [app/pages/index.vue] <script setup lang="ts"> const { status, data: posts } = await useLazyAsyncData('posts', () => $fetch('/api/posts')) </script> <template> <div> <div v-if="status === 'pending'"> Loading... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> {{ posts }} </div> </div> </template> ``` `useLazyAsyncData` lets navigation continue while it fetches data. Check `status === 'pending'` and `status === 'error'` in your component's template before using the result. <warning> `useLazyAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyAsyncData`. </warning> ## Type ```ts [Signature] export function useLazyAsyncData<ResT, DataE = unknown, DataT = ResT> ( handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> export function useLazyAsyncData<ResT, DataE = unknown, DataT = ResT> ( key: MaybeRefOrGetter<string>, handler: AsyncDataHandler<ResT>, options?: AsyncDataOptions<ResT, DataT>, ): AsyncData<DataT, DataE> & Promise<AsyncData<DataT, DataE>> ``` `useLazyAsyncData` has the same signature as [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data). ## Parameters `useLazyAsyncData` accepts the same parameters as [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data), with the `lazy` option automatically set to `true`. <read-more to="https://nuxt.com/docs/4.x/api/composables/use-async-data#parameters"> </read-more> ## Return Values `useLazyAsyncData` returns the same values as [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data). <read-more to="https://nuxt.com/docs/4.x/api/composables/use-async-data#return-values"> </read-more> ## Example ```vue [app/pages/index.vue] <script setup lang="ts"> /* useLazyAsyncData lets navigation continue before the fetch completes. Handle loading and error states in the template. */ const { status, data: count } = await useLazyAsyncData('count', () => $fetch('/api/count')) watch(count, (newCount) => { // Because count might start out null, you won't have access // to its contents immediately, but you can watch it. }) </script> <template> <div v-if="status === 'pending'"> Loading </div> <div v-else-if="status === 'error'"> Error loading count </div> <div v-else> {{ count }} </div> </template> ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # useLazyFetch > This wrapper around useFetch triggers navigation immediately. `useLazyFetch` provides a wrapper around [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. ## Usage By default, [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) blocks navigation until its async handler is resolved. `useLazyFetch` allows navigation to proceed immediately, with data being fetched in the background. ```vue [app/pages/index.vue] <script setup lang="ts"> const { status, data: posts } = await useLazyFetch('/api/posts') </script> <template> <div v-if="status === 'pending'"> Loading ... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` <note> `useLazyFetch` has the same signature as [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch). </note> <warning> Awaiting `useLazyFetch` initializes the call but does not wait for the data. During client-side navigation, check `status === 'pending'` and `status === 'error'` in your component's template before using the result. </warning> <warning> `useLazyFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyFetch`. </warning> ## Type ```ts [Signature] export function useLazyFetch<ResT, ErrorT = NuxtError<unknown>, DataT = ResT> ( url: string | Request | Ref<string | Request> | (() => string | Request), options?: UseFetchOptions<ResT, DataT>, ): AsyncData<DataT, ErrorT> & Promise<AsyncData<DataT, ErrorT>> ``` <note> `useLazyFetch` is equivalent to `useFetch` with `lazy: true` option set. See [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) for full type definitions. </note> ## Parameters `useLazyFetch` accepts the same parameters as [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch): - `URL` (`string | Request | Ref<string | Request> | () => string | Request`): The URL or request to fetch. - `options` (object): Same as [`useFetch` options](https://nuxt.com/docs/4.x/api/composables/use-fetch#parameters), with `lazy` automatically set to `true`. <read-more to="https://nuxt.com/docs/4.x/api/composables/use-fetch#parameters"> </read-more> ## Return Values Returns the same `AsyncData` object as [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch): <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous fetch. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the data fetching failed. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the data request. Use it to distinguish <code> idle </code> , <code> pending </code> , <code> success </code> , and <code> error </code> . </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> <code> true </code> while a request is in flight. See <a href="https://nuxt.com/docs/4.x/api/composables/use-fetch#return-values"> <code> useFetch </code> </a> . </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> , <code> error </code> to <code> undefined </code> , sets <code> status </code> to <code> idle </code> , and cancels any pending requests. </td> </tr> </tbody> </table> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-fetch#return-values"> </read-more> ## Example ### Handling Loading State ```vue [app/pages/index.vue] <script setup lang="ts"> /* useLazyFetch lets navigation continue before the fetch completes. * Handle loading and error states in the template. */ const { status, data: posts } = await useLazyFetch('/api/posts') watch(posts, (newPosts) => { // Because posts might start out null, you won't have access // to its contents immediately, but you can watch it. }) </script> <template> <div v-if="status === 'pending'"> Loading ... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # useLoadingIndicator > This composable gives you access to the loading state of the app page. ## Description A composable which returns the loading state of the page. Used by [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/4.x/api/components/nuxt-loading-indicator) and controllable. It hooks into [`page:loading:start`](https://nuxt.com/docs/4.x/api/advanced/hooks#app-hooks-runtime) and [`page:loading:end`](https://nuxt.com/docs/4.x/api/advanced/hooks#app-hooks-runtime) to change its state. ## Parameters - `duration`: Duration of the loading bar, in milliseconds (default `2000`). - `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`). - `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100. ## Properties ### `isLoading` - **type**: `Readonly<ShallowRef<boolean>>` - **description**: The loading state ### `error` - **type**: `Readonly<ShallowRef<boolean>>` - **description**: The error state ### `progress` - **type**: `Readonly<ShallowRef<number>>` - **description**: The progress state. From `0` to `100`. ## Methods ### `start()` Set `isLoading` to true and start to increase the `progress` value. `start` accepts a `{ force: true }` option to skip the interval and show the loading state immediately. ### `set()` Set the `progress` value to a specific value. `set` accepts a `{ force: true }` option to skip the interval and show the loading state immediately. ### `finish()` Set the `progress` value to `100`, stop all timers and intervals then reset the loading state `500` ms later. `finish` accepts a `{ force: true }` option to skip the interval before the state is reset, and `{ error: true }` to change the loading bar color and set the error property to true. ### `clear()` Used by `finish()`. Clear all timers and intervals used by the composable. ## Example ```vue <script setup lang="ts"> const { progress, isLoading, start, finish, clear } = useLoadingIndicator({ duration: 2000, throttle: 200, // This is how progress is calculated by default estimatedProgress: (duration, elapsed) => (2 / Math.PI * 100) * Math.atan(elapsed / duration * 100 / 50), }) </script> ``` ```vue <script setup lang="ts"> const { start, set } = useLoadingIndicator() // same as set(0, { force: true }) // set the progress to 0, and show loading immediately start({ force: true }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/loading-indicator.ts) # useNuxtApp > Access the shared runtime context of the Nuxt Application. `useNuxtApp` is a built-in composable that provides a way to access shared runtime context of Nuxt, also known as the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context), which is available on both client and server side (but not within Nitro routes). It helps you access the Vue app instance, runtime hooks, runtime config variables and internal states, such as `ssrContext` and `payload`. ```vue [app/app.vue] <script setup lang="ts"> const nuxtApp = useNuxtApp() </script> ``` If runtime context is unavailable in your scope, `useNuxtApp` will throw an exception when called. You can use [`tryUseNuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#tryusenuxtapp) instead for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception. ## Methods ### `provide (name, value)` `nuxtApp` is a runtime context that you can extend using [Nuxt plugins](https://nuxt.com/docs/4.x/directory-structure/app/plugins). Use the `provide` function to create Nuxt plugins to make values and helper methods available in your Nuxt application across all composables and components. `provide` function accepts `name` and `value` parameters. ```ts [app/plugins/hello.ts] const nuxtApp = useNuxtApp() nuxtApp.provide('hello', name => `Hello ${name}!`) // Prints "Hello name!" console.log(nuxtApp.$hello('name')) ``` As you can see in the example above, `$hello` has become the new and custom part of `nuxtApp` context and it is available in all places where `nuxtApp` is accessible. ### `hook(name, cb)` Hooks available in `nuxtApp` allows you to customize the runtime aspects of your Nuxt application. You can use runtime hooks in Vue.js composables and [Nuxt plugins](https://nuxt.com/docs/4.x/directory-structure/app/plugins) to hook into the rendering lifecycle. `hook` function is useful for adding custom logic by hooking into the rendering lifecycle at a specific point. `hook` function is mostly used when creating Nuxt plugins. See [Runtime Hooks](https://nuxt.com/docs/4.x/api/advanced/hooks#app-hooks-runtime) for available runtime hooks called by Nuxt. ```ts [app/plugins/test.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:start', () => { /* your code goes here */ }) nuxtApp.hook('vue:error', (..._args) => { console.log('vue:error') // if (import.meta.client) { // console.log(..._args) // } }) }) ``` ### `callHook(name, ...args)` `callHook` returns a promise when called with any of the existing hooks. ```ts [app/plugins/my-plugin.ts] await nuxtApp.callHook('my-plugin:init') ``` ## Properties `useNuxtApp()` exposes the following properties that you can use to extend and customize your app and share state, data and variables. ### `vueApp` `vueApp` is the global Vue.js [application instance](https://vuejs.org/api/application#application-api) that you can access through `nuxtApp`. Some useful methods: - [`component()`](https://vuejs.org/api/application#app-component) - Registers a global component if passing both a name string and a component definition, or retrieves an already registered one if only the name is passed. - [`directive()`](https://vuejs.org/api/application#app-directive) - Registers a global custom directive if passing both a name string and a directive definition, or retrieves an already registered one if only the name is passed[(example)](https://nuxt.com/docs/4.x/directory-structure/app/plugins#vue-directives). - [`use()`](https://vuejs.org/api/application#app-use) - Installs a **Vue.js Plugin** [(example)](https://nuxt.com/docs/4.x/directory-structure/app/plugins#vue-plugins). <read-more to="https://vuejs.org/api/application.html#application-api" icon="i-simple-icons-vuedotjs"> </read-more> ### `ssrContext` `ssrContext` is generated during server-side rendering and it is only available on the server side. Nuxt exposes the following properties through `ssrContext`: - `url` (string) - Current request url. - `event` ([h3js/h3](https://github.com/h3js/h3) request event) - Access the request & response of the current route. - `payload` (object) - NuxtApp payload object. ### `payload` `payload` exposes data and state variables from server side to client side. The following keys will be available on the client after they have been passed from the server side: - `serverRendered` (boolean) - Indicates if response is server-side-rendered. - `data` (object) - When you fetch the data from an API endpoint using either [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) , resulting payload can be accessed from the `payload.data`. This data is cached and helps you prevent fetching the same data in case an identical request is made more than once.<code-group> ```vue [app/app.vue] <script setup lang="ts"> const { data } = await useAsyncData('count', (_nuxtApp, { signal }) => $fetch('/api/count', { signal })) </script> ``` ```ts [server/api/count.ts] export default defineEventHandler((event) => { return { count: 1 } }) ``` </code-group> <br /> After fetching the value of `count` using [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) in the example above, if you access `payload.data`, you will see `{ count: 1 }` recorded there.<br /> When accessing the same `payload.data` from [`ssrcontext`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#ssrcontext), you can access the same value on the server side as well. - `state` (object) - When you use [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) composable in Nuxt to set shared state, this state data is accessed through `payload.state.[name-of-your-state]`.```ts [app/plugins/my-plugin.ts] export const useColor = () => useState<string>('color', () => 'pink') export default defineNuxtPlugin((nuxtApp) => { if (import.meta.server) { const color = useColor() } }) ``` <br /> It is also possible to use more advanced types, such as `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError`. #### Custom Reducer/Reviver <badge className="align-middle" color="info" size="xs">v3.4</badge> Since [Nuxt v3.4](https://nuxt.com/blog/v3-4#payload-enhancements), it is possible to define your own reducer/reviver for types that are not supported by Nuxt. <video-accordion title="Watch a video from Alexander Lichter about serializing payloads, especially with regards to classes" video-id="8w6ffRBs8a4"> </video-accordion> In the example below, we define a reducer (or a serializer) and a reviver (or deserializer) for the [Luxon](https://moment.github.io/luxon/#/) DateTime class, using a payload plugin. ```ts [app/plugins/date-time-payload.ts] /** * This kind of plugin runs very early in the Nuxt lifecycle, before we revive the payload. * You will not have access to the router or other Nuxt-injected properties. * * Note that the "DateTime" string is the type identifier and must * be the same on both the reducer and the reviver. */ export default definePayloadPlugin((nuxtApp) => { definePayloadReducer('DateTime', (value) => { return value instanceof DateTime && value.toJSON() }) definePayloadReviver('DateTime', (value) => { return DateTime.fromISO(value) }) }) ``` ### `isHydrating` Use `nuxtApp.isHydrating` (boolean) to check if the Nuxt app is hydrating on the client side. ```ts [app/components/nuxt-error-boundary.ts] export default defineComponent({ setup (_props, { slots, emit }) { const nuxtApp = useNuxtApp() onErrorCaptured((err) => { if (import.meta.client && !nuxtApp.isHydrating) { // ... } }) }, }) ``` ### `runWithContext` <note> You are likely here because you got a "Nuxt instance unavailable" message. Please use this method sparingly, and report examples that are causing issues, so that it can ultimately be solved at the framework level. </note> The `runWithContext` method is meant to be used to call a function and give it an explicit Nuxt context. Typically, the Nuxt context is passed around implicitly and you do not need to worry about this. However, when working with complex `async`/`await` scenarios in middleware/plugins, you can run into instances where the current instance has been unset after an async call. ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware(async (to, from) => { const nuxtApp = useNuxtApp() let user try { user = await fetchUser() // the Vue/Nuxt compiler loses context here because of the try/catch block. } catch (e) { user = null } if (!user) { // apply the correct Nuxt context to our `navigateTo` call. return nuxtApp.runWithContext(() => navigateTo('/auth')) } }) ``` #### Usage ```ts [Usage] const result = nuxtApp.runWithContext(() => functionWithContext()) ``` - `functionWithContext`: Any function that requires the context of the current Nuxt application. This context will be correctly applied automatically. `runWithContext` will return whatever is returned by `functionWithContext`. #### A Deeper Explanation of Context Vue.js Composition API (and Nuxt composables similarly) work by depending on an implicit context. During the lifecycle, Vue sets the temporary instance of the current component (and Nuxt temporary instance of nuxtApp) to a global variable and unsets it in same tick. When rendering on the server side, there are multiple requests from different users and nuxtApp running in a same global context. Because of this, Nuxt and Vue immediately unset this global instance to avoid leaking a shared reference between two users or components. What it does mean? The Composition API and Nuxt Composables are only available during lifecycle and in same tick before any async operation: ```ts [Conceptual Example] // --- Vue internal --- const _vueInstance = null const getCurrentInstance = () => _vueInstance // --- // Vue / Nuxt sets a global variable referencing to current component in _vueInstance when calling setup() async function setup () { getCurrentInstance() // Works await someAsyncOperation() // Vue unsets the context in same tick before async operation! getCurrentInstance() // null } ``` The classic solution to this, is caching the current instance on first call to a local variable like `const instance = getCurrentInstance()` and use it in the next composable call but the issue is that any nested composable calls now needs to explicitly accept the instance as an argument and not depend on the implicit context of composition-api. This is design limitation with composables and not an issue per-se. To overcome this limitation, Vue does some behind the scenes work when compiling our application code and restores context after each call for `<script setup>`: ```ts [Compiled Output] const __instance = getCurrentInstance() // Generated by Vue compiler getCurrentInstance() // Works! await someAsyncOperation() // Vue unsets the context __restoreInstance(__instance) // Generated by Vue compiler getCurrentInstance() // Still works! ``` For a better description of what Vue actually does, see [unjs/unctx#2 (comment)](https://github.com/unjs/unctx/issues/2#issuecomment-942193723). #### Solution This is where `runWithContext` can be used to restore context, similarly to how `<script setup>` works. Nuxt internally uses [unjs/unctx](https://github.com/unjs/unctx) to support composables similar to Vue for plugins and middleware. This enables composables like `navigateTo()` to work without directly passing `nuxtApp` to them - bringing the DX and performance benefits of Composition API to the whole Nuxt framework. Nuxt composables have the same design as the Vue Composition API and therefore need a similar solution to magically do this transform. Check out [unjs/unctx#2](https://github.com/unjs/unctx/issues/2) (proposal), [unjs/unctx#4](https://github.com/unjs/unctx/pull/4) (transform implementation), and [nuxt/framework#3884](https://github.com/nuxt/framework/pull/3884) (Integration to Nuxt). Vue currently only supports async context restoration for `<script setup>` for async/await usage. In Nuxt, the transform support for `defineNuxtPlugin()` and `defineNuxtRouteMiddleware()` was added, which means when you use them Nuxt automatically transforms them with context restoration. #### Remaining Issues The `unjs/unctx` transformation to automatically restore context seems buggy with `try/catch` statements containing `await` which ultimately needs to be solved in order to remove the requirement of the workaround suggested above. #### Native Async Context Using a new experimental feature, it is possible to enable native async context support using [Node.js `AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) and new unctx support to make async context available **natively** to **any nested async composable** without needing a transform or manual passing/calling with context. <tip> Native async context support works currently in Bun and Node. </tip> <read-more to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#asynccontext"> </read-more> ## tryUseNuxtApp <badge className="align-middle" color="info" size="xs">v3.10</badge> This function works exactly the same as `useNuxtApp`, but returns `null` if context is unavailable instead of throwing an exception. You can use it for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception. Example usage: ```ts [composable.ts] export function useStandType () { // Always works on the client if (tryUseNuxtApp()) { return useRuntimeConfig().public.STAND_TYPE } else { return process.env.STAND_TYPE } } ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # useNuxtData > Access the current cached value of data fetching composables. <note> `useNuxtData` gives you access to the current cached value of [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) , [`useLazyAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-lazy-async-data), [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) and [`useLazyFetch`](https://nuxt.com/docs/4.x/api/composables/use-lazy-fetch) with explicitly provided key. </note> ## Usage The `useNuxtData` composable is used to access the current cached value of data-fetching composables such as `useAsyncData`, `useLazyAsyncData`, `useFetch`, and `useLazyFetch`. By providing the key used during the data fetch, you can retrieve the cached data and use it as needed. This is particularly useful for optimizing performance by reusing already-fetched data or implementing features like Optimistic Updates or cascading data updates. To use `useNuxtData`, ensure that the data-fetching composable (`useFetch`, `useAsyncData`, etc.) has been called with an explicitly provided key. <video-accordion title="Watch a video from LearnVue about useNuxtData" video-id="e-_u6swXRWk"> </video-accordion> ## Type ```ts [Signature] export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | undefined> } ``` ## Parameters - `key`: The unique key that identifies the cached data. This key should match the one used during the original data fetch. ## Return Values - `data`: A reactive reference to the cached data associated with the provided key. If no cached data exists, the value will be `undefined`. This `Ref` automatically updates if the cached data changes, allowing seamless reactivity in your components. ## Example The example below shows how you can use cached data as a placeholder while the most recent data is being fetched from the server. ```vue [app/pages/posts.vue] <script setup lang="ts"> // We can access same data later using 'posts' key const { data } = await useFetch('/api/posts', { key: 'posts' }) </script> ``` ```vue [app/pages/posts/[id].vue] <script setup lang="ts"> // Access to the cached value of useFetch in posts.vue (parent route) const { data: posts } = useNuxtData('posts') const route = useRoute() const { data } = useLazyFetch(`/api/posts/${route.params.id}`, { key: `post-${route.params.id}`, default () { // Find the individual post from the cache and set it as the default value. return posts.value.find(post => post.id === route.params.id) }, }) </script> ``` ## Optimistic Updates The example below shows how implementing Optimistic Updates can be achieved using useNuxtData. Optimistic Updates is a technique where the user interface is updated immediately, assuming a server operation will succeed. If the operation eventually fails, the UI is rolled back to its previous state. ```vue [app/pages/todos.vue] <script setup lang="ts"> // We can access same data later using 'todos' key const { data } = await useAsyncData('todos', (_nuxtApp, { signal }) => $fetch('/api/todos', { signal })) </script> ``` ```vue [app/components/NewTodo.vue] <script setup lang="ts"> const newTodo = ref('') let previousTodos = [] // Access to the cached value of useAsyncData in todos.vue const { data: todos } = useNuxtData('todos') async function addTodo () { await $fetch('/api/addTodo', { method: 'post', body: { todo: newTodo.value, }, onRequest () { // Store the previously cached value to restore if fetch fails. previousTodos = todos.value // Optimistically update the todos. todos.value = [...todos.value, newTodo.value] }, onResponseError () { // Rollback the data if the request failed. todos.value = previousTodos }, async onResponse () { // Invalidate todos in the background if the request succeeded. await refreshNuxtData('todos') }, }) } </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # `usePreviewMode` Preview mode allows you to see how your changes would be displayed on a live site without revealing them to users. You can use the built-in `usePreviewMode` composable to access and control preview state in Nuxt. If the composable detects preview mode it will automatically force any updates necessary for [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) to rerender preview content. ```ts const { enabled, state } = usePreviewMode() ``` ## Options ### Custom `enable` check You can specify a custom way to enable preview mode. By default the `usePreviewMode` composable will enable preview mode if there is a `preview` param in url that is equal to `true` (for example, `http://localhost:3000?preview=true`). You can wrap the `usePreviewMode` into custom composable, to keep options consistent across usages and prevent any errors. ```ts export function useMyPreviewMode () { const route = useRoute() return usePreviewMode({ shouldEnable: () => { return !!route.query.customPreview }, }) } ``` ### Modify default state `usePreviewMode` will try to store the value of a `token` param from url in state. You can modify this state and it will be available for all [`usePreviewMode`](https://nuxt.com/docs/4.x/api/composables/use-preview-mode) calls. ```ts const data1 = ref('data1') const { enabled, state } = usePreviewMode({ getState: (currentState) => { return { data1, data2: 'data2' } }, }) ``` <note> The `getState` function will append returned values to current state, so be careful not to accidentally overwrite important state. </note> ### Customize the `onEnable` and `onDisable` callbacks By default, when `usePreviewMode` is enabled, it will call `refreshNuxtData()` to re-fetch all data from the server. When preview mode is disabled, the composable will attach a callback to call `refreshNuxtData()` to run after a subsequent router navigation. You can specify custom callbacks to be triggered by providing your own functions for the `onEnable` and `onDisable` options. ```ts const { enabled, state } = usePreviewMode({ onEnable: () => { console.log('preview mode has been enabled') }, onDisable: () => { console.log('preview mode has been disabled') }, }) ``` ## Example The example below creates a page where part of a content is rendered only in preview mode. ```vue [app/pages/some-page.vue] <script setup> const { enabled, state } = usePreviewMode() const { data } = await useFetch('/api/preview', { query: { apiKey: state.token, }, }) </script> <template> <div> Some base content <p v-if="enabled"> Only preview content: {{ state.token }} <br> <button @click="enabled = false"> disable preview mode </button> </p> </div> </template> ``` Now you can generate your site and serve it: ```bash [Terminal] npx nuxt generate npx nuxt preview ``` Then you can see your preview page by adding the query param `preview` to the end of the page you want to see once, for example `http://localhost:3000/?preview=true`. <note> `usePreviewMode` should be tested locally with `nuxt generate` and then `nuxt preview` rather than `nuxt dev`. (The [preview command](https://nuxt.com/docs/4.x/api/commands/preview) is not related to preview mode.) </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preview.ts) # useRequestEvent > Access the incoming request event with the useRequestEvent composable. Within the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context) you can use `useRequestEvent` to access the incoming request. ```ts // Get underlying request event const event = useRequestEvent() // Get the URL const url = event?.path ``` <tip> In the browser, `useRequestEvent` will return `undefined`. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestFetch > Forward the request context and headers for server-side fetch requests with the useRequestFetch composable. You can use `useRequestFetch` to forward the request context and headers when making server-side fetch requests. When making a client-side fetch request, the browser automatically sends the necessary headers. However, when making a request during server-side rendering, due to security considerations, we need to forward the headers manually. <note> Headers that are **not meant to be forwarded** will **not be included** in the request. These headers include, for example: `transfer-encoding`, `connection`, `keep-alive`, `upgrade`, `expect`, `host`, `accept` </note> <tip> The [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) composable uses `useRequestFetch` under the hood to automatically forward the request context and headers. </tip> <code-group> ```vue [app/pages/index.vue] <script setup lang="ts"> // This will forward the user's headers to the `/api/cookies` event handler // Result: { cookies: { foo: 'bar' } } const requestFetch = useRequestFetch() const { data: forwarded } = await useAsyncData(() => requestFetch('/api/cookies')) // This will NOT forward anything // Result: { cookies: {} } const { data: notForwarded } = await useAsyncData((_nuxtApp, { signal }) => $fetch('/api/cookies', { signal })) </script> ``` ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` </code-group> <tip> In the browser during client-side navigation, `useRequestFetch` will behave just like regular [`$fetch`](https://nuxt.com/docs/4.x/api/utils/dollarfetch). </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestHeader > Use useRequestHeader to access a certain incoming request header. You can use the built-in [`useRequestHeader`](https://nuxt.com/docs/4.x/api/composables/use-request-header) composable to access any incoming request header within your pages, components, and plugins. ```ts // Get the authorization request header const authorization = useRequestHeader('authorization') ``` <tip> In the browser, `useRequestHeader` will return `undefined`. </tip> ## Example We can use `useRequestHeader` to easily figure out if a user is authorized or not. The example below reads the `authorization` request header to find out if a person can access a restricted resource. ```ts [app/middleware/authorized-only.ts] export default defineNuxtRouteMiddleware((to, from) => { if (!useRequestHeader('authorization')) { return navigateTo('/not-authorized') } }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestHeaders > Use useRequestHeaders to access the incoming request headers. You can use built-in [`useRequestHeaders`](https://nuxt.com/docs/4.x/api/composables/use-request-headers) composable to access the incoming request headers within your pages, components, and plugins. ```ts // Get all request headers const headers = useRequestHeaders() // Get only cookie request header const { cookie } = useRequestHeaders(['cookie']) ``` <tip> In the browser, `useRequestHeaders` will return an empty object. </tip> ## Example We can use `useRequestHeaders` to access and proxy the initial request's `authorization` header to any future internal requests during SSR. The example below adds the `authorization` request header to an isomorphic `$fetch` call. ```vue [app/pages/some-page.vue] <script setup lang="ts"> const { data } = await useFetch('/api/confidential', { headers: useRequestHeaders(['authorization']), }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestURL > Access the incoming request URL with the useRequestURL composable. `useRequestURL` is a helper function that returns an [URL object](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) working on both server-side and client-side. <important> When utilizing [Hybrid Rendering](https://nuxt.com/docs/4.x/guide/concepts/rendering#hybrid-rendering) with cache strategies, all incoming request headers are dropped when handling the cached responses via the [Nitro caching layer](https://nitro.build/guide/cache) (meaning `useRequestURL` will return `localhost` for the `host`). You can define the [`cache.varies` option](https://nitro.build/guide/cache#options) to specify headers that will be considered when caching and serving the responses, such as `host` and `x-forwarded-host` for multi-tenant environments. </important> <code-group> ```vue [app/pages/about.vue] <script setup lang="ts"> const url = useRequestURL() </script> <template> <p>URL is: {{ url }}</p> <p>Path is: {{ url.pathname }}</p> </template> ``` ```html [Result in development] <p>URL is: http://localhost:3000/about</p> <p>Path is: /about</p> ``` </code-group> <tip icon="i-simple-icons-mdnwebdocs" target="_blank" to="https://developer.mozilla.org/en-US/docs/Web/API/URL#instance_properties"> Read about the URL instance properties on the MDN documentation. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/url.ts) # useResponseHeader > Use useResponseHeader to set a server response header. <important> This composable is available in Nuxt v3.14+. </important> You can use the built-in [`useResponseHeader`](https://nuxt.com/docs/4.x/api/composables/use-response-header) composable to set any server response header within your pages, components, and plugins. ```ts // Set a custom response header const header = useResponseHeader('X-My-Header') header.value = 'my-value' ``` ## Example We can use `useResponseHeader` to easily set a response header on a per-page basis. ```vue [app/pages/test.vue] <script setup> // pages/test.vue const header = useResponseHeader('X-My-Header') header.value = 'my-value' </script> <template> <h1>Test page with custom header</h1> <p>The response from the server for this "/test" page will have a custom "X-My-Header" header.</p> </template> ``` We can use `useResponseHeader` for example in Nuxt [middleware](https://nuxt.com/docs/4.x/directory-structure/app/middleware) to set a response header for all pages. ```ts [app/middleware/my-header-middleware.ts] export default defineNuxtRouteMiddleware((to, from) => { const header = useResponseHeader('X-My-Always-Header') header.value = `I'm Always here!` }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRoute > The useRoute composable returns the current route. <note> Within the template of a Vue component, you can access the route using `$route`. </note> The `useRoute` composable is a wrapper around the identically named composable from `vue-router`, providing access to the current route in a Nuxt application. The key difference is that in Nuxt, the composable ensures that the route is updated **only after** the page content has changed after navigation. In contrast, the `vue-router` version updates the route **immediately**, which can lead to synchronization issues between different parts of the template that rely on the route metadata, for example. ## Example In the following example, we call an API via [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) using a dynamic page parameter - `slug` - as part of the URL. ```html [~/pages/[slug].vue] <script setup lang="ts"> const route = useRoute() const { data: mountain } = await useFetch(`/api/mountains/${route.params.slug}`) </script> <template> <div> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </div> </template> ``` If you need to access the route query parameters (for example `example` in the path `/test?example=true`), then you can use `useRoute().query` instead of `useRoute().params`. ## API Apart from dynamic parameters and query parameters, `useRoute()` also provides the following computed references related to the current route: - `fullPath`: encoded URL associated with the current route that contains path, query and hash - `hash`: decoded hash section of the URL that starts with a # - `query`: access route query parameters - `matched`: array of normalized matched routes with current route location - `meta`: custom data attached to the record - `name`: unique name for the route record - `path`: encoded pathname section of the URL - `redirectedFrom`: route location that was attempted to access before ending up on the current route location ## Common Pitfalls ### Route Synchronization Issues Itโ€™s important to use the `useRoute()` composable from Nuxt rather than the one from `vue-router` to avoid synchronization issues during page navigation. Importing `useRoute` directly from `vue-router` bypasses Nuxt's implementation. ```tstwoslash // โŒ do not use `useRoute` from `vue-router` // @errors: 2300 import { useRoute } from 'vue-router' // โœ… use Nuxt's `useRoute` composable import { useRoute } from '#app' ``` ### Calling `useRoute` in Middleware Using `useRoute` in middleware is not recommended because it can lead to unexpected behavior. There is no concept of a "current route" in middleware. The `useRoute()` composable should only be used in the setup function of a Vue component or in a Nuxt plugin. <warning> This applies to any composable that uses `useRoute()` internally too. </warning> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/middleware"> Read more about accessing the route in the middleware section. </read-more> ### Hydration Issues with `route.fullPath` Browsers don't send [URL fragments](https://url.spec.whatwg.org/#concept-url-fragment) (for example `#foo`) when making requests. So using `route.fullPath` to affect the template can trigger hydration issues because this will include the fragment on client but not the server. <read-more to="https://router.vuejs.org/api/type-aliases/RouteLocationNormalizedLoaded.html" icon="i-simple-icons-vuedotjs"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # useRouteAnnouncer > This composable observes the page title changes and updates the announcer message accordingly. <important> This composable is available in Nuxt v3.12+. </important> ## Description A composable which observes the page title changes and updates the announcer message accordingly. Used by [`<NuxtRouteAnnouncer>`](https://nuxt.com/docs/4.x/api/components/nuxt-route-announcer) and controllable. It hooks into Unhead's `dom:rendered` hook to read the page's title and set it as the announcer message. <read-more title="Nuxt accessibility" to="https://nuxt.com/docs/4.x/guide/best-practices/accessibility#route-announcements"> </read-more> ## Parameters - `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`). ## Properties ### `message` - **type**: `Ref<string>` - **description**: The message to announce ### `politeness` - **type**: `Ref<string>` - **description**: Screen reader announcement urgency level `off`, `polite`, or `assertive` ## Methods ### `set(message, politeness = "polite")` Sets the message to announce with its urgency level. ### `polite(message)` Sets the message with `politeness = "polite"` ### `assertive(message)` Sets the message with `politeness = "assertive"` ## Example ```vue [app/pages/index.vue] <script setup lang="ts"> const { message, politeness, set, polite, assertive } = useRouteAnnouncer({ politeness: 'assertive', }) </script> ``` <callout> For announcing dynamic in-page content changes (form validation, toasts, loading states), use [`useAnnouncer`](https://nuxt.com/docs/4.x/api/composables/use-announcer) instead. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/route-announcer.ts) # useRouter > The useRouter composable returns the router instance. ```vue [app/pages/index.vue] <script setup lang="ts"> const router = useRouter() </script> ``` If you only need the router instance within your template, use `$router`: ```vue [app/pages/index.vue] <template> <button @click="$router.back()"> Back </button> </template> ``` If you have a `app/pages/` directory, `useRouter` is identical in behavior to the one provided by `vue-router`. <read-more to="https://router.vuejs.org/api/interfaces/router#Properties-currentRoute-" icon="i-simple-icons-vuedotjs" target="_blank"> Read `vue-router` documentation about the `Router` interface. </read-more> ## Basic Manipulation - [`addRoute()`](https://router.vuejs.org/api/interfaces/router#addRoute-): Add a new route to the router instance. `parentName` can be provided to add new route as the child of an existing route. - [`removeRoute()`](https://router.vuejs.org/api/interfaces/router#removeRoute-): Remove an existing route by its name. - [`getRoutes()`](https://router.vuejs.org/api/interfaces/router#getRoutes-): Get a full list of all the route records. - [`hasRoute()`](https://router.vuejs.org/api/interfaces/router#hasRoute-): Checks if a route with a given name exists. - [`resolve()`](https://router.vuejs.org/api/interfaces/router#resolve-): Returns the normalized version of a route location. Also includes an `href` property that includes any existing base. ```ts [Example] const router = useRouter() router.addRoute({ name: 'home', path: '/home', component: Home }) router.removeRoute('home') router.getRoutes() router.hasRoute('home') router.resolve({ name: 'home' }) ``` <note> `router.addRoute()` adds route details into an array of routes and it is useful while building [Nuxt plugins](https://nuxt.com/docs/4.x/directory-structure/app/plugins) while `router.push()` on the other hand, triggers a new navigation immediately and it is useful in pages, Vue components and composable. </note> ## Based on History API - [`back()`](https://router.vuejs.org/api/interfaces/router#back-): Go back in history if possible, same as `router.go(-1)`. - [`forward()`](https://router.vuejs.org/api/interfaces/router#forward-): Go forward in history if possible, same as `router.go(1)`. - [`go()`](https://router.vuejs.org/api/interfaces/router#go-): Move forward or backward through the history without the hierarchical restrictions enforced in `router.back()` and `router.forward()`. - [`push()`](https://router.vuejs.org/api/interfaces/router#push-): Programmatically navigate to a new URL by pushing an entry in the history stack. **It is recommended to use navigateTo instead.** - [`replace()`](https://router.vuejs.org/api/interfaces/router#replace-): Programmatically navigate to a new URL by replacing the current entry in the routes history stack. **It is recommended to use navigateTo instead.** ```ts [Example] const router = useRouter() router.back() router.forward() router.go(3) router.push({ path: '/home' }) router.replace({ hash: '#bio' }) ``` <read-more to="https://developer.mozilla.org/en-US/docs/Web/API/History" icon="i-simple-icons-mdnwebdocs" target="_blank"> Read more about the browser's History API. </read-more> ## Navigation Guards `useRouter` composable provides `afterEach`, `beforeEach` and `beforeResolve` helper methods that acts as navigation guards. However, Nuxt has a concept of **route middleware** that simplifies the implementation of navigation guards and provides a better developer experience. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/middleware"> </read-more> ## Promise and Error Handling - [`isReady()`](https://router.vuejs.org/api/interfaces/router#isReady-): Returns a Promise that resolves when the router has completed the initial navigation. - [`onError`](https://router.vuejs.org/api/interfaces/router#onError-): Adds an error handler that is called every time a non caught error happens during navigation. <read-more to="https://router.vuejs.org/api/interfaces/router#Methods-" icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs"> </read-more> ## Universal Router Instance If you do not have a `app/pages/` folder, then [`useRouter`](https://nuxt.com/docs/4.x/api/composables/use-router) will return a universal router instance with similar helper methods, but be aware that not all features may be supported or behave in exactly the same way as with `vue-router`. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # useRuntimeConfig > Access runtime config variables with the useRuntimeConfig composable. ## Usage ```vue [app/app.vue] <script setup lang="ts"> const config = useRuntimeConfig() </script> ``` ```ts [server/api/foo.ts] export default defineEventHandler((event) => { const config = useRuntimeConfig(event) }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> ## Define Runtime Config The example below shows how to set a public API base URL and a secret API token that is only accessible on the server. We should always define `runtimeConfig` variables inside `nuxt.config`. ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { // Private keys are only available on the server apiSecret: '123', // Public keys that are exposed to the client public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api', }, }, }) ``` <note> Variables that need to be accessible on the server are added directly inside `runtimeConfig`. Variables that need to be accessible on both the client and the server are defined in `runtimeConfig.public`. </note> <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> ## Access Runtime Config To access runtime config, we can use `useRuntimeConfig()` composable: ```ts [server/api/test.ts] export default defineEventHandler(async (event) => { const config = useRuntimeConfig(event) // Access public variables const result = await $fetch(`/test`, { baseURL: config.public.apiBase, headers: { // Access a private variable (only available on the server) Authorization: `Bearer ${config.apiSecret}`, }, }) return result }) ``` In this example, since `apiBase` is defined within the `public` namespace, it is universally accessible on both server and client-side, while `apiSecret` **is only accessible on the server-side**. ## Environment Variables It is possible to update runtime config values using a matching environment variable name prefixed with `NUXT_`. <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> ### Using the `.env` File We can set the environment variables inside the `.env` file to make them accessible during **development** and **build/generate**. ```ini [.env] NUXT_PUBLIC_API_BASE = "https://api.localhost:5555" NUXT_API_SECRET = "123" ``` <note> Any environment variables set within `.env` file are accessed using `process.env` in the Nuxt app during **development** and **build/generate**. </note> <warning> In **production runtime**, you should use platform environment variables and `.env` is not used. </warning> <read-more to="https://nuxt.com/docs/4.x/directory-structure/env"> </read-more> ## `app` namespace Nuxt uses `app` namespace in runtime-config with keys including `baseURL` and `cdnURL`. You can customize their values at runtime by setting environment variables. <note> This is a reserved namespace. You should not introduce additional keys inside `app`. </note> ### `app.baseURL` By default, the `baseURL` is set to `'/'`. However, the `baseURL` can be updated at runtime by setting the `NUXT_APP_BASE_URL` as an environment variable. Then, you can access this new base URL using `config.app.baseURL`: ```ts [/plugins/my-plugin.ts] export default defineNuxtPlugin((NuxtApp) => { const config = useRuntimeConfig() // Access baseURL universally const baseURL = config.app.baseURL }) ``` ### `app.cdnURL` This example shows how to set a custom CDN url and access them using `useRuntimeConfig()`. You can use a custom CDN for serving static assets inside `.output/public` using the `NUXT_APP_CDN_URL` environment variable. And then access the new CDN url using `config.app.cdnURL`. ```ts [server/api/foo.ts] export default defineEventHandler((event) => { const config = useRuntimeConfig(event) // Access cdnURL universally const cdnURL = config.app.cdnURL }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # useRuntimeHook > Registers a runtime hook in a Nuxt application and ensures it is properly disposed of when the scope is destroyed. <important> This composable is available in Nuxt v3.14+. </important> ```ts [Signature] function useRuntimeHook<THookName extends keyof RuntimeNuxtHooks> ( name: THookName, fn: RuntimeNuxtHooks[THookName] extends HookCallback ? RuntimeNuxtHooks[THookName] : never, ): void ``` ## Usage ### Parameters - `name`: The name of the runtime hook to register. You can see the full list of [runtime Nuxt hooks here](https://nuxt.com/docs/4.x/api/advanced/hooks#app-hooks-runtime). - `fn`: The callback function to execute when the hook is triggered. The function signature varies based on the hook name. ### Return Values The composable doesn't return a value, but it automatically unregisters the hook when the component's scope is destroyed. ## Example ```vue [pages/index.vue]twoslash <script setup lang="ts"> // Register a hook that runs every time a link is prefetched, but which will be // automatically cleaned up (and not called again) when the component is unmounted useRuntimeHook('link:prefetch', (link) => { console.log('Prefetching', link) }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/runtime-hook.ts) # useSeoMeta > The useSeoMeta composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. This helps you avoid common mistakes, such as using `name` instead of `property`, as well as typos - with over 100+ meta tags fully typed. <important> This is the recommended way to add meta tags to your site as it is XSS safe and has full TypeScript support. </important> <read-more to="https://nuxt.com/docs/4.x/getting-started/seo-meta"> </read-more> ## Usage ```vue [app/app.vue] <script setup lang="ts"> useSeoMeta({ title: 'My Amazing Site', ogTitle: 'My Amazing Site', description: 'This is my amazing site, let me tell you all about it.', ogDescription: 'This is my amazing site, let me tell you all about it.', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script> ``` When inserting tags that are reactive, you should use the computed getter syntax (`() => value`): ```vue [app/app.vue] <script setup lang="ts"> const title = ref('My title') useSeoMeta({ title, description: () => `This is a description for the ${title.value} page`, }) </script> ``` ## Parameters There are over 100 parameters. See the [full list of parameters in the source code](https://github.com/harlan-zw/zhead/blob/main/packages/zhead/src/metaFlat.ts#L1035). <read-more to="https://nuxt.com/docs/4.x/getting-started/seo-meta"> </read-more> ## Performance In most instances, SEO meta tags don't need to be reactive as search engine robots primarily scan the initial page load. For better performance, you can wrap your `useSeoMeta` calls in a server-only condition when the meta tags don't need to be reactive: ```vue [app/app.vue] <script setup lang="ts"> if (import.meta.server) { // These meta tags will only be added during server-side rendering useSeoMeta({ robots: 'index, follow', description: 'Static description that does not need reactivity', ogImage: 'https://example.com/image.png', // other static meta tags... }) } const dynamicTitle = ref('My title') // Only use reactive meta tags outside the condition when necessary useSeoMeta({ title: () => dynamicTitle.value, ogTitle: () => dynamicTitle.value, }) </script> ``` This previously used the [`useServerSeoMeta`](https://nuxt.com/docs/4.x/api/composables/use-server-seo-meta) composable, but it has been deprecated in favor of this approach. --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useServerSeoMeta > The useServerSeoMeta composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. <warning> `useServerSeoMeta` is deprecated. Wrap [`useSeoMeta`](https://nuxt.com/docs/4.x/api/composables/use-seo-meta) in an `if (import.meta.server)` block instead. The auto-import is removed under `future.compatibilityVersion: 5`. </warning> `useServerSeoMeta` lets you define your site's SEO meta tags as a flat object with full TypeScript support, exactly like [`useSeoMeta`](https://nuxt.com/docs/4.x/api/composables/use-seo-meta), but it only runs server-side and is tree-shaken from the client bundle. <read-more to="https://nuxt.com/docs/4.x/api/composables/use-seo-meta"> </read-more> For new code, use the server-only pattern directly: ```vue [app/app.vue] <script setup lang="ts"> if (import.meta.server) { useSeoMeta({ robots: 'index, follow', }) } </script> ``` Parameters are exactly the same as with [`useSeoMeta`](https://nuxt.com/docs/4.x/api/composables/use-seo-meta). <read-more to="https://nuxt.com/docs/4.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useState > The useState composable creates a reactive and SSR-friendly shared state. ## Usage ```ts // Create a reactive state and set default value const count = useState('counter', () => Math.round(Math.random() * 100)) ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/state-management"> </read-more> <important> Because the data inside `useState` will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. </important> <warning> `useState` is a reserved function name transformed by the compiler, so you should not name your own function `useState`. </warning> <video-accordion title="Watch a video from Alexander Lichter about why and when to use useState" video-id="mv0WcBABcIk"> </video-accordion> ## Using `shallowRef` If you don't need your state to be deeply reactive, you can combine `useState` with [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref). This can improve performance when your state contains large objects and arrays. ```ts const state = useState('my-shallow-state', () => shallowRef({ deep: 'not reactive' })) // isShallow(state) === true ``` ## Type ```ts [Signature] export function useState<T> (init?: () => T | Ref<T>): Ref<T> export function useState<T> (key: string, init?: () => T | Ref<T>): Ref<T> ``` - `key`: A unique key ensuring that data fetching is properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file and line number of the instance of [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) will be generated for you. - `init`: A function that provides initial value for the state when not initiated. This function can also return a `Ref`. - `T`: (typescript only) Specify the type of state ## Troubleshooting ### `Cannot stringify arbitrary non-POJOs` This error occurs when you try to store a non-serializable payload with `useState`, such as class instances. If you want to store class instances with `useState` that are not supported by Nuxt, you can use [`definePayloadPlugin`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#custom-reducerreviver) to add a custom serializer and deserializer for your classes. <read-more to="https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/state.ts) # App Config > Nuxt Kit provides a set of utilities to help you access and modify Nuxt app configuration. ## `updateAppConfig` Update the app configuration that will be applied to `nuxt.options.appConfig`. This is useful for modules to set default values that can be overridden by user configuration. The update is merged with the existing configuration using [`defu`](https://github.com/unjs/defu). ### Type ```ts function updateAppConfig (appConfig: Record<string, unknown>): void ``` ### Example ```ts import { defineNuxtModule, updateAppConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { updateAppConfig({ myModule: { option: 'value', }, }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/app-config.ts) # Auto-imports > Nuxt Kit provides a set of utilities to help you work with auto-imports. These functions allow you to register your own utils, composables and Vue APIs. Nuxt auto-imports helper functions, composables and Vue APIs to use across your application without explicitly importing them. Based on the directory structure, every Nuxt application can also use auto-imports for its own composables and plugins. With Nuxt Kit you can also add your own auto-imports. `addImports` and `addImportsDir` allow you to add imports to the Nuxt application. `addImportsSources` allows you to add listed imports from 3rd party packages to the Nuxt application. These utilities are powered by [`unimport`](https://github.com/unjs/unimport), which provides the underlying auto-import mechanism used in Nuxt. <note> These functions are designed for registering your own utils, composables and Vue APIs. For pages, components and plugins, please refer to the specific sections: [Pages](https://nuxt.com/docs/4.x/api/kit/pages), [Components](https://nuxt.com/docs/4.x/api/kit/components), [Plugins](https://nuxt.com/docs/4.x/api/kit/plugins). </note> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/expanding-nuxt-s-auto-imports?friend=nuxt"> Watch Vue School video about Auto-imports Nuxt Kit utilities. </tip> ## `addImports` Add imports to the Nuxt application. It makes your imports available in the Nuxt app context without the need to import them manually. <tip> To add imports for the Nitro server context, refer to the [`addServerImports`](https://nuxt.com/docs/4.x/api/kit/nitro#addserverimports) function. </tip> ### Usage ```tstwoslash import { addImports, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const names = [ 'useStoryblok', 'useStoryblokApi', 'useStoryblokBridge', 'renderRichText', 'RichTextSchema', ] names.forEach(name => addImports({ name, as: name, from: '@storyblok/vue' }), ) }, }) ``` ### Type ```ts function addImports (imports: NuxtImport | NuxtImport[]): void ``` ### Parameters `imports`: An object or an array of objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Import name to be detected. </td> </tr> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the import; if multiple imports have the same name, the one with the highest priority will be used. </td> </tr> <tr> <td> <code> disabled </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is disabled. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Record<string, any> </code> </td> <td> <code> false </code> </td> <td> Metadata of the import. </td> </tr> <tr> <td> <code> type </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is a pure type import. </td> </tr> <tr> <td> <code> typeFrom </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Use this as the <code> from </code> value when generating type declarations. </td> </tr> <tr> <td> <code> as </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Import as this name. </td> </tr> </tbody> </table> ## `addImportsDir` Add imports from a directory to the Nuxt application. It will automatically import all files from the directory and make them available in the Nuxt application without the need to import them manually. ### Usage ```tstwoslash import { addImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: '@vueuse/motion', configKey: 'motion', }, setup (options, nuxt) { const resolver = createResolver(import.meta.url) addImportsDir(resolver.resolve('./runtime/composables')) }, }) ``` ### Type ```ts function addImportsDir (dirs: string | string[], options?: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A string or an array of strings with the path to the directory to import from. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> { </span> <span class="sZSNi"> prepend </span> <span class="sDfIl"> ?: </span> <span class="sZSNi"> boolean </span> <span class="sDfIl"> } </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the import. If <code> prepend </code> is set to <code> true </code> , the imports will be prepended to the list of imports. </td> </tr> </tbody> </table> ## `addImportsSources` Add listed imports to the Nuxt application. ### Usage ```tstwoslash import { addImportsSources, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addImportsSources([ { package: '@vueuse/core' }, { from: 'h3', imports: [ 'defineEventHandler', 'getQuery', 'getRouterParams', 'readBody', 'sendRedirect', ], }, ]) }, }) ``` ### Type ```ts function addImportsSources (importSources: NuxtImportPresetSource | NuxtImportPresetSource[]): void ``` ### Parameters **importSources**: An object or an array of objects with the following properties: - `NuxtImportPreset` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> imports </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> (NuxtImportEntry </span> <span class="sDfIl"> | </span> <span class="sZSNi"> NuxtImportPreset)[] </span> </code> </td> <td> <code> true </code> </td> <td> An array of entries, which can be import names, import objects or nested presets. </td> </tr> </tbody> </table> - `NuxtPackageImportPreset` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> package </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Name of the package. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/imports.ts) # Builder > Nuxt Kit provides a set of utilities to help you work with the builder. These functions allow you to extend the Vite and webpack configurations. Nuxt have builders based on [Vite](https://github.com/nuxt/nuxt/tree/main/packages/vite) and [webpack](https://github.com/nuxt/nuxt/tree/main/packages/webpack). You can extend the config passed to each one using `extendViteConfig` and `extendWebpackConfig` functions. You can also add additional plugins via `addVitePlugin`, `addWebpackPlugin` and `addBuildPlugin`. ## `extendViteConfig` Extends the Vite configuration. Callback function can be called multiple times, when applying to both client and server builds. <warning> This hook is now deprecated, and we recommend using a Vite plugin instead with a `config` hook, or โ€” for environment-specific configuration โ€” the `applyToEnvironment` hook. </warning> ### Usage ```tstwoslash import { defineNuxtModule, extendViteConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendViteConfig((config) => { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('cross-fetch') }) }, }) ``` For environment-specific configuration in Nuxt 5+, use `addVitePlugin()` instead: ```tstwoslash import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // For global configuration (affects all environments) addVitePlugin(() => ({ name: 'my-global-plugin', config (config) { // This runs before environment setup config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('cross-fetch') }, })) // For environment-specific configuration addVitePlugin(() => ({ name: 'my-client-plugin', applyToEnvironment (environment) { return environment.name === 'client' }, configEnvironment (name, config) { // This only affects the client environment config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('client-only-package') }, })) }, }) ``` <warning> **Important:** The `config` hook runs before `applyToEnvironment` and modifies the global configuration. Use `configEnvironment` for environment-specific configuration changes. </warning> ### Type ```tstwoslash // @errors: 2391 import type { UserConfig as ViteConfig } from 'vite' import type { ExtendViteConfigOptions } from '@nuxt/kit' // ---cut--- function extendViteConfig (callback: ((config: ViteConfig) => void), options?: ExtendViteConfigOptions): void ``` <read-more to="https://vite.dev/config/" icon="i-simple-icons-vite" target="_blank"> Check out the Vite website for more information about its configuration. </read-more> ### Parameters **callback**: A callback function that will be called with the Vite configuration object. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> addVitePlugin() </code> with <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> addVitePlugin() </code> with <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `extendWebpackConfig` Extends the webpack configuration. Callback function can be called multiple times, when applying to both client and server builds. ### Usage ```tstwoslash import { defineNuxtModule, extendWebpackConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendWebpackConfig((config) => { config.module!.rules!.push({ test: /\.txt$/, use: 'raw-loader', }) }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Configuration as WebpackConfig } from 'webpack' import type { ExtendWebpackConfigOptions } from '@nuxt/kit' // ---cut--- function extendWebpackConfig (callback: ((config: WebpackConfig) => void), options?: ExtendWebpackConfigOptions): void ``` <read-more to="https://webpack.js.org/configuration/" icon="i-simple-icons-webpack" target="_blank"> Check out webpack website for more information about its configuration. </read-more> ### Parameters **callback**: A callback function that will be called with the webpack configuration object. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addVitePlugin` Append Vite plugin to the config. <warning> In Nuxt 5+, plugins registered with `server: false` or `client: false` options will not have their `config` or `configResolved` hooks called. Instead, use the `applyToEnvironment()` method instead for environment-specific plugins. </warning> ### Usage ```tstwoslash // @errors: 2307 // ---cut--- import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' import { svg4VuePlugin } from 'vite-plugin-svg4vue' export default defineNuxtModule({ meta: { name: 'nuxt-svg-icons', configKey: 'nuxtSvgIcons', }, defaults: { svg4vue: { assetsDirName: 'assets/icons', }, }, setup (options) { addVitePlugin(svg4VuePlugin(options.svg4vue)) // or, to add a vite plugin to only one environment addVitePlugin(() => ({ name: 'my-client-plugin', applyToEnvironment (environment) { return environment.name === 'client' }, // ... rest of your client-only plugin })) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Plugin as VitePlugin } from 'vite' import type { ExtendViteConfigOptions } from '@nuxt/kit' // ---cut--- function addVitePlugin (pluginOrGetter: VitePlugin | VitePlugin[] | (() => VitePlugin | VitePlugin[]), options?: ExtendViteConfigOptions): void ``` <tip> See [Vite website](https://vite.dev/guide/api-plugin) for more information about Vite plugins. You can also use [this repository](https://github.com/vitejs/awesome-vite#plugins) to find a plugin that suits your needs. </tip> ### Parameters **pluginOrGetter**: A Vite plugin instance or an array of Vite plugin instances. If a function is provided, it must return a Vite plugin instance or an array of Vite plugin instances. The function can also be async or return a Promise, which is useful for lazy-loading plugins: ```tstwoslash // @errors: 2307 import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // Lazy load the plugin - only imported when the build actually runs addVitePlugin(() => import('my-vite-plugin').then(r => r.default())) }, }) ``` **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addWebpackPlugin` Append webpack plugin to the config. ### Usage ```ts import EslintWebpackPlugin from 'eslint-webpack-plugin' import { addWebpackPlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'nuxt-eslint', configKey: 'eslint', }, defaults: nuxt => ({ include: [`${nuxt.options.srcDir}/**/*.{js,jsx,ts,tsx,vue}`], lintOnStart: true, }), setup (options, nuxt) { const webpackOptions = { ...options, context: nuxt.options.srcDir, files: options.include, lintDirtyModulesOnly: !options.lintOnStart, } addWebpackPlugin(new EslintWebpackPlugin(webpackOptions), { server: false }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { WebpackPluginInstance } from 'webpack' import type { ExtendWebpackConfigOptions } from '@nuxt/kit' // ---cut--- function addWebpackPlugin (pluginOrGetter: WebpackPluginInstance | WebpackPluginInstance[] | (() => WebpackPluginInstance | WebpackPluginInstance[]), options?: ExtendWebpackConfigOptions): void ``` <tip> See [webpack website](https://webpack.js.org/concepts/plugins/) for more information about webpack plugins. You can also use [this collection](https://webpack.js.org/awesome-webpack/#webpack-plugins) to find a plugin that suits your needs. </tip> ### Parameters **pluginOrGetter**: A webpack plugin instance or an array of webpack plugin instances. If a function is provided, it must return a webpack plugin instance or an array of webpack plugin instances. The function can also be async or return a Promise, enabling lazy-loading of plugins. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addBuildPlugin` Builder-agnostic version of `addVitePlugin` and `addWebpackPlugin`. It will add the plugin to both Vite and webpack configurations if they are present. ### Type ```tstwoslash // @errors: 2391 import type { ExtendConfigOptions } from '@nuxt/kit' import type { Plugin as VitePlugin } from 'vite' import type { WebpackPluginInstance } from 'webpack' import type { RspackPluginInstance } from '@rspack/core' interface AddBuildPluginFactory { vite?: () => VitePlugin | VitePlugin[] webpack?: () => WebpackPluginInstance | WebpackPluginInstance[] rspack?: () => RspackPluginInstance | RspackPluginInstance[] } // ---cut--- function addBuildPlugin (pluginFactory: AddBuildPluginFactory, options?: ExtendConfigOptions): void ``` ### Parameters **pluginFactory**: A factory function that returns an object with `vite` and/or `webpack` properties. These properties must be functions that return a Vite plugin instance or an array of Vite plugin instances and/or a webpack plugin instance or an array of webpack plugin instances. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `setBuildOutput` Set a build output provider for the given key. Build outputs are the contract between builders (Vite, webpack, Rspack, or a custom builder) and the Nitro server runtime: each key maps to a `nuxt/*` subpath import the server runtime resolves at build time. This is typically called from inside a builder, or from a module that participates in the build. <read-more to="https://nuxt.com/docs/4.x/guide/going-further/builders#the-build-output-contract"> Learn how the build output contract works. </read-more> ### Type ```tstwoslash // @errors: 2391 import type { NuxtBuildOutputs } from '@nuxt/schema' // ---cut--- function setBuildOutput<K extends keyof NuxtBuildOutputs> (key: K, provider: NuxtBuildOutputs[K]): void ``` ### Parameters **key**: The build output key. One of `serverEntry`, `clientManifest`, `clientPrecomputed`, `ssrStyles`, `entryChunkName` or `entryIds`. **provider**: The value for that key: a (possibly async) function returning the module body as a string, read lazily when the server build resolves the corresponding `nuxt/*` import. ### Example ```ts import { setBuildOutput } from '@nuxt/kit' // Re-export the built SSR entry by absolute specifier. setBuildOutput('serverEntry', () => `export { default } from ${JSON.stringify(serverEntryURL)}`) // Provide the serialized client manifest. setBuildOutput('clientManifest', () => `export default ${serializedManifest}`) // Re-export the emitted per-component styles map for `nuxt/styles`. setBuildOutput('ssrStyles', () => `export { default } from ${JSON.stringify(pathToFileURL(resolve(serverDir, 'styles.mjs')).href)}`) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/build.ts) # Compatibility > Nuxt Kit provides a set of utilities to help you check the compatibility of your modules with different Nuxt versions. Nuxt Kit utilities can be used in Nuxt 3, Nuxt 2 with Bridge and even Nuxt 2 without Bridge. To make sure your module is compatible with all versions, you can use the `checkNuxtCompatibility`, `assertNuxtCompatibility` and `hasNuxtCompatibility` functions. They will check if the current Nuxt version meets the constraints you provide. Also you can use `isNuxt2`, `isNuxt3` and `getNuxtVersion` functions for more granular checks. ## `checkNuxtCompatibility` Checks if constraints are met for the current Nuxt version. If not, returns an array of messages. Nuxt 2 version also checks for `bridge` support. ### Usage ```tstwoslash import { checkNuxtCompatibility, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (_options, nuxt) { const issues = await checkNuxtCompatibility({ nuxt: '^2.16.0' }, nuxt) if (issues.length) { console.warn('Nuxt compatibility issues found:\n' + issues.toString()) } else { // do something } }, }) ``` ### Type ```ts function checkNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<NuxtCompatibilityIssues> ``` ### Parameters **constraints**: Version and builder constraints to check against. It accepts the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> nuxt </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Nuxt version in semver format. Versions may be defined in Node.js way, for example: <code> >=2.15.0 <3.0.0 </code> . </td> </tr> <tr> <td> <code> bridge </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sbKd-"> false </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Specifies version constraints or disables compatibility for specific Nuxt builders like <code> vite </code> , <code> webpack </code> , or <code> rspack </code> . Use <code> false </code> to disable. </td> </tr> </tbody> </table> **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `assertNuxtCompatibility` Asserts that constraints are met for the current Nuxt version. If not, throws an error with the list of issues as string. ### Type ```tstwoslash // @errors: 2391 import type { Nuxt, NuxtCompatibility } from '@nuxt/schema' // ---cut--- function assertNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<true> ``` ### Parameters **constraints**: Version and builder constraints to check against. Refer to the [constraints table in `checkNuxtCompatibility`](https://nuxt.com/docs/4.x/api/kit/compatibility#parameters) for details. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `hasNuxtCompatibility` Checks if constraints are met for the current Nuxt version. Return `true` if all constraints are met, otherwise returns `false`. Nuxt 2 version also checks for `bridge` support. ### Usage ```tstwoslash import { defineNuxtModule, hasNuxtCompatibility } from '@nuxt/kit' export default defineNuxtModule({ async setup (_options, nuxt) { const usingNewPostcss = await hasNuxtCompatibility({ nuxt: '^2.16.0' }, nuxt) if (usingNewPostcss) { // do something } else { // do something else } }, }) ``` ### Type ```ts function hasNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<boolean> ``` ### Parameters **constraints**: Version and builder constraints to check against. Refer to the [constraints table in `checkNuxtCompatibility`](https://nuxt.com/docs/4.x/api/kit/compatibility#parameters) for details. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxtMajorVersion` Check if current Nuxt instance is of specified major version ### Usage ```tstwoslash import { defineNuxtModule, isNuxtMajorVersion } from '@nuxt/kit' export default defineNuxtModule({ setup () { if (isNuxtMajorVersion(3)) { // do something for Nuxt 3 } else { // do something else for other versions } }, }) ``` ### Type ```ts function isNuxtMajorVersion (major: number, nuxt?: Nuxt): boolean ``` ### Parameters **major**: Major version to check against. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxt3` Checks if the current Nuxt version is 3.x. <note> Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in @nuxt/kit v5 or a future major version. </note> ### Type ```ts function isNuxt3 (nuxt?: Nuxt): boolean ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxt2` Checks if the current Nuxt version is 2.x. <note> Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in @nuxt/kit v5 or a future major version. </note> ### Type ```ts function isNuxt2 (nuxt?: Nuxt): boolean ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `getNuxtVersion` Returns the current Nuxt version. ### Type ```ts function getNuxtVersion (nuxt?: Nuxt): string ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/compatibility.ts) # Components > Nuxt Kit provides a set of utilities to help you work with components. You can register components globally or locally, and also add directories to be scanned for components. Components are the building blocks of your Nuxt application. They are reusable Vue instances that can be used to create a user interface. In Nuxt, components from the components directory are automatically imported by default. However, if you need to import components from an alternative directory or wish to selectively import them as needed, `@nuxt/kit` provides the `addComponentsDir` and `addComponent` methods. These utils allow you to customize the component configuration to better suit your needs. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-components-and-component-directories?friend=nuxt"> Watch Vue School video about injecting components. </tip> ## `addComponentsDir` Register a directory to be scanned for components and imported only when used. Keep in mind, that this does not register components globally, until you specify `global: true` option. ### Usage ```ts export default defineNuxtModule({ meta: { name: '@nuxt/ui', configKey: 'ui', }, setup () { addComponentsDir({ path: resolve('./runtime/components'), prefix: 'U', pathPrefix: false, }) }, }) ``` ### Type ```ts function addComponentsDir (dir: ComponentsDir, opts: { prepend?: boolean } = {}): void ``` ### Parameters `dir` An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path (absolute or relative) to the directory containing your components. You can use Nuxt aliases (~ or @) to refer to directories inside project or directly use an npm package path similar to require. </td> </tr> <tr> <td> <code> pattern </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> false </code> </td> <td> Accept Pattern that will be run against specified path. </td> </tr> <tr> <td> <code> ignore </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Ignore patterns that will be run against specified path. </td> </tr> <tr> <td> <code> prefix </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Prefix all matched components with this string. </td> </tr> <tr> <td> <code> pathPrefix </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Prefix component name by its path. </td> </tr> <tr> <td> <code> prefetch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> preload </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> isAsync </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> This flag indicates, component should be loaded async (with a separate chunk) regardless of using Lazy prefix or not. </td> </tr> <tr> <td> <code> extendComponent </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> component </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Component </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> Component </span> <span class="sDfIl"> | </span> <span class="sDfIl"> void> </span> <span class="sDfIl"> | </span> <span class="sZSNi"> (Component </span> <span class="sDfIl"> | </span> <span class="sDfIl"> void </span> <span class="sZSNi"> ) </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called for each component found in the directory. It accepts a component object and should return a component object or a promise that resolves to a component object. </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers components to be globally available. </td> </tr> <tr> <td> <code> island </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers components as islands. You can read more about islands in <a href="https://nuxt.com/docs/4.x/api/components/nuxt-island"> <code> <NuxtIsland/> </code> </a> component description. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Watch specified path for changes, including file additions and file deletions. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Extensions supported by Nuxt builder. </td> </tr> <tr> <td> <code> transpile </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> auto </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sZSNi"> boolean </span> </code> </td> <td> <code> false </code> </td> <td> Transpile specified path using build.transpile. If set to <code> 'auto' </code> , it will set <code> transpile: true </code> if <code> node_modules/ </code> is in path. </td> </tr> </tbody> </table> `opts` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the directory will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addComponent` Register a component to be automatically imported. ### Usage ```ts import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: '@nuxt/image', configKey: 'image', }, setup () { const resolver = createResolver(import.meta.url) addComponent({ name: 'NuxtImg', filePath: resolver.resolve('./runtime/components/NuxtImg.vue'), }) addComponent({ name: 'NuxtPicture', filePath: resolver.resolve('./runtime/components/NuxtPicture.vue'), }) }, }) ``` ### Type ```ts function addComponent (options: AddComponentOptions): void ``` ### Parameters `options`: An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Component name. </td> </tr> <tr> <td> <code> filePath </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the component. </td> </tr> <tr> <td> <code> declarationPath </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to component's declaration file. It is used to generate components' <a href="https://nuxt.com/docs/4.x/api/kit/templates#addtypetemplate"> type templates </a> ; if not provided, <code> filePath </code> is used instead. </td> </tr> <tr> <td> <code> pascalName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Pascal case component name. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> kebabName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Kebab case component name. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> export </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Specify named or default export. If not provided, it will be set to <code> 'default' </code> . </td> </tr> <tr> <td> <code> shortPath </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Short path to the component. If not provided, it will be generated from the component path. </td> </tr> <tr> <td> <code> chunkName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Chunk name for the component. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> prefetch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> preload </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers component to be globally available. </td> </tr> <tr> <td> <code> island </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers component as island. You can read more about islands in <a href="https://nuxt.com/docs/4.x/api/components/nuxt-island"> <code> <NuxtIsland/> </code> </a> component description. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> This options indicates if component should render on client, server or both. By default, it will render on both client and server. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the component, if multiple components have the same name, the one with the highest priority will be used. </td> </tr> </tbody> </table> ### Example If you want to auto-import a component from an npm package, and the component is a named export (rather than the default), you can use the `export` option to specify it. ```ts import { addComponent, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // import { MyComponent as MyAutoImportedComponent } from 'my-npm-package' addComponent({ name: 'MyAutoImportedComponent', export: 'MyComponent', filePath: 'my-npm-package', }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/components.ts) # Context > Nuxt Kit provides a set of utilities to help you work with context. Nuxt modules allow you to enhance Nuxt's capabilities. They offer a structured way to keep your code organized and modular. If you're looking to break down your module into smaller components, Nuxt offers the `useNuxt` and `tryUseNuxt` functions. These functions enable you to conveniently access the Nuxt instance from the context without having to pass it as an argument. <note> When you're working with the `setup` function in Nuxt modules, Nuxt is already provided as the second argument. This means you can access it directly without needing to call `useNuxt()`. </note> ## `useNuxt` Get the Nuxt instance from the context. It will throw an error if Nuxt is not available. ### Usage ```ts import { useNuxt } from '@nuxt/kit' const setupSomeFeature = () => { const nuxt = useNuxt() // You can now use the nuxt instance console.log(nuxt.options) } ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function useNuxt (): Nuxt ``` ### Return Value The `useNuxt` function returns the Nuxt instance, which contains all the options and methods available in Nuxt. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> options </code> </td> <td> <code> NuxtOptions </code> </td> <td> The resolved Nuxt configuration. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code> NuxtHookRegistry<NuxtHooks> </code> </td> <td> The Nuxt hook system. Allows registering and listening to lifecycle events. </td> </tr> <tr> <td> <code> hook </code> </td> <td> <code> (name: string, (...args: any[]) => Promise<void> | void) => () => void </code> </td> <td> Shortcut for <code> nuxt.hooks.hook </code> . Registers a single callback for a specific lifecycle hook. </td> </tr> <tr> <td> <code> callHook </code> </td> <td> <code> (name: string, ...args: any[]) => Promise<any> </code> </td> <td> Shortcut for <code> nuxt.hooks.callHook </code> . Triggers a lifecycle hook manually and runs all registered callbacks. </td> </tr> <tr> <td> <code> addHooks </code> </td> <td> <code> (configHooks: NuxtNestedHooks) => () => void </code> </td> <td> Shortcut for <code> nuxt.hooks.addHooks </code> . Registers multiple hooks at once. </td> </tr> </tbody> </table> ### Example <code-group> ```ts [setupTranspilation.ts]twoslash import { useNuxt } from '@nuxt/kit' export const setupTranspilation = () => { const nuxt = useNuxt() if (nuxt.options.builder === '@nuxt/webpack-builder') { nuxt.options.build.transpile ||= [] nuxt.options.build.transpile.push('xstate') } } ``` ```ts [module.ts]twoslash // @module: esnext // @filename: setupTranspilation.ts export const setupTranspilation = () => {} // @filename: module.ts import { defineNuxtModule } from '@nuxt/kit' // ---cut--- import { setupTranspilation } from './setupTranspilation' export default defineNuxtModule({ setup () { setupTranspilation() }, }) ``` </code-group> ## `tryUseNuxt` Get the Nuxt instance from the context. It will return `null` if Nuxt is not available. ### Usage ```tstwoslash import { tryUseNuxt } from '@nuxt/kit' function setupSomething () { const nuxt = tryUseNuxt() if (nuxt) { // You can now use the nuxt instance console.log(nuxt.options) } else { console.log('Nuxt is not available') } } ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function tryUseNuxt (): Nuxt | null ``` ### Return Value The `tryUseNuxt` function returns the Nuxt instance if available, or `null` if Nuxt is not available. The Nuxt instance as described in the `useNuxt` section. ### Example <code-group> ```ts [requireSiteConfig.ts]twoslash declare module '@nuxt/schema' { interface NuxtOptions { siteConfig: SiteConfig } } // ---cut--- import { tryUseNuxt } from '@nuxt/kit' interface SiteConfig { title?: string } export const requireSiteConfig = (): SiteConfig => { const nuxt = tryUseNuxt() if (!nuxt) { return {} } return nuxt.options.siteConfig } ``` ```ts [module.ts]twoslash // @module: esnext // @filename: requireSiteConfig.ts interface SiteConfig { title?: string } export const requireSiteConfig = (): SiteConfig => { return {} } // @filename: module.ts // ---cut--- import { defineNuxtModule, useNuxt } from '@nuxt/kit' import { requireSiteConfig } from './requireSiteConfig' export default defineNuxtModule({ setup (_, nuxt) { const config = requireSiteConfig() nuxt.options.app.head.title = config.title }, }) ``` </code-group> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/context.ts) # Examples > Examples of Nuxt Kit utilities in use. ## Accessing Nuxt Vite Config If you are building an integration that needs access to the runtime Vite or webpack config that Nuxt uses, it is possible to extract this using Kit utilities. Some examples of projects doing this already: - [histoire](https://github.com/histoire-dev/histoire/blob/main/packages/histoire-plugin-nuxt/src/index.ts) - [nuxt-vitest](https://github.com/danielroe/nuxt-vitest/blob/main/packages/nuxt-vitest/src/config.ts) - [@storybook-vue/nuxt](https://github.com/storybook-vue/storybook-nuxt/blob/main/packages/storybook-nuxt/src/preset.ts) Here is a brief example of how you might access the Vite config from a project; you could implement a similar approach to get the webpack configuration. ```js import { buildNuxt, loadNuxt } from '@nuxt/kit' // https://github.com/nuxt/nuxt/issues/14534 async function getViteConfig () { const nuxt = await loadNuxt({ cwd: process.cwd(), dev: false, overrides: { ssr: false } }) return new Promise((resolve, reject) => { nuxt.hook('vite:extend', (config) => { resolve(config) throw new Error('_stop_') }) buildNuxt(nuxt).catch((err) => { if (!err.toString().includes('_stop_')) { reject(err) } }) }).finally(() => nuxt.close()) } const viteConfig = await getViteConfig() console.log(viteConfig) ``` # Head > Nuxt Kit provides utilities to help you manage head configuration in modules. ## `setGlobalHead` Sets global head configuration for your Nuxt application. This utility allows modules to programmatically configure meta tags, links, scripts, and other head elements that will be applied across all pages. The provided head configuration will be merged with any existing head configuration using deep merging, with your provided values taking precedence. <tip> This is particularly useful for modules that need to inject global meta tags, stylesheets, or scripts into the application head. </tip> ### Type ```tstwoslash // @errors: 2391 // ---cut--- import type { SerializableHead } from '@unhead/vue/types' interface AppHeadMetaObject extends SerializableHead { charset?: string viewport?: string } function setGlobalHead (head: AppHeadMetaObject): void ``` ### Parameters #### `head` **Type**: `AppHeadMetaObject` An object containing head configuration. All properties are optional and will be merged with existing configuration: - `charset`: Character encoding for the document - `viewport`: Viewport meta tag configuration - `meta`: Array of meta tag objects - `link`: Array of link tag objects (stylesheets, icons, etc.) - `style`: Array of inline style tag objects - `script`: Array of script tag objects - `noscript`: Array of noscript tag objects - `title`: Default page title - `titleTemplate`: Template for formatting page titles - `bodyAttrs`: Attributes to add to the `<body>` tag - `htmlAttrs`: Attributes to add to the `<html>` tag ### Example #### Adding Global Meta Tags ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ meta: [ { name: 'theme-color', content: '#ffffff' }, { name: 'author', content: 'Your Name' }, ], }) }, }) ``` #### Injecting Global Stylesheets ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ link: [ { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap', }, ], }) }, }) ``` #### Adding Global Scripts ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ script: [ { src: 'https://cdn.example.com/analytics.js', async: true, defer: true, }, ], }) }, }) ``` #### Setting HTML Attributes ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ htmlAttrs: { lang: 'en', dir: 'ltr', }, bodyAttrs: { class: 'custom-body-class', }, }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/head.ts) # Layers > Nuxt Kit provides utilities to help you work with layers and their directory structures. Nuxt layers provide a powerful way to share and extend functionality across projects. When working with layers in modules, you often need to access directory paths from each layer. Nuxt Kit provides the `getLayerDirectories` utility to access resolved directory paths for all layers in your Nuxt application. ## `getLayerDirectories` Get the resolved directory paths for all layers in a Nuxt application. This function provides a structured way to access layer directories without directly accessing the private `nuxt.options._layers` property. ### Usage ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Access directories from all layers for (const [index, layer] of layerDirs.entries()) { console.log(`Layer ${index}:`) console.log(` Root: ${layer.root}`) console.log(` App: ${layer.app}`) console.log(` Server: ${layer.server}`) console.log(` Pages: ${layer.appPages}`) // ... other directories } }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function getLayerDirectories (nuxt?: Nuxt): LayerDirectories[] interface LayerDirectories { /** Nuxt rootDir (`/` by default) */ readonly root: string /** Nitro source directory (`/server` by default) */ readonly server: string /** Local modules directory (`/modules` by default) */ readonly modules: string /** Shared directory (`/shared` by default) */ readonly shared: string /** Public directory (`/public` by default) */ readonly public: string /** Nuxt srcDir (`/app/` by default) */ readonly app: string /** Layouts directory (`/app/layouts` by default) */ readonly appLayouts: string /** Middleware directory (`/app/middleware` by default) */ readonly appMiddleware: string /** Pages directory (`/app/pages` by default) */ readonly appPages: string /** Plugins directory (`/app/plugins` by default) */ readonly appPlugins: string } ``` ### Parameters **nuxt** (optional): The Nuxt instance to get layers from. If not provided, the function will use the current Nuxt context. ### Return Value The `getLayerDirectories` function returns an array of `LayerDirectories` objects, one for each layer in the application. **Layer Priority Ordering**: The layers are ordered by priority, where: - The **first layer** is the user/project layer (highest priority) - **Earlier layers override later layers** in the array - **Base layers appear last** in the array (lowest priority) This ordering matches Nuxt's layer resolution system, where user-defined configurations and files take precedence over those from base layers. **LayerDirectories**: An object containing the resolved directory paths for a layer. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> root </code> </td> <td> <code> string </code> </td> <td> The root directory of the layer (equivalent to <code> rootDir </code> ) </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> string </code> </td> <td> The server directory for Nitro server-side code </td> </tr> <tr> <td> <code> modules </code> </td> <td> <code> string </code> </td> <td> The local modules directory </td> </tr> <tr> <td> <code> shared </code> </td> <td> <code> string </code> </td> <td> The shared directory for code used by both client and server </td> </tr> <tr> <td> <code> app </code> </td> <td> <code> string </code> </td> <td> The source directory of the layer (equivalent to <code> srcDir </code> ) </td> </tr> <tr> <td> <code> public </code> </td> <td> <code> string </code> </td> <td> The public directory for static assets </td> </tr> <tr> <td> <code> appLayouts </code> </td> <td> <code> string </code> </td> <td> The layouts directory for Vue layout components </td> </tr> <tr> <td> <code> appMiddleware </code> </td> <td> <code> string </code> </td> <td> The middleware directory for route middleware </td> </tr> <tr> <td> <code> appPages </code> </td> <td> <code> string </code> </td> <td> The pages directory for file-based routing </td> </tr> <tr> <td> <code> appPlugins </code> </td> <td> <code> string </code> </td> <td> The plugins directory for Nuxt plugins </td> </tr> </tbody> </table> ### Example **Processing files from all layers:** ```tstwoslash // @errors: 2307 // ---cut--- import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { resolve } from 'pathe' import { globby } from 'globby' export default defineNuxtModule({ async setup () { const layerDirs = getLayerDirectories() // Find all component files across layers // Note: layerDirs[0] is the user layer (highest priority) // Later layers in the array have lower priority const componentFiles = [] for (const [index, layer] of layerDirs.entries()) { const files = await globby('**/*.vue', { cwd: resolve(layer.app, 'components'), absolute: true, }) console.log(`Layer ${index} (${index === 0 ? 'user' : 'base'}):`, files.length, 'components') componentFiles.push(...files) } }, }) ``` **Adding templates from multiple layers:** ```tstwoslash import { addTemplate, defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { basename, resolve } from 'pathe' import { existsSync } from 'node:fs' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Add a config file from each layer that has one for (const dirs of layerDirs) { const configPath = resolve(dirs.app, 'my-module.config.ts') if (existsSync(configPath)) { addTemplate({ filename: `my-module-${basename(dirs.root)}.config.ts`, src: configPath, }) } } }, }) ``` **Respecting layer priority:** ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { resolve } from 'pathe' import { existsSync, readFileSync } from 'node:fs' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Find the first (highest priority) layer that has a specific config file // This respects the layer priority system let configContent = null for (const dirs of layerDirs) { const configPath = resolve(dirs.app, 'my-config.json') if (existsSync(configPath)) { configContent = readFileSync(configPath, 'utf-8') console.log(`Using config from layer: ${dirs.root}`) break // Use the first (highest priority) config found } } // Alternative: Collect configs from all layers, with user layer taking precedence const allConfigs = {} for (const dirs of layerDirs.reverse()) { // Process from lowest to highest priority const configPath = resolve(dirs.app, 'my-config.json') if (existsSync(configPath)) { const config = JSON.parse(readFileSync(configPath, 'utf-8')) Object.assign(allConfigs, config) // Later assignments override earlier ones } } }, }) ``` **Checking for layer-specific directories:** ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { existsSync } from 'node:fs' import { resolve } from 'pathe' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Find layers that have a specific custom directory const layersWithAssets = layerDirs.filter((layer) => { return existsSync(resolve(layer.app, 'assets')) }) console.log(`Found ${layersWithAssets.length} layers with assets directory`) }, }) ``` <note> The `getLayerDirectories` function includes caching via a WeakMap to avoid recomputing directory paths for the same layers repeatedly, improving performance when called multiple times. </note> <note> Directory paths returned by this function always include a trailing slash for consistency. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/layers.ts) # Layout > Nuxt Kit provides a set of utilities to help you work with layouts. Layouts is used to be a wrapper around your pages. It can be used to wrap your pages with common components, for example, a header and a footer. Layouts can be registered using `addLayout` utility. ## `addLayout` Register template as layout and add it to the layouts. <note> In Nuxt 2 `error` layout can also be registered using this utility. In Nuxt 3+ `error` layout [replaced](https://nuxt.com/docs/4.x/getting-started/error-handling#error-page) with `error.vue` page in project root. </note> ### Usage ```tstwoslash import { addLayout, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addLayout({ src: resolve('templates/custom-layout.ts'), filename: 'custom-layout.ts', }, 'custom') }, }) ``` ### Type ```ts function addLayout (layout: NuxtTemplate | string, name: string): void ``` ### Parameters **layout**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> </tbody> </table> **name**: The name to register the layout under (e.g., `default`, `custom`, etc.). ### Example This will register a layout named `custom` that wraps pages with a header and footer. ```tstwoslash import { addLayout, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addLayout({ write: true, filename: 'my-layout.vue', getContents: () => `<template> <div> <header>My Header</header> <slot /> <footer>My Footer</footer> </div> </template>`, }, 'custom') }, }) ``` You can then use this layout in your pages: ```vue [app/pages/about.vue] <script setup lang="ts"> definePageMeta({ layout: 'custom', }) </script> <template> <div>About Page</div> </template> ``` <warning> Due to the lack of support for virtual `.vue` files by `@vitejs/plugin-vue`, you can work around this limitation by passing `write: true` to the first argument of `addLayout`. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/layout.ts) # Logging > Nuxt Kit provides a set of utilities to help you work with logging. These functions allow you to log messages with extra features. Nuxt provides a logger instance that you can use to log messages with extra features. `useLogger` allows you to get a logger instance. ## `useLogger` Returns a logger instance. It uses [consola](https://github.com/unjs/consola) under the hood. ### Usage ```tstwoslash import { defineNuxtModule, useLogger } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const logger = useLogger('my-module') logger.info('Hello from my module!') }, }) ``` ### Type ```ts function useLogger (tag?: string, options?: NuxtLoggerOptions): NuxtLogger ``` ### Parameters **tag**: A tag to suffix all log messages with, displayed on the right near the timestamp. **options**: Logger options, such as `level`, `reporters`, `defaults` and `formatOptions`. ### Example ```tstwoslash import { defineNuxtModule, useLogger } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const logger = useLogger('my-module', { level: options.quiet ? 0 : 3 }) logger.info('Hello from my module!') }, }) ``` ## `useTerminal` Returns a set of primitives for interacting with the user's terminal. When Nuxt is running inside an interactive host such as the `nuxt dev` terminal UI, prompts, tasks and notifications are handed to it, so they are answerable and rendered in one place. Otherwise they fall back to logging. ### Usage ```tstwoslash declare function runPackageInstall (name: string): Promise<void> // ---cut--- import { defineNuxtModule, useTerminal } from '@nuxt/kit' export default defineNuxtModule({ async setup () { const terminal = useTerminal() const install = await terminal.prompt('Do you want to install `my-module`?', { type: 'confirm' }) if (!install) { return } const task = terminal.startTask('Installing `my-module`...') // run your actual task await runPackageInstall('my-module') task.stop('Installed `my-module`') }, }) ``` ### Type ```ts function useTerminal (): NuxtTerminal interface NuxtTerminal { readonly interactive: boolean withTerminal: <T>(work: () => Promise<T>) => Promise<T> prompt: (message: string, options?: NuxtPromptOptions) => Promise<any> startTask: (label: string) => NuxtTerminalTask notify: (notification: NuxtTerminalNotification) => NuxtTerminalNotice } ``` ### Properties **interactive**: Whether an interactive host is present. When `false`, the primitives below log to the current process streams instead. **withTerminal**: Borrows the terminal for the duration of `work`, suspending any host UI and releasing `stdin`. Use it when you need to write to the terminal or read from `stdin` directly. Concurrent callers are serialised, and a nested call from within a borrow runs immediately. **prompt**: Asks the user a question, borrowing the terminal for as long as the prompt is open. Takes the same options as `logger.prompt`. **startTask**: Starts a long-running task, rendered on the host's status surface where available. Finish it with `task.stop(message?, outcome?)`, or change its label with `task.update(label)`. **notify**: Shows a message and holds it on screen until the user acknowledges it or `notice.dismiss()` is called. `notice.dismissed` settles once the notice is gone. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/logger.ts) # Modules > Nuxt Kit provides a set of utilities to help you create and use modules. You can use these utilities to create your own modules or to reuse existing modules. Modules are the building blocks of Nuxt. Kit provides a set of utilities to help you create and use modules. You can use these utilities to create your own modules or to reuse existing modules. For example, you can use the `defineNuxtModule` function to define a module and specify dependencies using the `moduleDependencies` option. ## `defineNuxtModule` Define a Nuxt module, automatically merging defaults with user provided options, installing any hooks that are provided, and calling an optional setup function for full control. ### Usage ```tstwoslash import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, defaults: { enabled: true, }, setup (options) { if (options.enabled) { console.log('My Nuxt module is enabled!') } }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { ModuleDefinition, ModuleOptions, NuxtModule } from '@nuxt/schema' // ---cut--- export function defineNuxtModule<TOptions extends ModuleOptions> ( definition?: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>, ): NuxtModule<TOptions, TOptions, false> export function defineNuxtModule<TOptions extends ModuleOptions> (): { with: <TOptionsDefaults extends Partial<TOptions>> ( definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>, ) => NuxtModule<TOptions, TOptionsDefaults, true> } ``` ### Parameters **definition**: A module definition object or a module function. The module definition object should contain the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> meta </code> </td> <td> <code> ModuleMeta </code> </td> <td> <code> false </code> </td> <td> Metadata of the module. It defines the module name, version, config key and compatibility. </td> </tr> <tr> <td> <code> defaults </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> T </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> T) </span> </code> </td> <td> <code> false </code> </td> <td> Default options for the module. If a function is provided, it will be called with the Nuxt instance as the first argument. </td> </tr> <tr> <td> <code> schema </code> </td> <td> <code> T </code> </td> <td> <code> false </code> </td> <td> Schema for the module options. If provided, options will be applied to the schema. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Partial </span> <span class="sDfIl"> < </span> <span class="sZSNi"> NuxtHooks </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Hooks to be installed for the module. If provided, the module will install the hooks. </td> </tr> <tr> <td> <code> moduleDependencies </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> ModuleDependency </span> <span class="sDfIl"> > </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> ModuleDependency </span> <span class="sDfIl"> > </span> <span class="sZSNi"> ) </span> </code> </td> <td> <code> false </code> </td> <td> Dependencies on other modules with version constraints and configuration. Can be an object or a function that receives the Nuxt instance. See <a href="https://nuxt.com/docs/4.x/api/kit/modules#specifying-module-dependencies"> example </a> . </td> </tr> <tr> <td> <code> onInstall </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void> </span> </code> </td> <td> <code> false </code> </td> <td> Lifecycle hook called when the module is first installed. Requires <code> meta.name </code> and <code> meta.version </code> to be defined. </td> </tr> <tr> <td> <code> onUpgrade </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> , </span> <span class="s1nJG"> options </span> <span class="sDfIl"> : </span> <span class="s52Pk"> T </span> <span class="sDfIl"> , </span> <span class="s1nJG"> previousVersion </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void> </span> </code> </td> <td> <code> false </code> </td> <td> Lifecycle hook called when the module is upgraded to a newer version. Requires <code> meta.name </code> and <code> meta.version </code> to be defined. </td> </tr> <tr> <td> <code> setup </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s8R28"> this </span> <span class="sDfIl"> : </span> <span class="s52Pk"> void </span> <span class="sDfIl"> , </span> <span class="s1nJG"> resolvedOptions </span> <span class="sDfIl"> : </span> <span class="s52Pk"> T </span> <span class="sDfIl"> , </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void </span> <span class="sDfIl"> | </span> <span class="sbKd-"> false </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ModuleSetupInstallResult </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Setup function for the module. If provided, the module will call the setup function. </td> </tr> </tbody> </table> ### Example #### Using `configKey` to Make Your Module Configurable When defining a Nuxt module, you can set a `configKey` to specify how users should configure the module in their `nuxt.config`. ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, defaults: { // Module options enabled: true, }, setup (options) { if (options.enabled) { console.log('My Nuxt module is enabled!') } }, }) ``` Users can provide options for this module under the corresponding key in `nuxt.config`. ```ts export default defineNuxtConfig({ myModule: { enabled: false, }, }) ``` Users can also completely disable a module by setting the config key to `false`. This prevents the module's setup function from running while still generating types for module options. ```ts export default defineNuxtConfig({ // Disable the module entirely myModule: false, }) ``` <tip> This is particularly useful when you want to disable modules inherited from [Nuxt layers](https://nuxt.com/docs/4.x/guide/going-further/layers#disabling-modules-from-layers). </tip> #### Defining Module Compatibility Requirements If you're developing a Nuxt module and using APIs that are only supported in specific Nuxt versions, it's highly recommended to include `compatibility.nuxt`. ```ts export default defineNuxtModule({ meta: { name: '@nuxt/icon', configKey: 'icon', compatibility: { // Required nuxt version in semver format. nuxt: '>=3.0.0', // or use '^3.0.0' }, }, setup () { const resolver = createResolver(import.meta.url) // Implement }, }) ``` If the user tries to use your module with an incompatible Nuxt version, they will receive a warning in the console. ```terminal WARN Module @nuxt/icon is disabled due to incompatibility issues: - [nuxt] Nuxt version ^3.1.0 is required but currently using 3.0.0 ``` #### Type Safety for Resolved Options with `.with()` When you need type safety for your resolved/merged module options, you can use the `.with()` method. This enables TypeScript to properly infer the relationship between your module's defaults and the final resolved options that your setup function receives. ```ts import { defineNuxtModule } from '@nuxt/kit' // Define your module options interface interface ModuleOptions { apiKey: string baseURL: string timeout?: number retries?: number } export default defineNuxtModule<ModuleOptions>().with({ meta: { name: '@nuxtjs/my-api', configKey: 'myApi', }, defaults: { baseURL: 'https://api.example.com', timeout: 5000, retries: 3, }, setup (resolvedOptions, nuxt) { // resolvedOptions is properly typed as: // { // apiKey: string // Required, no default provided // baseURL: string // Required, has default value // timeout: number // Optional, has default value // retries: number // Optional, has default value // } console.log(resolvedOptions.baseURL) // โœ… TypeScript knows this is always defined console.log(resolvedOptions.timeout) // โœ… TypeScript knows this is always defined console.log(resolvedOptions.retries) // โœ… TypeScript knows this is always defined }, }) ``` Without using `.with()`, the `resolvedOptions` parameter would be typed as the raw `ModuleOptions` interface, where `timeout` and `retries` could be `undefined` even when defaults are provided. The `.with()` method enables TypeScript to understand that default values make those properties non-optional in the resolved options. #### Using Lifecycle Hooks for Module Installation and Upgrade You can define lifecycle hooks that run when your module is first installed or upgraded to a new version. These hooks are useful for performing one-time setup tasks, database migrations, or cleanup operations. <important> For lifecycle hooks to work, you **must** provide both `meta.name` and `meta.version` in your module definition. The hooks use these values to track the module's installation state in the project's `.nuxtrc` file. </important> Lifecycle hooks run before the main `setup` function, and if a hook throws an error, it's logged but doesn't stop the build process. **onInstall** runs only once when the module is first added to a project. **onUpgrade** runs each time the module version increases (using semver comparison) โ€” but only once for each version bump. ##### Example ```ts import { defineNuxtModule } from '@nuxt/kit' import { isLess } from 'verkit' export default defineNuxtModule({ meta: { name: 'my-awesome-module', version: '1.2.0', // Required for lifecycle hooks configKey: 'myAwesomeModule', }, defaults: { apiKey: '', enabled: true, }, onInstall (nuxt) { // This runs only when the module is first installed console.log('Setting up my-awesome-module for the first time!') // You might want to: // - Create initial configuration files // - Set up database schemas // - Display welcome messages // - Perform initial data migration }, onUpgrade (nuxt, options, previousVersion) { // This runs when the module is upgraded to a newer version console.log(`Upgrading my-awesome-module from ${previousVersion} to 1.2.0`) // You might want to: // - Migrate configuration files // - Update database schemas // - Clean up deprecated files // - Display upgrade notes if (isLess(previousVersion, '1.1.0')) { console.log('โš ๏ธ Breaking changes in 1.1.0 - please check the migration guide') } }, setup (options, nuxt) { // Regular setup logic runs on every build if (options.enabled) { // Configure the module } }, }) ``` #### Specifying Module Dependencies You can use the `moduleDependencies` option to declare dependencies on other modules. This provides a robust way to ensure proper setup order, version compatibility, and configuration management. The `moduleDependencies` option can be either an object or a function that receives the Nuxt instance: ##### Example ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', }, moduleDependencies: { '@nuxtjs/tailwindcss': { // Specify a version constraint (semver format) version: '>=6.0.0', // Configuration that overrides user settings overrides: { exposeConfig: true, }, // Configuration that sets defaults but respects user settings defaults: { config: { darkMode: 'class', }, }, }, '@nuxtjs/fontaine': { // Optional dependencies won't be installed but ensure that options // can be set if they _are_ installed optional: true, defaults: { fonts: [ { family: 'Roboto', fallbacks: ['Impact'], }, ], }, }, }, setup (options, nuxt) { }, }) ``` You can also use a function to dynamically determine dependencies based on the Nuxt configuration: ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', }, moduleDependencies (nuxt) { const dependencies: Record<string, any> = { '@nuxtjs/tailwindcss': { version: '>=6.0.0', }, } // Conditionally add dependencies based on Nuxt config if (nuxt.options.experimental?.someFeature) { dependencies['@nuxtjs/fontaine'] = { optional: true, } } return dependencies }, setup (options, nuxt) { // Your setup logic runs after all dependencies are initialized }, }) ``` ## `installModule` <callout type="warning"> **Deprecated:** Use the [`moduleDependencies`](https://nuxt.com/docs/4.x/api/kit/modules#specifying-module-dependencies) option in `defineNuxtModule` instead. The `installModule` function will be removed (or may become non-blocking) in a future version. </callout> Install specified Nuxt module programmatically. This is helpful when your module depends on other modules. You can pass the module options as an object to `inlineOptions` and they will be passed to the module's `setup` function. ### Usage ```tstwoslash import { defineNuxtModule, installModule } from '@nuxt/kit' export default defineNuxtModule({ async setup () { // will install @nuxtjs/fontaine with Roboto font and Impact fallback await installModule('@nuxtjs/fontaine', { // module configuration fonts: [ { family: 'Roboto', fallbacks: ['Impact'], fallbackName: 'fallback-a', }, ], }) }, }) ``` ### Type ```ts async function installModule (moduleToInstall: string | NuxtModule, inlineOptions?: any, nuxt?: Nuxt) ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> moduleToInstall </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> NuxtModule </span> </code> </td> <td> <code> true </code> </td> <td> The module to install. Can be either a string with the module name or a module object itself. </td> </tr> <tr> <td> <code> inlineOptions </code> </td> <td> <code> any </code> </td> <td> <code> false </code> </td> <td> An object with the module options to be passed to the module's <code> setup </code> function. </td> </tr> <tr> <td> <code> nuxt </code> </td> <td> <code> Nuxt </code> </td> <td> <code> false </code> </td> <td> Nuxt instance. If not provided, it will be retrieved from the context via <code> useNuxt() </code> call. </td> </tr> </tbody> </table> ### Example ```ts import { defineNuxtModule, installModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (options, nuxt) { // will install @nuxtjs/fontaine with Roboto font and Impact fallback await installModule('@nuxtjs/fontaine', { // module configuration fonts: [ { family: 'Roboto', fallbacks: ['Impact'], fallbackName: 'fallback-a', }, ], }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/tree/main/packages/kit/src/module) # Nitro > Nuxt Kit provides a set of utilities to help you work with Nitro. These functions allow you to add server handlers, plugins, and prerender routes. Nitro is an open source TypeScript framework to build ultra-fast web servers. Nuxt uses Nitro as its server engine. You can use `useNitro` to access the Nitro instance (or `tryUseNitro` if your module should also work without Nitro), `addServerHandler` to add a server handler, `addDevServerHandler` to add a server handler to be used only in development mode, `addNitroPlugin` to add a plugin to extend Nitro's runtime behavior, and `addPrerenderRoutes` to add routes to be prerendered by Nitro. ## `addServerHandler` Adds a Nitro server handler. Use this if you want to create server middleware or a custom route. ### Usage ```tstwoslash import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) addServerHandler({ route: '/robots.txt', handler: resolve('./runtime/robots.get'), }) }, }) ``` ### Type ```ts function addServerHandler (handler: NitroEventHandler): void ``` ### Parameters **handler**: A handler object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> handler </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to event handler. </td> </tr> <tr> <td> <code> route </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path prefix or route. If an empty string used, will be used as a middleware. </td> </tr> <tr> <td> <code> middleware </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Specifies this is a middleware handler. Middleware are called on every route and should normally return nothing to pass to the next handlers. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Use lazy loading to import the handler. This is useful when you only want to load the handler on demand. </td> </tr> <tr> <td> <code> method </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Router method matcher. If handler name contains method name, it will be used as a default value. </td> </tr> </tbody> </table> ### Example #### Basic Usage You can use `addServerHandler` to add a server handler from your module. <code-group> ```ts [module.ts]twoslash import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) addServerHandler({ route: '/robots.txt', handler: resolve('./runtime/robots.get'), }) }, }) ``` ```ts [runtime/robots.get.ts]twoslash export default defineEventHandler(() => { return { body: `User-agent: *\nDisallow: /`, } }) ``` </code-group> When you access `/robots.txt`, it will return the following response: ```txt User-agent: * Disallow: / ``` ## `addDevServerHandler` Adds a Nitro server handler to be used only in development mode. This handler will be excluded from production build. ### Usage ```tstwoslash import { defineEventHandler } from 'h3' import { addDevServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addDevServerHandler({ handler: defineEventHandler(() => { return { body: `Response generated at ${new Date().toISOString()}`, } }), route: '/_handler', }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NitroDevEventHandler } from 'nitropack/types' // ---cut--- function addDevServerHandler (handler: NitroDevEventHandler): void ``` ### Parameters **handler**: A handler object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> handler </code> </td> <td> <code> EventHandler </code> </td> <td> <code> true </code> </td> <td> Event handler. </td> </tr> <tr> <td> <code> route </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path prefix or route. If an empty string used, will be used as a middleware. </td> </tr> </tbody> </table> ### Example #### Basic Usage In some cases, you may want to create a server handler specifically for development purposes, such as a Tailwind config viewer. ```ts import { joinURL } from 'ufo' import { addDevServerHandler, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (options, nuxt) { const route = joinURL(nuxt.options.app?.baseURL, '/_tailwind') // @ts-expect-error - tailwind-config-viewer does not have correct types const createServer = await import('tailwind-config-viewer/server/index.js').then(r => r.default || r) as any const viewerDevMiddleware = createServer({ tailwindConfigProvider: () => options, routerPrefix: route }).asMiddleware() addDevServerHandler({ route, handler: viewerDevMiddleware }) }, }) ``` ## `useNitro` Returns the Nitro instance. <warning> You can call `useNitro()` only after `ready` hook. </warning> <note> Changes to the Nitro instance configuration are not applied. </note> ### Usage ```ts import { defineNuxtModule, useNitro } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const resolver = createResolver(import.meta.url) nuxt.hook('ready', () => { const nitro = useNitro() // Do something with Nitro instance }) }, }) ``` ### Type ```ts function useNitro (): Nitro ``` ## `tryUseNitro` Returns the Nitro instance, or `undefined` when there is none. There is no Nitro instance before the `ready` hook has run, and none at all when the configured [`server.builder`](https://nuxt.com/docs/4.x/api/nuxt-config#builder-1) does not use Nitro, such as a builder that outputs a client-only SPA. Use this rather than `useNitro()` for anything that should keep working without a server: server routes, route rules and prerendering are all absent in that case. ### Usage ```ts import { defineNuxtModule, tryUseNitro } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { nuxt.hook('ready', () => { const nitro = tryUseNitro() if (!nitro) { // no server: skip anything that would only run there return } }) }, }) ``` ### Type ```ts function tryUseNitro (): Nitro | undefined ``` ## `addNitroPlugin` Add plugin to extend Nitro's runtime behavior. <note> This was named `addServerPlugin` before Nuxt v4.6. </note> <tip> You can read more about Nitro plugins in the [Nitro documentation](https://nitro.build/guide/plugins). </tip> <warning> It is necessary to explicitly import `defineNitroPlugin` from `nitropack/runtime` within your plugin file. The same requirement applies to utilities such as `useRuntimeConfig`. </warning> ### Usage ```tstwoslash import { addNitroPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addNitroPlugin(resolve('./runtime/plugin.ts')) }, }) ``` ### Type ```ts function addNitroPlugin (plugin: string | { nitro2?: string, nitro3?: string }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> plugin </code> </td> <td> <code> string | { nitro2?: string, nitro3?: string } </code> </td> <td> <code> true </code> </td> <td> Path to the plugin, or one path per nitro major for a module shipping an implementation for each. The plugin must export a default function that accepts the Nitro instance as an argument. </td> </tr> </tbody> </table> ### Example <code-group> ```ts [module.ts] import { addNitroPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addNitroPlugin(resolve('./runtime/plugin.ts')) }, }) ``` ```ts [runtime/plugin.ts] export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('request', (event) => { console.log('on request', event.path) }) nitroApp.hooks.hook('beforeResponse', (event, { body }) => { console.log('on response', event.path, { body }) }) nitroApp.hooks.hook('afterResponse', (event, { body }) => { console.log('on after response', event.path, { body }) }) }) ``` </code-group> ## `addPrerenderRoutes` Add routes to be prerendered to Nitro. ### Usage ```ts import { addPrerenderRoutes, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'nuxt-sitemap', configKey: 'sitemap', }, defaults: { sitemapUrl: '/sitemap.xml', prerender: true, }, setup (options) { if (options.prerender) { addPrerenderRoutes(options.sitemapUrl) } }, }) ``` ### Type ```ts function addPrerenderRoutes (routes: string | string[]): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> routes </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A route or an array of routes to prerender. </td> </tr> </tbody> </table> ## `addServerImports` Add imports to the server. It makes your imports available in Nitro without the need to import them manually. <warning> If you want to provide a utility that works in both server and client contexts and is usable in the [`shared/`](https://nuxt.com/docs/4.x/directory-structure/shared) directory, the function must be imported from the same source file for both [`addImports`](https://nuxt.com/docs/4.x/api/kit/autoimports#addimports) and `addServerImports` and should have identical signature. That source file should not import anything context-specific (i.e., Nitro context, Nuxt app context) or else it might cause errors during type-checking. </warning> ### Usage ```tstwoslash import { addServerImports, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const names = [ 'useStoryblok', 'useStoryblokApi', 'useStoryblokBridge', 'renderRichText', 'RichTextSchema', ] names.forEach(name => addServerImports({ name, as: name, from: '@storyblok/vue' }), ) }, }) ``` ### Type ```ts function addServerImports (dirs: NuxtImport | NuxtImport[]): void ``` ### Parameters `imports`: An object or an array of objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Import name to be detected. </td> </tr> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the import; if multiple imports have the same name, the one with the highest priority will be used. </td> </tr> <tr> <td> <code> disabled </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is disabled. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Record<string, any> </code> </td> <td> <code> false </code> </td> <td> Metadata of the import. </td> </tr> <tr> <td> <code> type </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is a pure type import. </td> </tr> <tr> <td> <code> typeFrom </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Use this as the <code> from </code> value when generating type declarations. </td> </tr> <tr> <td> <code> as </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Import as this name. </td> </tr> </tbody> </table> ## `addServerImportsDir` Add a directory to be scanned for auto-imports by Nitro. ### Usage ```tstwoslash import { addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerImportsDir(resolve('./runtime/server/composables')) }, }) ``` ### Type ```ts function addServerImportsDir (dirs: string | string[], opts: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A directory or an array of directories to register to be scanned by Nitro. </td> </tr> <tr> <td> <code> opts </code> </td> <td> <code> { prepend?: boolean } </code> </td> <td> <code> false </code> </td> <td> Options for the import directory. If <code> prepend </code> is <code> true </code> , the directory is added to the beginning of the scan list. </td> </tr> </tbody> </table> ### Example You can use `addServerImportsDir` to add a directory to be scanned by Nitro. This is useful when you want Nitro to auto-import functions from a custom server directory. <code-group> ```ts [module.ts]twoslash import { addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerImportsDir(resolve('./runtime/server/composables')) }, }) ``` ```ts [runtime/server/composables/index.ts]twoslash export function useApiSecret () { const { apiSecret } = useRuntimeConfig() return apiSecret } ``` </code-group> You can then use the `useApiSecret` function in your server code: ```ts [runtime/server/api/hello.ts]twoslash const useApiSecret = (): string => '' // ---cut--- export default defineEventHandler(() => { const apiSecret = useApiSecret() // Do something with the apiSecret }) ``` ## `addServerScanDir` Add directories to be scanned by Nitro. It will check for subdirectories, which will be registered just like the `~~/server` folder is. <note> Only `~~/server/api`, `~~/server/routes`, `~~/server/middleware`, and `~~/server/utils` are scanned. </note> ### Usage ```tstwoslash import { addServerScanDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerScanDir(resolve('./runtime/server')) }, }) ``` ### Type ```ts function addServerScanDir (dirs: string | string[], opts: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A directory or an array of directories to register to be scanned for by Nitro as server dirs. </td> </tr> <tr> <td> <code> opts </code> </td> <td> <code> { prepend?: boolean } </code> </td> <td> <code> false </code> </td> <td> Options for the import directory. If <code> prepend </code> is <code> true </code> , the directory is added to the beginning of the scan list. </td> </tr> </tbody> </table> ### Example You can use `addServerScanDir` to add a directory to be scanned by Nitro. This is useful when you want to add a custom server directory. <code-group> ```ts [module.ts]twoslash import { addServerScanDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerScanDir(resolve('./runtime/server')) }, }) ``` ```ts [runtime/server/utils/index.ts]twoslash export function hello () { return 'Hello from server utils!' } ``` </code-group> You can then use the `hello` function in your server code. ```ts [runtime/server/api/hello.ts]twoslash function hello () { return 'Hello from server utils!' } // ---cut--- export default defineEventHandler(() => { return hello() // Hello from server utils! }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/nitro.ts) # Pages > Nuxt Kit provides a set of utilities to help you create and use pages. You can use these utilities to manipulate the pages configuration or to define route rules. ## `extendPages` In Nuxt, routes are automatically generated based on the structure of the files in the `app/pages` directory. However, there may be scenarios where you'd want to customize these routes. For instance, you might need to add a route for a dynamic page not generated by Nuxt, remove an existing route, or modify the configuration of a route. For such customizations, Nuxt offers the `extendPages` feature, which allows you to extend and alter the pages configuration. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/extend-and-alter-nuxt-pages?friend=nuxt"> Watch Vue School video about extendPages. </tip> ### Usage ```tstwoslash import { createResolver, defineNuxtModule, extendPages } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) extendPages((pages) => { pages.unshift({ name: 'prismic-preview', path: '/preview', file: resolve('runtime/preview.vue'), }) }) }, }) ``` ### Type ```ts function extendPages (callback: (pages: NuxtPage[]) => void): void ``` ### Parameters **callback**: A function that will be called with the pages configuration. You can alter this array by adding, deleting, or modifying its elements. Note: You should modify the provided pages array directly, as changes made to a copied array will not be reflected in the configuration. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The name of the route. Useful for programmatic navigation and identifying routes. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The route URL path. If not set, Nuxt will infer it from the file location. </td> </tr> <tr> <td> <code> file </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the Vue file that should be used as the component for the route. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> NuxtPageMeta </span> </code> </td> <td> <code> false </code> </td> <td> Custom metadata for the route. Can be used in layouts, middlewares, or navigation guards. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string[] </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string </span> </code> </td> <td> <code> false </code> </td> <td> One or more alias paths for the route. Useful for supporting multiple URLs. </td> </tr> <tr> <td> <code> redirect </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> RouteLocationRaw </span> </code> </td> <td> <code> false </code> </td> <td> Redirect rule for the route. Supports named routes, objects, or string paths. </td> </tr> <tr> <td> <code> children </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> NuxtPage[] </span> </code> </td> <td> <code> false </code> </td> <td> Nested child routes under this route for layout or view nesting. </td> </tr> </tbody> </table> ### Typing Custom Page Metadata You can augment the `NuxtPageMeta` interface to add type-safe custom metadata for pages when using `extendPages` or the `pages:extend` hook: ```ts [index.d.ts] declare module '@nuxt/schema' { interface NuxtPageMeta { requiresAuth?: boolean } } export {} ``` ```ts [modules/auth.ts] import { defineNuxtModule, extendPages } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendPages((pages) => { for (const page of pages) { // requiresAuth is now typed as boolean | undefined if (page.meta?.requiresAuth) { // ... } } }) }, }) ``` ## `extendRouteRules` Nuxt is powered by the [Nitro](https://nitro.build/) server engine. With Nitro, you can incorporate high-level logic directly into your configuration, which is useful for actions like redirects, proxying, caching, and appending headers to routes. This configuration works by associating route patterns with specific route settings. <tip> You can read more about Nitro route rules in the [Nitro documentation](https://nitro.build/guide/routing#route-rules). </tip> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/adding-route-rules-and-route-middlewares?friend=nuxt"> Watch Vue School video about adding route rules and route middlewares. </tip> ### Usage ```tstwoslash import { createResolver, defineNuxtModule, extendPages, extendRouteRules } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) extendPages((pages) => { pages.unshift({ name: 'preview-new', path: '/preview-new', file: resolve('runtime/preview.vue'), }) }) extendRouteRules('/preview', { redirect: { to: '/preview-new', statusCode: 302, }, }) extendRouteRules('/preview-new', { cache: { maxAge: 60 * 60 * 24 * 7, }, }) }, }) ``` ### Type ```ts function extendRouteRules (route: string, rule: NitroRouteConfig, options?: ExtendRouteRulesOptions): void ``` ### Parameters **route**: A route pattern to match against.<br /> **rule**: A route rule configuration to apply to the matched route. <tip> About route rules configurations, you can get more detail in [Hybrid Rendering > Route Rules](https://nuxt.com/docs/4.x/guide/concepts/rendering#route-rules). </tip> **options**: An object to pass to the route configuration. If `override` is set to `true`, it will override the existing route configuration. <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> override </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Override route rule config, default is false </td> </tr> </tbody> </table> ## `addRouteMiddleware` Registers route middlewares to be available for all routes or for specific routes. Route middlewares can be also defined in plugins via [`addRouteMiddleware`](https://nuxt.com/docs/4.x/api/utils/add-route-middleware) composable. <tip> Read more about route middlewares in the [Route middleware documentation](https://nuxt.com/docs/4.x/getting-started/routing#route-middleware). </tip> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/adding-route-rules-and-route-middlewares?friend=nuxt"> Watch Vue School video about adding route rules and route middlewares. </tip> ### Usage <code-group> ```ts [module.ts]twoslash import { addRouteMiddleware, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addRouteMiddleware({ name: 'auth', path: resolve('runtime/auth'), global: true, }, { prepend: true }) }, }) ``` ```ts [runtime/auth.ts]twoslash function isAuthenticated (): boolean { return false } // ---cut--- export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (to.path !== '/login' && isAuthenticated() === false) { return navigateTo('/login') } }) ``` </code-group> ### Type ```ts function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], options?: AddRouteMiddlewareOptions): void ``` ### Parameters **input**: A middleware object or an array of middleware objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> The name of the middleware. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> The file path to the middleware. </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , applies middleware to all routes. </td> </tr> </tbody> </table> **options**: An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> override </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , replaces middleware with the same name. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , prepends middleware before existing middlewares. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/pages.ts) # Plugins > Nuxt Kit provides a set of utilities to help you create and use plugins. You can add plugins or plugin templates to your module using these functions. Plugins are self-contained code that usually add app-level functionality to Vue. In Nuxt, plugins are automatically imported from the `app/plugins/` directory. However, if you need to ship a plugin with your module, Nuxt Kit provides the `addPlugin` and `addPluginTemplate` methods. These utils allow you to customize the plugin configuration to better suit your needs. ## `addPlugin` Registers a Nuxt plugin and adds it to the plugins array. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-plugins?friend=nuxt"> Watch Vue School video about `addPlugin`. </tip> ### Usage ```tstwoslash import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addPlugin({ src: resolve('runtime/plugin.js'), mode: 'client', }) }, }) ``` ### Type ```ts function addPlugin (plugin: NuxtPlugin | string, options?: AddPluginOptions): NuxtPlugin ``` ### Parameters **plugin**: A plugin object or a string with the path to the plugin. If a string is provided, it will be converted to a plugin object with `src` set to the string value. If a plugin object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the plugin file. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> If set to <code> 'all' </code> , the plugin will be included in both client and server bundles. If set to <code> 'server' </code> , the plugin will only be included in the server bundle. If set to <code> 'client' </code> , the plugin will only be included in the client bundle. You can also use <code> .client </code> and <code> .server </code> modifiers when specifying <code> src </code> option to use plugin only in client or server side. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Order of the plugin. This allows more granular control over plugin order and should only be used by advanced users. Lower numbers run first, and user plugins default to <code> 0 </code> . It's recommended to set <code> order </code> to a number between <code> -20 </code> for <code> pre </code> -plugins (plugins that run before Nuxt plugins) and <code> 20 </code> for <code> post </code> -plugins (plugins that run after Nuxt plugins). </td> </tr> </tbody> </table> <warning> Avoid using `order` unless necessary. Use `append` if you simply need to register plugins after Nuxt defaults. </warning> **options**: Optional object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> append </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the plugin will be appended to the plugins array. If <code> false </code> , it will be prepended. Defaults to <code> false </code> . </td> </tr> </tbody> </table> ### Example <code-group> ```ts [module.ts] import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addPlugin({ src: resolve('runtime/plugin.js'), mode: 'client', }) }, }) ``` ```ts [runtime/plugin.ts] export default defineNuxtPlugin((nuxtApp) => { const colorMode = useColorMode() nuxtApp.hook('app:mounted', () => { if (colorMode.preference !== 'dark') { colorMode.preference = 'dark' } }) }) ``` </code-group> ## `addPluginTemplate` Adds a template and registers as a nuxt plugin. This is useful for plugins that need to generate code at build time. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-plugin-templates?friend=nuxt"> Watch Vue School video about `addPluginTemplate`. </tip> ### Usage ```tstwoslash import { addPluginTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { addPluginTemplate({ filename: 'module-plugin.mjs', getContents: () => `import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'module-plugin', setup (nuxtApp) { ${options.log ? 'console.log("Plugin install")' : ''} } })`, }) }, }) ``` ### Type ```ts function addPluginTemplate (pluginOptions: NuxtPluginTemplate, options?: AddPluginOptions): NuxtPlugin ``` ### Parameters **pluginOptions**: A plugin template object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> If set to <code> 'all' </code> , the plugin will be included in both client and server bundles. If set to <code> 'server' </code> , the plugin will only be included in the server bundle. If set to <code> 'client' </code> , the plugin will only be included in the client bundle. You can also use <code> .client </code> and <code> .server </code> modifiers when specifying <code> src </code> option to use plugin only in client or server side. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Record </span> <span class="sDfIl"> < </span> <span class="s52Pk"> string </span> <span class="sDfIl"> , </span> <span class="s52Pk"> any </span> <span class="sDfIl"> >) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Order of the plugin. This allows more granular control over plugin order and should only be used by advanced users. Lower numbers run first, and user plugins default to <code> 0 </code> . It's recommended to set <code> order </code> to a number between <code> -20 </code> for <code> pre </code> -plugins (plugins that run before Nuxt plugins) and <code> 20 </code> for <code> post </code> -plugins (plugins that run after Nuxt plugins). </td> </tr> </tbody> </table> <warning> Prefer using `getContents` for dynamic plugin generation. Avoid setting `order` unless necessary. </warning> **options**: Optional object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> append </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the plugin will be appended to the plugins array. If <code> false </code> , it will be prepended. Defaults to <code> false </code> . </td> </tr> </tbody> </table> ### Example #### Generate a plugin template with different options Use `addPluginTemplate` when you need to generate plugin code dynamically at build time. This allows you to generate different plugin contents based on the options passed to it. For example, Nuxt internally uses this function to generate Vue app configurations. ```ts [module.ts]twoslash import { addPluginTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (_, nuxt) { if (nuxt.options.vue.config && Object.values(nuxt.options.vue.config).some(v => v !== null && v !== undefined)) { addPluginTemplate({ filename: 'vue-app-config.mjs', write: true, getContents: () => `import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { ${Object.keys(nuxt.options.vue.config!) .map(k => `nuxtApp.vueApp.config[${JSON.stringify(k)}] = ${JSON.stringify(nuxt.options.vue.config![k as 'idPrefix'])}`) .join('\n') } } })`, }) } }, }) ``` This generates different plugin code depending on the provided configuration. <code-group> ```ts [nuxt.config.ts] export default defineNuxtConfig({ vue: { config: { idPrefix: 'nuxt', }, }, }) ``` ```ts [#build/vue-app-config.mjs] import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { nuxtApp.vueApp.config.idPrefix = 'nuxt' }, }) ``` </code-group> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/plugin.ts) # Programmatic Usage > Nuxt Kit provides a set of utilities to help you work with Nuxt programmatically. These functions allow you to load Nuxt, build Nuxt, and load Nuxt configuration. Programmatic usage can be helpful when you want to use Nuxt programmatically, for example, when building a [CLI tool](https://github.com/nuxt/cli) or [test utils](https://github.com/nuxt/test-utils). ## `loadNuxt` Load Nuxt programmatically. It will load the Nuxt configuration, instantiate and return the promise with Nuxt instance. ### Type ```ts function loadNuxt (loadOptions?: LoadNuxtOptions): Promise<Nuxt> ``` ### Parameters **loadOptions**: Loading conditions for Nuxt. `loadNuxt` uses [`c12`](https://github.com/unjs/c12) under the hood, so it accepts the same options as `c12.loadConfig` with some additional options: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , Nuxt will be loaded in development mode. </td> </tr> <tr> <td> <code> ready </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If set to <code> true </code> , Nuxt will be ready to use after the <code> loadNuxt </code> call. If set to <code> false </code> , you will need to call <code> nuxt.ready() </code> to make sure Nuxt is ready to use. </td> </tr> </tbody> </table> ## `buildNuxt` Build Nuxt programmatically. It will invoke the builder (currently [@nuxt/vite-builder](https://github.com/nuxt/nuxt/tree/main/packages/vite) or [@nuxt/webpack-builder](https://github.com/nuxt/nuxt/tree/main/packages/webpack)) to bundle the application. ### Type ```ts function buildNuxt (nuxt: Nuxt): Promise<any> ``` ### Parameters **nuxt**: Nuxt instance to build. It can be retrieved from the context via `useNuxt()` call. ## `loadNuxtConfig` Load Nuxt configuration. It will return the promise with the configuration object. ### Type ```ts function loadNuxtConfig (options: LoadNuxtConfigOptions): Promise<NuxtOptions> ``` ### Parameters **options**: Options to pass in [`c12`](https://github.com/unjs/c12#options) `loadConfig` call. ## `writeTypes` Generates `tsconfig.json` and writes it to the project buildDir. ### Type ```ts function writeTypes (nuxt?: Nuxt): void ``` ### Parameters **nuxt**: Nuxt instance to build. It can be retrieved from the context via `useNuxt()` call. --- - [Source](https://github.com/nuxt/nuxt/tree/main/packages/kit/src/loader) # Resolving > Nuxt Kit provides utilities to resolve paths from the Nuxt root directory or a custom base. Sometimes you need to resolve a path without knowing its name or extension. For example, you may want to add a plugin that is located in the same directory as a module. To handle these cases, Nuxt provides a set of utilities to resolve paths. `resolvePath` resolves paths from the Nuxt root directory by default, while `resolveAlias` applies configured aliases. `findPath` finds the first existing file in a given set of paths. `createResolver` creates a resolver relative to a base path. ## `resolvePath` Resolves the full path to a file or directory, respecting Nuxt alias and extensions options. If a path could not be resolved, a normalized input path will be returned. ### Usage ```ts import { defineNuxtModule, resolvePath } from '@nuxt/kit' export default defineNuxtModule({ async setup () { const entrypoint = await resolvePath('@unhead/vue') console.log(`Unhead entrypoint is ${entrypoint}`) }, }) ``` ### Type ```ts function resolvePath (path: string, options?: ResolvePathOptions): Promise<string> ``` ### Parameters **path**: A path to resolve. **options**: Options to pass to the resolver. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> cwd </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Base for resolving paths from. Default is Nuxt rootDir. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> An object of aliases. Default is Nuxt configured aliases. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> The file extensions to try. Default is Nuxt configured extensions. </td> </tr> <tr> <td> <code> virtual </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template). </td> </tr> <tr> <td> <code> fallbackToOriginal </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to fallback to the original path if the resolved path does not exist instead of returning the normalized input path. </td> </tr> </tbody> </table> <note> `resolvePath` follows standard module resolution and does not search dependencies nested inside other packages. To resolve a dependency declared by your Nuxt module, use `createResolver(import.meta.url).resolvePath()`. This makes resolution independent of whether the package manager hoists the dependency. </note> ### Example ```ts import { defineNuxtModule, resolvePath } from '@nuxt/kit' import { join } from 'pathe' const headlessComponents: ComponentGroup[] = [ { relativePath: 'combobox/combobox.js', chunkName: 'headlessui/combobox', exports: [ 'Combobox', 'ComboboxLabel', 'ComboboxButton', 'ComboboxInput', 'ComboboxOptions', 'ComboboxOption', ], }, ] export default defineNuxtModule({ meta: { name: 'nuxt-headlessui', configKey: 'headlessui', }, defaults: { prefix: 'Headless', }, async setup (options) { const entrypoint = await resolvePath('@headlessui/vue') const root = join(entrypoint, '../components') for (const group of headlessComponents) { for (const e of group.exports) { addComponent( { name: e, export: e, filePath: join(root, group.relativePath), chunkName: group.chunkName, mode: 'all', }, ) } } }, }) ``` ## `resolveAlias` Resolves path aliases respecting Nuxt alias options. ### Type ```ts function resolveAlias (path: string, alias?: Record<string, string>): string ``` ### Parameters **path**: A path to resolve. **alias**: An object of aliases. If not provided, it will be read from `nuxt.options.alias`. ## `findPath` Try to resolve first existing file in a given set of paths. ### Usage ```ts import { defineNuxtModule, findPath } from '@nuxt/kit' import { join } from 'pathe' export default defineNuxtModule({ async setup (_, nuxt) { // Resolve main (app.vue) const mainComponent = await findPath([ join(nuxt.options.srcDir, 'App'), join(nuxt.options.srcDir, 'app'), ]) }, }) ``` ### Type ```ts function findPath (paths: string | string[], options?: ResolvePathOptions, pathType: 'file' | 'dir'): Promise<string | null> ``` ### Parameters **paths**: A path or an array of paths to resolve. **options**: Options to pass to the resolver. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> cwd </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Base for resolving paths from. Default is Nuxt rootDir. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> An object of aliases. Default is Nuxt configured aliases. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> The file extensions to try. Default is Nuxt configured extensions. </td> </tr> <tr> <td> <code> virtual </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template). </td> </tr> <tr> <td> <code> fallbackToOriginal </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to fallback to the original path if the resolved path does not exist instead of returning the normalized input path. </td> </tr> </tbody> </table> ## `createResolver` Creates resolver relative to base path. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/resolving-paths-and-injecting-assets-to-the-app?friend=nuxt"> Watch Vue School video about createResolver. </tip> ### Usage ```ts import { createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (_, nuxt) { const { resolve, resolvePath } = createResolver(import.meta.url) }, }) ``` ### Type ```ts function createResolver (basePath: string | URL): Resolver ``` ### Parameters **basePath**: A base path to resolve from. It can be a string or a URL. ### Return Value The `createResolver` function returns an object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> resolve </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> path </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> </code> </td> <td> A function that resolves a path relative to the base path. </td> </tr> <tr> <td> <code> resolvePath </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> path </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> , </span> <span class="s1nJG"> options </span> <span class="sDfIl"> ?: </span> <span class="s52Pk"> ResolvePathOptions </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> A function that resolves a path relative to the base path and respects Nuxt alias and extensions options. </td> </tr> </tbody> </table> ### Example ```ts import { createResolver, defineNuxtModule, isNuxt2 } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const resolver = createResolver(import.meta.url) nuxt.hook('modules:done', () => { if (isNuxt2()) { addPlugin(resolver.resolve('./runtime/plugin.vue2')) } else { addPlugin(resolver.resolve('./runtime/plugin.vue3')) } }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/resolve.ts) # Runtime Config > Nuxt Kit provides a set of utilities to help you access and modify Nuxt runtime configuration. ## `useRuntimeConfig` At build-time, it is possible to access the resolved Nuxt [runtime config](https://nuxt.com/docs/4.x/guide/going-further/runtime-config). ### Type ```ts function useRuntimeConfig (): Record<string, unknown> ``` ## `updateRuntimeConfig` It is also possible to update runtime configuration. This will be merged with the existing runtime configuration, and if Nitro has already been initialized it will trigger an HMR event to reload the Nitro runtime config. ### Type ```ts function updateRuntimeConfig (config: Record<string, unknown>): void | Promise<void> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/runtime-config.ts) # Templates > Nuxt Kit provides a set of utilities to help you work with templates. These functions allow you to generate extra files during development and build time. Templates allow you to generate extra files during development and build time. These files will be available in virtual filesystem and can be used in plugins, layouts, components, etc. `addTemplate` and `addTypeTemplate` allow you to add templates to the Nuxt application. `updateTemplates` allows you to regenerate templates that match the filter. ## `addTemplate` Renders given template during build into the virtual file system, and optionally to disk in the project `buildDir` ### Usage ```tstwoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' import { defu } from 'defu' export default defineNuxtModule({ setup (options, nuxt) { const globalMeta = defu(nuxt.options.app.head, { charset: options.charset, viewport: options.viewport, }) addTemplate({ filename: 'meta.config.mjs', getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' }), }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NuxtTemplate, ResolvedNuxtTemplate } from '@nuxt/schema' // ---cut--- function addTemplate (template: NuxtTemplate | string): ResolvedNuxtTemplate ``` ### Parameters **template**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code> Options </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Options </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> <tr> <td> <code> dependsOn </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Array </span> <span class="sDfIl"> < </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> pages </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> plugins </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> > </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> change </span> <span class="sDfIl"> : </span> <span class="sDfIl"> { </span> <span class="sRlkE"> event </span> <span class="sDfIl"> , </span> <span class="sRlkE"> path </span> <span class="sDfIl"> }, </span> <span class="s1nJG"> ctx </span> <span class="sDfIl"> : </span> <span class="sDfIl"> { </span> <span class="sRlkE"> nuxt </span> <span class="sDfIl"> , </span> <span class="sRlkE"> app </span> <span class="sDfIl"> , </span> <span class="sRlkE"> options </span> <span class="sDfIl"> }) </span> <span class="smZ93"> => </span> <span class="sZSNi"> boolean) </span> </code> </td> <td> <code> false </code> </td> <td> The watched inputs the output of the template can depend on, beyond <code> nuxt.options </code> and the resolved structure of the app. Set to <code> [] </code> if the template never reads the contents of a watched file, so that Nuxt can skip recompiling it in dev mode when a file changes without any file being added or removed. List well-known keys if the template reads those sources, or pass a function to decide per change. A template that declares nothing is regenerated on every change. </td> </tr> </tbody> </table> ### Example #### Creating a Virtual File for Runtime Plugin In this example, we merge an object inside a module and consume the result in a runtime plugin. ```ts [module.ts]twoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' import { defu } from 'defu' export default defineNuxtModule({ setup (options, nuxt) { const globalMeta = defu(nuxt.options.app.head, { charset: options.charset, viewport: options.viewport, }) addTemplate({ filename: 'meta.config.mjs', getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' }), }) }, }) ``` #### Skipping Regeneration in Development By default, Nuxt recompiles a template on every watched file event because it cannot know what the template reads. If your template is built only from configuration and from which files exist, declare that so Nuxt can leave it alone when a file is edited: ```ts [module.ts]twoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { addTemplate({ filename: 'my-module/config.mjs', dependsOn: [], getContents: () => 'export default ' + JSON.stringify(options), }) }, }) ``` If the template reads well-known sources, declare them by key: ```ts addTemplate({ filename: 'my-module/routes.mjs', dependsOn: ['pages'], getContents: ({ app }) => generateRoutes(app.pages), }) ``` And if it reads files Nuxt doesn't know about, say a set of YAML files you scan yourself, pass a function instead: ```ts addTemplate({ filename: 'my-module/content.mjs', dependsOn: ({ path }) => path.endsWith('.yaml'), getContents: () => generateContents(), }) ``` In the module above, we generate a virtual file named `meta.config.mjs`. In the runtime plugin, we can import it using the `#build` alias: ```ts [runtime/plugin.ts] import { createHead as createServerHead } from '@unhead/vue/server' import { createHead as createClientHead } from '@unhead/vue/client' import { defineNuxtPlugin } from '#imports' // @ts-expect-error - virtual file import metaConfig from '#build/meta.config.mjs' export default defineNuxtPlugin((nuxtApp) => { const createHead = import.meta.server ? createServerHead : createClientHead const head = createHead() head.push(metaConfig.globalMeta) nuxtApp.vueApp.use(head) }) ``` ## `addTypeTemplate` Renders given template during build into the project buildDir, then registers it as types. ### Usage ```tstwoslash import { addTypeTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addTypeTemplate({ filename: 'types/markdown.d.ts', getContents: () => `declare module '*.md' { import type { ComponentOptions } from 'vue' const Component: ComponentOptions export default Component }`, }) }, }) ``` ### Type ```ts function addTypeTemplate (template: NuxtTypeTemplate | string, context?: { nitro?: boolean, nuxt?: boolean }): ResolvedNuxtTemplate ``` ### Parameters **template**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code> Options </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Options </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> </tbody> </table> **context**: An optional context object can be passed to control where the type is added. If omitted, the type will only be added to the Nuxt context. This object supports the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> nuxt </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the type will be added to the Nuxt context. </td> </tr> <tr> <td> <code> nitro </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the type will be added to the Nitro context. </td> </tr> </tbody> </table> ### Example #### Adding Type Templates to the Nitro Context By default, ๏ผ๏ผ only adds the type declarations to the Nuxt context. To also add them to the Nitro context, set nitro to true. ```tstwoslash import { addTypeTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addTypeTemplate({ filename: 'types/auth.d.ts', getContents: () => `declare module '#auth-utils' { interface User { id: string; name: string; } }`, }, { nitro: true, }) }, }) ``` This allows the `#auth-utils` module to be used within the Nitro context. ```ts [server/api/auth.ts] import type { User } from '#auth-utils' export default eventHandler(() => { const user: User = { id: '123', name: 'John Doe', } // do something with the user return user }) ``` ## `addServerTemplate` Adds a virtual file that can be used within the Nuxt Nitro server build. ### Usage ```tstwoslash import { addServerTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addServerTemplate({ filename: '#my-module/test.mjs', getContents () { return 'export const test = 123' }, }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NuxtServerTemplate } from '@nuxt/schema' // ---cut--- function addServerTemplate (template: NuxtServerTemplate): NuxtServerTemplate ``` ### Parameters **template**: A template object. It must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Filename of the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> () </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> true </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. </td> </tr> </tbody> </table> ### Example ### Creating a Virtual File for Nitro In this example, we create a virtual file that can be used within the Nuxt Nitro server build. ```tstwoslash import { addServerTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addServerTemplate({ filename: '#my-module/test.mjs', getContents () { return 'export const test = 123' }, }) }, }) ``` And then in a runtime file ```ts [server/api/test.ts] import { test } from '#my-module/test.js' export default eventHandler(() => { return test }) ``` ## `updateTemplates` Regenerate templates that match the filter. If no filter is provided, all templates will be regenerated. ### Usage ```ts import { defineNuxtModule, updateTemplates } from '@nuxt/kit' import { resolve } from 'pathe' export default defineNuxtModule({ setup (options, nuxt) { const updateTemplatePaths = [ resolve(nuxt.options.srcDir, 'pages'), ] // watch and rebuild routes template list when one of the pages changes nuxt.hook('builder:watch', async (event, relativePath) => { if (event === 'change') { return } const path = resolve(nuxt.options.srcDir, relativePath) if (updateTemplatePaths.some(dir => path.startsWith(dir))) { await updateTemplates({ filter: template => template.filename === 'routes.mjs', }) } }) }, }) ``` ### Type ```ts async function updateTemplates (options: UpdateTemplatesOptions): void ``` ### Parameters **options**: Options to pass to the template. This object can have the following property: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> filter </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> template </span> <span class="sDfIl"> : </span> <span class="s52Pk"> ResolvedNuxtTemplate </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> boolean </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> template </code> object. It should return a boolean indicating whether the template should be regenerated. If <code> filter </code> is not provided, all templates will be regenerated. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/template.ts) # Nuxt Configuration > Discover all the options you can use in your nuxt.config.ts file. ## alias You can improve your DX by defining additional aliases to access custom directories within your JavaScript and CSS. - **Type**: `object` - **Default** ```json { "~": "/<rootDir>/app", "@": "/<rootDir>/app", "~~": "/<rootDir>", "@@": "/<rootDir>", "#shared": "/<rootDir>/shared", "#server": "/<rootDir>/server", "assets": "/<rootDir>/app/assets", "public": "/<rootDir>/public", "#build": "/<rootDir>/.nuxt", "#internal/nuxt/paths": "/<rootDir>/.nuxt/paths.mjs" } ``` <callout> **Note**: Within a webpack context (image sources, CSS - but not JavaScript) you *must* access your alias by prefixing it with `~`. </callout> <callout> **Note**: These aliases will be automatically added to the generated TypeScript configurations (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, etc.) so you can get full type support and path auto-complete. In case you need to extend options provided by the generated configurations further, make sure to add them here or within the `typescript.tsConfig` property in `nuxt.config`. </callout> **Example**: ```ts import { fileURLToPath } from 'node:url' export default defineNuxtConfig({ alias: { 'images': fileURLToPath(new URL('./assets/images', import.meta.url)), 'style': fileURLToPath(new URL('./assets/style', import.meta.url)), 'data': fileURLToPath(new URL('./assets/other/data', import.meta.url)), }, }) ``` ```html <template> <img src="~images/main-bg.jpg"> </template> <script> import data from 'data/test.json' </script> <style> // Uncomment the below //@import '~style/variables.scss'; //@import '~style/utils.scss'; //@import '~style/base.scss'; body { background-image: url('~images/main-bg.jpg'); } </style> ``` ## analyzeDir The directory where Nuxt will store the generated files when running `nuxt analyze`. If a relative path is specified, it will be relative to your `rootDir`. - **Type**: `string` - **Default:** `"/<rootDir>/.nuxt/analyze"` ## app Nuxt App configuration. ### `baseURL` The base path of your Nuxt application. For example: - **Type**: `string` - **Default:** `"/"` **Example**: ```ts export default defineNuxtConfig({ app: { baseURL: '/prefix/', }, }) ``` This can also be set at runtime by setting the NUXT_APP_BASE_URL environment variable. **Example**: ```bash NUXT_APP_BASE_URL=/prefix/ node .output/server/index.mjs ``` <note> Relative paths (like `./`) are not supported directly in `nuxt.config.ts` due to Nitro limitations. For static hosting with relative asset paths, use one of these approaches: ```bash # Option 1: Environment variable at build time NUXT_APP_BASE_URL=./ npm run generate ``` ```ts // Option 2: Nitro runtime config export default defineNuxtConfig({ nitro: { runtimeConfig: { app: { baseURL: './', }, }, }, }) ``` </note> ### `buildAssetsDir` The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set). This is set at build time and should not be customized at runtime. - **Type**: `string` - **Default:** `"/_nuxt/"` ### `cdnURL` An absolute URL to serve the public folder from (production-only). For example: - **Type**: `string` - **Default:** `""` **Example**: ```ts export default defineNuxtConfig({ app: { cdnURL: 'https://mycdn.org/', }, }) ``` This can be set to a different value at runtime by setting the `NUXT_APP_CDN_URL` environment variable. **Example**: ```bash NUXT_APP_CDN_URL=https://mycdn.org/ node .output/server/index.mjs ``` ### `head` Set default configuration for `<head>` on every page. - **Type**: `object` - **Default** ```json { "meta": [ { "name": "viewport", "content": "width=device-width, initial-scale=1" }, { "charset": "utf-8" } ], "link": [], "style": [], "script": [], "noscript": [] } ``` **Example**: ```ts export default defineNuxtConfig({ app: { head: { meta: [ // <meta name="viewport" content="width=device-width, initial-scale=1"> { name: 'viewport', content: 'width=device-width, initial-scale=1' }, ], script: [ // <script src="https://myawesome-lib.js"></script> { src: 'https://awesome-lib.js' }, ], link: [ // <link rel="stylesheet" href="https://myawesome-lib.css"> { rel: 'stylesheet', href: 'https://awesome-lib.css' }, ], // please note that this is an area that is likely to change style: [ // <style>:root { color: red }</style> { textContent: ':root { color: red }' }, ], noscript: [ // <noscript>JavaScript is required</noscript> { textContent: 'JavaScript is required' }, ], }, }, }) ``` ### `keepalive` Default values for KeepAlive configuration between pages. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean` - **Default:** `false` **See**: [Vue KeepAlive](https://vuejs.org/api/built-in-components#keepalive) ### `layoutTransition` Default values for layout transitions. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean | TransitionProps` - **Default:** `false` **See**: [Vue Transition docs](https://vuejs.org/api/built-in-components#transition) ### `pageTransition` Default values for page transitions. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean | TransitionProps` - **Default:** `false` **See**: [Vue Transition docs](https://vuejs.org/api/built-in-components#transition) ### `rootAttrs` Customize Nuxt root element id. - **Type**: `object` - **Default** ```json { "id": "__nuxt" } ``` ### `rootId` Customize Nuxt root element id. - **Type**: `string` - **Default:** `"__nuxt"` ### `rootTag` Customize Nuxt root element tag. - **Type**: `string` - **Default:** `"div"` ### `spaLoaderAttrs` Customize Nuxt SPA loading template element attributes. - **Type**: `object` - **Default:** ```json { "id": "__nuxt-loader" } ``` #### `id` - **Type**: `string` - **Default:** `"__nuxt-loader"` ### `spaLoaderTag` Customize Nuxt SpaLoader element tag. - **Type**: `string` - **Default:** `"div"` ### `teleportAttrs` Customize Nuxt Teleport element attributes. - **Type**: `object` - **Default** ```json { "id": "teleports" } ``` ### `teleportId` Customize Nuxt Teleport element id. - **Type**: `string` - **Default:** `"teleports"` ### `teleportTag` Customize Nuxt Teleport element tag. - **Type**: `string` - **Default:** `"div"` ### `viewTransition` Default values for view transitions. This only has an effect when **experimental** support for View Transitions is [enabled in your nuxt.config file](https://nuxt.com/docs/4.x/getting-started/transitions#view-transitions-api-experimental). This can be overridden with `definePageMeta` on an individual page. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt View Transition API docs](https://nuxt.com/docs/4.x/getting-started/transitions#view-transitions-api-experimental) ## appConfig Additional app configuration For programmatic usage and type support, you can directly provide app config with this option. It will be merged with `app.config` file as default value. ### `nuxt` ## appId For multi-app projects, the unique id of the Nuxt application. Defaults to `nuxt-app`. - **Type**: `string` - **Default:** `"nuxt-app"` ## build Shared build configuration. ### `analyze` Nuxt allows visualizing your bundles and how to optimize them. Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - **Type**: `object` - **Default** ```json { "template": "treemap", "projectRoot": "/<rootDir>", "filename": "/<rootDir>/.nuxt/analyze/{name}.html" } ``` **Example**: ```ts export default defineNuxtConfig({ analyze: { analyzerMode: 'static', }, }) ``` ### `templates` It is recommended to use `addTemplate` from `@nuxt/kit` instead of this option. - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ build: { templates: [ { src: '~~/modules/support/plugin.js', // `src` can be absolute or relative dst: 'support.js', // `dst` is relative to project `.nuxt` dir }, ], }, }) ``` ### `transpile` If you want to transpile specific dependencies with Babel, you can add them here. Each item in transpile can be a package name, a function, a string or regex object matching the dependency's file name. You can also use a function to conditionally transpile. The function will receive an object ({ isDev, isServer, isClient, isModern, isLegacy }). - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ build: { transpile: [({ isLegacy }) => isLegacy && 'ky'], }, }) ``` ## buildDir Define the directory where your built Nuxt files will be placed. Many tools assume that `.nuxt` is a hidden directory (because it starts with a `.`). If that is a problem, you can use this option to prevent that. - **Type**: `string` - **Default:** `"/<rootDir>/.nuxt"` **Example**: ```ts export default defineNuxtConfig({ buildDir: 'nuxt-build', }) ``` ## buildId A unique identifier matching the build. This may contain the hash of the current state of the project. - **Type**: `string` - **Default:** `"4a2e2d30-418f-41df-8e58-ed5df06de7fd"` ## builder The builder to use for bundling the Vue part of your application. Nuxt supports multiple builders for the client-side application. By default, Vite is used, but you can switch to webpack, Rspack, or even provide a custom builder implementation. - **Type**: `'vite' | 'webpack' | 'rspack' | string | { bundle: (nuxt: Nuxt) => Promise<void> }` - **Default:** `"@nuxt/vite-builder"` **Using supported builders:** ```ts export default defineNuxtConfig({ // default - uses @nuxt/vite-builder // builder: 'vite', // uses @nuxt/webpack-builder // builder: 'webpack', // uses @nuxt/rspack-builder builder: 'rspack', }) ``` If you are using `webpack` or `rspack` you will need to make sure `@nuxt/webpack-builder` or `@nuxt/rspack-builder` is explicitly installed in your project. **Using a custom builder object:** You can provide a custom builder by passing an object with a `bundle` function: ```ts export default defineNuxtConfig({ builder: { async bundle (nuxt) { const entry = await resolvePath(resolve(nuxt.options.appDir, 'entry')) // Build client and server bundles await buildClient(nuxt, entry) if (nuxt.options.ssr) { await buildServer(nuxt, entry) } // ... it's a bit more complicated than that, of course! }, }, }) ``` **Creating a custom builder package:** To create a custom builder as a separate package, it should export a `bundle` function. You can then specify the package name in your `nuxt.config.ts`: ```ts export default defineNuxtConfig({ builder: 'my-custom-builder', }) ``` ## compatibilityDate Specify a compatibility date for your app. This is used to control the behavior of presets in Nitro, Nuxt Image and other modules that may change behavior without a major version bump. We plan to improve the tooling around this feature in the future. ## components Configure Nuxt component auto-registration. Any components in the directories configured here can be used throughout your pages, layouts (and other components) without needing to explicitly import them. - **Type**: `object` - **Default** ```json { "dirs": [ { "path": "~/components/global", "global": true }, "~/components" ] } ``` **See**: [`app/components/` directory documentation](https://nuxt.com/docs/4.x/directory-structure/app/components) ## css You can define the CSS files/modules/libraries you want to set globally (included in every page). Nuxt will automatically guess the file type by its extension and use the appropriate pre-processor. You will still need to install the required loader if you need to use them. - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ css: [ // Load a Node.js module directly (here it's a Sass file). 'bulma', // CSS file in the project '~/assets/css/main.css', // SCSS file in the project '~/assets/css/main.scss', ], }) ``` ## debug Set to `true` to enable debug mode. At the moment, it prints out hook names and timings on the server, and logs hook arguments as well in the browser. You can also set this to an object to enable specific debug options. - **Type**: `boolean` - **Default:** `false` ## dev Whether Nuxt is running in development mode. Normally, you should not need to set this. - **Type**: `boolean` - **Default:** `false` ## devServer ### `cors` Set CORS options for the dev server #### `origin` - **Type**: `array` - **Default** ```json [ {} ] ``` ### `host` Dev server listening host ### `https` Whether to enable HTTPS. - **Type**: `boolean` - **Default:** `false` **Example**: ```ts export default defineNuxtConfig({ devServer: { https: { key: './server.key', cert: './server.crt', }, }, }) ``` ### `loadingTemplate` Template to show a loading screen - **Type**: `function` ### `port` Dev server listening port - **Type**: `number` - **Default:** `3000` ### `url` Listening dev server URL. This should not be set directly as it will always be overridden by the dev server with the full URL (for module and internal use). - **Type**: `string` - **Default:** `"http://localhost:3000"` ## devServerHandlers Nitro development-only server handlers. - **Type**: `array` **See**: [Nitro server routes documentation](https://nitro.build/guide/routing) ## devtools Enable Nuxt DevTools for development. Breaking changes for devtools might not reflect on the version of Nuxt. **See**: [Nuxt DevTools](https://devtools.nuxt.com/) for more information. ## dir Customize default directory structure used by Nuxt. It is better to stick with defaults unless needed. ### `app` - **Type**: `string` - **Default:** `"app"` ### `assets` The assets directory (aliased as `~assets` in your build). - **Type**: `string` - **Default:** `"app/assets"` ### `layouts` The layouts directory, each file of which will be auto-registered as a Nuxt layout. - **Type**: `string` - **Default:** `"app/layouts"` ### `middleware` The middleware directory, each file of which will be auto-registered as a Nuxt middleware. - **Type**: `string` - **Default:** `"app/middleware"` ### `modules` The modules directory, each file in which will be auto-registered as a Nuxt module. - **Type**: `string` - **Default:** `"modules"` ### `pages` The directory which will be processed to auto-generate your application page routes. - **Type**: `string` - **Default:** `"app/pages"` ### `plugins` The plugins directory, each file of which will be auto-registered as a Nuxt plugin. - **Type**: `string` - **Default:** `"app/plugins"` ### `public` The directory containing your static files, which will be directly accessible via the Nuxt server and copied across into your `dist` folder when your app is generated. - **Type**: `string` - **Default:** `"public"` ### `shared` The shared directory. This directory is shared between the app and the server. - **Type**: `string` - **Default:** `"shared"` ## esbuild ### `options` Configure shared esbuild options used within Nuxt and passed to other builders, such as Vite or webpack. #### `jsxFactory` - **Type**: `string` - **Default:** `"h"` #### `jsxFragment` - **Type**: `string` - **Default:** `"Fragment"` #### `target` - **Type**: `string` - **Default:** `"esnext"` #### `tsconfigRaw` - **Type**: `object` ## experimental <read-more to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features"> Learn more about Nuxt's experimental features. </read-more> ## extends Extend project from multiple local or remote sources. Value should be either a string or array of strings pointing to source directories or config path relative to current config. You can use `github:`, `gh:` `gitlab:` or `bitbucket:` **See**: [`c12` docs on extending config layers](https://github.com/unjs/c12#extending-config-layer-from-remote-sources) **See**: [`giget` documentation](https://github.com/unjs/giget) ## extensions The extensions that should be resolved by the Nuxt resolver. - **Type**: `array` - **Default** ```json [ ".js", ".jsx", ".mjs", ".ts", ".tsx", ".vue" ] ``` ## features <read-more to="https://nuxt.com/docs/4.x/guide/going-further/features#features"> Learn more about Nuxt's opt-in features. </read-more> ## future <read-more to="https://nuxt.com/docs/4.x/guide/going-further/features#features"> Learn more about opting-in to new features that will become default in a future (possibly major) version of the framework. </read-more> ## hooks Hooks are listeners to Nuxt events that are typically used in modules, but are also available in `nuxt.config`. Internally, hooks follow a naming pattern using colons (e.g., build:done). For ease of configuration, you can also structure them as an hierarchical object in `nuxt.config` (as below). **Example**: ```ts import fs from 'node:fs' import path from 'node:path' export default defineNuxtConfig({ hooks: { build: { done (builder) { const extraFilePath = path.join( builder.nuxt.options.buildDir, 'extra-file', ) fs.writeFileSync(extraFilePath, 'Something extra') }, }, }, }) ``` ## ignore More customizable than `ignorePrefix`: all files matching glob patterns specified inside the `ignore` array will be ignored in building. - **Type**: `array` - **Default** ```json [ "**/*.stories.{js,cts,mts,ts,jsx,tsx}", "**/*.{spec,test}.{js,cts,mts,ts,jsx,tsx}", "**/*.d.{cts,mts,ts}", "**/*.d.vue.{cts,mts,ts}", "**/.{pnpm-store,vercel,netlify,output,git,cache,data}", "**/*.sock", ".nuxt/analyze", ".nuxt", "**/-*.*" ] ``` ## ignoreOptions Pass options directly to `node-ignore` (which is used by Nuxt to ignore files). **See**: [node-ignore](https://github.com/kaelzhang/node-ignore) **Example**: ```ts export default defineNuxtConfig({ ignoreOptions: { ignorecase: false, }, }) ``` ## ignorePrefix Any file in `app/pages/`, `app/layouts/`, `app/middleware/`, and `public/` directories will be ignored during the build process if its filename starts with the prefix specified by `ignorePrefix`. This is intended to prevent certain files from being processed or served in the built application. By default, the `ignorePrefix` is set to '-', ignoring any files starting with '-'. - **Type**: `string` - **Default:** `"-"` ## imports Configure how Nuxt auto-imports composables into your application. **See**: [Nuxt documentation](https://nuxt.com/docs/4.x/directory-structure/app/composables) ### `dirs` An array of custom directories that will be auto-imported. Note that this option will not override the default directories (~/composables, ~/utils). - **Type**: `array` **Example**: ```ts export default defineNuxtConfig({ imports: { // Auto-import pinia stores defined in `~/stores` dirs: ['stores'], }, }) ``` ### `global` - **Type**: `boolean` - **Default:** `false` ### `scan` Whether to scan your `app/composables/` and `app/utils/` directories for composables to auto-import. Auto-imports registered by Nuxt or other modules, such as imports from `vue` or `nuxt`, will still be enabled. - **Type**: `boolean` - **Default:** `true` ## logLevel Log level when building logs. Defaults to 'silent' when running in CI or when a TTY is not available. This option is then used as 'silent' in Vite and 'none' in webpack - **Type**: `string` - **Default:** `"info"` ## modules Modules are Nuxt extensions which can extend its core functionality and add endless integrations. Each module is either a string (which can refer to a package, or be a path to a file), a tuple with the module as first string and the options as a second object, or an inline module function. Nuxt tries to resolve each item in the modules array using node require path (in `node_modules`) and then will be resolved from project `rootDir` if `~~` alias is used. - **Type**: `array` <callout> **Note**: Modules are executed sequentially so the order is important. First, the modules defined in `nuxt.config.ts` are loaded. Then, modules found in the `modules/` directory are executed, and they load in alphabetical order. </callout> **Example**: ```ts export default defineNuxtConfig({ modules: [ // Using package name '@nuxt/scripts', // Relative to your project rootDir '~~/custom-modules/awesome.js', // Providing options ['@nuxtjs/google-analytics', { ua: 'X1234567' }], // Inline definition function () {}, ], }) ``` ## modulesDir Used to set the modules directories for path resolving (for example, webpack's `resolveLoading`, `nodeExternals` and `postcss`). The configuration path is relative to `options.rootDir` (default is current working directory). Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository. - **Type**: `array` - **Default** ```json [ "/<rootDir>/node_modules" ] ``` **Example**: ```ts export default defineNuxtConfig({ modulesDir: ['../../node_modules'], }) ``` ## nitro Configuration for Nitro. **See**: [Nitro configuration docs](https://nitro.build/config) ### `routeRules` - **Type**: `object` ### `runtimeConfig` - **Type**: `object` - **Default** ```json { "public": {}, "app": { "buildId": "4a2e2d30-418f-41df-8e58-ed5df06de7fd", "baseURL": "/", "buildAssetsDir": "/_nuxt/", "cdnURL": "" }, "nitro": { "envPrefix": "NUXT_" } } ``` ## optimization Build time optimization configuration. ### `asyncTransforms` Options passed directly to the transformer from `unctx` that preserves async context after `await`. #### `asyncFunctions` - **Type**: `array` - **Default** ```json [ "defineNuxtPlugin", "defineNuxtRouteMiddleware" ] ``` #### `objectDefinitions` ##### `defineNuxtComponent` - **Type**: `array` - **Default** ```json [ "asyncData", "setup" ] ``` ##### `defineNuxtPlugin` - **Type**: `array` - **Default** ```json [ "setup" ] ``` ##### `definePageMeta` - **Type**: `array` - **Default** ```json [ "middleware", "validate" ] ``` ### `keyedComposables` Functions to inject a key for. As long as the number of arguments passed to the function is less than `argumentLength`, an additional magic string will be injected as the last argument. This key is stable between SSR and client-side hydration. You will need to take steps to handle this additional key. The key is unique based on the location of the function being invoked within the file. <read-more to="https://nuxt.com/docs/4.x/guide/modules/recipes-basics#add-keyed-functions"> Learn more about keyed functions. </read-more> - **Type**: `array` - **Default** ```json [ { "name": "callOnce", "argumentLength": 3, "source": "#app/composables/once" }, { "name": "defineNuxtComponent", "argumentLength": 2, "source": "#app/composables/component" }, { "name": "useState", "argumentLength": 2, "source": "#app/composables/state" }, { "name": "useFetch", "argumentLength": 3, "source": "#app/composables/fetch" }, { "name": "useAsyncData", "argumentLength": 3, "source": "#app/composables/asyncData" }, { "name": "useLazyAsyncData", "argumentLength": 3, "source": "#app/composables/asyncData" }, { "name": "useLazyFetch", "argumentLength": 3, "source": "#app/composables/fetch" } ] ``` ### `treeShake` Tree shake code from specific builds. #### `composables` Tree shake composables from the server or client builds. **Example**: ```ts export default defineNuxtConfig({ optimization: { treeShake: { composables: { client: { vue: ['onMounted'] }, server: { vue: ['onServerPrefetch'] }, }, }, }, }) ``` ##### `client` - **Type**: `object` - **Default** ```json { "vue": [ "onRenderTracked", "onRenderTriggered", "onServerPrefetch" ], "#app": [ "definePayloadReducer", "definePageMeta", "onPrehydrate" ] } ``` ##### `server` - **Type**: `object` - **Default** ```json { "vue": [ "onMounted", "onUpdated", "onUnmounted", "onBeforeMount", "onBeforeUpdate", "onBeforeUnmount", "onRenderTracked", "onRenderTriggered", "onActivated", "onDeactivated" ], "#app": [ "definePayloadReviver", "definePageMeta" ] } ``` ## pages Whether to use the vue-router integration in Nuxt 3. If you do not provide a value it will be enabled if you have a `app/pages/` directory in your source folder. Additionally, you can provide a glob pattern or an array of patterns to scan only certain files for pages. **Example**: ```ts export default defineNuxtConfig({ pages: { pattern: ['**/*/*.vue', '!**/*.spec.*'], }, }) ``` ## plugins An array of nuxt app plugins. Each plugin can be a string (which can be an absolute or relative path to a file). If it ends with `.client` or `.server` then it will be automatically loaded only in the appropriate context. It can also be an object with `src` and `mode` keys. - **Type**: `array` <callout> **Note**: Plugins are also auto-registered from the `~/plugins` directory and these plugins do not need to be listed in `nuxt.config` unless you need to customize their order. All plugins are deduplicated by their src path. </callout> **See**: [`app/plugins/` directory documentation](https://nuxt.com/docs/4.x/directory-structure/app/plugins) **Example**: ```ts export default defineNuxtConfig({ plugins: [ '~/custom-plugins/foo.client.js', // only in client side '~/custom-plugins/bar.server.js', // only in server side '~/custom-plugins/baz.js', // both client & server { src: '~/custom-plugins/both-sides.js' }, { src: '~/custom-plugins/client-only.js', mode: 'client' }, // only on client side { src: '~/custom-plugins/server-only.js', mode: 'server' }, // only on server side ], }) ``` ## postcss ### `order` A strategy for ordering PostCSS plugins. - **Type**: `function` ### `plugins` Options for configuring PostCSS plugins. **See**: [PostCSS docs](https://postcss.org/) #### `autoprefixer` Plugin to parse CSS and add vendor prefixes to CSS rules. **See**: [`autoprefixer`](https://github.com/postcss/autoprefixer) #### `cssnano` - **Type**: `object` **See**: [`cssnano` configuration options](https://cssnano.github.io/cssnano/docs/config-file/#configuration-options) ## rootDir Define the root directory of your application. This property can be overwritten (for example, running `nuxt ./my-app/` will set the `rootDir` to the absolute path of `./my-app/` from the current/working directory. It is normally not needed to configure this option. - **Type**: `string` - **Default:** `"/<rootDir>"` ## routeRules Global route options applied to matching server routes. **Experimental**: This is an experimental feature and API may change in the future. **See**: [Nitro route rules documentation](https://nitro.build/config#routerules) ## router ### `options` Additional router options passed to `vue-router`. On top of the options for `vue-router`, Nuxt offers additional options to customize the router (see below). <callout> **Note**: Only JSON serializable options should be passed by Nuxt config. For more control, you can use an `router.options.ts` file. </callout> **See**: [Vue Router documentation](https://router.vuejs.org/api/interfaces/routeroptions) #### `hashMode` You can enable hash history in SPA mode. In this mode, router uses a hash character (#) before the actual URL that is internally passed. When enabled, the **URL is never sent to the server** and **SSR is not supported**. - **Type**: `boolean` - **Default:** `false` **Default**: false #### `scrollBehaviorType` Customize the scroll behavior for hash links. - **Type**: `string` - **Default:** `"auto"` **Default**: 'auto' ## runtimeConfig Runtime config allows passing dynamic config and environment variables to the Nuxt app context. The value of this object is accessible from server only using `useRuntimeConfig`. It mainly should hold *private* configuration which is not exposed on the frontend. This could include a reference to your API secret tokens. Anything under `public` and `app` will be exposed to the frontend as well. Values are automatically replaced by matching env variables at runtime, e.g. setting an environment variable `NUXT_API_KEY=my-api-key NUXT_PUBLIC_BASE_URL=/foo/` would overwrite the two values in the example below. - **Type**: `object` - **Default** ```json { "public": {}, "app": { "buildId": "4a2e2d30-418f-41df-8e58-ed5df06de7fd", "baseURL": "/", "buildAssetsDir": "/_nuxt/", "cdnURL": "" } } ``` **Example**: ```ts export default defineNuxtConfig({ runtimeConfig: { apiKey: '', // Default to an empty string, automatically set at runtime using process.env.NUXT_API_KEY public: { baseURL: '', // Exposed to the frontend as well. }, }, }) ``` ## server Configuration for Nuxt's server builder. ### `builder` Specify the server builder to use for bundling the server part of your application. By default, Nuxt uses `@nuxt/nitro-server`, which provides standalone Nitro integration. This architecture allows for different Nitro integration patterns, such as using Nitro as a Vite plugin (with the Vite Environment API). `"nitro"` and `"vite"` are shorthands for `@nuxt/nitro-server` and `@nuxt/vite-server`. The latter is experimental and implemented with Vite alone: with `ssr: false` it produces a static SPA, and with SSR enabled it builds a server from the Nuxt SSR renderer whose entry exports a web-standard `{ fetch }` (`.output/server/index.mjs` serves the static output in front of it, and `nuxt preview` runs it). Every dependency is bundled into that output, so it deploys without `node_modules`. `nuxt generate` crawls that server at the end of the build and writes a static `.output/public`. It ships no server runtime, so server routes, route rules other than `prerender`, inlined styles and server components are unavailable, and modules that need a server will not work. - **Type**: `string | { bundle: (nuxt: Nuxt) => Promise<void> }` - **Default:** `"@nuxt/nitro-server"` <callout type="warning"> This option is intended for internal use and the API is not finalized. Please open an issue before relying on the current implementation. </callout> ## serverDir Define the server directory of your Nuxt application, where Nitro routes, middleware and plugins are kept. If a relative path is specified, it will be relative to your `rootDir`. - **Type**: `string` - **Default:** `"/<rootDir>/server"` ## serverHandlers Nitro server handlers. Each handler accepts the following options: - handler: The path to the file defining the handler. - route: The route under which the handler is available. This follows the conventions of [rou3](https://github.com/h3js/rou3). - method: The HTTP method of requests that should be handled. - middleware: Specifies whether it is a middleware handler. - lazy: Specifies whether to use lazy loading to import the handler. - **Type**: `array` **See**: [`server/` directory documentation](https://nuxt.com/docs/4.x/directory-structure/server) <callout> **Note**: Files from `server/api`, `server/middleware` and `server/routes` will be automatically registered by Nuxt. </callout> **Example**: ```ts export default defineNuxtConfig({ serverHandlers: [ { route: '/path/foo/**:name', handler: '#server/foohandler.ts' }, ], }) ``` ## sourcemap Configures whether and how sourcemaps are generated for server and/or client bundles. If set to a single boolean, that value applies to both server and client. Additionally, the `'hidden'` option is also available for both server and client. Available options for both client and server: - `true`: Generates sourcemaps and includes source references in the final bundle. - `false`: Does not generate any sourcemaps. - `'hidden'`: Generates sourcemaps but does not include references in the final bundle. - **Type**: `object` - **Default** ```json { "server": true, "client": false } ``` ## spaLoadingTemplate Boolean or a path to an HTML file with the contents of which will be inserted into any HTML page rendered with `ssr: false`. - If it is unset, it will use `~/spa-loading-template.html` file in one of your layers, if it exists. - If it is false, no SPA loading indicator will be loaded. - If true, Nuxt will look for `~/spa-loading-template.html` file in one of your layers, or a default Nuxt image will be used. Some good sources for spinners are [SpinKit](https://github.com/tobiasahlin/SpinKit) or [SVG Spinners](https://icones.js.org/collection/svg-spinners). - **Default:** `null` **Example**: ~/spa-loading-template.html ```html <!-- https://github.com/barelyhuman/snips/blob/dev/pages/css-loader.md --> <div class="loader"></div> <style> .loader { display: block; position: fixed; z-index: 1031; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 18px; height: 18px; box-sizing: border-box; border: solid 2px transparent; border-top-color: #000; border-left-color: #000; border-bottom-color: #efefef; border-right-color: #efefef; border-radius: 50%; -webkit-animation: loader 400ms linear infinite; animation: loader 400ms linear infinite; } @-webkit-keyframes loader { 0% { -webkit-transform: translate(-50%, -50%) rotate(0deg); } 100% { -webkit-transform: translate(-50%, -50%) rotate(360deg); } } @keyframes loader { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } </style> ``` ## srcDir Define the source directory of your Nuxt application. If a relative path is specified, it will be relative to the `rootDir`. - **Type**: `string` - **Default:** `"app"` (Nuxt 4), `"."` (Nuxt 3 with `compatibilityMode: 3`) **Example**: ```ts export default defineNuxtConfig({ srcDir: 'app/', }) ``` This expects the following folder structure: ```bash -| app/ ---| assets/ ---| components/ ---| composables/ ---| layouts/ ---| middleware/ ---| pages/ ---| plugins/ ---| utils/ ---| app.config.ts ---| app.vue ---| error.vue -| server/ -| shared/ -| public/ -| modules/ -| layers/ -| nuxt.config.ts -| package.json ``` ## ssr Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time. If set to `false` generated pages will have no content. - **Type**: `boolean` - **Default:** `true` ## telemetry Manually disable nuxt telemetry. **See**: [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information. ## test Whether your app is being unit tested. - **Type**: `boolean` - **Default:** `false` ## theme Extend project from a local or remote source. Value should be a string pointing to source directory or config path relative to current config. You can use `github:`, `gitlab:`, `bitbucket:` or `https://` to extend from a remote git repository. - **Type**: `string` ## typescript Configuration for Nuxt's TypeScript integration. ### `appTsConfig` You can extend the generated `.nuxt/tsconfig.app.json` (and legacy `.nuxt/tsconfig.json`) TypeScript configuration using this option. Options set here take precedence over `tsConfig`. **See**: [tsconfig.json information](https://nuxt.com/docs/4.x/directory-structure/tsconfig) ### `builder` Which builder types to include for your project. By default Nuxt infers this based on your `builder` option (defaulting to 'vite') but you can either turn off builder environment types (with `false`) to handle this fully yourself, or opt for a 'shared' option. The 'shared' option is advised for module authors, who will want to support multiple possible builders. - **Default:** `null` ### `hoist` Modules to generate deep aliases for within `compilerOptions.paths`. This does not yet support subpaths. It may be necessary when using Nuxt within a pnpm monorepo with `shamefully-hoist=false`. - **Type**: `array` - **Default** ```json [ "nitropack/types", "nitropack/runtime", "nitropack", "defu", "h3", "consola", "ofetch", "@unhead/vue", "@nuxt/devtools", "vue", "@vue/runtime-core", "@vue/compiler-sfc", "vue-router", "vue-router/auto-routes", "unplugin-vue-router/client", "@nuxt/schema", "nuxt" ] ``` ### `includeWorkspace` Include parent workspace in the Nuxt project. Mostly useful for themes and module authors. - **Type**: `boolean` - **Default:** `false` ### `nodeTsConfig` You can extend the generated `.nuxt/tsconfig.node.json` TypeScript configuration using this option. **See**: [tsconfig.json information](https://nuxt.com/docs/4.x/directory-structure/tsconfig) ### `serverTsConfig` You can extend the generated `.nuxt/tsconfig.server.json` TypeScript configuration using this option. Options set here take precedence over `tsConfig`. **See**: [tsconfig.json information](https://nuxt.com/docs/4.x/directory-structure/tsconfig) ### `sharedTsConfig` You can extend the generated `.nuxt/tsconfig.shared.json` TypeScript configuration using this option. **See**: [tsconfig.json information](https://nuxt.com/docs/4.x/directory-structure/tsconfig) ### `shim` Generate a `*.vue` shim. We recommend instead letting the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) generate accurate types for your components. Note that you may wish to set this to `true` if you are using other libraries, such as ESLint, that are unable to understand the type of `.vue` files. - **Type**: `boolean` - **Default:** `false` ### `strict` TypeScript comes with certain checks to give you more safety and analysis of your program. Once youโ€™ve converted your codebase to TypeScript, you can start enabling these checks for greater safety. [Read More](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) - **Type**: `boolean` - **Default:** `true` ### `tsConfig` You can extend the generated tsconfig files with shared options using this option. `compilerOptions` apply to all generated tsconfigs (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, `.nuxt/tsconfig.node.json` and `.nuxt/tsconfig.shared.json`), while `include`, `exclude` and `vueCompilerOptions` apply only to `.nuxt/tsconfig.app.json` (and the legacy `.nuxt/tsconfig.json`). Two groups of `compilerOptions` are exceptions: DOM- and Vue-specific options (such as `lib`, `jsx` and `jsxImportSource`) apply only to `.nuxt/tsconfig.app.json`, and `types`, `paths` and `noEmit` are managed by Nuxt per context, so they cannot be set globally for the `node`, `shared` and `server` tsconfigs. Use `appTsConfig`, `serverTsConfig`, `nodeTsConfig` or `sharedTsConfig` for context-specific overrides; they take precedence over this option. **See**: [tsconfig.json information](https://nuxt.com/docs/4.x/directory-structure/tsconfig) ### `typeCheck` Enable build-time type checking. If set to true, this will type check in development. You can restrict this to build-time type checking by setting it to `build`. Requires to install `typescript` and `vue-tsc` as dev dependencies. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt TypeScript docs](https://nuxt.com/docs/4.x/guide/concepts/typescript) ## unhead An object that allows us to configure the `unhead` nuxt module. ### `legacy` Enable the legacy compatibility mode for `unhead` module. This applies the following changes: - Disables Capo.js sorting - Adds the `DeprecationsPlugin`: supports `hid`, `vmid`, `children`, `body` - Adds the `PromisesPlugin`: supports promises as input - **Type**: `boolean` - **Default:** `false` **See**: [`unhead` migration documentation](https://unhead.unjs.io/docs/typescript/head/guides/get-started/migration) **Example**: ```ts export default defineNuxtConfig({ unhead: { legacy: true, }, }) ``` ### `renderSSRHeadOptions` An object that will be passed to `renderSSRHead` to customize the output. - **Type**: `object` - **Default** ```json { "omitLineBreaks": false } ``` **Example**: ```ts export default defineNuxtConfig({ unhead: { renderSSRHeadOptions: { omitLineBreaks: true, }, }, }) ``` ## vite Configuration that will be passed directly to Vite. Top-level `vite` options are shared across both client and server environments. Use `$client` and `$server` to provide environment-specific configuration that will be merged into their respective builds. **Example**: ```ts export default defineNuxtConfig({ vite: { $client: { build: { rollupOptions: { output: { manualChunks: { analytics: ['analytics-package'], }, }, }, }, }, $server: { build: { sourcemap: 'inline', }, }, }, }) ``` **See**: [Vite configuration docs](https://vite.dev/config/) for more information. Please note that not all vite options are supported in Nuxt. ### `$client` Configuration that will be merged into Vite's configuration for the client (browser) build. - **Type**: `object` ### `$server` Configuration that will be merged into Vite's configuration for the server build. - **Type**: `object` ### `build` #### `assetsDir` - **Type**: `string` - **Default:** `"_nuxt/"` #### `emptyOutDir` - **Type**: `boolean` - **Default:** `false` ### `cacheDir` - **Type**: `string` - **Default:** `"/<rootDir>/node_modules/.cache/vite"` ### `clearScreen` - **Type**: `boolean` - **Default:** `true` ### `define` - **Type**: `object` - **Default** ```json { "__VUE_PROD_HYDRATION_MISMATCH_DETAILS__": false, "process.dev": false, "import.meta.dev": false, "process.test": false, "import.meta.test": false } ``` ### `esbuild` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` ### `mode` - **Type**: `string` - **Default:** `"production"` ### `optimizeDeps` #### `esbuildOptions` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` #### `exclude` - **Type**: `array` - **Default** ```json [ "vue-demi" ] ``` ### `publicDir` ### `resolve` #### `extensions` - **Type**: `array` - **Default** ```json [ ".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue" ] ``` ### `root` - **Type**: `string` - **Default:** `"/<rootDir>"` ### `server` #### `fs` ##### `allow` - **Type**: `array` - **Default** ```json [ "/<rootDir>/.nuxt", "/<rootDir>/app", "/<rootDir>", "/<workspaceDir>" ] ``` ### `vue` #### `features` ##### `propsDestructure` - **Type**: `boolean` - **Default:** `true` #### `isProduction` - **Type**: `boolean` - **Default:** `true` #### `script` ##### `hoistStatic` #### `template` ##### `compilerOptions` - **Type**: `object` ##### `transformAssetUrls` - **Type**: `object` - **Default** ```json { "video": [ "src", "poster" ], "source": [ "src" ], "img": [ "src" ], "image": [ "xlink:href", "href" ], "use": [ "xlink:href", "href" ] } ``` ### `vueJsx` - **Type**: `object` - **Default** ```json { "isCustomElement": { "$schema": { "title": "", "description": "", "tags": [] } } } ``` ## vue Vue.js config ### `compilerOptions` Options for the Vue compiler that will be passed at build time. **See**: [Vue documentation](https://vuejs.org/api/application#app-config-compileroptions) ### `config` It is possible to pass configure the Vue app globally. Only serializable options may be set in your `nuxt.config`. All other options should be set at runtime in a Nuxt plugin. **See**: [Vue app config documentation](https://vuejs.org/api/application#app-config) ### `propsDestructure` Enable reactive destructure for `defineProps` - **Type**: `boolean` - **Default:** `true` ### `runtimeCompiler` Include Vue compiler in runtime bundle. Enabling this allows components to compile templates at runtime (for example, string `template` options or templates supplied via data). - **Type**: `boolean` - **Default:** `false` <warning> Runtime template compilation executes the compiled template as JavaScript. Never compile templates built from user-provided or otherwise untrusted input; doing so is equivalent to `eval` and can lead to cross-site scripting or remote code execution. See the [Vue security guide](https://vuejs.org/guide/best-practices/security.html). </warning> ### `transformAssetUrls` #### `image` - **Type**: `array` - **Default** ```json [ "xlink:href", "href" ] ``` #### `img` - **Type**: `array` - **Default** ```json [ "src" ] ``` #### `source` - **Type**: `array` - **Default** ```json [ "src" ] ``` #### `use` - **Type**: `array` - **Default** ```json [ "xlink:href", "href" ] ``` #### `video` - **Type**: `array` - **Default** ```json [ "src", "poster" ] ``` ## watch The watch property lets you define patterns that will restart the Nuxt dev server when changed. It is an array of strings or regular expressions. Strings should be either absolute paths or relative to the `srcDir` (and the `srcDir` of any layers). Regular expressions will be matched against the path relative to the project `srcDir` (and the `srcDir` of any layers). - **Type**: `array` ## watchers The watchers property lets you overwrite watchers configuration in your `nuxt.config`. ### `chokidar` Options to pass directly to `chokidar`. **See**: [chokidar](https://github.com/paulmillr/chokidar#api) #### `ignoreInitial` - **Type**: `boolean` - **Default:** `true` #### `ignorePermissionErrors` - **Type**: `boolean` - **Default:** `true` ### `rewatchOnRawEvents` An array of event types, which, when received, will cause the watcher to restart. ### `webpack` `watchOptions` to pass directly to webpack. **See**: [webpack@4 watch options](https://v4.webpack.js.org/configuration/watch/#watchoptions). #### `aggregateTimeout` - **Type**: `number` - **Default:** `1000` ## webpack ### `aggressiveCodeRemoval` Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle. - **Type**: `boolean` - **Default:** `false` ### `analyze` If you are using webpack, Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them. Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - **Type**: `object` - **Default** ```json { "template": "treemap", "projectRoot": "/<rootDir>", "filename": "/<rootDir>/.nuxt/analyze/{name}.html" } ``` **Example**: ```ts export default defineNuxtConfig({ webpack: { analyze: { analyzerMode: 'static', }, }, }) ``` ### `cssSourceMap` Enables CSS source map support (defaults to `true` in development). - **Type**: `boolean` - **Default:** `false` ### `devMiddleware` See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options. #### `stats` - **Type**: `string` - **Default:** `"none"` ### `experiments` Configure [webpack experiments](https://webpack.js.org/configuration/experiments/) ### `extractCSS` Enables Common CSS Extraction. Using [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin) under the hood, your CSS will be extracted into separate files, usually one per component. This allows caching your CSS and JavaScript separately. - **Type**: `boolean` - **Default:** `true` **Example**: ```ts export default defineNuxtConfig({ webpack: { extractCSS: true, // or extractCSS: { ignoreOrder: true, }, }, }) ``` If you want to extract all your CSS to a single file, there is a workaround for this. However, note that it is not recommended to extract everything into a single file. Extracting into multiple CSS files is better for caching and preload isolation. It can also improve page performance by downloading and resolving only those resources that are needed. **Example**: ```ts export default defineNuxtConfig({ webpack: { extractCSS: true, optimization: { splitChunks: { cacheGroups: { styles: { name: 'styles', test: /\.(css|vue)$/, chunks: 'all', enforce: true, }, }, }, }, }, }) ``` ### `filenames` Customize bundle filenames. To understand a bit more about the use of manifests, take a look at [webpack documentation](https://webpack.js.org/guides/code-splitting/). <callout> **Note**: Be careful when using non-hashed based filenames in production as most browsers will cache the asset and not detect the changes on first load. </callout> This example changes fancy chunk names to numerical ids: **Example**: ```ts export default defineNuxtConfig({ webpack: { filenames: { chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js'), }, }, }) ``` #### `app` - **Type**: `function` #### `chunk` - **Type**: `function` #### `css` - **Type**: `function` #### `font` - **Type**: `function` #### `img` - **Type**: `function` #### `video` - **Type**: `function` ### `friendlyErrors` Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin). - **Type**: `boolean` - **Default:** `true` ### `hotMiddleware` See [webpack-hot-middleware](https://github.com/webpack/webpack-hot-middleware) for available options. ### `loaders` Customize the options of Nuxt's integrated webpack loaders. #### `css` See [css-loader](https://github.com/webpack/css-loader) for available options. ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `importLoaders` - **Type**: `number` - **Default:** `0` ##### `url` ###### `filter` - **Type**: `function` #### `cssModules` See [css-loader](https://github.com/webpack/css-loader) for available options. ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `importLoaders` - **Type**: `number` - **Default:** `0` ##### `modules` ###### `localIdentName` - **Type**: `string` - **Default:** `"[local]_[hash:base64:5]"` ##### `url` ###### `filter` - **Type**: `function` #### `esbuild` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` **See**: [esbuild loader](https://github.com/privatenumber/esbuild-loader) #### `file` **See**: [`file-loader` Options](https://github.com/webpack/file-loader#options) **Default**: ```json { "esModule": false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `fontUrl` **See**: [`file-loader` Options](https://github.com/webpack/file-loader#options) **Default**: ```json { "esModule": false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `imgUrl` **See**: [`file-loader` Options](https://github.com/webpack/file-loader#options) **Default**: ```json { "esModule": false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `less` - **Default** ```json { "sourceMap": false } ``` **See**: [`less-loader` Options](https://github.com/webpack/less-loader#options) #### `pugPlain` **See**: [`pug` options](https://pugjs.org/api/reference.html#options) #### `sass` **See**: [`sass-loader` Options](https://github.com/webpack/sass-loader#options) **Default**: ```json { "sassOptions": { "indentedSyntax": true } } ``` ##### `sassOptions` ###### `indentedSyntax` - **Type**: `boolean` - **Default:** `true` #### `scss` - **Default** ```json { "sourceMap": false } ``` **See**: [`sass-loader` Options](https://github.com/webpack/sass-loader#options) #### `stylus` - **Default** ```json { "sourceMap": false } ``` **See**: [`stylus-loader` Options](https://github.com/webpack/stylus-loader#options) #### `vue` See [vue-loader](https://github.com/vuejs/vue-loader) for available options. ##### `compilerOptions` - **Type**: `object` ##### `propsDestructure` - **Type**: `boolean` - **Default:** `true` ##### `transformAssetUrls` - **Type**: `object` - **Default** ```json { "video": [ "src", "poster" ], "source": [ "src" ], "img": [ "src" ], "image": [ "xlink:href", "href" ], "use": [ "xlink:href", "href" ] } ``` #### `vueStyle` - **Default** ```json { "sourceMap": false } ``` ### `optimization` Configure [webpack optimization](https://webpack.js.org/configuration/optimization/). #### `minimize` Set minimize to `false` to disable all minimizers. (It is disabled in development by default). - **Type**: `boolean` - **Default:** `true` #### `minimizer` You can set minimizer to a customized array of plugins. #### `runtimeChunk` - **Type**: `string` - **Default:** `"single"` #### `splitChunks` ##### `automaticNameDelimiter` - **Type**: `string` - **Default:** `"/"` ##### `cacheGroups` ##### `chunks` - **Type**: `string` - **Default:** `"all"` ### `optimizeCSS` OptimizeCSSAssets plugin options. Defaults to true when `extractCSS` is enabled. - **Type**: `boolean` - **Default:** `false` **See**: [css-minimizer-webpack-plugin documentation](https://github.com/webpack/css-minimizer-webpack-plugin). ### `plugins` Add webpack plugins. - **Type**: `array` **Example**: ```ts import webpack from 'webpack' import { version } from './package.json' export default defineNuxtConfig({ webpack: { plugins: [ // ... new webpack.DefinePlugin({ 'process.VERSION': version, }), ], }, }) ``` ### `postcss` Customize PostCSS Loader. same options as [`postcss-loader` options](https://github.com/webpack/postcss-loader#options) #### `postcssOptions` ##### `plugins` - **Type**: `object` - **Default** ```json { "autoprefixer": {}, "cssnano": {} } ``` ### `profile` Enable the profiler in webpackbar. It is normally enabled by CLI argument `--profile`. - **Type**: `boolean` - **Default:** `false` **See**: [webpackbar](https://github.com/unjs/webpackbar#profile). ### `serverURLPolyfill` The polyfill library to load to provide URL and URLSearchParams. Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)). - **Type**: `string` - **Default:** `"url"` ### `warningIgnoreFilters` Filters to hide build warnings. - **Type**: `array` ## workspaceDir Define the workspace directory of your application. Often this is used when in a monorepo setup. Nuxt will attempt to detect your workspace directory automatically, but you can override it here. It is normally not needed to configure this option. - **Type**: `string` - **Default:** `"/<workspaceDir>"` # abortNavigation > abortNavigation is a helper function that prevents navigation from taking place and throws an error if one is set as a parameter. <warning> `abortNavigation` is only usable inside a [route middleware handler](https://nuxt.com/docs/4.x/directory-structure/app/middleware). </warning> ## Type ```ts [Signature] export function abortNavigation (err?: Error | string): false ``` ## Parameters ### `err` - **Type**: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) | `string`<br /> Optional error to be thrown by `abortNavigation`. ## Example The example below shows how you can use `abortNavigation` in a route middleware to prevent unauthorized route access: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const user = useState('user') if (!user.value.isAuthorized) { return abortNavigation() } if (to.path !== '/edit-post') { return navigateTo('/edit-post') } }) ``` ### `err` as a String You can pass the error as a string: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const user = useState('user') if (!user.value.isAuthorized) { return abortNavigation('Insufficient permissions.') } }) ``` ### `err` as an Error Object You can pass the error as an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object, e.g. caught by the `catch`-block: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { try { /* code that might throw an error */ } catch (err) { return abortNavigation(err) } }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # addRouteMiddleware > addRouteMiddleware() is a helper function to dynamically add middleware in your application. <note> Route middleware are navigation guards stored in the [`app/middleware/`](https://nuxt.com/docs/4.x/directory-structure/app/middleware) directory of your Nuxt application (unless [set otherwise](https://nuxt.com/docs/4.x/api/nuxt-config#middleware)). </note> ## Type ```ts [Signature] function addRouteMiddleware (name: string, middleware: RouteMiddleware, options?: AddRouteMiddlewareOptions): void function addRouteMiddleware (middleware: RouteMiddleware): void interface AddRouteMiddlewareOptions { global?: boolean } ``` ## Parameters ### `name` - **Type:** `string` | `RouteMiddleware` Can be either a string or a function of type `RouteMiddleware`. Function takes the next route `to` as the first argument and the current route `from` as the second argument, both of which are Vue route objects. Learn more about available properties of [route objects](https://nuxt.com/docs/4.x/api/composables/use-route). ### `middleware` - **Type:** `RouteMiddleware` The second argument is a function of type `RouteMiddleware`. Same as above, it provides `to` and `from` route objects. It becomes optional if the first argument in `addRouteMiddleware()` is already passed as a function. ### `options` - **Type:** `AddRouteMiddlewareOptions` An optional `options` argument lets you set the value of `global` to `true` to indicate whether the router middleware is global or not (set to `false` by default). ## Example ### Named Route Middleware Named route middleware is defined by providing a string as the first argument and a function as the second: ```ts [app/plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware('named-middleware', () => { console.log('named middleware added in Nuxt plugin') }) }) ``` When defined in a plugin, it overrides any existing middleware of the same name located in the `app/middleware/` directory. ### Global Route Middleware Global route middleware can be defined in two ways: - Pass a function directly as the first argument without a name. It will automatically be treated as global middleware and applied on every route change.```ts [app/plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware((to, from) => { console.log('anonymous global middleware that runs on every route change') }) }) ``` - Set an optional, third argument `{ global: true }` to indicate whether the route middleware is global.```ts [app/plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware('global-middleware', (to, from) => { console.log('global middleware that runs on every route change') }, { global: true }, ) }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # callOnce > Run a given function or block of code once during SSR or CSR. <important> This utility is available since [Nuxt v3.9](https://nuxt.com/blog/v3-9). </important> ## Purpose The `callOnce` function is designed to execute a given function or block of code only once during: - server-side rendering but not hydration - client-side navigation This is useful for code that should be executed only once, such as logging an event or setting up a global state. ## Usage The default mode of `callOnce` is to run code only once. For example, if the code runs on the server it won't run again on the client. It also won't run again if you `callOnce` more than once on the client, for example by navigating back to this page. ```vue [app/app.vue] <script setup lang="ts"> const websiteConfig = useState('config') await callOnce(async () => { console.log('This will only be logged once') websiteConfig.value = await $fetch('https://my-cms.com/api/website-config') }) </script> ``` It is also possible to run on every navigation while still avoiding the initial server/client double execution. For this, it is possible to use the `navigation` mode <badge className="align-middle" color="info" size="xs"> v3.15 </badge> : ```vue [app/app.vue] <script setup lang="ts"> const websiteConfig = useState('config') await callOnce(async () => { console.log('This will only be logged once and then on every client side navigation') websiteConfig.value = await $fetch('https://my-cms.com/api/website-config') }, { mode: 'navigation' }) </script> ``` <important> `navigation` mode is available since [Nuxt v3.15](https://nuxt.com/blog/v3-15). </important> <tip to="https://nuxt.com/docs/4.x/getting-started/state-management#usage-with-pinia"> `callOnce` is useful in combination with the [Pinia module](https://nuxt.com/modules/pinia) to call store actions. </tip> <read-more to="https://nuxt.com/docs/4.x/getting-started/state-management"> </read-more> <warning> Note that `callOnce` doesn't return anything. You should use [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) or [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) if you want to do data fetching during SSR. </warning> <note> `callOnce` is a composable meant to be called directly in a setup function, plugin, or route middleware, because it needs to add data to the Nuxt payload to avoid re-calling the function on the client when the page hydrates. </note> ## Type ```ts [Signature] export function callOnce (key?: string, fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void> export function callOnce (fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void> type CallOnceOptions = { /** * Execution mode for the callOnce function * @default 'render' */ mode?: 'navigation' | 'render' } ``` ## Parameters - `key`: A unique key ensuring that the code is run once. If you do not provide a key, then a key that is unique to the file and line number of the instance of `callOnce` will be generated for you. - `fn`: The function to run once. It can be asynchronous. - `options`: Setup the mode, either to re-execute on navigation (`navigation`) or just once for the lifetime of the app (`render`). Defaults to `render`. - `render`: Executes once during initial render (either SSR or CSR) - Default mode - `navigation`: Executes once during initial render and once per subsequent client-side navigation --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/once.ts) # clearError > The clearError composable clears all handled errors. Within your pages, components, and plugins, you can use `clearError` to clear all errors and redirect the user. **Parameters:** - `options?: { redirect?: string }` You can provide an optional path to redirect to (for example, if you want to navigate to a 'safe' page). ```ts // Without redirect clearError() // With redirect clearError({ redirect: '/homepage' }) ``` Errors are set in state using [`useError()`](https://nuxt.com/docs/4.x/api/composables/use-error). The `clearError` composable will reset this state and calls the `app:error:cleared` hook with the provided options. <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # clearNuxtData > Delete cached data, error status and pending promises of useAsyncData and useFetch. <note> This method is useful if you want to invalidate the data fetching for another page. </note> ## Type ```ts [Signature] export function clearNuxtData (keys?: string | string[] | ((key: string) => boolean)): void ``` ## Parameters - `keys`: One or an array of keys that are used in [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) to delete their cached data. If no keys are provided, **all data** will be invalidated. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # clearNuxtState > Delete the cached state of useState. <note> This method is useful if you want to invalidate the state of `useState`. You can also reset the state to its initial value by passing `{ reset: true }` as the second parameter. </note> ## Type ```ts [Signature] export function clearNuxtState (keys?: string | string[] | ((key: string) => boolean), opts?: ClearNuxtStateOptions): void ``` ## Parameters - `keys`: One or an array of keys that are used in [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) to delete their cached state. If no keys are provided, **all state** will be invalidated. - `opts`: An options object to configure the clear behavior. - `reset` <badge className="align-middle" color="info" size="xs"> v4.4 </badge> : When set to `true`, resets the state to the initial value provided by the `init` function of [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) instead of setting it to `undefined`. When not specified, defaults to the value of `experimental.defaults.useState.resetOnClear` in your Nuxt config (which is `true` with `compatibilityVersion: 5`). --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/state.ts) # createError > Create an error object with additional metadata. You can use this function to create an error object with additional metadata. It is usable in both the Vue and Nitro portions of your app, and is meant to be thrown. ## Parameters - `err`: `string | { cause, data, message, name, stack, status, statusText, fatal }` You can pass either a string or an object to the `createError` function. If you pass a string, it will be used as the error `message`, and the `status` will default to `500`. If you pass an object, you can set multiple properties of the error, such as `status`, `message`, and other error properties. ## In Vue App If you throw an error created with `createError`: - on server-side, it will trigger a full-screen error page which you can clear with `clearError`. - on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`. ### Example ```vue [app/pages/movies/[slug].vue] <script setup lang="ts"> const route = useRoute() const { data } = await useFetch(`/api/movies/${route.params.slug}`) if (!data.value) { throw createError({ status: 404, statusText: 'Page Not Found' }) } </script> ``` ### Error Causes You can pass a `cause` when creating an error to preserve the original error you are wrapping: ```ts try { await fetchMovie(route.params.slug) } catch (cause) { throw createError({ status: 500, message: 'Could not load movie', cause, }) } ``` In development, the cause chain is exposed to your [error page](https://nuxt.com/docs/4.x/getting-started/error-handling#error-page) via the `cause` property of the error, serialized as `{ name, message, stack, cause }` (primitive causes are passed through as-is; other values are omitted). In production, causes are never included in error responses or in the error page payload. ## In API Routes Use `createError` to trigger error handling in server API routes. ### Example ```ts [server/api/error.ts] export default eventHandler(() => { throw createError({ status: 404, statusText: 'Page Not Found', }) }) ``` In API routes, using `createError` by passing an object with a short `statusText` is recommended because it can be accessed on the client side. Otherwise, a `message` passed to `createError` on an API route will not propagate to the client. Alternatively, you can use the `data` property to pass data back to the client. When handling the error with `useFetch`, the custom data is available at `error.value.data.data`. In any case, always consider avoiding to put dynamic user input to the message to avoid potential security issues. <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # defineLazyHydrationComponent > Define a lazy hydration component with a specific strategy. `defineLazyHydrationComponent` is a compiler macro that helps you create a component with a specific lazy hydration strategy. Lazy hydration defers hydration until components become visible or until the browser has completed more critical tasks. This can significantly reduce the initial performance cost, especially for non-essential components. ## Usage ### Visibility Strategy Hydrates the component when it becomes visible in the viewport. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'visible', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the element(s) is 100px away from entering the viewport. --> <LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" /> </div> </template> ``` The `hydrateOnVisible` prop is optional. You can pass an object to customize the behavior of the `IntersectionObserver` under the hood. <read-more title="IntersectionObserver options" to="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver"> Read more about the options for `hydrate-on-visible`. </read-more> <note> Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible). </note> ### Idle Strategy Hydrates the component when the browser is idle. This is suitable if you need the component to load as soon as possible, but not block the critical rendering path. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'idle', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the browser is idle or after 2000ms. --> <LazyHydrationMyComponent :hydrate-on-idle="2000" /> </div> </template> ``` The `hydrateOnIdle` prop is optional. You can pass a positive number to specify the maximum timeout. Idle strategy is for components that can be hydrated when the browser is idle. <note> Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle). </note> ### Interaction Strategy Hydrates the component after a specified interaction (e.g., click, mouseover). ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'interaction', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the element(s) is hovered over by the pointer. --> <LazyHydrationMyComponent hydrate-on-interaction="mouseover" /> </div> </template> ``` The `hydrateOnInteraction` prop is optional. If you do not pass an event or a list of events, it defaults to hydrating on `pointerenter`, `click`, and `focus`. <note> Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction). </note> ### Media Query Strategy Hydrates the component when the window matches a media query. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'mediaQuery', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the window width is greater than or equal to 768px. --> <LazyHydrationMyComponent hydrate-on-media-query="(min-width: 768px)" /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query). </note> ### Time Strategy Hydrates the component after a specified delay (in milliseconds). ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'time', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration is triggered after 1000ms. --> <LazyHydrationMyComponent :hydrate-after="1000" /> </div> </template> ``` Time strategy is for components that can wait a specific amount of time. ### If Strategy Hydrates the component based on a boolean condition. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'if', () => import('./components/MyComponent.vue'), ) const isReady = ref(false) function myFunction () { // Trigger custom hydration strategy... isReady.value = true } </script> <template> <div> <!-- Hydration is triggered when isReady becomes true. --> <LazyHydrationMyComponent :hydrate-when="isReady" /> </div> </template> ``` If strategy is best for components that might not always need to be hydrated. ### Never Hydrate Never hydrates the component. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'never', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- This component will never be hydrated by Vue. --> <LazyHydrationMyComponent /> </div> </template> ``` ### Listening to Hydration Events All delayed hydration components emit a `@hydrated` event when they are hydrated. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'visible', () => import('./components/MyComponent.vue'), ) function onHydrate () { console.log('Component has been hydrated!') } </script> <template> <div> <LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" @hydrated="onHydrated" /> </div> </template> ``` ## Parameters <warning> To ensure that the compiler correctly recognizes this macro, avoid using external variables. The following approach will prevent the macro from being properly recognized: ```vue <script setup lang="ts"> const strategy = 'visible' const source = () => import('./components/MyComponent.vue') const LazyHydrationMyComponent = defineLazyHydrationComponent(strategy, source) </script> ``` </warning> ### `strategy` - **Type**: `'visible' | 'idle' | 'interaction' | 'mediaQuery' | 'if' | 'time' | 'never'` - **Required**: `true` <table> <thead> <tr> <th> Strategy </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> visible </code> </td> <td> Hydrates when the component becomes visible in the viewport. </td> </tr> <tr> <td> <code> idle </code> </td> <td> Hydrates when the browser is idle or after a delay. </td> </tr> <tr> <td> <code> interaction </code> </td> <td> Hydrates upon user interaction (e.g., click, hover). </td> </tr> <tr> <td> <code> mediaQuery </code> </td> <td> Hydrates when the specified media query condition is met. </td> </tr> <tr> <td> <code> if </code> </td> <td> Hydrates when a specified boolean condition is met. </td> </tr> <tr> <td> <code> time </code> </td> <td> Hydrates after a specified time delay. </td> </tr> <tr> <td> <code> never </code> </td> <td> Prevents Vue from hydrating the component. </td> </tr> </tbody> </table> ### `source` - **Type**: `() => Promise<Component>` - **Required**: `true` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/components/plugins/lazy-hydration-macro-transform.ts) # defineNuxtComponent > defineNuxtComponent() is a helper function for defining type safe components with Options API. <note> `defineNuxtComponent()` is a helper function for defining type safe Vue components using options API similar to [`defineComponent()`](https://vuejs.org/api/general#definecomponent). `defineNuxtComponent()` wrapper also adds support for `asyncData` and `head` component options. </note> <note> Using `<script setup lang="ts">` is the recommended way of declaring Vue components in Nuxt. </note> <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> ## `asyncData()` If you choose not to use `setup()` in your app, you can use the `asyncData()` method within your component definition: ```vue [app/pages/index.vue] <script lang="ts"> export default defineNuxtComponent({ asyncData () { return { data: { greetings: 'hello world!', }, } }, }) </script> ``` ## `head()` If you choose not to use `setup()` in your app, you can use the `head()` method within your component definition: ```vue [app/pages/index.vue] <script lang="ts"> export default defineNuxtComponent({ head (nuxtApp) { return { title: 'My site', } }, }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/component.ts) # defineNuxtPlugin > defineNuxtPlugin() is a helper function for creating Nuxt plugins. `defineNuxtPlugin` is a helper function for creating Nuxt plugins with enhanced functionality and type safety. This utility normalizes different plugin formats into a consistent structure that works seamlessly within Nuxt's plugin system. ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp }) ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/plugins#creating-plugins"> </read-more> ## Type ```ts [Signature] export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPlugin<T>): Plugin<T> & ObjectPlugin<T> type Plugin<T> = (nuxt: NuxtApp) => Promise<void> | Promise<{ provide?: T }> | void | { provide?: T } interface ObjectPlugin<T> { name?: string enforce?: 'pre' | 'default' | 'post' dependsOn?: string[] order?: number parallel?: boolean setup?: Plugin<T> hooks?: Partial<RuntimeNuxtHooks> env?: { islands?: boolean } } ``` ## Parameters **plugin**: A plugin can be defined in two ways: 1. **Function Plugin**: A function that receives the [`NuxtApp`](https://nuxt.com/docs/4.x/guide/going-further/internals#the-nuxtapp-interface) instance and can return a promise with a potential object with a [`provide`](https://nuxt.com/docs/4.x/directory-structure/app/plugins#providing-helpers) property if you want to provide a helper on [`NuxtApp`](https://nuxt.com/docs/4.x/guide/going-further/internals#the-nuxtapp-interface) instance. 2. **Object Plugin**: An object that can include various properties to configure the plugin's behavior, such as `name`, `enforce`, `dependsOn`, `order`, `parallel`, `setup`, `hooks`, and `env`. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Optional name for the plugin, useful for debugging and dependency management. </td> </tr> <tr> <td> <code> enforce </code> </td> <td> <code> 'pre' </code> | <code> 'default' </code> | <code> 'post' </code> </td> <td> <code> false </code> </td> <td> Controls when the plugin runs relative to other plugins. </td> </tr> <tr> <td> <code> dependsOn </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Array of plugin names this plugin depends on. Ensures proper execution order. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> This allows more granular control over plugin order and should only be used by advanced users. <strong> It overrides the value of <code> enforce </code> and is used to sort plugins. </strong> </td> </tr> <tr> <td> <code> parallel </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to execute the plugin in parallel with other parallel plugins. </td> </tr> <tr> <td> <code> setup </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Plugin </span> <span class="sDfIl"> < </span> <span class="sZSNi"> T </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> The main plugin function, equivalent to a function plugin. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Partial </span> <span class="sDfIl"> < </span> <span class="sZSNi"> RuntimeNuxtHooks </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Nuxt app runtime hooks to register directly. </td> </tr> <tr> <td> <code> env </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> { </span> <span class="sZSNi"> islands </span> <span class="sDfIl"> ?: </span> <span class="sZSNi"> boolean </span> <span class="sDfIl"> } </span> </code> </td> <td> <code> false </code> </td> <td> Set this value to <code> false </code> if you don't want the plugin to run when rendering server-only or island components. </td> </tr> </tbody> </table> <video-accordion title="Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins" video-id="2aXZyXB1QGQ"> </video-accordion> ## Example ### Basic Usage The example below demonstrates a simple plugin that adds global functionality: ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Add a global method return { provide: { hello: (name: string) => `Hello ${name}!`, }, } }) ``` ### Object Syntax Plugin The example below shows the object syntax with advanced configuration: ```ts [plugins/advanced.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', enforce: 'pre', async setup (nuxtApp) { // Plugin setup logic const data = await $fetch('/api/config') return { provide: { config: data, }, } }, hooks: { 'app:created' () { console.log('App created!') }, }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # defineNuxtRouteMiddleware > Create named route middleware using defineNuxtRouteMiddleware helper function. Route middleware are stored in the [`app/middleware/`](https://nuxt.com/docs/4.x/directory-structure/app/middleware) of your Nuxt application (unless [set otherwise](https://nuxt.com/docs/4.x/api/nuxt-config#middleware)). ## Type ```ts [Signature] export function defineNuxtRouteMiddleware (middleware: RouteMiddleware): RouteMiddleware interface RouteMiddleware { (to: RouteLocationNormalized, from: RouteLocationNormalized): ReturnType<NavigationGuard> } ``` ## Parameters ### `middleware` - **Type**: `RouteMiddleware` A function that takes two Vue Router's route location objects as parameters: the next route `to` as the first, and the current route `from` as the second. Learn more about available properties of `RouteLocationNormalized` in the **Vue Router docs**. ## Example ### Showing Error Page You can use route middleware to throw errors and show helpful error messages: ```ts [app/middleware/error.ts] export default defineNuxtRouteMiddleware((to) => { if (to.params.id === '1') { throw createError({ status: 404, statusText: 'Page Not Found' }) } }) ``` The above route middleware will redirect a user to the custom error page defined in the `~/error.vue` file, and expose the error message and code passed from the middleware. ### Redirection Use [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) in combination with `navigateTo` helper function inside the route middleware to redirect users to different routes based on their authentication status: ```ts [app/middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const auth = useState('auth') if (!auth.value.isAuthenticated) { return navigateTo('/login') } if (to.path !== '/dashboard') { return navigateTo('/dashboard') } }) ``` Both [navigateTo](https://nuxt.com/docs/4.x/api/utils/navigate-to) and [abortNavigation](https://nuxt.com/docs/4.x/api/utils/abort-navigation) are globally available helper functions that you can use inside `defineNuxtRouteMiddleware`. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # definePageMeta > Define metadata for your page components. `definePageMeta` is a compiler macro that you can use to set metadata for your **page** components located in the [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory (unless [set otherwise](https://nuxt.com/docs/4.x/api/nuxt-config#pages)). This way you can set custom metadata for each static or dynamic route of your Nuxt application. ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ layout: 'default', }) </script> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/pages#page-metadata"> </read-more> ## Type ```ts [Signature] export function definePageMeta (meta: PageMeta): void interface PageMeta { validate?: ((route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>) redirect?: RouteRecordRedirectOption name?: string path?: string props?: RouteRecordRaw['props'] alias?: string | string[] groups?: string[] pageTransition?: boolean | TransitionProps layoutTransition?: boolean | TransitionProps viewTransition?: ViewTransitionPageOptions['enabled'] | ViewTransitionPageOptions key?: false | string | ((route: RouteLocationNormalizedLoaded) => string) keepalive?: boolean | KeepAliveProps layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey> | { name?: LayoutKey | false, props?: Record<string, unknown> /* or the selected layout's props */ } middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard> scrollToTop?: boolean | ((to: RouteLocationNormalizedLoaded, from: RouteLocationNormalizedLoaded) => boolean) [key: string]: unknown } ``` ## Parameters ### `meta` - **Type**: `PageMeta`<br /> An object accepting the following page metadata:<br /> **name** - **Type**: `string`<br /> You may define a name for this page's route. By default, name is generated based on path inside the [`app/pages/` directory](https://nuxt.com/docs/4.x/directory-structure/app/pages).<br /> **path** - **Type**: `string`<br /> You may define a [custom regular expression](https://nuxt.com/docs/4.x/api/utils/define-page-meta#using-a-custom-regular-expression) if you have a more complex pattern than can be expressed with the file name.<br /> **props** - **Type**: [`RouteRecordRaw['props']`](https://router.vuejs.org/guide/essentials/passing-props)<br /> Allows accessing the route `params` as props passed to the page component.<br /> **alias** - **Type**: `string | string[]`<br /> Aliases for the record. Allows defining extra paths that will behave like a copy of the record. Allows having paths shorthands like `/users/:id` and `/u/:id`. All `alias` and `path` values must share the same params.<br /> **groups** <badge className="align-middle" color="info" size="xs"> v4.3 </badge> - **Type**: `string[]`<br /> Route groups the page belongs to, based on the folder structure. Automatically populated for pages within [route groups](https://nuxt.com/docs/4.x/guide/directory-structure/app/pages#route-groups).<br /> **keepalive** - **Type**: `boolean` | [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive)<br /> Set to `true` when you want to preserve page state across route changes or use the [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive) for a fine-grained control.<br /> **key** - **Type**: `false` | `string` | `((route: RouteLocationNormalizedLoaded) => string)`<br /> Set `key` value when you need more control over when the `<NuxtPage>` component is re-rendered.<br /> **layout** - **Type**: `false` | `LayoutKey` | `Ref<LayoutKey>` | `ComputedRef<LayoutKey>` | `{ name?: LayoutKey | false; props?: Record<string, unknown> /* or the selected layout's props */ }`<br /> Set a static or dynamic name of the layout for each route. This can be set to `false` in case the default layout needs to be disabled.<br /> You can also pass an object with `name` and `props` to pass typed props to your layout component. When your layout defines props with `defineProps`, they will be fully typed in `definePageMeta`.<br /> **layoutTransition** - **Type**: `boolean` | [`TransitionProps`](https://vuejs.org/api/built-in-components#transition)<br /> Set name of the transition to apply for current layout. You can also set this value to `false` to disable the layout transition.<br /> **middleware** - **Type**: `MiddlewareKey` | [`NavigationGuard`](https://router.vuejs.org/api/interfaces/navigationguard) | `Array<MiddlewareKey | NavigationGuard>`<br /> Define anonymous or named middleware directly within `definePageMeta`. Learn more about [route middleware](https://nuxt.com/docs/4.x/directory-structure/app/middleware).<br /> **pageTransition** - **Type**: `boolean` | [`TransitionProps`](https://vuejs.org/api/built-in-components#transition)<br /> Set name of the transition to apply for current page. You can also set this value to `false` to disable the page transition.<br /> **viewTransition** - **Type**: `boolean | 'always' | ViewTransitionPageOptions`<br /> **Experimental feature, only available when enabled in your nuxt.config file**<br /> Enable/disable View Transitions for the current page. If set to true, Nuxt will not apply the transition if the users browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition.<br /> You can also pass a `ViewTransitionPageOptions` object to configure [view transition types](https://nuxt.com/docs/4.x/getting-started/transitions#view-transition-types): - `enabled`: `boolean | 'always'` - enable/disable the transition - `types`: `string[] | (to, from) => string[]` - types applied to any transition involving this page - `toTypes`: `string[] | (to, from) => string[]` - types applied only when navigating **to** this page - `fromTypes`: `string[] | (to, from) => string[]` - types applied only when navigating **from** this page<br /> **redirect** - **Type**: [`RouteRecordRedirectOption`](https://router.vuejs.org/guide/essentials/redirect-and-alias)<br /> Where to redirect if the route is directly matched. The redirection happens before any navigation guard and triggers a new navigation with the new target location.<br /> **validate** - **Type**: `(route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>`<br /> Validate whether a given route can validly be rendered with this page. Return true if it is valid, or false if not. If another match can't be found, this will mean a 404. You can also directly return an object with `status`/`statusText` to respond immediately with an error (other matches will not be checked).<br /> **scrollToTop** - **Type**: `boolean | (to: RouteLocationNormalized, from: RouteLocationNormalized) => boolean`<br /> Tell Nuxt to scroll to the top before rendering the page or not. Navigation is independent from rendering, so scroll behavior is always triggered even when the page doesn't re-render (e.g. when using a fixed [`key`](https://nuxt.com/docs/4.x/api/utils/define-page-meta#key)). Set `scrollToTop: false` to disable scrolling in such cases. If you want to overwrite the default scroll behavior of Nuxt, you can do so in `~/router.options.ts` (see [custom routing](https://nuxt.com/docs/4.x/guide/recipes/custom-routing#using-routeroptions)) for more info.<br /> **[key: string]** - **Type**: `any`<br /> Apart from the above properties, you can also set **custom** metadata. You may wish to do so in a type-safe way by [augmenting the type of the `meta` object](https://nuxt.com/docs/4.x/directory-structure/app/pages/#typing-custom-metadata). ## Example ### Basic Usage The example below demonstrates: - how `key` can be a function that returns a value; - how `keepalive` property makes sure that the `<modal>` component is not cached when switching between multiple components; - adding `pageType` as a custom property: ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, keepalive: { exclude: ['modal'], }, pageType: 'Checkout', }) </script> ``` ### Defining Middleware The example below shows how the middleware can be defined using a `function` directly within the `definePageMeta` or set as a `string` that matches the middleware file name located in the `app/middleware/` directory: ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ // define middleware as a function middleware: [ function (to, from) { const auth = useState('auth') if (!auth.value.authenticated) { return navigateTo('/login') } if (to.path !== '/checkout') { return navigateTo('/checkout') } }, ], // ... or a string middleware: 'auth', // ... or multiple strings middleware: ['auth', 'another-named-middleware'], }) </script> ``` ### Using a Custom Regular Expression A custom regular expression is a good way to resolve conflicts between overlapping routes, for instance: The two routes "/test-category" and "/1234-post" match both `[postId]-[postSlug].vue` and `[categorySlug].vue` page routes. To make sure that we are only matching digits (`\d+`) for `postId` in the `[postId]-[postSlug]` route, we can add the following to the `[postId]-[postSlug].vue` page template: ```vue [app/pages/[postId]-[postSlug].vue] <script setup lang="ts"> definePageMeta({ path: '/:postId(\\d+)-:postSlug', }) </script> ``` For more examples see [Vue Router's Matching Syntax](https://router.vuejs.org/guide/essentials/route-matching-syntax). ### Defining Layout You can define the layout that matches the layout's file name located (by default) in the [`app/layouts/` directory](https://nuxt.com/docs/4.x/directory-structure/app/layouts). You can also disable the layout by setting the `layout` to `false`: ```vue [app/pages/some-page.vue] <script setup lang="ts"> definePageMeta({ // set custom layout layout: 'admin', // ... or disable a default layout layout: false, }) </script> ``` ### Passing Props to a Layout You can pass props to a layout by using the object syntax for `layout`. If your layout defines props with `defineProps`, the props will be fully typed. <code-group> ```vue [app/pages/dashboard.vue] <script setup lang="ts"> definePageMeta({ layout: { name: 'panel', props: { sidebar: true, title: 'Dashboard', }, }, }) </script> ``` ```vue [app/layouts/panel.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` </code-group> <tip> Layout props set via `definePageMeta` are fully typed based on the layout's `defineProps`. You'll get autocomplete and type-checking in your editor. </tip> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/layouts#passing-props-to-layouts"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/composables.ts) # defineRouteRules > Define route rules for hybrid rendering at the page level. <read-more icon="i-lucide-star" to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#inlinerouterules"> This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`. </read-more> ## Usage ```vue [app/pages/index.vue] <script setup lang="ts"> defineRouteRules({ prerender: true, }) </script> <template> <h1>Hello world!</h1> </template> ``` Will be translated to: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, }) ``` <note> When running [`nuxt build`](https://nuxt.com/docs/4.x/api/commands/build), the home page will be pre-rendered in `.output/public/index.html` and statically served. </note> ## Notes - A rule defined in `~/pages/foo/bar.vue` will be applied to `/foo/bar` requests. - A rule in `~/pages/foo/[id].vue` will be applied to `/foo/*` requests. - A rule in a page with a finite set of alternatives, such as a custom `path` of `/:locale(en|fr)/about`, will generate one rule per alternative (`/en/about` and `/fr/about`). If a page path cannot be converted to an equivalent route rule pattern (for example, a param with a regular expression like `/:id(\d+)`, a partial segment like `/prefix-:id`, or a repeatable param like `/:slug+`), the rules for that page are **not** applied and Nuxt warns during build. In that case, define the rules explicitly in `nitro.routeRules` in your `nuxt.config`. For more control, such as if you are using a custom `path` or `alias` set in the page's [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta), you should set `routeRules` directly within your `nuxt.config`. <read-more icon="i-lucide-medal" to="https://nuxt.com/docs/4.x/guide/concepts/rendering#hybrid-rendering"> Read more about the `routeRules`. </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/composables.ts) # $fetch > Nuxt uses ofetch to expose globally the $fetch helper for making HTTP requests. Nuxt uses [ofetch](https://github.com/unjs/ofetch) to expose globally the `$fetch` helper for making HTTP requests within your Vue app or API routes. <tip icon="i-lucide-rocket"> During server-side rendering, calling `$fetch` to fetch your internal [API routes](https://nuxt.com/docs/4.x/directory-structure/server) will directly call the relevant function (emulating the request), **saving an additional API call**. </tip> <note color="blue" icon="i-lucide-info"> Using `$fetch` in components without wrapping it with [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) causes fetching the data twice: initially on the server, then again on the client-side during hydration, because `$fetch` does not transfer state from the server to the client. Thus, the fetch will be executed on both sides because the client has to get the data again. </note> ## Usage We recommend using [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) + `$fetch` to prevent double data fetching when fetching the component data. ```vue [app/app.vue] <script setup lang="ts"> // During SSR data is fetched twice, once on the server and once on the client. const dataTwice = await $fetch('/api/item') // During SSR data is fetched only on the server side and transferred to the client. const { data } = await useAsyncData('item', () => $fetch('/api/item')) // You can also useFetch as shortcut of useAsyncData + $fetch const { data } = await useFetch('/api/item') </script> ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> You can use `$fetch` in any methods that are executed only on client-side. ```vue [app/pages/contact.vue] <script setup lang="ts"> async function contactForm () { await $fetch('/api/contact', { method: 'POST', body: { hello: 'world' }, }) } </script> <template> <button @click="contactForm"> Contact </button> </template> ``` <tip> `$fetch` is the preferred way to make HTTP calls in Nuxt instead of [@nuxt/http](https://github.com/nuxt/http) and [@nuxtjs/axios](https://github.com/nuxt-community/axios-module) that are made for Nuxt 2. </tip> <note> If you use `$fetch` to call an (external) HTTPS URL with a self-signed certificate in development, you will need to set `NODE_TLS_REJECT_UNAUTHORIZED=0` in your environment. </note> ### Passing Headers and Cookies When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. However, during Server-Side Rendering, due to security risks such as **Server-Side Request Forgery (SSRF)** or **Authentication Misuse**, the `$fetch` wouldn't include the user's browser cookies, nor pass on cookies from the fetch response. <code-group> ```vue [app/pages/index.vue] <script setup lang="ts"> // This will NOT forward headers or cookies during SSR const { data } = await useAsyncData(() => $fetch('/api/cookies')) </script> ``` ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const foo = getCookie(event, 'foo') // ... Do something with the cookie }) ``` </code-group> If you need to forward headers and cookies on the server, you must manually pass them: ```vue [app/pages/index.vue] <script setup lang="ts"> // This will forward the user's headers and cookies to `/api/cookies` const requestFetch = useRequestFetch() const { data } = await useAsyncData(() => requestFetch('/api/cookies')) </script> ``` However, when calling `useFetch` with a relative URL on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/4.x/api/composables/use-request-fetch) to proxy headers and cookies (with the exception of headers not meant to be forwarded, like `host`). --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/entry.ts) # navigateTo > navigateTo is a helper function that programmatically navigates users. ## Usage `navigateTo` is available on both server side and client side. It can be used within the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context), or directly, to perform page navigation. <warning> Make sure to always use `await` or `return` on result of `navigateTo` when calling it. </warning> <note> `navigateTo` cannot be used within Nitro routes. To perform a server-side redirect in Nitro routes, use [`sendRedirect`](https://h3.dev/utils/response#redirectlocation-status-statustext) instead. </note> ### Within a Vue Component ```vue <script setup lang="ts"> // passing 'to' as a string await navigateTo('/search') // ... or as a route object await navigateTo({ path: '/search' }) // ... or as a route object with query parameters await navigateTo({ path: '/search', query: { page: 1, sort: 'asc', }, }) </script> ``` <note> Calling `navigateTo` does not stop execution of the rest of your `<script setup>` code. If you want a successful navigation to return early from `setup()`, enable [`experimental.navigateToEarlyReturn`](https://nuxt.com/docs/4.x/guide/going-further/experimental-features#navigatetoearlyreturn). </note> ### Within Route Middleware ```ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { // setting the redirect code to '301 Moved Permanently' return navigateTo('/search', { redirectCode: 301 }) } }) ``` When using `navigateTo` within route middleware, you must **return its result** to ensure the middleware execution flow works correctly. For example, the following implementation **will not work as expected**: ```ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { // โŒ This will not work as expected navigateTo('/search', { redirectCode: 301 }) return } }) ``` In this case, `navigateTo` will be executed but not returned, which may lead to unexpected behavior. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/middleware"> </read-more> ### Navigating to an External URL The `external` parameter in `navigateTo` influences how navigating to URLs is handled: - **Without external: true**: - Internal URLs navigate as expected. - External URLs throw an error. - **With external: true**: - Internal URLs navigate with a full-page reload. - External URLs navigate as expected. #### Example ```vue <script setup lang="ts"> // will throw an error; // navigating to an external URL is not allowed by default await navigateTo('https://nuxt.com') // will redirect successfully with the 'external' parameter set to 'true' await navigateTo('https://nuxt.com', { external: true, }) </script> ``` ### Opening a Page in a New Tab ```vue <script setup lang="ts"> // will open 'https://nuxt.com' in a new tab await navigateTo('https://nuxt.com', { open: { target: '_blank', windowFeatures: { width: 500, height: 500, }, }, }) </script> ``` ## Type ```ts [Signature] export function navigateTo ( to: RouteLocationRaw | undefined | null, options?: NavigateToOptions, ): Promise<void | NavigationFailure | false> | false | void | RouteLocationRaw interface NavigateToOptions { replace?: boolean redirectCode?: number external?: boolean open?: OpenOptions } type OpenOptions = { target: string windowFeatures?: OpenWindowFeatures } type OpenWindowFeatures = { popup?: boolean noopener?: boolean noreferrer?: boolean } & XOR<{ width?: number }, { innerWidth?: number }> & XOR<{ height?: number }, { innerHeight?: number }> & XOR<{ left?: number }, { screenX?: number }> & XOR<{ top?: number }, { screenY?: number }> ``` ## Parameters ### `to` **Type**: [`RouteLocationRaw`](https://router.vuejs.org/api/interfaces/routelocationoptions) | `undefined` | `null` **Default**: `'/'` `to` can be a plain string or a route object to redirect to. When passed as `undefined` or `null`, it will default to `'/'`. #### Example ```ts // Passing the URL directly will redirect to the '/blog' page await navigateTo('/blog') // Using the route object, will redirect to the route with the name 'blog' await navigateTo({ name: 'blog' }) // Redirects to the 'product' route while passing a parameter (id = 1) using the route object. await navigateTo({ name: 'product', params: { id: 1 } }) ``` ### `options` (optional) **Type**: `NavigateToOptions` An object accepting the following properties: - `replace` - **Type**: `boolean` - **Default**: `false` - By default, `navigateTo` pushes the given route into the Vue Router's instance on the client side.<br /> This behavior can be changed by setting `replace` to `true`, to indicate that given route should be replaced. - `redirectCode` - **Type**: `number` - **Default**: `302` - `navigateTo` redirects to the given path and sets the redirect code to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) by default when the redirection takes place on the server side.<br /> This default behavior can be modified by providing different `redirectCode`. Commonly, [`301 Moved Permanently`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) can be used for permanent redirections. - `external` - **Type**: `boolean` - **Default**: `false` - Allows navigating to an external URL when set to `true`. Otherwise, `navigateTo` will throw an error, as external navigation is not allowed by default. - `open` - **Type**: `OpenOptions` - Allows navigating to the URL using the [open()](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) method of the window. This option is only applicable on the client side and will be ignored on the server side.<br /> An object accepting the following properties: - `target` - **Type**: `string` - **Default**: `'_blank'` - A string, without whitespace, specifying the name of the browsing context the resource is being loaded into. - `windowFeatures` - **Type**: `OpenWindowFeatures` - An object accepting the following properties:<table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> popup </code> </td> <td> <code> boolean </code> </td> <td> Requests a minimal popup window instead of a new tab, with UI features decided by the browser. </td> </tr> <tr> <td> <code> width </code> or <code> innerWidth </code> </td> <td> <code> number </code> </td> <td> Specifies the content area's width (minimum 100 pixels), including scrollbars. </td> </tr> <tr> <td> <code> height </code> or <code> innerHeight </code> </td> <td> <code> number </code> </td> <td> Specifies the content area's height (minimum 100 pixels), including scrollbars. </td> </tr> <tr> <td> <code> left </code> or <code> screenX </code> </td> <td> <code> number </code> </td> <td> Sets the horizontal position of the new window relative to the left edge of the screen. </td> </tr> <tr> <td> <code> top </code> or <code> screenY </code> </td> <td> <code> number </code> </td> <td> Sets the vertical position of the new window relative to the top edge of the screen. </td> </tr> <tr> <td> <code> noopener </code> </td> <td> <code> boolean </code> </td> <td> Prevents the new window from accessing the originating window via <code> window.opener </code> . </td> </tr> <tr> <td> <code> noreferrer </code> </td> <td> <code> boolean </code> </td> <td> Prevents the Referer header from being sent and implicitly enables <code> noopener </code> . </td> </tr> </tbody> </table> <br /> Refer to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#windowfeatures) for more detailed information on the **windowFeatures** properties. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onBeforeRouteLeave > The onBeforeRouteLeave composable allows registering a route guard within a component. <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs" to="https://router.vuejs.org/api/functions/onbeforerouteleave"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onBeforeRouteUpdate > The onBeforeRouteUpdate composable allows registering a route guard within a component. <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs" to="https://router.vuejs.org/api/functions/onbeforerouteupdate"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onNuxtReady > The onNuxtReady composable allows running a callback after your app has finished initializing. <important> `onNuxtReady` only runs on the client-side. <br /> It is ideal for running code that should not block the initial rendering of your app. </important> ```ts [app/plugins/ready.client.ts] export default defineNuxtPlugin(() => { onNuxtReady(async () => { const myAnalyticsLibrary = await import('my-big-analytics-library') // do something with myAnalyticsLibrary }) }) ``` It is 'safe' to run even after your app has initialized. In this case, then the code will be registered to run in the next idle callback. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ready.ts) # prefetchComponents > Nuxt provides utilities to give you control over prefetching components. Prefetching component downloads the code in the background, this is based on the assumption that the component will likely be used for rendering, enabling the component to load instantly if and when the user requests it. The component is downloaded and cached for anticipated future use without the user making an explicit request for it. Use `prefetchComponents` to manually prefetch individual components that have been registered globally in your Nuxt app. By default Nuxt registers these as async components. You must use the Pascal-cased version of the component name. ```ts await prefetchComponents('MyGlobalComponent') await prefetchComponents(['MyGlobalComponent1', 'MyGlobalComponent2']) ``` <note> Current implementation behaves exactly the same as [`preloadComponents`](https://nuxt.com/docs/4.x/api/utils/preload-components) by preloading components instead of just prefetching we are working to improve this behavior. </note> <note> On server, `prefetchComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # preloadComponents > Nuxt provides utilities to give you control over preloading components. Preloading components loads components that your page will need very soon, which you want to start loading early in rendering lifecycle. This ensures they are available earlier and are less likely to block the page's render, improving performance. Use `preloadComponents` to manually preload individual components that have been registered globally in your Nuxt app. By default Nuxt registers these as async components. You must use the Pascal-cased version of the component name. ```ts await preloadComponents('MyGlobalComponent') await preloadComponents(['MyGlobalComponent1', 'MyGlobalComponent2']) ``` <note> On server, `preloadComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # preloadRouteComponents > preloadRouteComponents allows you to manually preload individual pages in your Nuxt app. Preloading routes loads the components of a given route that the user might navigate to in future. This ensures that the components are available earlier and less likely to block the navigation, improving performance. <tip icon="i-lucide-rocket"> Nuxt already automatically preloads the necessary routes if you're using the `NuxtLink` component. </tip> <read-more to="https://nuxt.com/docs/4.x/api/components/nuxt-link"> </read-more> ## Example Preload a route when using `navigateTo`. ```ts // we don't await this async function, to avoid blocking rendering // this component's setup function preloadRouteComponents('/dashboard') const submit = async () => { const results = await $fetch('/api/authentication') if (results.token) { await navigateTo('/dashboard') } } ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/navigate-to"> </read-more> <note> On server, `preloadRouteComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # prerenderRoutes > prerenderRoutes hints to Nitro to prerender an additional route. When prerendering, you can hint to Nitro to prerender additional paths, even if their URLs do not show up in the HTML of the generated page. <important> `prerenderRoutes` can only be called within the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context). </important> <note> `prerenderRoutes` has to be executed during prerendering. If the `prerenderRoutes` is used in dynamic pages/routes which are not prerendered, then it will not be executed. </note> ```ts const route = useRoute() prerenderRoutes('/') prerenderRoutes(['/', '/about']) ``` <note> In the browser, or if called outside prerendering, `prerenderRoutes` will have no effect. </note> You can even prerender API routes which is particularly useful for full statically generated sites (SSG) because you can then `$fetch` data as if you have an available server! ```ts prerenderRoutes('/api/content/article/name-of-article') // Somewhere later in App const articleContent = await $fetch('/api/content/article/name-of-article', { responseType: 'json', }) ``` <warning> Prerendered API routes in production may not return the expected response headers, depending on the provider you deploy to. For example, a JSON response might be served with an `application/octet-stream` content type. Always manually set `responseType` when fetching prerendered API routes. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # refreshCookie > Refresh useCookie values manually when a cookie has changed <important> This utility is available since [Nuxt v3.10](https://nuxt.com/blog/v3-10). </important> ## Purpose The `refreshCookie` function is designed to refresh cookie value returned by `useCookie`. This is useful for updating the `useCookie` ref when we know the new cookie value has been set in the browser. ## Usage ```vue [app/app.vue] <script setup lang="ts"> const tokenCookie = useCookie('token') const login = async (username, password) => { const token = await $fetch('/api/token', { /** ... */ }) // Sets `token` cookie on response refreshCookie('token') } const loggedIn = computed(() => !!tokenCookie.value) </script> ``` <note to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#cookiestore"> Since [Nuxt v3.12.0](https://github.com/nuxt/nuxt/releases/tag/v3.12.0), the experimental `cookieStore` option is enabled by default. It automatically refreshes the `useCookie` value when cookies change in the browser. </note> ## Type ```ts [Signature] export function refreshCookie (name: string): void ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts) # refreshNuxtData > Refresh all or specific asyncData instances in Nuxt `refreshNuxtData` is used to refetch all or specific `asyncData` instances, including those from [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data), [`useLazyAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-lazy-async-data), [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch), and [`useLazyFetch`](https://nuxt.com/docs/4.x/api/composables/use-lazy-fetch). <note> If your component is cached by `<KeepAlive>` and enters a deactivated state, the `asyncData` inside the component will still be refetched until the component is unmounted. </note> ## Type ```ts [Signature] export function refreshNuxtData (keys?: string | string[]) ``` ## Parameters - `keys`: A single string or an array of strings as `keys` that are used to fetch the data. This parameter is **optional**. All [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) keys are re-fetched when no `keys` are explicitly specified. ## Return Values `refreshNuxtData` returns a promise, resolving when all or specific `asyncData` instances have been refreshed. ## Example ### Refresh All Data This example below refreshes all data being fetched using `useAsyncData` and `useFetch` in Nuxt application. ```vue [app/pages/some-page.vue] <script setup lang="ts"> const refreshing = ref(false) async function refreshAll () { refreshing.value = true try { await refreshNuxtData() } finally { refreshing.value = false } } </script> <template> <div> <button :disabled="refreshing" @click="refreshAll" > Refetch All Data </button> </div> </template> ``` ### Refresh Specific Data This example below refreshes only data where the key matches to `count` and `user`. ```vue [app/pages/some-page.vue] <script setup lang="ts"> const refreshing = ref(false) async function refresh () { refreshing.value = true try { // you could also pass an array of keys to refresh multiple data await refreshNuxtData(['count', 'user']) } finally { refreshing.value = false } } </script> <template> <div v-if="refreshing"> Loading </div> <button @click="refresh"> Refresh </button> </template> ``` <note> If you have access to the `asyncData` instance, it is recommended to use its `refresh` or `execute` method as the preferred way to refetch the data. </note> <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # reloadNuxtApp > reloadNuxtApp will perform a hard reload of the page. <note> `reloadNuxtApp` will perform a hard reload of your app, re-requesting a page and its dependencies from the server. </note> By default, it will also save the current `state` of your app (that is, any state you could access with `useState`). <read-more icon="i-lucide-star" to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#restorestate"> You can enable experimental restoration of this state by enabling the `experimental.restoreState` option in your `nuxt.config` file. </read-more> ## Type ```ts [Signature] export function reloadNuxtApp (options?: ReloadNuxtAppOptions) interface ReloadNuxtAppOptions { ttl?: number force?: boolean path?: string persistState?: boolean } ``` ### `options` (optional) **Type**: `ReloadNuxtAppOptions` An object accepting the following properties: - `path` (optional)<br /> **Type**: `string`<br /> **Default**: `window.location.pathname`<br /> The path to reload (defaulting to the current path). If this is different from the current window location it will trigger a navigation and add an entry in the browser history. - `ttl` (optional)<br /> **Type**: `number`<br /> **Default**: `10000`<br /> The number of milliseconds in which to ignore future reload requests. If called again within this time period, `reloadNuxtApp` will not reload your app to avoid reload loops. - `force` (optional)<br /> **Type**: `boolean`<br /> **Default**: `false`<br /> This option allows bypassing reload loop protection entirely, forcing a reload even if one has occurred within the previously specified TTL. - `persistState` (optional)<br /> **Type**: `boolean`<br /> **Default**: `false`<br /> Whether to dump the current Nuxt state to sessionStorage (as `nuxt:reload:state`). By default this will have no effect on reload unless `experimental.restoreState` is also set, or unless you handle restoring the state yourself. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/chunk.ts) # setPageLayout > setPageLayout allows you to dynamically change the layout of a page. <important> `setPageLayout` allows you to dynamically change the layout of a page. It relies on access to the Nuxt context and therefore can only be called within the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context). </important> ```ts [app/middleware/custom-layout.ts] export default defineNuxtRouteMiddleware((to) => { // Set the layout on the route you are navigating _to_ setPageLayout('other') }) ``` ## Passing Props to Layouts <badge className="align-middle" color="info" size="xs">v4.3</badge> You can pass props to the layout by providing an object as the second argument: ```ts [app/middleware/admin-layout.ts] export default defineNuxtRouteMiddleware((to) => { setPageLayout('admin', { sidebar: true, title: 'Dashboard', }) }) ``` The layout can then receive these props: ```vue [app/layouts/admin.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` <note> If you choose to set the layout dynamically on the server side, you *must* do so before the layout is rendered by Vue (that is, within a plugin or route middleware) to avoid a hydration mismatch. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # setResponseStatus > setResponseStatus sets the status (and optionally the statusText) of the response. Nuxt provides composables and utilities for first-class server-side-rendering support. `setResponseStatus` sets the status (and optionally the statusText) of the response. <important> `setResponseStatus` can only be called in the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context). </important> ```ts const event = useRequestEvent() // event will be undefined in the browser if (event) { // Set the status code to 404 for a custom 404 page setResponseStatus(event, 404) // Set the status message as well setResponseStatus(event, 404, 'Page Not Found') } ``` <note> In the browser, `setResponseStatus` will have no effect. </note> <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # showError > Nuxt provides a quick and simple way to show a full screen error page if needed. Within the [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context) you can use `showError` to show an error. **Parameters:** - `error`: `string | Error | Partial<{ cause, data, message, name, stack, status, statusText }>` ```ts showError('๐Ÿ˜ฑ Oh no, an error has been thrown.') showError({ status: 404, statusText: 'Page Not Found', }) ``` The error is set in the state using [`useError()`](https://nuxt.com/docs/4.x/api/composables/use-error) to create a reactive and SSR-friendly shared error state across components. <tip> `showError` calls the `app:error` hook. </tip> <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # updateAppConfig > Update the App Config at runtime. <note> Updates the [`app.config`](https://nuxt.com/docs/4.x/directory-structure/app/app-config) using deep assignment. Existing (nested) properties will be preserved. </note> ## Usage ```js import { updateAppConfig, useAppConfig } from '#imports' const appConfig = useAppConfig() // { foo: 'bar' } const newAppConfig = { foo: 'baz' } updateAppConfig(newAppConfig) console.log(appConfig) // { foo: 'baz' } ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/app-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/config.ts) # Legacy Composition API > Learn how to migrate to Composition API with Nuxt Bridge. Nuxt Bridge provides access to Composition API syntax. It is specifically designed to be aligned with Nuxt 3. Because of this, there are a few extra steps to take when enabling Nuxt Bridge, if you have been using the Composition API previously. ## Remove Modules - Remove `@vue/composition-api` from your dependencies. - Remove `@nuxtjs/composition-api` from your dependencies (and from your modules in `nuxt.config`). ## Using `@vue/composition-api` If you have been using just `@vue/composition-api` and not `@nuxtjs/composition-api`, then things are very straightforward. 1. First, remove the plugin where you are manually registering the Composition API. Nuxt Bridge will handle this for you.```diff - import Vue from 'vue' - import VueCompositionApi from '@vue/composition-api' - - Vue.use(VueCompositionApi) ``` 2. Otherwise, there is nothing you need to do. However, if you want, you can remove your explicit imports from `@vue/composition-api` and rely on Nuxt Bridge auto-importing them for you. ## Migrating from `@nuxtjs/composition-api` Nuxt Bridge implements the Composition API slightly differently from `@nuxtjs/composition-api` and provides different composables (designed to be aligned with the composables that Nuxt 3 provides). Because some composables have been removed and don't yet have a replacement, this will be a slightly more complicated process. ### Remove `@nuxtjs/composition-api/module` from your buildModules You don't have to immediately update your imports yet - Nuxt Bridge will automatically provide a 'shim' for most imports you currently have, to give you time to migrate to the new, Nuxt 3-compatible composables, with the following exceptions: - `withContext` has been removed. See [below](https://nuxt.com/docs/4.x/bridge/nuxt3-compatible-api#usecontext-and-withcontext). - `useStatic` has been removed. There is no current replacement. Feel free to raise a discussion if you have a use case for this. - `reqRef` and `reqSsrRef`, which were deprecated, have now been removed entirely. Follow the instructions below regarding [ssrRef](https://nuxt.com/docs/4.x/bridge/nuxt3-compatible-api#ssrref-and-shallowssrref) to replace this. ### Set `bridge.capi` ```ts import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { capi: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` For each other composable you are using from `@nuxtjs/composition-api`, follow the steps below. ### useFetch `$fetchState` and `$fetch` have been removed. ```diff const { - $fetch, - $fetchState, + fetch, + fetchState, } = useFetch(() => { posts.value = await $fetch('/api/posts') }) ``` ### `defineNuxtMiddleware` This was a type-helper stub function that is now removed. Remove the `defineNuxtMiddleware` wrapper: ```diff - import { defineNuxtMiddleware } from '@nuxtjs/composition-api` - export default defineNuxtMiddleware((ctx) => {}) + export default (ctx) => {} ``` For typescript support, you can use `@nuxt/types`: ```ts import type { Middleware } from '@nuxt/types' export default <Middleware> function (ctx) { } ``` ### `defineNuxtPlugin` This was a type-helper stub function that is now removed. You may also keep using Nuxt 2-style plugins, by removing the function (as with [defineNuxtMiddleware](https://nuxt.com/docs/4.x/bridge/bridge-composition-api#definenuxtmiddleware)). Remove the `defineNuxtPlugin` wrapper: ```diff - import { defineNuxtPlugin } from '@nuxtjs/composition-api' - export default defineNuxtPlugin((ctx, inject) => {}) + export default (ctx, inject) => {} ``` For typescript support, you can use `@nuxt/types`: ```ts import type { Plugin } from '@nuxt/types' export default <Plugin> function (ctx, inject) {} ``` <warning> While this example is valid, Nuxt 3 introduces a new defineNuxtPlugin function that has a slightly different signature. </warning> <read-more link="/docs/4.x/directory-structure/app/plugins#creating-plugins"> </read-more> ### `useRouter` and `useRoute` Nuxt Bridge provides direct replacements for these composables via [`useRouter`](https://nuxt.com/docs/4.x/api/composables/use-router) and `useRoute`. The only key difference is that [`useRoute`](https://nuxt.com/docs/4.x/api/composables/use-route) no longer returns a computed property. ```diff - import { useRouter, useRoute } from '@nuxtjs/composition-api' const router = useRouter() const route = useRoute() - console.log(route.value.path) + console.log(route.path) ``` # Configuration > Learn how to configure Nuxt Bridge to your own needs. ## Feature Flags You can optionally disable some features from bridge or opt-in to less stable ones. In normal circumstances, it is always best to stick with defaults! You can check [bridge/src/module.ts](https://github.com/nuxt/bridge/blob/main/packages/bridge/src/module.ts) for latest defaults. ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { // -- Opt-in features -- // Use Vite as the bundler instead of webpack 4 // vite: true, // Enable Nuxt 3 compatible useHead // meta: true, // Enable definePageMeta macro // macros: { // pageMeta: true // }, // Enable transpiling TypeScript with esbuild // typescript: { // esbuild: true // }, // -- Default features -- // Use legacy server instead of Nitro // nitro: false, // Disable Nuxt 3 compatible `nuxtApp` interface // app: false, // Disable Composition API support // capi: false, // ... or just disable legacy Composition API support // capi: { // legacy: false // }, // Do not transpile modules // transpile: false, // Disable <script setup> support // scriptSetup: false, // Disable composables auto importing // imports: false, // Do not warn about module incompatibilities // constraints: false }, vite: { // Config for Vite }, }) ``` ## Migration of Each Option ### router.base ```diff export default defineNuxtConfig({ - router: { - base: '/my-app/' - } + app: { + baseURL: '/my-app/' + } }) ``` ### build.publicPath ```diff export default defineNuxtConfig({ - build: { - publicPath: 'https://my-cdn.net' - } + app: { + cdnURL: 'https://my-cdn.net' + } }) ``` # Meta Tags > Learn how to migrate from Nuxt 2 to Nuxt Bridge new meta tags. If you need to access the component state with `head`, you should migrate to using [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) . If you need to use the Options API, there is a `head()` method you can use when you use `defineNuxtComponent`. ## Migration ### Set `bridge.meta` ```js import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { meta: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` ### Update head properties In your `nuxt.config`, rename `head` to `app.head`. (Note that objects no longer have a `hid` key for deduplication.) <code-group> ```ts [Nuxt 2] export default { head: { titleTemplate: '%s - Nuxt', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'Meta description' }, ], }, } ``` ```ts [Nuxt 3] export default defineNuxtConfig({ app: { head: { titleTemplate: '%s - Nuxt', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { name: 'description', content: 'Meta description' }, ], }, }, }) ``` </code-group> ## `useHead` Composables Nuxt Bridge provides a new Nuxt 3 meta API that can be accessed with a new [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable. ```vue <script setup lang="ts"> useHead({ title: 'My Nuxt App', }) </script> ``` <tip> This [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`. </tip> <warning> We recommend not using the native Nuxt 2 `head()` properties in addition to [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) , as they may conflict. </warning> For more information on how to use this composable, see [the docs](https://nuxt.com/docs/4.x/getting-started/seo-meta). ## Options API ```vue <script> // if using options API `head` method you must use `defineNuxtComponent` export default defineNuxtComponent({ head (nuxtApp) { // `head` receives the nuxt app but cannot access the component instance return { meta: [{ name: 'description', content: 'This is my page description.', }], } }, }) </script> ``` <warning> Possible breaking change: `head` receives the nuxt app but cannot access the component instance. If the code in your `head` tries to access the data object through `this` or `this.$data`, you will need to migrate to the `useHead` composable. </warning> ## Title Template If you want to use a function (for full control), then this cannot be set in your nuxt.config, and it is recommended instead to set it within your `/layouts` directory. ```vue [app/layouts/default.vue] <script setup lang="ts"> useHead({ titleTemplate: (titleChunk) => { return titleChunk ? `${titleChunk} - Site Title` : 'Site Title' }, }) </script> ``` # Nitro > Activate Nitro to your Nuxt 2 application with Nuxt Bridge. ## Remove Modules - Remove `@nuxt/nitro`: Bridge injects same functionality ## Update Config ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { nitro: true, }, }) ``` ## Update Your Scripts You will also need to update your scripts within your `package.json` to reflect the fact that Nuxt will now produce a Nitro server as build output. ### Install Nuxi Install `nuxi` as a development dependency: <code-group sync="pm"> ```bash [npm] npm install -D nuxi ``` ```bash [yarn] yarn add --dev nuxi ``` ```bash [pnpm] pnpm add -D nuxi ``` ```bash [bun] bun add -D nuxi ``` ```bash [deno] deno add -D npm:nuxi ``` </code-group> ### Nuxi Nuxt 3 introduced the new Nuxt CLI command [`nuxi`](https://nuxt.com/docs/4.x/api/commands/add). Update your scripts as follows to leverage the better support from Nuxt Bridge: ```diff { "scripts": { - "dev": "nuxt", + "dev": "nuxi dev", - "build": "nuxt build", + "build": "nuxi build", - "start": "nuxt start", + "start": "nuxi preview" } } ``` <tip> If `nitro: false`, use the `nuxt2` command. </tip> ### Static Target If you have set `target: 'static'` in your `nuxt.config` then you need to ensure that you update your build script to be `nuxi generate`. ```json [package.json] { "scripts": { "build": "nuxi generate" } } ``` ### Server Target For all other situations, you can use the `nuxi build` command. ```json [package.json] { "scripts": { "build": "nuxi build", "start": "nuxi preview" } } ``` ## Exclude Built Nitro Folder From Git Add the folder `.output` to the `.gitignore` file. ## Ensure Everything Goes Well โœ”๏ธ Try with `nuxi dev` and `nuxi build` (or `nuxi generate`) to see if everything goes well. # New Composition API > Nuxt Bridge implements composables compatible with Nuxt 3. By migrating from `@nuxtjs/composition-api` to the Nuxt 3 compatible API, there will be less rewriting when migrating to Nuxt 3. ## `ssrRef` and `shallowSsrRef` These two functions have been replaced with a new composable that works very similarly under the hood: `useState`. The key differences are that you must provide a *key* for this state (which Nuxt generated automatically for `ssrRef` and `shallowSsrRef`), and that it can only be called within a Nuxt 3 plugin (which is defined by `defineNuxtPlugin`) or a component instance. (In other words, you cannot use [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) with a global/ambient context, because of the danger of shared state across requests.) ```diff - import { ssrRef } from '@nuxtjs/composition-api' - const ref1 = ssrRef('initialData') - const ref2 = ssrRef(() => 'factory function') + const ref1 = useState('ref1-key', () => 'initialData') + const ref2 = useState('ref2-key', () => 'factory function') // accessing the state console.log(ref1.value) ``` Because the state is keyed, you can access the same state from multiple locations, as long as you are using the same key. You can read more about how to use this composable in [the Nuxt 3 docs](https://nuxt.com/docs/4.x/api/composables/use-state). ## `ssrPromise` This function has been removed, and you will need to find an alternative implementation if you were using it. If you have a use case for `ssrPromise`, please let us know via a discussion. ## `onGlobalSetup` This function has been removed, but its use cases can be met by using [`useNuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) or [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) within `defineNuxtPlugin`. You can also run any custom code within the `setup()` function of a layout. ```diff - import { onGlobalSetup } from '@nuxtjs/composition-api' - export default () => { - onGlobalSetup(() => { + export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.hook('vue:setup', () => { // ... }) - } + }) ``` ## `useStore` In order to access Vuex store instance, you can use `useNuxtApp().$store`. ```diff - import { useStore } from '@nuxtjs/composition-api` + const { $store } = useNuxtApp() ``` ## `useContext` and `withContext` You can access injected helpers using `useNuxtApp`. ```diff - import { useContext } from '@nuxtjs/composition-api` + const { $axios } = useNuxtApp() ``` <note> `useNuxtApp()` also provides a key called `nuxt2Context` which contains all the same properties you would normally access from Nuxt 2 context, but it's advised *not* to use this directly, as it won't exist in Nuxt 3. Instead, see if there is another way to access what you need. (If not, please raise a feature request or discussion.) </note> ## `wrapProperty` This helper function is not provided any more but you can replace it with the following code: ```ts import { computed, getCurrentInstance } from 'vue' const wrapProperty = (property: string, makeComputed = true) => () => { const vm = getCurrentInstance().proxy return makeComputed ? computed(() => vm[property]) : vm[property] } ``` ## `useAsync` and `useFetch` These two composables can be replaced with `useLazyAsyncData` and `useLazyFetch`, which are documented [in the Nuxt 3 docs](https://nuxt.com/docs/4.x/getting-started/data-fetching). Just like the previous `@nuxtjs/composition-api` composables, these composables do not block route navigation on the client-side (hence the 'lazy' part of the name). <important> Note that the API is entirely different, despite similar sounding names. Importantly, you should not attempt to change the value of other variables outside the composable (as you may have been doing with the previous `useFetch`). </important> <warning> The `useLazyFetch` must have been configured for [Nitro](https://nuxt.com/docs/4.x/bridge/nitro). </warning> Migrating to the new composables from `useAsync`: ```diff <script setup> - import { useAsync } from '@nuxtjs/composition-api' - const posts = useAsync(() => $fetch('/api/posts')) + const { data: posts } = useLazyAsyncData('posts', () => $fetch('/api/posts')) + // or, more simply! + const { data: posts } = useLazyFetch('/api/posts') </script> ``` Migrating to the new composables from `useFetch`: ```diff <script setup> - import { useFetch } from '@nuxtjs/composition-api' - const posts = ref([]) - const { fetch } = useFetch(() => { posts.value = await $fetch('/api/posts') }) + const { data: posts, refresh } = useLazyAsyncData('posts', () => $fetch('/api/posts')) + // or, more simply! + const { data: posts, refresh } = useLazyFetch('/api/posts') function updatePosts() { - return fetch() + return refresh() } </script> ``` ### `useMeta` In order to interact with `vue-meta`, you may use `useNuxt2Meta`, which will work in Nuxt Bridge (but not Nuxt 3) and will allow you to manipulate your meta tags in a `vue-meta`-compatible way. ```diff <script setup> - import { useMeta } from '@nuxtjs/composition-api' useNuxt2Meta({ title: 'My Nuxt App', }) </script> ``` You can also pass in computed values or refs, and the meta values will be updated reactively: ```vue <script setup> const title = ref('my title') useNuxt2Meta({ title, }) title.value = 'new title' </script> ``` <note> Be careful not to use both `useNuxt2Meta()` and the Options API `head()` within the same component, as behavior may be unpredictable. </note> Nuxt Bridge also provides a Nuxt 3-compatible meta implementation that can be accessed with the [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable. ```diff <script setup> - import { useMeta } from '@nuxtjs/composition-api' useHead({ title: 'My Nuxt App', }) </script> ``` You will also need to enable it explicitly in your `nuxt.config`: ```js import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { meta: true, }, }) ``` This [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`. Accordingly, it is recommended not to use both the native Nuxt 2 `head()` properties as well as [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) , as they may conflict. For more information on how to use this composable, see [the Nuxt 3 docs](https://nuxt.com/docs/4.x/getting-started/seo-meta). ### Explicit Imports Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed: ```vue <script setup lang="ts"> import { computed, ref } from '#imports' const count = ref(1) const double = computed(() => count.value * 2) </script> ``` ### Disabling Auto-imports If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ imports: { autoImport: false, }, }) ``` This will disable auto-imports completely but it's still possible to use [explicit imports](https://nuxt.com/docs/4.x/bridge/nuxt3-compatible-api#explicit-imports) from `#imports`. # Overview > Reduce the differences with Nuxt 3 and reduce the burden of migration to Nuxt 3. <note> If you're starting a fresh Nuxt 3 project, please skip this section and go to [Nuxt 3 Installation](https://nuxt.com/docs/4.x/getting-started/introduction). </note> <warning> Nuxt Bridge provides identical features to Nuxt 3 ([docs](https://nuxt.com/docs/4.x/guide/concepts/auto-imports)) but there are some limitations, notably that [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) composables are not available. Please read the rest of this page for details. </warning> Bridge is a forward-compatibility layer that allows you to experience many of the new Nuxt 3 features by simply installing and enabling a Nuxt module. Using Nuxt Bridge, you can make sure your project is (almost) ready for Nuxt 3 and you can gradually proceed with the transition to Nuxt 3. ## First Step ### Upgrade Nuxt 2 Make sure your dev server (`nuxt dev`) isn't running, remove any package lock files (`package-lock.json` and `yarn.lock`), and install the latest Nuxt 2 version: ```diff [package.json] - "nuxt": "^2.16.3" + "nuxt": "^2.17.3" ``` Then, reinstall your dependencies: <code-group sync="pm"> ```bash [npm] npm install ``` ```bash [yarn] yarn install ``` ```bash [pnpm] pnpm install ``` ```bash [bun] bun install ``` ```bash [deno] deno install ``` </code-group> <note> Once the installation is complete, make sure both development and production builds are working as expected before proceeding. </note> ### Install Nuxt Bridge Install `@nuxt/bridge` and `nuxi` as development dependencies: <code-group sync="pm"> ```bash [npm] npm install -D @nuxt/bridge nuxi ``` ```bash [yarn] yarn add --dev @nuxt/bridge nuxi ``` ```bash [pnpm] pnpm add -D @nuxt/bridge nuxi ``` ```bash [bun] bun add -D @nuxt/bridge nuxi ``` ```bash [deno] deno add -D npm:@nuxt/bridge npm:nuxi ``` </code-group> ### Update `nuxt.config` Please make sure to avoid any CommonJS syntax such as `module.exports`, `require` or `require.resolve` in your config file. It will soon be deprecated and unsupported. You can use static `import`, dynamic `import()` and `export default` instead. Using TypeScript by renaming to [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) is also possible and recommended. ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: false, }) ``` ### Update Commands The `nuxt` command should now be changed to the `nuxt2` command. ```diff { "scripts": { - "dev": "nuxt", + "dev": "nuxt2", - "build": "nuxt build", + "build": "nuxt2 build", - "start": "nuxt start", + "start": "nuxt2 start" } } ``` Try running `nuxt2` once here. You will see that the application works as before. (If 'bridge' is set to false, your application will operate without any changes as before.) ## Upgrade Steps With Nuxt Bridge, the migration to Nuxt 3 can proceed in steps. The below `Upgrade Steps` does not need to be done all at once. - [TypeScript](https://nuxt.com/docs/4.x/bridge/typescript) - [Migrate Legacy Composition API](https://nuxt.com/docs/4.x/bridge/bridge-composition-api) - [Plugins and Middleware](https://nuxt.com/docs/4.x/bridge/plugins-and-middleware) - [Migrate New Composition API](https://nuxt.com/docs/4.x/bridge/nuxt3-compatible-api) - [Meta Tags](https://nuxt.com/docs/4.x/bridge/meta) - [Runtime Config](https://nuxt.com/docs/4.x/bridge/runtime-config) - [Nitro](https://nuxt.com/docs/4.x/bridge/nitro) - [Vite](https://nuxt.com/docs/4.x/bridge/vite) ## Migrate from CommonJS to ESM Nuxt 3 natively supports TypeScript and ECMAScript Modules. Please check [Native ES Modules](https://nuxt.com/docs/4.x/guide/concepts/esm) for more info and upgrading. # Plugins and Middleware > Learn how to migrate from Nuxt 2 to Nuxt Bridge new plugins and middleware. ## New Plugins Format You can now migrate to the Nuxt 3 plugins API, which is slightly different in format from Nuxt 2. Plugins now take only one argument (`nuxtApp`). You can find out more in [the docs](https://nuxt.com/docs/4.x/directory-structure/app/plugins). ```ts [app/plugins/hello.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.provide('injected', () => 'my injected function') // now available on `nuxtApp.$injected` }) ``` <note> If you want to use the new Nuxt composables (such as [`useNuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) or `useRuntimeConfig`) within your plugins, you will need to use the `defineNuxtPlugin` helper for those plugins. </note> <warning> Although a compatibility interface is provided via `nuxtApp.vueApp` you should avoid registering plugins, directives, mixins or components this way without adding your own logic to ensure they are not installed more than once, or this may cause a memory leak. </warning> ## New Middleware Format You can now migrate to the Nuxt 3 middleware API, which is slightly different in format from Nuxt 2. Middleware now take only two argument (`to`, `from`). You can find out more in [the docs](https://nuxt.com/docs/4.x/directory-structure/app/middleware). ```tstwoslash export default defineNuxtRouteMiddleware((to) => { if (to.path !== '/') { return navigateTo('/') } }) ``` <important> Use of `defineNuxtRouteMiddleware` is not supported outside of the `app/middleware` directory. </important> ## definePageMeta You can also use [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) in Nuxt Bridge. It can be enabled with the `macros.pageMeta` option in your configuration file ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { macros: { pageMeta: true, }, }, }) ``` <note> But only for `middleware` and `layout`. </note> # Runtime Config > Nuxt provides a runtime config API to expose configuration and secrets within your application. <warning> When using `runtimeConfig` option, [nitro](https://nuxt.com/docs/4.x/bridge/nitro) must have been configured. </warning> ## Update Runtime Config Nuxt 3 approaches runtime config differently than Nuxt 2, using a new combined `runtimeConfig` option. First, you'll need to combine your `publicRuntimeConfig` and `privateRuntimeConfig` properties into a new one called `runtimeConfig`, with the public config within a key called `public`. ```diff // nuxt.config.js - privateRuntimeConfig: { - apiKey: process.env.NUXT_API_KEY || 'super-secret-key' - }, - publicRuntimeConfig: { - websiteURL: 'https://public-data.com' - } + runtimeConfig: { + apiKey: process.env.NUXT_API_KEY || 'super-secret-key', + public: { + websiteURL: 'https://public-data.com' + } + } ``` This also means that when you need to access public runtime config, it's behind a property called `public`. If you use public runtime config, you'll need to update your code. ```diff // MyWidget.vue - <div>Website: {{ $config.websiteURL }}</div> + <div>Website: {{ $config.public.websiteURL }}</div> ``` # TypeScript > Learn how to use TypeScript with Nuxt Bridge. ## Remove Modules - Remove `@nuxt/typescript-build`: Bridge enables same functionality - Remove `@nuxt/typescript-runtime` and `nuxt-ts`: Nuxt 2 has built-in runtime support ### Set `bridge.typescript` ```ts import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { typescript: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` ## Update `tsconfig.json` If you are using TypeScript, you can edit your `tsconfig.json` to benefit from auto-generated Nuxt types: ```diff [tsconfig.json] { + "extends": "./.nuxt/tsconfig.json", "compilerOptions": { ... } } ``` <note> As `.nuxt/tsconfig.json` is generated and not checked into version control, you'll need to generate that file before running your tests. Add `nuxi prepare` as a step before your tests, otherwise you'll see `TS5083: Cannot read file '~/.nuxt/tsconfig.json'` For modern Nuxt projects, we recommend using [TypeScript project references](https://nuxt.com/docs/4.x/directory-structure/tsconfig) instead of directly extending `.nuxt/tsconfig.json`. </note> <note> Keep in mind that all options extended from `./.nuxt/tsconfig.json` will be overwritten by the options defined in your `tsconfig.json`. Overwriting options such as `"compilerOptions.paths"` with your own configuration will lead TypeScript to not factor in the module resolutions from `./.nuxt/tsconfig.json`. This can lead to module resolutions such as `#imports` not being recognized. In case you need to extend options provided by `./.nuxt/tsconfig.json` further, you can use the `alias` property within your `nuxt.config`. `nuxi` will pick them up and extend `./.nuxt/tsconfig.json` accordingly. </note> # Vite > Activate Vite to your Nuxt 2 application with Nuxt Bridge. <warning> When using `vite`, [nitro](https://nuxt.com/docs/4.x/bridge/nitro) must have been configured. </warning> ## Remove Modules - Remove `nuxt-vite`: Bridge enables same functionality ## Update Config ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { vite: true, nitro: true, }, }) ``` ## Configuration ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ vite: { // Config for Vite }, }) ``` # Releases > Discover the latest releases of Nuxt & Nuxt official modules. <card-group> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/nuxt" to="https://github.com/nuxt/nuxt/releases"> Nuxt framework releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/cli" to="https://github.com/nuxt/cli/releases"> Nuxt CLI (`@nuxt/cli`) releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/a11y" to="https://github.com/nuxt/a11y/releases"> Nuxt A11y releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/content" to="https://github.com/nuxt/content/releases"> Nuxt Content releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/devtools" to="https://github.com/nuxt/devtools/releases"> Nuxt DevTools releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/fonts" to="https://github.com/nuxt/fonts/releases"> Nuxt Fonts releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/hints" to="https://github.com/nuxt/hints/releases"> Nuxt Hints releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/image" to="https://github.com/nuxt/image/releases"> Nuxt Image releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/scripts" to="https://github.com/nuxt/scripts/releases"> Nuxt Scripts releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/ui" to="https://github.com/nuxt/ui/releases"> Nuxt UI releases. </card> </card-group> <read-more icon="i-simple-icons-github" target="_blank" to="https://github.com/nuxt"> Discover the `nuxt` organization on GitHub </read-more> # Contribution > Nuxt is a community project - and so we love contributions of all kinds! โค๏ธ There is a range of different ways you might be able to contribute to the Nuxt ecosystem. ## Ecosystem The Nuxt ecosystem includes many different projects and organizations: - [nuxt/](https://github.com/nuxt) - core repositories for the Nuxt framework itself. [**nuxt/nuxt**](https://github.com/nuxt/nuxt) contains the Nuxt framework (both versions 2 and 3). - [nuxt-modules/](https://github.com/nuxt-modules) - community-contributed and maintained modules and libraries. There is a [process to migrate a module](https://nuxt.com/docs/4.x/guide/modules/ecosystem) to `nuxt-modules`. While these modules have individual maintainers, they are not dependent on a single person. - [unjs/](https://github.com/unjs) - many of these libraries are used throughout the Nuxt ecosystem. They are designed to be universal libraries that are framework- and environment-agnostic. We welcome contributions and usage by other frameworks and projects. ## How To Contribute ### Triage Issues and Help Out in Discussions Check out the issues and discussions for the project you want to help. For example, here are [the issues board](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) for Nuxt. Helping other users, sharing workarounds, creating reproductions, or even poking into a bug a little bit and sharing your findings makes a huge difference. ### Creating an Issue Thank you for taking the time to create an issue! โค๏ธ - **Reporting bugs**: Check out [our guide](https://nuxt.com/docs/4.x/community/reporting-bugs) for some things to do before opening an issue. - **Feature requests**: Check that there is not an existing issue or discussion covering the scope of the feature you have in mind. If the feature is to another part of the Nuxt ecosystem (such as a module), please consider raising a feature request there first. If the feature you have in mind is general or the API is not entirely clear, consider opening a discussion in the **Ideas** section to discuss with the community first. We'll do our best to follow our [internal issue decision making flowchart](https://mermaid.live/view#pako:eNqFlE1v2zAMhv8K4UuToslhx2Bo0TZt12Edhm7YMCAXWqJtorLk6qOpkfS_j7KdfpyWQ-BQr8mHL6nsCuU0FauiMm6rGvQRfq03FuRzvvvTYIQHthpcBT_ugQNwPHuZjheLxf4i1VDx8x4udrf5EBCOQvSsYg4ffS79KS9pmX9QALTgyid2KYB7Ih-4bmKWbDk2YB0E1gRUVaRi-FDmmjAmT3u4nB3DmoNKIUA1BsGSohA49jnVMQhHbDh_EZQUImyxh-gAtfaiG-KWSJ-N8nt6YtpCdgEeE5rXPOdav5YwWJIJU7zrvNADV9C7JBIyIC07Wxupkx3LFQ5vCkguRno5f9fP2qnUko0Y2dk9rGdvHAa9IIhVGlCp5FFNPN-ce4DKeXBd53xMliOLp9IZtyORQVsnrGm-WJzejtUu5fFqdr5FGQ3bLslYvGthjZbJTLpReZG5_lLYw7XQ_CbPVT92ws9gnEJj-v84dk-PiaXnmF1XGAaPsOsMKywNvYmG80ZohV8k4wDR9_N3KN_dHm5mh1lnkM5FsYzRfNiTvJoT5gnQsl6uxjqXLhkNQ9syHJ0UZZ8ERUIlNShr6N8gZDEliR-ow7QZa0fhY4LoHLRo-8N7ZxPwjRj5ZZYXpvOSNs9v3Jjs8NXB4ets92xan3zydXZHvj64lKMayh4-gZC1bjASW2ipLeWuzIuToiXfImu5rbucclMIc0ubYiWPGv3DptjYF9Fhiu5nb1Wxij7RSZE6jZHWjLXHtlhVaIJESXN0_m68_sO_wMs_oO9gyg) when responding to issues. ### Send a Pull Request We always welcome pull requests! โค๏ธ #### Before You Start Before you fix a bug, we recommend that you check whether **there's an issue that describes it**, as it's possible it's a documentation issue or that there is some context that would be helpful to know. If you're working on a feature, then we ask that you **open a feature request issue first** to discuss with the maintainers whether the feature is desired - and the design of those features. This helps save time for both the maintainers and the contributors and means that features can be shipped faster. The issue **should be confirmed** by a framework team member before building out a feature in a pull request. For typo fixes, it's recommended to batch multiple typo fixes into one pull request to maintain a cleaner commit history. For bigger changes to Nuxt itself, we recommend that you first [create a Nuxt module](https://nuxt.com/docs/4.x/community/contribution#create-a-module) and implement the feature there. This allows for quick proof-of-concept. You can then [create an RFC](https://nuxt.com/docs/4.x/community/contribution#make-an-rfc) in the form of a discussion. As users adopt it and you gather feedback, it can then be refined and either added to Nuxt core or continue as a standalone module. #### Commit Conventions We use [Conventional Commits](https://www.conventionalcommits.org) for commit messages, which [allows a changelog to be auto-generated](https://github.com/unjs/changelogen) based on the commits. Please read the guide through if you aren't familiar with it already. Note that `fix:` and `feat:` are for **actual code changes** (that might affect logic). For typo or document changes, use `docs:` or `chore:` instead: - ~~fix: typo~~ -> `docs: fix typo` If you are working in a project with a monorepo, like `nuxt/nuxt`, ensure that you specify the main scope of your commit in brackets. For example: `feat(kit): add 'addMagicStuff' utility`. #### Making the Pull Request If you don't know how to send a pull request, we recommend reading [the guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). When sending a pull request, make sure your PR's title also follows the [Commit Convention](https://nuxt.com/docs/4.x/community/contribution#commit-conventions). If your PR fixes or resolves existing issues, please make sure you mention them in the PR description. It's ok to have multiple commits in a single PR; you don't need to rebase or force push for your changes as we will use `Squash and Merge` to squash the commits into one commit when merging. We do not add any commit hooks to allow for quick commits. But before you make a pull request, you should ensure that any lint/test scripts are passing. In general, please also make sure that there are no *unrelated* changes in a PR. For example, if your editor has made any changes to whitespace or formatting elsewhere in a file that you edited, please revert these so it is more obvious what your PR changes. And please avoid including multiple unrelated features or fixes in a single PR. If it is possible to separate them, it is better to have multiple PRs to review and merge separately. In general, a PR should do *one thing only*. #### Once You've Made a Pull Request Once you've made a pull request, we'll do our best to review it promptly. If we assign it to a maintainer, then that means that person will take special care to review it and implement any changes that may be required. If we request changes on a PR, please ignore the red text! It doesn't mean we think it's a bad PR - it's just a way of easily telling the status of a list of pull requests at a glance. If we mark a PR as 'pending', that means we likely have another task to do in reviewing the PR - it's an internal note-to-self, and not necessarily a reflection on whether the PR is a good idea or not. We will do our best to explain via a comment the reason for the pending status. We'll do our best to follow [our PR decision making flowchart](https://mermaid.live/view#pako:eNp9VE1v2kAQ_SsjXzBSEqlALlaUisSh0ACK2l4qcVm8Y9hi7672Iwly-O-ZtYPt5FAOCHbee_PmzdpVlCmOURLlhXrJ9sw4-JNuJNBnWs1UQafIQVjrERyWumAOv58-AJeXt29_0b7BXbWwwL0uRPa1vlZvcB_fF8oiMMmB2QM4BXkt3UoON7Lh3LWaDz2SVkK6QGt7DHvw0CKt5sxCKaQoWQEGtVHcZ04oGdw04LTVngW_LHOeFcURGGz97mw6PSv-iJdsi0UCA4nI7SfNwc3W3JZit3eQ1SZFDlKB15yswQ2MgbOjbYeatY3n8bcr-IWlekYYaJRcyB04I9gOB1CEfkF5dAVTzmFAtnqn4-bUYAiMMmHZgWhNPRhgus5mW2BATxq0NkIZ4Y4NbNjzE2ZchBzcHmGLe_ZMSKCcyRXyLrVFa_5n_PBK2xKy3kk9eOjULUdltk6C8kI-7NFDr8f4EVGDoqlp-wa4sJm3ltIMIuZ_mTQXJyTSkQZtunPqsKxShV9GKdkBYe1fHXjpbcjlvONlO9Kqx_M7YHmOmav_luxfE5zKwVs09hM5DLSupgYDlr5flDkwo7ykixKG-xDsUly1LZ-uY32dgDc7lG7YqwbNp0msJwmIUivjWFtfd-xRrEcJ7Omydz37qFplHOtxEp4GskI2qB5dRCWakglOz3oV8JuITJa4iRL6yZk5bKKNPBGOead-H2UWJc54vIiaW53SPgwrz4fIhVNm1bw76lfI6R2_MW21) when responding and reviewing to pull requests. ### AI-Assisted Contributions We welcome the thoughtful use of AI tools when contributing to Nuxt, yet ask all contributors to follow [two core principles](https://roe.dev/blog/using-ai-in-open-source). #### Never let an LLM speak for you - All comments, issues, and pull request descriptions should be written in your own voice - We value clear, human communication over perfect grammar or spelling - Avoid copy-pasting AI-generated summaries that don't reflect your own understanding #### Never let an LLM think for you - Feel free to use AI tools to generate code or explore ideas - Only submit contributions you fully understand and can explain - Contributions should reflect your own reasoning and problem-solving Our aim is ensuring quality and maintaining the joy of collaborating and communicating with real people. If you have ideas for improving our policy on AI in the Nuxt community, we'd love to hear them! โค๏ธ ### Create a Module If you've built something with Nuxt that's cool, why not [extract it into a module](https://nuxt.com/docs/4.x/guide/modules), so it can be shared with others? We have [many excellent modules already](https://nuxt.com/modules), but there's always room for more. If you need help while building it, feel free to [check in with us](https://nuxt.com/docs/4.x/community/getting-help). ### Make an RFC We highly recommend [creating a module](https://nuxt.com/docs/4.x/community/contribution#create-a-module) first to test out big new features and gain community adoption. If you have done this already, or it's not appropriate to create a new module, then please start by creating a new discussion. Make sure it explains your thinking as clearly as possible. Include code examples or function signatures for new APIs. Reference existing issues or pain points with examples. If we think this should be an RFC, we'll change the category to RFC and broadcast it more widely for feedback. An RFC will then move through the following stages: - `rfc: active` - currently open for comment - `rfc: approved` - approved by the Nuxt team - `rfc: ready to implement` - an issue has been created and assigned to implement - `rfc: shipped` - implemented - `rfc: archived` - not approved, but archived for future reference ### Conventions Across Ecosystem The following conventions are *required* within the `nuxt/` organization and recommended for other maintainers in the ecosystem. #### Module Conventions Modules should follow the [Nuxt module template](https://github.com/nuxt/starter/tree/module). See [module guide](https://nuxt.com/docs/4.x/guide/modules) for more information. #### Use Core `unjs/` Libraries We recommend the following libraries which are used throughout the ecosystem: - [pathe](https://github.com/unjs/pathe) - universal path utilities (replacement for node `path`) - [ufo](https://github.com/unjs/ufo) - URL parsing and joining utilities - [obuild](https://github.com/unjs/obuild) - rolldown-powered build system - ... check out the rest of the [unjs/](https://github.com/unjs) organization for many more! #### Use ESM Syntax and Default to `type: module` Most of the Nuxt ecosystem can consume ESM directly. In general we advocate that you avoid using CJS-specific code, such as `__dirname` and `require` statements. You can [read more about ESM](https://nuxt.com/docs/4.x/guide/concepts/esm). #### What's Corepack [Corepack](https://github.com/nodejs/corepack) makes sure you are using the correct version for package manager when you run corresponding commands. Projects might have `packageManager` field in their `package.json`. Under projects with configuration as shown below, Corepack will install `v7.5.0` of `pnpm` (if you don't have it already) and use it to run your commands. ```jsonc [package.json] { "packageManager": "pnpm@7.5.0" } ``` #### Use ESLint We use [ESLint](https://eslint.org) for both linting and formatting with [`@nuxt/eslint`](https://github.com/nuxt/eslint). ##### IDE Setup We recommend using [VS Code](https://code.visualstudio.com) along with the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint). If you would like, you can enable auto-fix and formatting when you save the code you are editing: ```json [settings.json] { "editor.codeActionsOnSave": { "source.fixAll": "never", "source.fixAll.eslint": "explicit" } } ``` #### No Prettier Since ESLint is already configured to format the code, there is no need to duplicate the functionality with Prettier. To format the code, you can run `yarn lint --fix`, `pnpm lint --fix`, `bun run lint --fix`, or `deno run lint --fix` or referring the [ESLint section](https://nuxt.com/docs/4.x/community/contribution#use-eslint) for IDE Setup. If you have Prettier installed in your editor, we recommend you disable it when working on the project to avoid conflict. #### Package Manager We recommend `pnpm` as a package manager for modules, libraries and apps. It is important to enable Corepack to ensure you are on the same version of the package manager as the project. Corepack is built-in to new node versions for seamless package manager integration. To enable it, run ```bash [Terminal] corepack enable ``` You only need to do this one time, after Node.js is installed on your computer. ## Documentation Style Guide Documentation is an essential part of Nuxt. We aim to be an intuitive framework - and a big part of that is making sure that both the developer experience and the docs are perfect across the ecosystem. ๐Ÿ‘Œ Here are some tips that may help improve your documentation: ### Language - Use **American English** spelling (*behavior* rather than *behaviour*, *customize* rather than *customise*). - Write tool and project names using their official capitalization, even when the npm package name is lowercase (for example, *PostCSS* rather than *postcss*, *Vite* rather than *vite*, *ESLint* rather than *eslint*). Use the lowercase npm package name in backticks only when referring to the package itself, such as in installation instructions.<caution icon="i-lucide-circle-x"> Nuxt supports postcss out of the box. </caution> <tip icon="i-lucide-circle-check"> Nuxt supports PostCSS out of the box. You don't need to install `postcss` manually. </tip> <note> Casing of common tool names is checked automatically by [case police](https://github.com/antfu/case-police) when you run `pnpm lint:docs`. </note> ### Headings - Capitalize headings following Chicago title case. In short: capitalize the first word, the last word, and all major words (nouns, verbs, adjectives, adverbs, pronouns); lowercase articles, coordinating conjunctions, and prepositions regardless of length (for example, a, and, or, with, from, and to). When in doubt, [capitalizemytitle.com](https://capitalizemytitle.com/style/Chicago) can help.<caution icon="i-lucide-circle-x"> How to contribute to the docs </caution> <tip icon="i-lucide-circle-check"> How to Contribute to the Docs </tip> - Code in headings keeps its original casing and is not counted for capitalization purposes (for example, *Using useFetch in Components*). ### Inline Code Wrap the following in backticks so they render as inline code: - File names and paths: `nuxt.config.ts`, `server/api/` - npm package names: `@nuxt/kit`, `postcss` - Configuration keys, options, and values: `ssr: false`, the `css` option - Code identifiers such as functions, composables, components, variables, and types: `useFetch`, `<NuxtLink>`, `defineNuxtConfig` - Terminal commands: `npx nuxt init` Do not use backticks for names of tools, projects, or general concepts (use *Vite*, not `vite`, when referring to the tool). ### Code Examples - Add a filename to code blocks so readers know where the code belongs. If the code doesn't belong in a particular file (for example, a shell command), use a descriptive label like `[Terminal]`.```markdown ```ts [nuxt.config.ts] export default defineNuxtConfig({ ssr: false, }) ``` ``` - Make examples copy-pasteable. Include the necessary imports and avoid placeholders such as `...` in the middle of code that a reader would paste into their project. A reader should be able to copy an example into their project and have it work with minimal changes. ### Links - When linking to other documentation pages, use relative paths without the domain or a version segment: `/docs/getting-started/installation` rather than `/docs/4.x/getting-started/installation` or `https://nuxt.com/docs/4.x/getting-started/installation`. nuxt.com inserts the version segment of the branch the page was built from, so the same link resolves correctly on every version and docs changes can be cherry-picked between branches unchanged. - Only write a version segment when you deliberately mean *another* version's docs (the release table in the roadmap, for example). In that case use the full URL, `https://nuxt.com/docs/3.x/getting-started/introduction`, so the intent is obvious in review. - When linking to external resources, link to the final URL rather than one that redirects. You can check with:```bash [Terminal] curl -sILo /dev/null -w '%{http_code} %{url_effective}\n' https://example.com/some-page ``` <br /> This follows any chain of redirects and prints the final status and URL. A `200` status with the URL you requested means the link is fine. If the final URL differs, link to that instead. ### Tone We aim for a tone that is friendly and professional. Write directly to the reader ("you"), be concise, and assume good faith: readers come from many different backgrounds and levels of experience, so avoid language that could make anyone feel talked down to. It's fine to be warm - the docs can have personality - but clarity always comes first. ### Writing Style - Avoid subjective words like *simply*, *just*, *obviously...* when possible.<br /> Keep in mind your readers can have different backgrounds and experiences. Therefore, these words don't convey meaning and can be harmful.<caution icon="i-lucide-circle-x"> Simply make sure the function returns a promise. </caution> <tip icon="i-lucide-circle-check"> Make sure the function returns a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). </tip> - Prefer [active voice](https://developers.google.com/tech-writing/one/active-voice).<caution icon="i-lucide-circle-x"> An error will be thrown by Nuxt. </caution> <tip icon="i-lucide-circle-check"> Nuxt will throw an error. </tip> - Use consistent section names and ordering when documenting API pages, including composables, utilities, and components. Include only the sections that apply: 1. **Usage**: Explain how to use the API and cover common use cases. 2. **Type**: Provide the relevant TypeScript declarations. 3. **Parameters**: Describe each input, including its type, default value, and available options. 4. **Return Values**: Describe the returned value and its type. 5. **Example**: Show a practical example.<br /> Use these exact section names. For example, use `Parameters` rather than `Params` and `Example` rather than `Examples`. - When documenting API pages (composables, utils, components), add the **minimal Nuxt version** when a feature or utility was introduced, so readers know which version they need.<br /> Use two levels: - **Global (whole page):** Add `minimalVersion: "3.9"` in the frontmatter (without the "v" prefix). The docs layout renders the version badge automatically from this field, displaying it as `vX.Y` (e.g. `v3.9`, `v3.15`). - **Local (specific option or feature):** Add a small badge next to the option or section: `:badge[v3.8]{color="info" size="xs" class="align-middle"}` (e.g. for `getCachedData` in useFetch, or for the `navigation` mode in callOnce).<br /> To find the version, check `@since` in JSDoc in the source, the [release notes](https://github.com/nuxt/nuxt/releases), or the [Nuxt blog](https://nuxt.com/blog). <read-more to="https://nuxt.com/docs/4.x/community/framework-contribution#documentation-guide"> Learn how to contribute to the documentation. </read-more> # Framework > Some specific points about contributions to the framework repository. Once you've read the [general contribution guide](https://nuxt.com/docs/4.x/community/contribution), here are some specific points to make about contributions to the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository. ## Monorepo Guide - `packages/kit`: Toolkit for authoring Nuxt modules, published as [`@nuxt/kit`](https://www.npmjs.com/package/@nuxt/kit). - `packages/nuxt`: The core of Nuxt, published as [`nuxt`](https://www.npmjs.com/package/nuxt). - `packages/schema`: Cross-version Nuxt typedefs and defaults, published as [`@nuxt/schema`](https://www.npmjs.com/package/@nuxt/schema). - `packages/rspack`: The [Rspack](https://rspack.rs) bundler for Nuxt, published as [`@nuxt/rspack-builder`](https://www.npmjs.com/package/@nuxt/rspack-builder). - `packages/vite`: The [Vite](https://vite.dev) bundler for Nuxt, published as [`@nuxt/vite-builder`](https://www.npmjs.com/package/@nuxt/vite-builder). - `packages/webpack`: The [webpack](https://webpack.js.org) bundler for Nuxt, published as [`@nuxt/webpack-builder`](https://www.npmjs.com/package/@nuxt/webpack-builder). ## Setup To contribute to Nuxt, you need to set up a local environment. 1. [Fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository to your own GitHub account and then [clone](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) it to your local device. 2. Ensure using the latest [Node.js](https://nodejs.org/en) 3. Enable [Corepack](https://github.com/nodejs/corepack) to have `pnpm` and `yarn````bash [Terminal] corepack enable ``` 4. Run `pnpm install --frozen-lockfile` to Install the dependencies with pnpm: ```bash [Terminal] pnpm install --frozen-lockfile ``` <note> If you are adding a dependency, please use `pnpm add`. <br /> The `pnpm-lock.yaml` file is the source of truth for all Nuxt dependencies. </note> 5. Activate the passive development system ```bash [Terminal] pnpm dev:prepare ``` 6. Check out a branch where you can work and commit your changes: ```bash [Terminal] git checkout -b my-new-branch ``` Then, test your changes against the [playground](https://nuxt.com/docs/4.x/community/framework-contribution#playground) and [test](https://nuxt.com/docs/4.x/community/framework-contribution#testing) your changes before submitting a pull request. ### Playground While working on a pull request, you will likely want to check if your changes are working correctly. You can modify the example app in `playground/`, and run: ```bash [Terminal] pnpm dev ``` <important> Please make sure not to commit it to your branch, but it could be helpful to add some example code to your PR description. This can help reviewers and other Nuxt users understand the feature you've built in-depth. </important> ### Testing Every new feature should have a corresponding unit test (if possible). The `test/` directory in this repository is currently a work in progress, but do your best to create a new test following the example of what's already there. Before creating a PR or marking it as ready-to-review, ensure that all tests pass by running: ```bash [Terminal] pnpm test ``` ### Linting You might have noticed already that we use ESLint to enforce a coding standard. Before committing your changes, to verify that the code style is correct, run: ```bash [Terminal] pnpm lint ``` <note> You can use `pnpm lint --fix` to fix most of the style changes. <br /> If there are still errors left, you must correct them manually. </note> ### Documentation If you are adding a new feature or refactoring or changing the behavior of Nuxt in any other manner, you'll likely want to document the changes. Please include any changes to the docs in the same PR. You don't have to write documentation up on the first commit (but please do so as soon as your pull request is mature enough). <important> Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/4.x/community/contribution#documentation-style-guide). </important> ### Final Checklist When submitting your PR, there is a simple template that you have to fill out. Please tick all appropriate "answers" in the checklists. ## Documentation Guide If you spot an area where we can improve documentation or error messages, please do open a PR - even if it's just to fix a typo! <important> Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/4.x/community/contribution#documentation-style-guide). </important> ### Quick Edits If you spot a typo or want to rephrase a sentence, you can click on the **Edit this page** link located on the right aside in the **Community** section. Make the change directly in the GitHub interface and open a Pull Request. ### Longer Edits The documentation content is inside the `docs/` directory of the [nuxt/nuxt](https://github.com/nuxt/nuxt) repository and written in markdown. <note> To preview the docs locally, follow the steps on [nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) repository. </note> <note> We recommend that you install the [MDC extension](https://marketplace.visualstudio.com/items?itemName=Nuxt.mdc) for VS Code. </note> ### Linting Docs Documentation is linted using [MarkdownLint](https://github.com/DavidAnson/markdownlint) and [case police](https://github.com/antfu/case-police) to keep the documentation cohesive. ```bash [Terminal] pnpm lint:docs ``` <note> You can also run `pnpm lint:docs:fix` to highlight and resolve any lint issues. </note> ### Open a PR Please make sure your PR title adheres to the [conventional commits](https://www.conventionalcommits.org) guidelines. ```bash [Example of PR title] docs: update the section about the nuxt.config.ts file ``` # Getting Help > We're a friendly community of developers and we'd love to help. At some point, you may find that there's an issue you need some help with. But don't worry! We're a friendly community of developers and we'd love to help. <card-group> <card icon="i-simple-icons-discord" target="_blank" title="Discord" to="https://go.nuxt.com/discord"> Get real-time help, exchange with the core team and the community, and stay updated on the latest Nuxt news. </card> <card icon="i-simple-icons-nuxt" target="_blank" title="Nuxters" to="https://nuxters.nuxt.com"> Connect with other Nuxt enthusiasts. </card> </card-group> ## "I can't figure out how to (...)." You've read through these docs and you think it should be possible, but it's not clear how. The best thing is to [open a GitHub Discussion](https://github.com/nuxt/nuxt/discussions). Please don't feel embarrassed about asking a question that you think is easy - we've all been there! โค๏ธ Everyone you'll encounter is helping out because they care, not because they are paid to do so. The kindest thing to do is make it easy for them to help you. Here are some ideas: - *Explain what your objective is, not just the problem you're facing.* "I need to ensure my form inputs are accessible, so I'm trying to get the ids to match between server and client." - *Make sure you've first read the docs and used your favorite search engine*. Let people know by saying something like "I've Googled for 'nuxt script setup' but I couldn't find code examples anywhere." - *Explain what you've tried.* Tell people the kind of solutions you've experimented with, and why. Often this can make people's advice more relevant to your situation. - *Share your code.* People probably won't be able to help if they just see an error message or a screenshot - but that all changes if you share your code in a copy/pasteable format - preferably in the form of a minimal reproduction like a CodeSandbox. And finally, just ask the question! There's no need to [ask permission to ask a question](https://dontasktoask.com) or [wait for someone to reply to your 'hello'](https://www.nohello.com). If you do, you might not get a response because people are waiting for the whole question before engaging. ## "Could there be a bug?" Something isn't working the way that the docs say that it should. You're not sure if it's a bug. You've searched through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) but you can't find anything. (if there is a closed issue, please create a new one) We recommend taking a look at [how to report bugs](https://nuxt.com/docs/4.x/community/reporting-bugs). Nuxt is still in active development, and every issue helps make it better. ## "I need professional help" If the community couldn't provide the help you need in the time-frame you have, NuxtLabs offers professional support with the [Nuxt Experts](https://nuxt.com/enterprise/agencies). The objective of the Nuxt Expert is to provide support to the Vue ecosystem, while also creating freelance opportunities for those contributing to open-source solutions, thus helping to maintain the sustainability of the ecosystem. The Nuxt experts are Vue, Nuxt and Vite chosen contributors providing professional support and consulting services. # Reporting Bugs > One of the most valuable roles in open source is taking the time to report bugs helpfully. Try as we might, we will never completely eliminate bugs. Even if you can't fix the underlying code, reporting a bug well can enable someone else with a bit more familiarity with the codebase to spot a pattern or make a quick fix. Here are a few key steps. ## Is It Really a Bug? Consider if you're looking to get help with something, or whether you think there's a bug with Nuxt itself. If it's the former, we'd love to help you - but the best way to do that is through [asking for help](https://nuxt.com/docs/4.x/community/getting-help) rather than reporting a bug. ## Search the Issues Search through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) first. If you find anything that seems like the same bug, it's much better to comment on an existing thread than create a duplicate. ## Create a Minimal Reproduction It's important to be able to reproduce the bug reliably - in a minimal way and apart from the rest of your project. This narrows down what could be causing the issue and makes it possible for someone not only to find the cause, but also to test a potential solution. Start with the Nuxt sandbox and add the **minimum** amount of code necessary to reproduce the bug you're experiencing. <note> If your issue concerns Vue or Vite, please try to reproduce it first with the Vue SSR starter. </note> **Nuxt**: <card-group> <card icon="i-simple-icons-stackblitz" target="_blank" title="Nuxt on StackBlitz" to="https://nuxt.new/s/v4"> </card> <card icon="i-simple-icons-codesandbox" target="_blank" title="Nuxt on CodeSandbox" to="https://nuxt.new/c/v4"> </card> </card-group> **Vue**: <card-group> <card icon="i-simple-icons-stackblitz" target="_blank" title="Vue SSR on StackBlitz" to="https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter/tree/main?terminal=dev"> </card> <card icon="i-simple-icons-codesandbox" target="_blank" title="Vue SSR on CodeSandbox" to="https://codesandbox.io/p/sandbox/github/nuxt-contrib/vue3-ssr-starter/main"> </card> <card icon="i-simple-icons-github" target="_blank" title="Vue SSR Template on GitHub" to="https://github.com/nuxt-contrib/vue3-ssr-starter/generate"> </card> </card-group> Once you've reproduced the issue, remove as much code from your reproduction as you can (while still recreating the bug). The time spent making the reproduction as minimal as possible will make a huge difference to whoever sets out to fix the issue. ## Figure Out What the Cause Might Be With a Nuxt project, there are lots of moving pieces - from [Nuxt modules](https://nuxt.com/modules) to [other JavaScript libraries](https://www.npmjs.com). Try to report the bug at the most relevant and specific place. That will likely be the Nuxt module causing an issue, or the upstream library that Nuxt is depending on. # Roadmap > Nuxt is constantly evolving, with new features and modules being added all the time. <read-more to="https://nuxt.com/blog"> See our blog for the latest framework and ecosystem announcements. </read-more> ## Status Reports <read-more to="https://github.com/nuxt/nuxt/issues/13653" icon="i-simple-icons-github" target="_blank"> Documentation Progress </read-more> <read-more to="https://github.com/nuxt/nuxt/discussions/16119" icon="i-simple-icons-github" target="_blank"> Rendering Optimizations: Today and Tomorrow </read-more> <read-more to="https://github.com/nuxt/image/discussions/563" icon="i-simple-icons-github" target="_blank"> Nuxt Image: Performance and Status </read-more> ## Roadmap In roadmap below are some features we are planning or working on at the moment. <tip> Check [Discussions](https://github.com/nuxt/nuxt/discussions) and [RFCs](https://github.com/nuxt/nuxt/discussions/categories/rfcs) for more upcoming features and ideas. </tip> <table> <thead> <tr> <th> Milestone </th> <th> Expected date </th> <th> Notes </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> SEO & PWA </td> <td> 2025 </td> <td> <a href="https://github.com/nuxt/nuxt/discussions/18395" rel="nofollow"> nuxt/nuxt#18395 </a> </td> <td> Migrating from <a href="https://github.com/nuxt-community/pwa-module" rel="nofollow"> nuxt-community/pwa-module </a> for built-in SEO utils and service worker support </td> </tr> <tr> <td> Assets </td> <td> 2025 </td> <td> <a href="https://github.com/nuxt/nuxt/discussions/22012" rel="nofollow"> nuxt/nuxt#22012 </a> </td> <td> Allow developers and modules to handle loading third-party assets. </td> </tr> <tr> <td> Translations </td> <td> - </td> <td> <a href="https://github.com/nuxt/nuxt.com/issues/1711" rel="nofollow"> nuxt/nuxt.com#1711 </a> </td> <td> A collaborative project for a stable translation process for Nuxt docs. Currently pending for ideas and documentation tooling support. </td> </tr> </tbody> </table> ## Core Modules Roadmap In addition to the Nuxt framework, there are modules that are vital for the ecosystem. Their status will be updated below. <table> <thead> <tr> <th> Module </th> <th> Status </th> <th> Nuxt Support </th> <th> Repository </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> Auth Utils </td> <td> Planned </td> <td> 4.x, 5.x </td> <td> <code> nuxt/auth-utils </code> to be announced </td> <td> The temporary repository <a href="https://github.com/atinux/nuxt-auth-utils" rel="nofollow"> atinux/nuxt-auth-utils </a> is available while awaiting its official integration into Nuxt via RFC. </td> </tr> <tr> <td> <a href="https://github.com/nuxt/a11y" rel="nofollow"> a11y </a> </td> <td> Public Alpha </td> <td> 4.x, 5.x </td> <td> <a href="https://github.com/nuxt/a11y" rel="nofollow"> nuxt/a11y </a> . </td> <td> Real-time accessibility feedback and automated testing in your browser during development (see <a href="https://github.com/nuxt/nuxt/issues/23255" rel="nofollow"> nuxt/nuxt#23255 </a> ). </td> </tr> </tbody> </table> ## Release Cycle Since January 2023, we've adopted a consistent release cycle for Nuxt, following [semver](https://semver.org). We aim for major framework releases every year, with an expectation of patch releases every week or so and minor releases every month or so. They should never contain breaking changes except within options clearly marked as `experimental`. We are planning a slight variation from this plan for Nuxt 4 and Nuxt 5. Nuxt 4 will be a stability-focused release containing all `compatibilityVersion: 4` features, and will be followed shortly by Nuxt 5 which will include an upgrade to Nitro v3 and additional changes. This approach separates breaking changes into manageable phases, allowing for better ecosystem testing and smoother migrations. ### Ongoing Support for Nuxt We commit to support each major version of Nuxt for a minimum of six months after the release of the next major version, and to providing an upgrade path for current users at that point. ### Current Packages The current active version of [Nuxt](https://nuxt.com) is **v4** which is available as `nuxt` on npm with the `latest` tag. Nuxt 3 reached end of life on 31 July 2026 and no longer receives bug fixes or security patches. If you are still on Nuxt 3, follow the [upgrade guide](https://nuxt.com/docs/4.x/getting-started/upgrade) to move to Nuxt 4. Each active version has its own nightly releases which are generated automatically. For more about enabling the Nuxt nightly release channel, see [the nightly release channel docs](https://nuxt.com/docs/4.x/guide/going-further/nightly-release-channel). <table> <thead> <tr> <th> Release </th> <th> </th> <th> Initial release </th> <th> End Of Life </th> <th> Docs </th> </tr> </thead> <tbody> <tr> <td> <strong> 5.x </strong> (scheduled) </td> <td> </td> <td> Q4 2026 (estimated) </td> <td> TBA </td> <td> </td> </tr> <tr> <td> <strong> 4.x </strong> (stable) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt latest version" src="https://img.shields.io/npm/v/nuxt.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2025-07-16 </td> <td> 6 months after 5.x release </td> <td> <a href="https://nuxt.com/docs/4.x/getting-started/introduction" rel="nofollow"> nuxt.com </a> </td> </tr> <tr> <td> <strong> 3.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 3.x version" src="https://img.shields.io/npm/v/nuxt/3x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2022-11-16 </td> <td> 2026-07-31 </td> <td> <a href="https://nuxt.com/docs/3.x/getting-started/introduction" rel="nofollow"> nuxt.com </a> </td> </tr> <tr> <td> <strong> 2.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 2.x version" src="https://img.shields.io/npm/v/nuxt/2x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2018-09-21 </td> <td> 2024-06-30 </td> <td> <a href="https://v2.nuxt.com/docs/get-started/installation/" rel="nofollow"> v2.nuxt.com </a> </td> </tr> <tr> <td> <strong> 1.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 1.x version" src="https://img.shields.io/npm/v/nuxt/1x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2018-01-08 </td> <td> 2019-09-21 </td> <td> </td> </tr> </tbody> </table> ### Support Status <table> <thead> <tr> <th> Status </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> Unsupported </td> <td> This version is not maintained any more and will not receive security patches </td> </tr> <tr> <td> Maintenance </td> <td> This version will only receive security patches </td> </tr> <tr> <td> Stable </td> <td> This version is being developed for and will receive security patches </td> </tr> <tr> <td> Development </td> <td> This version could be unstable </td> </tr> <tr> <td> Scheduled </td> <td> This version does not exist yet but is planned </td> </tr> </tbody> </table> # Nuxt Directory Structure > Learn about the directory structure of a Nuxt application and how to use it. Nuxt applications have a specific directory structure that is used to organize the code. This structure is designed to be easy to understand and to be used in a consistent way. ## Root Directory The root directory of a Nuxt application is the directory that contains the `nuxt.config.ts` file. This file is used to configure the Nuxt application. ## App Directory The `app/` directory is the main directory of the Nuxt application. It contains the following subdirectories: - [`assets/`](https://nuxt.com/docs/4.x/directory-structure/app/assets): website's assets that the build tool (Vite or webpack) will process - [`components/`](https://nuxt.com/docs/4.x/directory-structure/app/components): Vue components of the application - [`composables/`](https://nuxt.com/docs/4.x/directory-structure/app/composables): add your Vue composables - [`layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts): Vue components that wrap around your pages and avoid re-rendering between pages - [`middleware/`](https://nuxt.com/docs/4.x/directory-structure/app/middleware): run code before navigating to a particular route - [`pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages): file-based routing to create routes within your web application - [`plugins/`](https://nuxt.com/docs/4.x/directory-structure/app/plugins): use Vue plugins and more at the creation of your Nuxt application - [`utils/`](https://nuxt.com/docs/4.x/directory-structure/app/utils): add functions throughout your application that can be used in your components, composables, and pages. This directory also includes specific files: - [`app.config.ts`](https://nuxt.com/docs/4.x/directory-structure/app/app-config): a reactive configuration within your application - [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app): the root component of your Nuxt application - [`error.vue`](https://nuxt.com/docs/4.x/directory-structure/app/error): the error page of your Nuxt application ## Public Directory The [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory is the directory that contains the public files of the Nuxt application. Files contained within this directory are served at the root and are not modified by the build process. This is suitable for files that have to keep their names (e.g. `robots.txt`) *or* likely won't change (e.g. `favicon.ico`). ## Server Directory The [`server/`](https://nuxt.com/docs/4.x/directory-structure/server) directory is the directory that contains the server-side code of the Nuxt application. It contains the following subdirectories: - [`api/`](https://nuxt.com/docs/4.x/directory-structure/server#server-routes): contains the API routes of the application. - [`routes/`](https://nuxt.com/docs/4.x/directory-structure/server#server-routes): contains the server routes of the application (e.g. dynamic `/sitemap.xml`). - [`middleware/`](https://nuxt.com/docs/4.x/directory-structure/server#server-middleware): run code before a server route is processed - [`plugins/`](https://nuxt.com/docs/4.x/directory-structure/server#server-plugins): use plugins and more at the creation of the Nuxt server - [`utils/`](https://nuxt.com/docs/4.x/directory-structure/server#server-utilities): add functions throughout your application that can be used in your server code. ## Shared Directory The [`shared/`](https://nuxt.com/docs/4.x/directory-structure/shared) directory is the directory that contains the shared code of the Nuxt application and Nuxt server. This code can be used in both the Vue app and the Nitro server. ## Test Directory The [`test/`](https://nuxt.com/docs/4.x/directory-structure/test) directory is the recommended place for application tests (unit, Nuxt runtime, and end-to-end). See [Organizing Your Tests](https://nuxt.com/docs/4.x/getting-started/testing#organizing-your-tests) for layout and setup details. ## Content Directory The [`content/`](https://nuxt.com/docs/4.x/directory-structure/content) directory is enabled by the [Nuxt Content](https://content.nuxt.com) module. It is used to create a file-based CMS for your application using Markdown files. ## Modules Directory The [`modules/`](https://nuxt.com/docs/4.x/directory-structure/modules) directory is the directory that contains the local modules of the Nuxt application. Modules are used to extend the functionality of the Nuxt application. ## Layers Directory The [`layers/`](https://nuxt.com/docs/4.x/directory-structure/layers) directory allows you to organize and share reusable code, components, composables, and configurations. Layers within this directory are automatically registered in your project. ## Nuxt Files - [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file is the main configuration file for the Nuxt application. - [`.nuxtrc`](https://nuxt.com/docs/4.x/directory-structure/nuxtrc) file is another syntax for configuring the Nuxt application (useful for global configurations). - [`.nuxtignore`](https://nuxt.com/docs/4.x/directory-structure/nuxtignore) file is used to ignore files in the root directory during the build phase. # app.vue > The app.vue file is the main component of your Nuxt application. <tip> If you have a `app/pages/` directory, the `app.vue` file is optional. Nuxt will automatically include a default `app.vue`, but you can still add your own to customize the structure and content as needed. </tip> ## Usage ### Minimal Usage With Nuxt, the [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory is optional. If it is not present, Nuxt will not include the [vue-router](https://router.vuejs.org) dependency. This is useful when building a landing page or an application that does not require routing. ```vue [app/app.vue] <template> <h1>Hello World!</h1> </template> ``` <link-example to="https://nuxt.com/docs/4.x/examples/hello-world"> </link-example> ### Usage with Pages When you have a [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory, you need to use the [`<NuxtPage>`](https://nuxt.com/docs/4.x/api/components/nuxt-page) component to display the current page: ```vue [app/app.vue] <template> <NuxtPage /> </template> ``` You can also define the common structure of your application directly in `app.vue`. This is useful when you want to include global elements such as a header or footer: ```vue [app/app.vue] <template> <header> Header content </header> <NuxtPage /> <footer> Footer content </footer> </template> ``` <note> Remember that `app.vue` acts as the main component of your Nuxt application. Anything you add to it (JS and CSS) will be global and included in every page. </note> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/pages"> Learn more about how to structure your pages using the `app/pages/` directory. </read-more> ### Usage with Layouts When your application requires different layouts for different pages, you can use the `app/layouts/` directory with the [`<NuxtLayout>`](https://nuxt.com/docs/4.x/api/components/nuxt-layout) component. This allows you to define multiple layouts and apply them per page. ```vue [app/app.vue] <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/layouts"> Learn more about how to structure your layouts using the `app/layouts/` directory. </read-more> # app.config.ts > Expose reactive configuration within your application with the App Config file. Nuxt provides an `app/app.config.ts` config file to expose reactive configuration within your application with the ability to update it at runtime within lifecycle or using a nuxt plugin and editing it with HMR (hot-module-replacement). You can easily provide runtime app configuration using `app.config.ts` file. It can have either of `.ts`, `.js`, or `.mjs` extensions. ```ts [app/app.config.ts]twoslash export default defineAppConfig({ foo: 'bar', }) ``` <caution> Do not put any secret values inside `app.config` file. It is exposed to the user client bundle. </caution> <note> When configuring a custom [`srcDir`](https://nuxt.com/docs/4.x/api/nuxt-config#srcdir), make sure to place the `app.config` file at the root of the new `srcDir` path. </note> ## Usage To expose config and environment variables to the rest of your app, you will need to define configuration in `app.config` file. ```ts [app/app.config.ts]twoslash export default defineAppConfig({ theme: { primaryColor: '#ababab', }, }) ``` We can now universally access `theme` both when server-rendering the page and in the browser using [`useAppConfig`](https://nuxt.com/docs/4.x/api/composables/use-app-config) composable. ```vue [app/pages/index.vue] <script setup lang="ts"> const appConfig = useAppConfig() console.log(appConfig.theme) </script> ``` The [`updateAppConfig`](https://nuxt.com/docs/4.x/api/utils/update-app-config) utility can be used to update the `app.config` at runtime. ```vue [app/pages/index.vue] <script setup> const appConfig = useAppConfig() // { foo: 'bar' } const newAppConfig = { foo: 'baz' } updateAppConfig(newAppConfig) console.log(appConfig) // { foo: 'baz' } </script> ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/update-app-config"> Read more about the `updateAppConfig` utility. </read-more> ## Typing App Config Nuxt tries to automatically generate a TypeScript interface from provided app config so you won't have to type it yourself. The fully inferred type is only available in app code (components, composables, plugins and so on). In server routes, code in the `shared/` directory and `nuxt.config`, keys defined in `app.config` files are typed as `unknown` instead: typing them there would require typechecking your app code outside the app context, where app auto-imports are not available. Keys defined inline in the `appConfig` option of `nuxt.config` are typed everywhere. If you need other keys typed outside app code, you can extend the `SharedAppConfig` interface as described below. The location of the augmentation file determines which contexts see it: a `.d.ts` file in the `shared/` directory covers app code, shared code and server routes. However, there are some cases where you might want to type it yourself. There are two possible things you might want to type. ### App Config Input `AppConfigInput` might be used by module authors who are declaring what valid *input* options are when setting app config. This will not affect the type of `useAppConfig()`. ```ts [index.d.ts] declare module 'nuxt/schema' { interface AppConfigInput { /** Theme configuration */ theme?: { /** Primary app color */ primaryColor?: string } } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ### App Config Output If you want to type the result of calling [`useAppConfig()`](https://nuxt.com/docs/4.x/api/composables/use-app-config) in app code, then you will want to extend `AppConfig`. Outside app code (server routes, the `shared/` directory and `nuxt.config`) `useAppConfig()` returns `SharedAppConfig`, so extend that interface instead. <warning> Be careful when typing `AppConfig` as you will overwrite the types Nuxt infers from your actually defined app config. </warning> ```ts [index.d.ts] declare module 'nuxt/schema' { interface AppConfig { // This will entirely replace the existing inferred `theme` property theme: { // You might want to type this value to add more specific types than Nuxt can infer, // such as string literal types primaryColor?: 'red' | 'blue' } } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ## Merging Strategy Nuxt uses a custom merging strategy for the `AppConfig` within [the layers](https://nuxt.com/docs/4.x/getting-started/layers) of your application. This strategy is implemented using a [Function Merger](https://github.com/unjs/defu#function-merger), which allows defining a custom merging strategy for every key in `app.config` that has an array as value. <note> The function merger can only be used in the extended layers and not the main `app.config` in project. </note> Here's an example of how you can use: <code-group> ```ts [layer/app/app.config.ts]twoslash export default defineAppConfig({ // Default array value array: ['hello'], }) ``` ```ts [app/app.config.ts]twoslash export default defineAppConfig({ // Overwrite default array value by using a merger function array: () => ['bonjour'], }) ``` </code-group> ## Known Limitations As of Nuxt v3.3, the `app.config.ts` file is shared with Nitro, which results in the following limitations: 1. You cannot import Vue components directly in `app.config.ts`. 2. Some auto-imports are not available in the Nitro context. These limitations occur because Nitro processes the app config without full Vue component support. While it's possible to use Vite plugins in the Nitro config as a workaround, this approach is not recommended: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { vite: { plugins: [vue()], }, }, }) ``` <warning> Using this workaround may lead to unexpected behavior and bugs. The Vue plugin is one of many that are not available in the Nitro context. </warning> Related issues: - [Issue #19858](https://github.com/nuxt/nuxt/issues/19858) - [Issue #19854](https://github.com/nuxt/nuxt/issues/19854) <note> Nitro v3 will resolve these limitations by removing support for the app config. You can track the progress in [this pull request](https://github.com/nitrojs/nitro/pull/2521). </note> # assets > The assets/ directory is used to add all the website's assets that the build tool will process. The directory usually contains the following types of files: - Stylesheets (CSS, SASS, etc.) - Fonts - Images that won't be served from the [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory. If you want to serve assets from the server, we recommend taking a look at the [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory. <read-more to="https://nuxt.com/docs/4.x/getting-started/assets"> </read-more> # components > The components/ directory is where you put all your Vue components. Nuxt automatically imports any components in this directory (along with components that are registered by any modules you may be using). ```bash [Directory Structure] -| components/ ---| AppHeader.vue ---| AppFooter.vue ``` ```html [app/app.vue] <template> <div> <AppHeader /> <NuxtPage /> <AppFooter /> </div> </template> ``` ## Component Names If you have a component in nested directories such as: ```bash [Directory Structure] -| components/ ---| base/ -----| foo/ -------| Button.vue ``` ... then the component's name will be based on its own path directory and filename, with duplicate segments being removed. Therefore, the component's name will be: ```html <BaseFooButton /> ``` <note> For clarity, we recommend that the component's filename matches its name. So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue`. </note> If you want to group components in a directory without affecting their name, you can use the parenthesis `(` `)` to name the grouping directory. ```bash [Grouping Directory] -| components/ ---| base/ -----| (foo)/ -------| Button.vue ``` ... then the component's name will skip the grouping directory, resulting in: ```html <BaseButton /> ``` If you want to auto-import components based only on its name, not path, then you need to set `pathPrefix` option to `false` using extended form of the configuration object: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ { path: '~/components', pathPrefix: false, // [!code ++] }, ], }) ``` This registers the components using the same strategy as used in Nuxt 2. For example, `~/components/Some/MyComponent.vue` will be usable as `<MyComponent>` and not `<SomeMyComponent>`. ## Dynamic Components If you want to use the Vue `<component :is="someComputedComponent">` syntax, you need to use the `resolveComponent` helper provided by Vue or import the component directly from `#components` and pass it into `is` prop. For example: ```vue [app/pages/index.vue] <script setup lang="ts"> import { SomeComponent } from '#components' const MyButton = resolveComponent('MyButton') </script> <template> <component :is="clickable ? MyButton : 'div'" /> <component :is="SomeComponent" /> </template> ``` <important> If you are using `resolveComponent` to handle dynamic components, make sure not to insert anything but the name of the component, which must be a literal string and not be or contain a variable. The string is statically analyzed at the compilation step. </important> <video-accordion title="Watch Daniel Roe's short video about resolveComponent()" video-id="4kq8E5IUM2U"> </video-accordion> Alternatively, though not recommended, you can register all your components globally, which will create async chunks for all your components and make them available throughout your application. ```diff export default defineNuxtConfig({ components: { + global: true, + dirs: ['~/components'] }, }) ``` You can also selectively register some components globally by placing them in a `~/components/global` directory, or by using a `.global.vue` suffix in the filename. As noted above, each global component is rendered in a separate chunk, so be careful not to overuse this feature. <note> The `global` option can also be set per component directory. </note> ## Dynamic Imports To dynamically import a component (also known as lazy-loading a component) all you need to do is add the `Lazy` prefix to the component's name. This is particularly useful if the component is not always needed. By using the `Lazy` prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size. ```vue [app/pages/index.vue] <script setup lang="ts"> const show = ref(false) </script> <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true" > Show List </button> </div> </template> ``` ## Delayed (or Lazy) Hydration Lazy components are great for controlling the chunk sizes in your app, but they don't always enhance runtime performance, as they still load eagerly unless conditionally rendered. In real-world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive as soon as the page is loaded. Having them all load eagerly can negatively impact performance. In order to optimize your app, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks. Nuxt supports this using lazy (or delayed) hydration, allowing you to control when components become interactive. ### Hydration Strategies Nuxt provides a range of built-in hydration strategies. Only one strategy can be used per lazy component. <note> Any prop change on a lazily hydrated component will trigger hydration immediately. (e.g., changing a prop on a component with `hydrate-never` will cause it to hydrate) </note> <warning> Currently Nuxt's built-in lazy hydration only works in single-file components (SFCs), and requires you to define the prop in the template (rather than spreading an object of props via `v-bind`). It also does not work with direct imports from `#components`. </warning> #### `hydrate-on-visible` Hydrates the component when it becomes visible in the viewport. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-visible /> </div> </template> ``` <read-more to="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver" title="IntersectionObserver options"> Read more about the options for `hydrate-on-visible`. </read-more> <note> Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible). </note> #### `hydrate-on-idle` Hydrates the component when the browser is idle. This is suitable if you need the component to load as soon as possible, but not block the critical rendering path. You can also pass a number which serves as a max timeout. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-idle /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle). </note> #### `hydrate-on-interaction` Hydrates the component after a specified interaction (e.g., click, mouseover). ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-interaction="mouseover" /> </div> </template> ``` If you do not pass an event or list of events, it defaults to hydrating on `pointerenter`, `click` and `focus`. <note> Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction). </note> #### `hydrate-on-media-query` Hydrates the component when the window matches a media query. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-media-query="(max-width: 768px)" /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query). </note> #### `hydrate-after` Hydrates the component after a specified delay (in milliseconds). ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent :hydrate-after="2000" /> </div> </template> ``` #### `hydrate-when` Hydrates the component based on a boolean condition. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent :hydrate-when="isReady" /> </div> </template> <script setup lang="ts"> const isReady = ref(false) function myFunction () { // trigger custom hydration strategy... isReady.value = true } </script> ``` #### `hydrate-never` Never hydrates the component. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-never /> </div> </template> ``` ### Listening to Hydration Events All delayed hydration components emit a `@hydrated` event when they are hydrated. ```vue [app/pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-visible @hydrated="onHydrate" /> </div> </template> <script setup lang="ts"> function onHydrate () { console.log('Component has been hydrated!') } </script> ``` ### Caveats and Best Practices Delayed hydration can offer performance benefits, but it's essential to use it correctly: 1. **Prioritize In-Viewport Content:** Avoid delayed hydration for critical, above-the-fold content. It's best suited for content that isn't immediately needed. 2. **Conditional Rendering:** When using `v-if="false"` on a lazy component, you might not need delayed hydration. You can just use a normal lazy component. 3. **Shared State:** Be mindful of shared state (`v-model`) across multiple components. Updating the model in one component can trigger hydration in all components bound to that model. 4. **Use Each Strategy's Intended Use Case:** Each strategy is optimized for a specific purpose. - `hydrate-when` is best for components that might not always need to be hydrated. - `hydrate-after` is for components that can wait a specific amount of time. - `hydrate-on-idle` is for components that can be hydrated when the browser is idle. 5. **Avoid hydrate-never on interactive components:** If a component requires user interaction, it should not be set to never hydrate. ## Direct Imports You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality. ```vue [app/pages/index.vue] <script setup lang="ts"> import { LazyMountainsList, NuxtLink } from '#components' const show = ref(false) </script> <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true" > Show List </button> <NuxtLink to="/">Home</NuxtLink> </div> </template> ``` ## Custom Directories By default, only the `~/components` directory is scanned. If you want to add other directories, or change how the components are scanned within a subfolder of this directory, you can add additional directories to the configuration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ // ~/calendar-module/components/event/Update.vue => <EventUpdate /> { path: '~/calendar-module/components' }, // ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog /> { path: '~/user-module/components', pathPrefix: false }, // ~/components/special-components/Btn.vue => <SpecialBtn /> { path: '~/components/special-components', prefix: 'Special' }, // It's important that this comes last if you have overrides you wish to apply // to sub-directories of `~/components`. // // ~/components/Btn.vue => <Btn /> // ~/components/base/Btn.vue => <BaseBtn /> '~/components', ], }) ``` <note> Any nested directories need to be added first as they are scanned in order. </note> Each directory entry also accepts `pattern` and `ignore` glob options, which control which files are scanned within `path`. This is useful when your components live in nested folders that don't follow the default layout, such as a domain-driven structure: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ // ~/domains/blog/components/PostCard.vue => <PostCard /> { path: '~/domains', pattern: '*/components/**', pathPrefix: false, }, ], }) ``` <note> If `pattern` is specified, the `extensions` option has no effect, so make sure your pattern matches the file extensions you want to scan. </note> ## npm Packages If you want to auto-import components from an npm package, you can use [`addComponent`](https://nuxt.com/docs/4.x/api/kit/components#addcomponent) in a [local module](https://nuxt.com/docs/4.x/directory-structure/modules) to register them. <code-group> ```ts [~/modules/register-component.ts]twoslash import { addComponent, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // import { MyComponent as MyAutoImportedComponent } from 'my-npm-package' addComponent({ name: 'MyAutoImportedComponent', export: 'MyComponent', filePath: 'my-npm-package', }) }, }) ``` ```vue [app/app.vue] <template> <div> <!-- the component uses the name we specified and is auto-imported --> <MyAutoImportedComponent /> </div> </template> ``` </code-group> ## Component Extensions By default, any file with an extension specified in the [extensions key of `nuxt.config.ts`](https://nuxt.com/docs/4.x/api/nuxt-config#extensions) is treated as a component. If you need to restrict the file extensions that should be registered as components, you can use the extended form of the components directory declaration and its `extensions` key: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ { path: '~/components', extensions: ['.vue'], // [!code ++] }, ], }) ``` ## Client Components If a component is meant to be rendered only client-side, you can add the `.client` suffix to your component. ```bash [Directory Structure] | components/ --| Comments.client.vue ``` ```vue [app/pages/example.vue] <template> <div> <!-- this component will only be rendered on client side --> <Comments /> </div> </template> ``` <note> This feature only works with Nuxt auto-imports and `#components` imports. Explicitly importing these components from their real paths does not convert them into client-only components. </note> <important> `.client` components are rendered only after being mounted. To access the rendered template using `onMounted()`, add `await nextTick()` in the callback of the `onMounted()` hook. </important> <read-more to="https://nuxt.com/docs/4.x/api/components/client-only"> You can also achieve a similar result with the `<ClientOnly>` component. </read-more> ## Server Components Server components allow server-rendering individual components within your client-side apps. It's possible to use server components within Nuxt, even if you are generating a static site. That makes it possible to build complex sites that mix dynamic components, server-rendered HTML and even static chunks of markup. Server components can either be used on their own or paired with a [client component](https://nuxt.com/docs/4.x/directory-structure/app/components#paired-with-a-client-component). <video-accordion title="Watch Learn Vue video about Nuxt Server Components" video-id="u1yyXe86xJM"> </video-accordion> <tip icon="i-lucide-newspaper" target="_blank" to="https://roe.dev/blog/nuxt-server-components"> Read Daniel Roe's guide to Nuxt Server Components. </tip> ### Standalone server components Standalone server components will always be rendered on the server, also known as Islands components. When their props update, this will result in a network request that will update the rendered HTML in-place. Register server-only components with the `.server` suffix and use them anywhere in your application automatically. ```bash [Directory Structure] -| components/ ---| HighlightedMarkdown.server.vue ``` ```vue [app/pages/example.vue] <template> <div> <!-- this will automatically be rendered on the server, meaning your markdown parsing + highlighting libraries are not included in your client bundle. --> <HighlightedMarkdown markdown="# Headline" /> </div> </template> ``` Server-only components use [`<NuxtIsland>`](https://nuxt.com/docs/4.x/api/components/nuxt-island) under the hood, meaning that `lazy` prop and `#fallback` slot are both passed down to it. <warning> Server components (and islands) must have a single root element. (HTML comments are considered elements as well.) </warning> <read-more to="https://nuxt.com/docs/4.x/guide/concepts/server-components"> Read more about how islands are rendered, the isolated island context, selective hydration with `nuxt-client`, slots, caching and current limitations in the dedicated server components guide. </read-more> ### Paired with a Client component In this case, the `.server` + `.client` components are two 'halves' of a component and can be used in advanced use cases for separate implementations of a component on server and client side. ```bash [Directory Structure] -| components/ ---| Comments.client.vue ---| Comments.server.vue ``` ```vue [app/pages/example.vue] <template> <div> <!-- this component will render Comments.server on the server then Comments.client once mounted in the browser --> <Comments /> </div> </template> ``` ## Built-In Nuxt Components There are a number of components that Nuxt provides, including `<ClientOnly>` and `<DevOnly>`. You can read more about them in the API documentation. <read-more to="https://nuxt.com/docs/4.x/api"> </read-more> ## Library Authors Making Vue component libraries with automatic tree-shaking and component registration is super easy. โœจ You can use the [`addComponentsDir`](https://nuxt.com/docs/4.x/api/kit/components#addcomponentsdir) method provided from the `@nuxt/kit` to register your components directory in your Nuxt module. Imagine a directory structure like this: ```bash [Directory Structure] -| node_modules/ ---| awesome-ui/ -----| components/ -------| Alert.vue -------| Button.vue -----| nuxt.ts -| pages/ ---| index.vue -| nuxt.config.ts ``` Then in `awesome-ui/nuxt.ts` you can use the `addComponentsDir` hook: ```tstwoslash import { addComponentsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const resolver = createResolver(import.meta.url) // Add ./components dir to the list addComponentsDir({ path: resolver.resolve('./components'), prefix: 'awesome', }) }, }) ``` That's it! Now in your project, you can import your UI library as a Nuxt module in your `nuxt.config` file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ modules: ['awesome-ui/nuxt'], }) ``` ... and directly use the module components (prefixed with `awesome-`) in our `app/pages/index.vue`: ```vue <template> <div> My <AwesomeButton>UI button</AwesomeButton>! <awesome-alert>Here's an alert!</awesome-alert> </div> </template> ``` It will automatically import the components only if used and also support HMR when updating your components in `node_modules/awesome-ui/components/`. <link-example to="https://nuxt.com/docs/4.x/examples/features/auto-imports"> </link-example> # composables > Use the composables/ directory to auto-import your Vue composables into your application. ## Usage **Method 1:** Using named export ```ts [app/composables/useFoo.ts] export const useFoo = () => { return useState('foo', () => 'bar') } ``` **Method 2:** Using default export ```ts [app/composables/use-foo.ts or composables/useFoo.ts] // It will be available as useFoo() (camelCase of file name without extension) export default function () { return useState('foo', () => 'bar') } ``` **Usage:** You can now use auto imported composable in `.js`, `.ts` and `.vue` files ```vue [app/app.vue] <script setup lang="ts"> const foo = useFoo() </script> <template> <div> {{ foo }} </div> </template> ``` <note> The `app/composables/` directory in Nuxt does not provide any additional reactivity capabilities to your code. Instead, any reactivity within composables is achieved using Vue's Composition API mechanisms, such as ref and reactive. Note that reactive code is also not limited to the boundaries of the `app/composables/` directory. You are free to employ reactivity features wherever they're needed in your application. </note> <read-more to="https://nuxt.com/docs/4.x/guide/concepts/auto-imports"> </read-more> <link-example to="https://nuxt.com/docs/4.x/examples/features/auto-imports"> </link-example> ## Types Under the hood, Nuxt auto generates the file `.nuxt/imports.d.ts` to declare the types. Be aware that you have to run [`nuxt prepare`](https://nuxt.com/docs/4.x/api/commands/prepare), [`nuxt dev`](https://nuxt.com/docs/4.x/api/commands/dev) or [`nuxt build`](https://nuxt.com/docs/4.x/api/commands/build) in order to let Nuxt generate the types. <note> If you create a composable without having the dev server running, TypeScript will throw an error, such as `Cannot find name 'useBar'.` </note> ## Example ### Nested Composables You can use a composable within another composable using auto imports: ```ts [app/composables/test.ts] export const useFoo = () => { const nuxtApp = useNuxtApp() const bar = useBar() } ``` ### Access Plugin Injections You can access [plugin injections](https://nuxt.com/docs/4.x/directory-structure/app/plugins#providing-helpers) from composables: ```ts [app/composables/test.ts] export const useHello = () => { const nuxtApp = useNuxtApp() return nuxtApp.$hello } ``` ## How Files Are Scanned Nuxt only scans files at the top level of the [`app/composables/` directory](https://nuxt.com/docs/4.x/directory-structure/app/composables), e.g.: ```bash [Directory Structure] -| composables/ ---| index.ts // scanned ---| useFoo.ts // scanned ---| nested/ -----| utils.ts // not scanned ``` Only `app/composables/index.ts` and `app/composables/useFoo.ts` would be searched for imports. To get auto imports working for nested modules, you could either re-export them (recommended) or configure the scanner to include nested directories: **Example:** Re-export the composables you need from the `app/composables/index.ts` file: ```ts [app/composables/index.ts] // Enables auto import for this export export { utils } from './nested/utils.ts' ``` **Example:** Scan nested directories inside the `app/composables/` folder: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { dirs: [ // Scan top-level composables '~/composables', // ... or scan composables nested one level deep with a specific name and file extension '~/composables/*/index.{ts,js,mjs,mts}', // ... or scan all composables within given directory '~/composables/**', ], }, }) ``` # error.vue > The error.vue file is the error page in your Nuxt application. During the lifespan of your application, some errors may appear unexpectedly at runtime. In such case, we can use the `error.vue` file to override the default error files and display the error nicely. ```vue [error.vue] <script setup lang="ts"> import type { NuxtError } from '#app' const props = defineProps<{ error: NuxtError }>() </script> <template> <div> <h1>{{ error.status }}</h1> <NuxtLink to="/">Go back home</NuxtLink> </div> </template> ``` <note> Although it is called an 'error page' it's not a route and shouldn't be placed in your `~/pages` directory. For the same reason, you shouldn't use `definePageMeta` within this page. That being said, you can still use layouts in the error file, by utilizing the [`NuxtLayout`](https://nuxt.com/docs/4.x/api/components/nuxt-layout) component and specifying the name of the layout. </note> The error page has a single prop - `error` which contains an error for you to handle. The `error` object provides the following fields: ```ts interface NuxtError { status: number fatal: boolean unhandled: boolean statusText?: string data?: unknown cause?: unknown // legacy/deprecated equivalent of `status` statusCode: number // legacy/deprecated equivalent of `statusText` statusMessage?: string } ``` If you have an error with custom fields they will be lost; you should assign them to `data` instead: ```ts throw createError({ status: 404, statusText: 'Page Not Found', data: { myCustomField: true, }, }) ``` # layouts > Nuxt provides a layouts framework to extract common UI patterns into reusable layouts. <tip icon="i-lucide-rocket"> For best performance, components placed in this directory will be automatically loaded via asynchronous import when used. </tip> ## Enable Layouts Layouts are enabled by adding [`<NuxtLayout>`](https://nuxt.com/docs/4.x/api/components/nuxt-layout) to your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app): ```vue [app/app.vue] <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` To use a layout: - Set a `layout` property in your page with [definePageMeta](https://nuxt.com/docs/4.x/api/utils/define-page-meta). - Set the `name` prop of `<NuxtLayout>`. - Set the `appLayout` property in route rules. <note> The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`. </note> <note> If no layout is specified, `app/layouts/default.vue` will be used. </note> <important> If you only have a single layout in your application, we recommend using [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) instead. </important> <important> Unlike other components, your layouts must have a single root element to allow Nuxt to apply transitions between layout changes - and this root element cannot be a `<slot />`. </important> ## Default Layout Add a `~/layouts/default.vue`: ```vue [app/layouts/default.vue] <template> <div> <p>Some default layout content shared across all pages</p> <slot /> </div> </template> ``` In a layout file, the content of the page will be displayed in the `<slot />` component. ## Named Layout ```bash [Directory Structure] -| layouts/ ---| default.vue ---| custom.vue ``` Then you can use the `custom` layout in your page: ```vue [pages/about.vue]twoslash <script setup lang="ts"> declare module 'nuxt/app' { interface NuxtLayouts { 'custom': unknown } } // ---cut--- definePageMeta({ layout: 'custom', }) </script> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/pages#page-metadata"> Learn more about `definePageMeta`. </read-more> You can directly override the default layout for all pages using the `name` property of [`<NuxtLayout>`](https://nuxt.com/docs/4.x/api/components/nuxt-layout): ```vue [app/app.vue] <script setup lang="ts"> // You might choose this based on an API call or logged-in status const layout = 'custom' </script> <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> ``` If you have a layout in nested directories, the layout's name will be based on its own path directory and filename, with duplicate segments being removed. <table> <thead> <tr> <th> File </th> <th> Layout Name </th> </tr> </thead> <tbody> <tr> <td> <code> ~/layouts/desktop/default.vue </code> </td> <td> <code> desktop-default </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop-base/base.vue </code> </td> <td> <code> desktop-base </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop/index.vue </code> </td> <td> <code> desktop </code> </td> </tr> </tbody> </table> For clarity, we recommend that the layout's filename matches its name: <table> <thead> <tr> <th> File </th> <th> Layout Name </th> </tr> </thead> <tbody> <tr> <td> <code> ~/layouts/desktop/DesktopDefault.vue </code> </td> <td> <code> desktop-default </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop-base/DesktopBase.vue </code> </td> <td> <code> desktop-base </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop/Desktop.vue </code> </td> <td> <code> desktop </code> </td> </tr> </tbody> </table> <link-example to="https://nuxt.com/docs/4.x/examples/features/layouts"> </link-example> ## Changing the Layout Dynamically You can also use the [`setPageLayout`](https://nuxt.com/docs/4.x/api/utils/set-page-layout) helper to change the layout dynamically: ```vue [app/pages/index.vue]twoslash <script setup lang="ts"> declare module 'nuxt/app' { interface NuxtLayouts { 'custom': unknown } } // ---cut--- function enableCustomLayout () { setPageLayout('custom') } definePageMeta({ layout: false, }) </script> <template> <div> <button @click="enableCustomLayout"> Update layout </button> </div> </template> ``` You can also set layouts for specific routes using the `appLayout` property in route rules <badge className="align-middle" color="info" size="xs"> v4.3 </badge> : ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { // Set layout for specific route '/admin': { appLayout: 'admin' }, // Set layout for multiple routes '/dashboard/**': { appLayout: 'dashboard' }, // Disable layout for a route '/landing': { appLayout: false }, }, }) ``` <tip> This is useful when you want to manage layouts centrally in your configuration rather than in each page file, or when you need to apply layouts to routes that don't have corresponding page components (such as catchall pages which might match many paths). </tip> <link-example to="https://nuxt.com/docs/4.x/examples/features/layouts"> </link-example> ## Passing Props to Layouts <badge className="align-middle" color="primary">+4.4</badge> You can pass props to layouts in several ways. ### Via `definePageMeta` Use the object syntax for the `layout` property to pass props directly from your page: <code-group> ```vue [app/pages/dashboard.vue] <script setup lang="ts"> definePageMeta({ layout: { name: 'panel', props: { sidebar: true, title: 'Dashboard', }, }, }) </script> ``` ```vue [app/layouts/panel.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` </code-group> <tip> Props are fully typed based on your layout's `defineProps`. You'll get autocomplete and type-checking in your editor. </tip> ### Via `setPageLayout` You can also pass props when changing the layout dynamically with [`setPageLayout`](https://nuxt.com/docs/4.x/api/utils/set-page-layout): ```ts setPageLayout('panel', { sidebar: true, title: 'Dashboard' }) ``` ## Overriding a Layout on a Per-page Basis If you are using pages, you can take full control by setting `layout: false` and then using the `<NuxtLayout>` component within the page. <code-group> ```vue [app/pages/index.vue] <script setup lang="ts"> definePageMeta({ layout: false, }) </script> <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> The rest of the page </NuxtLayout> </div> </template> ``` ```vue [app/layouts/custom.vue] <template> <div> <header> <slot name="header"> Default header content </slot> </header> <main> <slot /> </main> </div> </template> ``` </code-group> <important> If you use `<NuxtLayout>` within your pages, make sure it is not the root element (or [disable layout/page transitions](https://nuxt.com/docs/4.x/getting-started/transitions#disable-transitions)). </important> # middleware > Nuxt provides middleware to run code before navigating to a particular route. Nuxt provides a customizable **route middleware** framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route. There are three kinds of route middleware: 1. Anonymous (or inline) route middleware are defined directly within the page. 2. Named route middleware, placed in the `app/middleware/` and automatically loaded via asynchronous import when used on a page. 3. Global route middleware, placed in the `app/middleware/` with a `.global` suffix and is run on every route change. The first two kinds of route middleware can be defined in [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta). <note> Name of middleware are normalized to kebab-case: `myMiddleware` becomes `my-middleware`. </note> <note> Only files at the top level of the directory (or index files within any subdirectories) are registered. An index file takes its name from the folder that contains it: `middleware/auth/index.ts` is registered as `auth`. </note> <note> Route middleware run within the Vue part of your Nuxt app. Despite the similar name, they are completely different from [server middleware](https://nuxt.com/docs/4.x/directory-structure/server#server-middleware), which are run in the Nitro server part of your app. </note> <video-accordion platform="vimeo" title="Watch a video from Vue School on all 3 kinds of middleware" video-id="761471577"> </video-accordion> ## Usage Route middleware are navigation guards that receive the current route and the next route as arguments. ```ts [middleware/my-middleware.ts]twoslash export default defineNuxtRouteMiddleware((to, from) => { if (to.params.id === '1') { return abortNavigation() } // In a real app you would probably not redirect every route to `/` // however it is important to check `to.path` before redirecting or you // might get an infinite redirect loop if (to.path !== '/') { return navigateTo('/') } }) ``` Nuxt provides two globally available helpers that can be returned directly from the middleware. 1. [`navigateTo`](https://nuxt.com/docs/4.x/api/utils/navigate-to) - Redirects to the given route 2. [`abortNavigation`](https://nuxt.com/docs/4.x/api/utils/abort-navigation) - Aborts the navigation, with an optional error message. Unlike [navigation guards](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) from `vue-router`, a third `next()` argument is not passed, and **redirect or route cancellation is handled by returning a value from the middleware**. Possible return values are: - nothing (a simple `return` or no return at all) - does not block navigation and will move to the next middleware function, if any, or complete the route navigation - `return navigateTo('/')` - redirects to the given path and will set the redirect code to [`302` Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) if the redirect happens on the server side - `return navigateTo('/', { redirectCode: 301 })` - redirects to the given path and will set the redirect code to [`301` Moved Permanently](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) if the redirect happens on the server side - `return abortNavigation()` - stops the current navigation - `return abortNavigation(error)` - rejects the current navigation with an error <read-more to="https://nuxt.com/docs/4.x/api/utils/navigate-to"> </read-more> <read-more to="https://nuxt.com/docs/4.x/api/utils/abort-navigation"> </read-more> <important> We recommend using the helper functions above for performing redirects or stopping navigation. Other possible return values described in [the vue-router docs](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) may work but there may be breaking changes in future. </important> ## Middleware Order Middleware runs in the following order: 1. Global Middleware 2. Page defined middleware order (if there are multiple middleware declared with the array syntax) For example, assuming you have the following middleware and component: ```bash [app/middleware/ directory] -| middleware/ ---| analytics.global.ts ---| setup.global.ts ---| auth.ts ``` ```vue [pages/profile.vue]twoslash <script setup lang="ts"> definePageMeta({ middleware: [ function (to, from) { // Custom inline middleware }, 'auth', ], }) </script> ``` You can expect the middleware to be run in the following order: 1. `analytics.global.ts` 2. `setup.global.ts` 3. Custom inline middleware 4. `auth.ts` ### Ordering Global Middleware By default, global middleware is executed alphabetically based on the filename. However, there may be times you want to define a specific order. For example, in the last scenario, `setup.global.ts` may need to run before `analytics.global.ts`. In that case, we recommend prefixing global middleware with 'alphabetical' numbering. ```bash [Directory structure] -| middleware/ ---| 01.setup.global.ts ---| 02.analytics.global.ts ---| auth.ts ``` <note> In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.new.global.ts` would come before `2.new.global.ts`. This is why the example prefixes single digit numbers with `0`. </note> ## When Middleware Runs If your site is server-rendered or generated, middleware for the initial page will be executed both when the page is rendered and then again on the client. This might be needed if your middleware needs a browser environment, such as if you have a generated site, aggressively cache responses, or want to read a value from local storage. However, if you want to avoid this behaviour you can do so: ```ts [middleware/example.ts]twoslash export default defineNuxtRouteMiddleware((to) => { // skip middleware on server if (import.meta.server) { return } // skip middleware on client side entirely if (import.meta.client) { return } // or only skip middleware on initial client load const nuxtApp = useNuxtApp() if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) { return } }) ``` This is true even if you throw an error in your middleware on the server, and an error page is rendered. The middleware will still run again in the browser. <note> Rendering an error page is an entirely separate page load, meaning any registered middleware will run again. You can use [`useError`](https://nuxt.com/docs/4.x/getting-started/error-handling#useerror) in middleware to check if an error is being handled. </note> ## Accessing Route in Middleware Always use the `to` and `from` parameters in your middleware to access the next and previous routes. Avoid using the [`useRoute()`](https://nuxt.com/docs/4.x/api/composables/use-route) composable in this context altogether. There is **no concept of a "current route" in middleware**, as middleware can abort a navigation or redirect to a different route. The `useRoute()` composable will always be inaccurate in this context. <warning> Sometimes, you might call a composable that uses `useRoute()` internally, which can trigger this warning even if there is no direct call in your middleware. This leads to the **same issue as above**, so you should structure your functions to accept the route as an argument instead when they are used in middleware. </warning> <code-group> ```ts [middleware/access-route.ts]twoslash // @errors: 2304 export default defineNuxtRouteMiddleware((to) => { // passing the route to the function to avoid calling `useRoute()` in middleware doSomethingWithRoute(to) // โŒ this will output a warning and is NOT recommended callsRouteInternally() }) ``` ```ts [utils/handle-route.ts]twoslash // providing the route as an argument so that it can be used in middleware correctly export function doSomethingWithRoute (route = useRoute()) { // ... } ``` ```ts [utils/dont-do-this.ts]twoslash // โŒ this function is not suitable for use in middleware export function callsRouteInternally () { const route = useRoute() // ... } ``` </code-group> ## Adding Middleware Dynamically It is possible to add global or named route middleware manually using the [`addRouteMiddleware()`](https://nuxt.com/docs/4.x/api/utils/add-route-middleware) helper function, such as from within a plugin. ```tstwoslash export default defineNuxtPlugin(() => { addRouteMiddleware('global-test', () => { console.log('this global middleware was added in a plugin and will be run on every route change') }, { global: true }) addRouteMiddleware('named-test', () => { console.log('this named middleware was added in a plugin and would override any existing middleware of the same name') }) }) ``` ## Example ```bash [Directory Structure] -| middleware/ ---| auth.ts ``` In your page file, you can reference this route middleware: ```vuetwoslash <script setup lang="ts"> definePageMeta({ middleware: ['auth'], // or middleware: 'auth' }) </script> ``` Now, before navigation to that page can complete, the `auth` route middleware will be run. <link-example to="https://nuxt.com/docs/4.x/examples/routing/middleware"> </link-example> ## Setting Middleware at Build Time Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook. ```ts [nuxt.config.ts]twoslash import type { NuxtPage } from 'nuxt/schema' export default defineNuxtConfig({ hooks: { 'pages:extend' (pages) { function setMiddleware (pages: NuxtPage[]) { for (const page of pages) { if (/* some condition */ Math.random() > 0.5) { page.meta ||= {} // Note that this will override any middleware set in `definePageMeta` in the page page.meta.middleware = ['named'] } if (page.children) { setMiddleware(page.children) } } } setMiddleware(pages) }, }, }) ``` # pages > Nuxt provides file-based routing to create routes within your web application. <note> To reduce your application's bundle size, this directory is **optional**, meaning that [`vue-router`](https://router.vuejs.org) won't be included if you only use [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app). To force the pages system, set `pages: true` in `nuxt.config` or have a [`router.options.ts`](https://nuxt.com/docs/4.x/guide/recipes/custom-routing#using-routeroptions). </note> ## Usage Pages are Vue components and can have any [valid extension](https://nuxt.com/docs/4.x/api/nuxt-config#extensions) that Nuxt supports (by default `.vue`, `.js`, `.jsx`, `.mjs`, `.ts` or `.tsx`). Nuxt will automatically create a route for every page in your `~/pages/` directory. <tip> Pages are only automatically registered for prerendering if you have not disabled `nitro.prerender.crawlLinks` and you have at least one page in your `nitro.prerender.routes` list. See the [prerendering guide](https://nuxt.com/docs/4.x/getting-started/prerendering). </tip> <code-group> ```vue [app/pages/index.vue] <template> <h1>Index page</h1> </template> ``` ```ts [pages/index.ts]twoslash // https://vuejs.org/guide/extras/render-function.html export default defineComponent({ render () { return h('h1', 'Index page') }, }) ``` ```tsx [pages/index.tsx]twoslash // /docs/examples/advanced/jsx // https://vuejs.org/guide/extras/render-function.html#jsx-tsx export default defineComponent({ render () { return <h1>Index page</h1> }, }) ``` </code-group> The `app/pages/index.vue` file will be mapped to the `/` route of your application. If you are using [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app), make sure to use the [`<NuxtPage/>`](https://nuxt.com/docs/4.x/api/components/nuxt-page) component to display the current page: ```vue [app/app.vue] <template> <div> <!-- Markup shared across all pages, ex: NavBar --> <NuxtPage /> </div> </template> ``` Pages **must have a single root element** to allow [route transitions](https://nuxt.com/docs/4.x/getting-started/transitions) between pages. HTML comments are considered elements as well. This means that when the route is server-rendered, or statically generated, you will be able to see its contents correctly, but when you navigate towards that route during client-side navigation the transition between routes will fail and you'll see that the route will not be rendered. Here are some examples to illustrate what a page with a single root element looks like: <code-group> ```vue [app/pages/working.vue] <template> <div> <!-- This page correctly has only one single root element --> Page content </div> </template> ``` ```vue [app/pages/bad-1.vue] <template> <!-- This page will not render when route changes during client side navigation, because of this comment --> <div>Page content</div> </template> ``` ```vue [app/pages/bad-2.vue] <template> <div>This page</div> <div>Has more than one root element</div> <div>And will not render when route changes during client side navigation</div> </template> ``` </code-group> ## Dynamic Routes If you place anything within square brackets, it will be turned into a [dynamic route](https://router.vuejs.org/guide/essentials/dynamic-matching) parameter. You can mix and match multiple parameters and even non-dynamic text within a file name or directory. If you want a parameter to be *optional*, you must enclose it in double square brackets - for example, `~/pages/[[slug]]/index.vue` or `~/pages/[[slug]].vue` will match both `/` and `/test`. ```bash [Directory Structure] -| pages/ ---| index.vue ---| users-[group]/ -----| [id].vue ``` Given the example above, you can access group/id within your component via the `$route` object: ```vue [app/pages/users-[group]/[id].vue] <template> <p>{{ $route.params.group }} - {{ $route.params.id }}</p> </template> ``` Navigating to `/users-admins/123` would render: ```html <p>admins - 123</p> ``` If you want to access the route using Composition API, there is a global [`useRoute`](https://nuxt.com/docs/4.x/api/composables/use-route) function that will allow you to access the route just like `this.$route` in the Options API. ```vuetwoslash <script setup lang="ts"> const route = useRoute() if (route.params.group === 'admins' && !route.params.id) { console.log('Warning! Make sure user is authenticated!') } </script> ``` <note> Named parent routes will take priority over nested dynamic routes. For the `/foo/hello` route, `~/pages/foo.vue` will take priority over `~/pages/foo/[slug].vue`. <br /> Use `~/pages/foo/index.vue` and `~/pages/foo/[slug].vue` to match `/foo` and `/foo/hello` with different pages,. </note> <video-accordion platform="vimeo" title="Watch a video from Vue School on dynamic routes" video-id="754465699"> </video-accordion> ## Catch-all Route If you need a catch-all route, you create it by using a file named like `[...slug].vue`. This will match *all* routes under that path. ```vue [app/pages/[...slug].vue] <template> <p>{{ $route.params.slug }}</p> </template> ``` Navigating to `/hello/world` would render: ```html <p>["hello", "world"]</p> ``` ## Nested Routes It is possible to display [nested routes](https://router.vuejs.org/guide/essentials/nested-routes) with `<NuxtPage>`. Example: ```bash [Directory Structure] -| pages/ ---| parent/ -----| child.vue ---| parent.vue ``` This file tree will generate these routes: ```js [ { path: '/parent', component: '~/pages/parent.vue', name: 'parent', children: [ { path: 'child', component: '~/pages/parent/child.vue', name: 'parent-child', }, ], }, ] ``` To display the `child.vue` component, you have to insert the `<NuxtPage>` component inside `app/pages/parent.vue`: ```vue [pages/parent.vue] <template> <div> <h1>I am the parent view</h1> <NuxtPage :foobar="123" /> </div> </template> ``` ```vue [pages/parent/child.vue] <script setup lang="ts"> const props = defineProps({ foobar: String, }) console.log(props.foobar) </script> ``` ### Child Route Keys If you want more control over when the `<NuxtPage>` component is re-rendered (for example, for transitions), you can either pass a string or function via the `pageKey` prop, or you can define a `key` value via `definePageMeta`: ```vue [pages/parent.vue] <template> <div> <h1>I am the parent view</h1> <NuxtPage :page-key="route => route.fullPath" /> </div> </template> ``` Or alternatively: ```vue [pages/parent/child.vue]twoslash <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, }) </script> ``` <link-example to="https://nuxt.com/docs/4.x/examples/routing/pages"> </link-example> ## Named Views <badge className="align-middle" color="info" size="xs">v4.5</badge> A single route can render into multiple `<NuxtPage>` outlets in a parent component by giving each outlet a `name` and providing a sibling page file for each name. Use the `name@view.vue` filename convention to declare a named view alongside the default route file: ```bash [Directory Structure] -| pages/ ---| parent/ -----| child.vue -----| child@sidebar.vue ---| parent.vue ``` Then render each outlet by name from the parent: ```vue [pages/parent.vue] <template> <div> <NuxtPage /> <aside> <NuxtPage name="sidebar" /> </aside> </div> </template> ``` When the user navigates to `/parent/child`, `child.vue` renders into the default `<NuxtPage />` and `child@sidebar.vue` renders into `<NuxtPage name="sidebar" />`. Outlets without a matching named view are left empty. <note> `definePageMeta` is read from the default route file only. Meta declared inside a `name@view.vue` sibling has no effect on the route. </note> <read-more to="https://router.vuejs.org/guide/essentials/named-views.html" target="_blank" title="Named Views"> </read-more> ## Route Groups In some cases, you may want to group a set of routes together in a way which doesn't affect file-based routing. For this purpose, you can put files in a folder which is wrapped in parentheses - `(` and `)`. For example: ```bash [Directory structure] -| pages/ ---| index.vue ---| (marketing)/ -----| about.vue -----| contact.vue ``` This will produce `/`, `/about` and `/contact` pages in your app. The `marketing` group is ignored for purposes of your URL structure. ### Accessing Route Groups <badge className="align-middle" color="info" size="xs">v4.3</badge> Route groups are automatically available in the route metadata as `route.meta.groups`. This allows you to access the group information in your components for conditional logic, styling, or other purposes. ```vue [pages/(marketing)/about.vue] <script setup lang="ts"> const route = useRoute() console.log(route.meta.groups) // Output: ['marketing'] </script> <template> <div> <p v-if="route.meta.groups?.includes('marketing')"> This is a marketing page </p> </div> </template> ``` ## Page Metadata You might want to define metadata for each route in your app. You can do this using the `definePageMeta` macro, which will work both in `<script>` and in `<script setup>`: ```vuetwoslash <script setup lang="ts"> definePageMeta({ title: 'My home page', }) </script> ``` This data can then be accessed throughout the rest of your app from the `route.meta` object. ```vuetwoslash <script setup lang="ts"> const route = useRoute() console.log(route.meta.title) // My home page </script> ``` If you are using nested routes, the page metadata from all these routes will be merged into a single object. For more on route meta, see the [vue-router docs](https://router.vuejs.org/guide/advanced/meta). Much like `defineEmits` or `defineProps` (see [Vue docs](https://vuejs.org/api/sfc-script-setup#defineprops-defineemits)), `definePageMeta` is a **compiler macro**. It will be compiled away so you cannot reference it within your component. Instead, the metadata passed to it will be hoisted out of the component. Therefore, the page meta object cannot reference the component. However, it can reference imported bindings, as well as locally defined **pure functions**. <warning> Make sure not to reference any reactive data or functions that cause side effects. This can lead to unexpected behavior. </warning> ```vue <script setup lang="ts"> import { someData } from '~/utils/example' function validateIdParam (route) { return route.params.id && !Number.isNaN(Number(route.params.id)) } const title = ref('') definePageMeta({ validate: validateIdParam, someData, title, // do not do this, the ref will be hoisted out of the component }) </script> ``` ### Special Metadata Of course, you are welcome to define metadata for your own use throughout your app. But some metadata defined with `definePageMeta` has a particular purpose: #### `alias` You can define page aliases. They allow you to access the same page from different paths. It can be either a string or an array of strings as defined [in the vue-router documentation](https://router.vuejs.org/guide/essentials/redirect-and-alias#Alias). #### `keepalive` Nuxt will automatically wrap your page in [the Vue `<KeepAlive>` component](https://vuejs.org/guide/built-ins/keep-alive#keepalive) if you set `keepalive: true` in your `definePageMeta`. This might be useful to do, for example, in a parent route that has dynamic child routes, if you want to preserve page state across route changes. When your goal is to preserve state for parent routes use this syntax: `<NuxtPage keepalive />`. You can also set props to be passed to `<KeepAlive>` (see [a full list](https://vuejs.org/api/built-in-components#keepalive)). You can set a default value for this property [in your `nuxt.config`](https://nuxt.com/docs/4.x/api/nuxt-config#keepalive). #### `key` [See above](https://nuxt.com/docs/4.x/directory-structure/app/pages#child-route-keys). #### `layout` You can define the layout used to render the route. This can be either false (to disable any layout), a string or a ref/computed, if you want to make it reactive in some way. [More about layouts](https://nuxt.com/docs/4.x/directory-structure/app/layouts). #### `layoutTransition` and `pageTransition` You can define transition properties for the `<transition>` component that wraps your pages and layouts, or pass `false` to disable the `<transition>` wrapper for that route. You can see [a list of options that can be passed](https://vuejs.org/api/built-in-components#transition) or read [more about how transitions work](https://vuejs.org/guide/built-ins/transition#transition). You can set default values for these properties [in your `nuxt.config`](https://nuxt.com/docs/4.x/api/nuxt-config#layouttransition). #### `middleware` You can define middleware to apply before loading this page. It will be merged with all the other middleware used in any matching parent/child routes. It can be a string, a function (an anonymous/inlined middleware function following [the global before guard pattern](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards)), or an array of strings/functions. [More about named middleware](https://nuxt.com/docs/4.x/directory-structure/app/middleware). #### `name` You may define a name for this page's route. #### `path` You may define a path matcher, if you have a more complex pattern than can be expressed with the file name. See [the `vue-router` docs](https://router.vuejs.org/guide/essentials/route-matching-syntax#Custom-regex-in-params) for more information. #### `props` Allows accessing the route `params` as props passed to the page component. See [the `vue-router` docs](https://router.vuejs.org/guide/essentials/passing-props) for more information. ### Typing Custom Metadata If you add custom metadata for your pages, you may wish to do so in a type-safe way. It is possible to augment the type of the object accepted by `definePageMeta`: ```ts [index.d.ts] declare module '#app' { interface PageMeta { pageType?: string } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ## Navigation To navigate between pages of your app, you should use the [`<NuxtLink>`](https://nuxt.com/docs/4.x/api/components/nuxt-link) component. This component is included with Nuxt and therefore you don't have to import it as you do with other components. A simple link to the `index.vue` page in your `app/pages` folder: ```vue <template> <NuxtLink to="/">Home page</NuxtLink> </template> ``` <read-more to="https://nuxt.com/docs/4.x/api/components/nuxt-link"> Learn more about `<NuxtLink>` usage. </read-more> ## Programmatic Navigation Nuxt allows programmatic navigation through the `navigateTo()` utility method. Using this utility method, you will be able to programmatically navigate the user in your app. This is great for taking input from the user and navigating them dynamically throughout your application. In this example, we have a simple method called `navigate()` that gets called when the user submits a search form. <note> Make sure to always `await` on `navigateTo` or chain its result by returning from functions. </note> ```vuetwoslash <script setup lang="ts"> const name = ref('') const type = ref(1) function navigate () { return navigateTo({ path: '/search', query: { name: name.value, type: type.value, }, }) } </script> ``` ## Client-Only Pages You can define a page as [client only](https://nuxt.com/docs/4.x/directory-structure/app/components#client-components) by giving it a `.client.vue` suffix. None of the content of this page will be rendered on the server. ## Server-Only Pages You can define a page as [server only](https://nuxt.com/docs/4.x/directory-structure/app/components#server-components) by giving it a `.server.vue` suffix. While you will be able to navigate to the page using client-side navigation, controlled by `vue-router`, it will be rendered with a server component automatically, meaning the code required to render the page will not be in your client-side bundle. <warning> Server-only pages must have a single root element. (HTML comments are considered elements as well.) </warning> ## Custom Routing As your app gets bigger and more complex, your routing might require more flexibility. For this reason, Nuxt directly exposes the router, routes and router options for customization in different ways. <read-more to="https://nuxt.com/docs/4.x/guide/recipes/custom-routing"> </read-more> ## Multiple Pages Directories By default, all your pages should be in one `app/pages` directory at the root of your project. However, you can use [Nuxt Layers](https://nuxt.com/docs/4.x/getting-started/layers) to create groupings of your app's pages: ```bash [Directory Structure] -| some-app/ ---| nuxt.config.ts ---| pages/ -----| app-page.vue -| nuxt.config.ts ``` ```ts [some-app/nuxt.config.ts]twoslash // some-app/nuxt.config.ts export default defineNuxtConfig({ }) ``` ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ extends: ['./some-app'], }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/going-further/layers"> </read-more> # plugins > Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application. Nuxt automatically reads the files in the `app/plugins/` directory and loads them at the creation of the Vue application. <note> All plugins inside are auto-registered, you don't need to add them to your `nuxt.config` separately. </note> <note> You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side. </note> ## Registered Plugins Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins. ```bash [Directory structure] -| plugins/ ---| foo.ts // scanned ---| bar/ -----| baz.ts // not scanned -----| foz.vue // not scanned -----| index.ts // currently scanned but deprecated ``` Only `foo.ts` and `bar/index.ts` would be registered. To add plugins in subdirectories, you can use the [`app/plugins`](https://nuxt.com/docs/4.x/api/nuxt-config#plugins-1) option in `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ plugins: [ '~/plugins/bar/baz', '~/plugins/bar/foz', ], }) ``` ## Creating Plugins The only argument passed to a plugin is [`nuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app). ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp }) ``` ### Object Syntax Plugins It is also possible to define a plugin using an object syntax, for more advanced use cases. For example: ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', enforce: 'pre', // or 'post' async setup (nuxtApp) { // this is the equivalent of a normal functional plugin }, hooks: { // You can directly register Nuxt app runtime hooks here 'app:created' () { const nuxtApp = useNuxtApp() // do something in the hook }, }, env: { // Set this value to `false` if you don't want the plugin to run when rendering server-only or island components. islands: true, }, }) ``` <video-accordion title="Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins" video-id="2aXZyXB1QGQ"> </video-accordion> <note> If you are using the object-syntax, the properties are statically analyzed to produce a more optimized build. So you should not define them at runtime. <br /> For example, setting `enforce: import.meta.server ? 'pre' : 'post'` would defeat any future optimization Nuxt is able to do for your plugins. Nuxt does statically pre-load any hook listeners when using object-syntax, allowing you to define hooks without needing to worry about order of plugin registration. </note> ## Registration Order You can control the order in which plugins are registered by prefixing with 'alphabetical' numbering to the file names. ```bash [Directory structure] plugins/ | - 01.myPlugin.ts | - 02.myOtherPlugin.ts ``` In this example, `02.myOtherPlugin.ts` will be able to access anything that was injected by `01.myPlugin.ts`. This is useful in situations where you have a plugin that depends on another plugin. <note> In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.myPlugin.ts` would come before `2.myOtherPlugin.ts`. This is why the example prefixes single digit numbers with `0`. </note> ## Loading Strategy ### Parallel Plugins By default, Nuxt loads plugins sequentially. You can define a plugin as `parallel` so Nuxt won't wait until the end of the plugin's execution before loading the next plugin. ```ts [plugins/my-plugin.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', parallel: true, async setup (nuxtApp) { // the next plugin will be executed immediately }, }) ``` ### Plugins With Dependencies If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the `dependsOn` array. ```ts [plugins/depending-on-my-plugin.ts]twoslash export default defineNuxtPlugin({ name: 'depends-on-my-plugin', dependsOn: ['my-plugin'], async setup (nuxtApp) { // this plugin will wait for the end of `my-plugin`'s execution before it runs }, }) ``` ## Using Composables You can use [composables](https://nuxt.com/docs/4.x/directory-structure/app/composables) as well as [utils](https://nuxt.com/docs/4.x/directory-structure/app/utils) within Nuxt plugins: ```ts [app/plugins/hello.ts] export default defineNuxtPlugin((nuxtApp) => { const foo = useFoo() }) ``` However, keep in mind there are some limitations and differences: <important> **If a composable depends on another plugin registered later, it might not work.** <br /> Plugins are called in order sequentially and before everything else. You might use a composable that depends on another plugin which has not been called yet. </important> <important> **If a composable depends on the Vue.js lifecycle, it won't work.** <br /> Normally, Vue.js composables are bound to the current component instance while plugins are only bound to [`nuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) instance. </important> ## Providing Helpers If you would like to provide a helper on the [`NuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) instance, return it from the plugin under a `provide` key. <code-group> ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin(() => { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }) ``` ```ts [plugins/hello-object-syntax.ts]twoslash export default defineNuxtPlugin({ name: 'hello', setup () { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }, }) ``` </code-group> You can then use the helper in your components: ```vue [app/components/Hello.vue] <script setup lang="ts"> // alternatively, you can also use it here const { $hello } = useNuxtApp() </script> <template> <div> {{ $hello('world') }} </div> </template> ``` <important> Note that we highly recommend using [`composables`](https://nuxt.com/docs/4.x/directory-structure/app/composables) instead of providing helpers to avoid polluting the global namespace and keep your main bundle entry small. </important> <warning> **If your plugin provides a ref or computed, it will not be unwrapped in a component <template>.** <br /> This is due to how Vue works with refs that aren't top-level to the template. You can read more about it [in the Vue documentation](https://vuejs.org/guide/essentials/reactivity-fundamentals#caveat-when-unwrapping-in-templates). </warning> ## Typing Plugins If you return your helpers from the plugin, they will be typed automatically; you'll find them typed for the return of `useNuxtApp()` and within your templates. <note> If you need to use a provided helper *within* another plugin, you can call [`useNuxtApp()`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) to get the typed version. But in general, this should be avoided unless you are certain of the plugins' order. </note> For advanced use-cases, you can declare the type of injected properties like this: ```ts [index.d.ts] declare module '#app' { interface NuxtApp { $hello (msg: string): string } } declare module 'vue' { interface ComponentCustomProperties { $hello (msg: string): string } } export {} ``` ## Vue Plugins If you want to use Vue plugins, like [vue-gtag](https://github.com/MatteoGabriele/vue-gtag) to add Google Analytics tags, you can use a Nuxt plugin to do so. First, install the Vue plugin dependency: <code-group sync="pm"> ```bash [npm] npm install --save-dev vue-gtag-next ``` ```bash [yarn] yarn add --dev vue-gtag-next ``` ```bash [pnpm] pnpm add -D vue-gtag-next ``` ```bash [bun] bun add -D vue-gtag-next ``` ```bash [deno] deno add -D npm:vue-gtag-next ``` </code-group> Then create a plugin file: ```ts [app/plugins/vue-gtag.client.ts] import VueGtag, { trackRouter } from 'vue-gtag-next' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(VueGtag, { property: { id: 'GA_MEASUREMENT_ID', }, }) trackRouter(useRouter()) }) ``` ## Vue Directives Similarly, you can register a custom Vue directive in a plugin. ```ts [plugins/my-directive.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.directive('focus', { mounted (el) { el.focus() }, getSSRProps (binding, vnode) { // you can provide SSR-specific props here return {} }, }) }) ``` <warning> If you register a Vue directive, you *must* register it on both client and server side unless you are only using it when rendering one side. If the directive only makes sense from a client side, you can always move it to `~/plugins/my-directive.client.ts` and provide a 'stub' directive for the server in `~/plugins/my-directive.server.ts`. </warning> <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Custom Directives on Vue Docs" to="https://vuejs.org/guide/reusability/custom-directives.html"> </read-more> # utils > Use the utils/ directory to auto-import your utility functions throughout your application. The main purpose of the [`app/utils/` directory](https://nuxt.com/docs/4.x/directory-structure/app/utils) is to allow a semantic distinction between your Vue composables and other auto-imported utility functions. ## Usage **Method 1:** Using named export ```ts [utils/index.ts]twoslash export const { format: formatNumber } = Intl.NumberFormat('en-GB', { notation: 'compact', maximumFractionDigits: 1, }) ``` **Method 2:** Using default export ```ts [utils/random-entry.ts or utils/randomEntry.ts]twoslash // It will be available as randomEntry() (camelCase of file name without extension) export default function (arr: Array<any>) { return arr[Math.floor(Math.random() * arr.length)] } ``` You can now use auto imported utility functions in `.js`, `.ts` and `.vue` files ```vue [app/app.vue] <template> <p>{{ formatNumber(1234) }}</p> </template> ``` <read-more to="https://nuxt.com/docs/4.x/guide/concepts/auto-imports"> </read-more> <link-example to="https://nuxt.com/docs/4.x/examples/features/auto-imports"> </link-example> <tip> The way `app/utils/` auto-imports work and are scanned is identical to the [`app/composables/`](https://nuxt.com/docs/4.x/directory-structure/app/composables) directory. </tip> <important> These utils are only available within the Vue part of your app. <br /> Only `server/utils` are auto-imported in the [`server/`](https://nuxt.com/docs/4.x/directory-structure/server#server-utilities) directory. </important> <tip> Types can be auto-imported the same way. Put app-only types in `app/types/`, server-only types in [`server/types/`](https://nuxt.com/docs/4.x/directory-structure/server#server-types), and types shared between both in [`shared/types/`](https://nuxt.com/docs/4.x/directory-structure/shared). </tip> # content > Use the content/ directory to create a file-based CMS for your application. [Nuxt Content](https://content.nuxt.com) reads the `content/` directory in your project and parses `.md`, `.yml`, `.csv` and `.json` files to create a file-based CMS for your application. - Render your content with built-in components. - Query your content with a MongoDB-like API. - Use your Vue components in Markdown files with the MDC syntax. - Automatically generate your navigation. <read-more target="_blank" to="https://content.nuxt.com"> Learn more in **Nuxt Content** documentation. </read-more> ## Enable Nuxt Content Install the `@nuxt/content` module in your project as well as adding it to your `nuxt.config.ts` with one command: ```bash [Terminal] npx nuxt module add content ``` ## Create Content Place your markdown files inside the `content/` directory: ```md [content/index.md] # Hello Content ``` The module automatically loads and parses them. ## Render Content To render content pages, add a [catch-all route](https://nuxt.com/docs/4.x/directory-structure/app/pages/#catch-all-route) using the [`<ContentRenderer>`](https://content.nuxt.com/docs/components/content-renderer) component: ```vue [app/pages/[...slug].vue] <script lang="ts" setup> const route = useRoute() const { data: page } = await useAsyncData(route.path, () => { return queryCollection('content').path(route.path).first() }) </script> <template> <div> <header><!-- ... --></header> <ContentRenderer v-if="page" :value="page" /> <footer><!-- ... --></footer> </div> </template> ``` ## Documentation <tip icon="i-lucide-book"> Head over to [https://content.nuxt.com](https://content.nuxt.com) to learn more about the Content module features, such as how to build queries and use Vue components in your Markdown files with the MDC syntax. </tip> # .env > A .env file specifies your build/dev-time environment variables. <important> This file should be added to your [`.gitignore`](https://nuxt.com/docs/4.x/directory-structure/gitignore) file to avoid pushing secrets to your repository. </important> ## Dev, Build and Generate Time Nuxt CLI has built-in `.env` support via [c12](https://github.com/unjs/c12) in development mode and when running [`nuxt build`](https://nuxt.com/docs/4.x/api/commands/build) and [`nuxt generate`](https://nuxt.com/docs/4.x/api/commands/generate). In addition to any process environment variables, if you have a `.env` file in your project root directory, it will be automatically loaded **at dev, build and generate time**. Any environment variables set there will be accessible within your `nuxt.config` file and modules. ```ini [.env] MY_ENV_VARIABLE=hello ``` <note> Note that removing a variable from `.env` or removing the `.env` file entirely will not unset values that have already been set. </note> ## Custom File If you want to use a different file - for example, to use `.env.local` or `.env.production` - you can do so by passing the `--dotenv` flag when using the Nuxt CLI. ```bash [Terminal] npx nuxt dev --dotenv .env.local ``` When updating `.env` in development mode, the Nuxt instance is automatically restarted to apply new values to the `process.env`. <important> In your application code, you should use [Runtime Config](https://nuxt.com/docs/4.x/guide/going-further/runtime-config) instead of plain env variables. </important> ## Production **After your server is built**, you are responsible for setting environment variables when you run the server. Your `.env` files will not be read at this point. How you do this is different for every environment. This design decision was made to ensure compatibility across various deployment environments, some of which may not have a traditional file system available, such as serverless platforms or edge networks like Cloudflare Workers. Since `.env` files are not used in production, you must explicitly set environment variables using the tools and methods provided by your hosting environment. Here are some common approaches: - You can pass the environment variables as arguments using the terminal:<br /> `$ NODE_ENV=production DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs` - You can set environment variables in shell configuration files like `.bashrc` or `.profile`. - Many cloud service providers, such as Vercel, Netlify, and AWS, provide interfaces for setting environment variables via their dashboards, CLI tools or configuration files. <important> `runtimeConfig` <span> won't pick up environment variables that don't start with `NUXT_` in production </span> (/docs/4.x/guide/going-further/runtime-config#environment-variables). </important> ## Production Preview For local production preview purpose, we recommend using [`nuxt preview`](https://nuxt.com/docs/4.x/api/commands/preview) since using this command, the `.env` file will be loaded into `process.env` for convenience. Note that this command requires dependencies to be installed in the package directory. Or you could pass the environment variables as arguments using the terminal. For example, on Linux or macOS: ```bash [Terminal] NODE_ENV=production DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs ``` Note that for a purely static site, it is not possible to set runtime configuration config after your project is prerendered. <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> <note> If you want to use environment variables set at build time but do not care about updating these down the line (or only need to update them reactively *within* your app) then `appConfig` may be a better choice. You can define `appConfig` both within your `nuxt.config` (using environment variables) and also within an `~/app.config.ts` file in your project. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/app-config"> </read-more> </note> # .gitignore > A .gitignore file specifies intentionally untracked files that git should ignore. A `.gitignore` file specifies intentionally untracked files that git should ignore. <read-more icon="i-simple-icons-git" target="_blank" title="the git documentation" to="https://git-scm.com/docs/gitignore"> </read-more> We recommend having a `.gitignore` file that has **at least** the following entries present: ```bash [.gitignore] # Nuxt dev/build outputs .output .data .nuxt .nitro .cache dist # Node dependencies node_modules # Logs logs *.log # Misc .DS_Store # Local env files .env .env.* !.env.example ``` # layers > Use the layers/ directory to organize and auto-register local layers within your application. The `layers/` directory allows you to organize and share reusable code, components, composables, and configurations across your Nuxt application. Any layers within your project in the `layers/` directory will be automatically registered. <note> The `layers/` directory auto-registration is available in Nuxt v3.12.0+. </note> <tip icon="i-lucide-lightbulb"> Layers are ideal for organizing large codebases with **Domain-Driven Design (DDD)**, creating reusable **UI libraries** or **themes**, sharing **configuration presets** across projects, and separating concerns like **admin panels** or **feature modules**. </tip> ## Structure Each subdirectory within `layers/` is treated as a separate layer. A layer can contain the same structure as a standard Nuxt application. <important> Every layer **must have** a `nuxt.config.ts` file to be recognized as a valid layer, even if it's empty. </important> ```bash [Directory structure] -| layers/ ---| base/ -----| nuxt.config.ts -----| app/ -------| components/ ---------| BaseButton.vue -------| composables/ ---------| useBase.ts -----| server/ -------| api/ ---------| hello.ts ---| admin/ -----| nuxt.config.ts -----| app/ -------| pages/ ---------| admin.vue -------| layouts/ ---------| admin.vue ``` ## Automatic Aliases Named layer aliases to the `srcDir` of each layer are automatically created. You can access a layer using the `#layers/[name]` alias: ```ts // Access the base layer import something from '#layers/base/path/to/file' // Access the admin layer import { useAdmin } from '#layers/admin/composables/useAdmin' ``` <note> Named layer aliases were introduced in Nuxt v3.16.0. </note> ## Layer Content Each layer can include: - [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) - Layer-specific configuration that will be merged with the main config - [`app.config.ts`](https://nuxt.com/docs/4.x/directory-structure/app/app-config) - Reactive application configuration - [`app/components/`](https://nuxt.com/docs/4.x/directory-structure/app/components) - Vue components (auto-imported) - [`app/composables/`](https://nuxt.com/docs/4.x/directory-structure/app/composables) - Vue composables (auto-imported) - [`app/utils/`](https://nuxt.com/docs/4.x/directory-structure/app/utils) - Utility functions (auto-imported) - [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) - Application pages - [`app/layouts/`](https://nuxt.com/docs/4.x/directory-structure/app/layouts) - Application layouts - [`app/middleware/`](https://nuxt.com/docs/4.x/directory-structure/app/middleware) - Route middleware - [`app/plugins/`](https://nuxt.com/docs/4.x/directory-structure/app/plugins) - Nuxt plugins - [`server/`](https://nuxt.com/docs/4.x/directory-structure/server) - Server routes, middleware, and utilities - [`shared/`](https://nuxt.com/docs/4.x/directory-structure/shared) - Shared code between app and server ## Priority Order When multiple layers define the same resource (component, composable, page, etc.), the layer with **higher priority wins**. Layers are sorted alphabetically, with later letters having higher priority (Z > A). To control the order, prefix directories with numbers: `1.base/`, `2.features/`, `3.admin/`. Alternatively, reference the directories in [`extends`](https://nuxt.com/docs/4.x/api/nuxt-config#extends) (e.g. `extends: ['~~/layers/admin', '~~/layers/base']`) to order them from `nuxt.config` without renaming, with the first entry taking the highest priority. <read-more to="https://nuxt.com/docs/4.x/getting-started/layers#layer-priority"> </read-more> <video-accordion title="Watch a video from Learn Vue about Nuxt Layers" video-id="lnFCM7c9f7I"> </video-accordion> # modules > Use the modules/ directory to automatically register local modules within your application. It is a good place to place any local modules you develop while building your application. The auto-registered files patterns are: - `modules/*/index.ts` - `modules/*.ts` You don't need to add those local modules to your [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) separately. <code-group> ```ts [modules/hello/index.ts]twoslash // `nuxt/kit` is a helper subpath import you can use when defining local modules // that means you do not need to add `@nuxt/kit` to your project's dependencies import { addComponentsDir, addServerHandler, createResolver, defineNuxtModule } from 'nuxt/kit' export default defineNuxtModule({ meta: { name: 'hello', }, setup () { const resolver = createResolver(import.meta.url) // Add an API route addServerHandler({ route: '/api/hello', handler: resolver.resolve('./runtime/api-route'), }) // Add components addComponentsDir({ path: resolver.resolve('./runtime/app/components'), pathPrefix: true, // Prefix your exports to avoid conflicts with user code or other modules }) }, }) ``` ```ts [modules/hello/runtime/api-route.ts]twoslash export default defineEventHandler(() => { return { hello: 'world' } }) ``` </code-group> When starting Nuxt, the `hello` module will be registered and the `/api/hello` route will be available. <note> Note that all components, pages, composables and other files that would be normally placed in your `app/` directory need to be in `modules/your-module/runtime/app/`. This ensures they can be type-checked properly. </note> Modules are executed in the following sequence: - First, the modules defined in [`nuxt.config.ts`](https://nuxt.com/docs/4.x/api/nuxt-config#modules-1) are loaded. - Then, modules found in the `modules/` directory are executed, and they load in alphabetical order. You can change the order of local module by adding a number to the front of each directory name: ```bash [Directory structure] modules/ 1.first-module/ index.ts 2.second-module.ts ``` <read-more to="https://nuxt.com/docs/4.x/guide/modules"> </read-more> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/creating-your-first-module-from-scratch?friend=nuxt"> Watch Vue School video about Nuxt private modules. </tip> # node_modules > The package manager stores the dependencies of your project in the node_modules/ directory. The package manager ([`npm`](https://docs.npmjs.com/cli/commands/npm/) or [`yarn`](https://yarnpkg.com) or [`pnpm`](https://pnpm.io/cli/install) or [`bun`](https://bun.com/package-manager) or [`deno`](https://docs.deno.com/runtime/getting_started/installation/)) creates this directory to store the dependencies of your project. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/4.x/directory-structure/gitignore) file to avoid pushing the dependencies to your repository. </important> # .nuxt > Nuxt uses the .nuxt/ directory in development to generate your Vue application. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/4.x/directory-structure/gitignore) file to avoid pushing the dev build output to your repository. </important> This directory is interesting if you want to learn more about the files Nuxt generates based on your directory structure. Nuxt also provides a Virtual File System (VFS) for modules to add templates to this directory without writing them to disk. You can explore the generated files by opening the [Nuxt DevTools](https://devtools.nuxt.com) in development mode and navigating to the **Virtual Files** tab. <warning> You should not touch any files inside since the whole directory will be re-created when running [`nuxt dev`](https://nuxt.com/docs/4.x/api/commands/dev). </warning> # nuxt.config.ts > Nuxt can be easily configured with a single nuxt.config file. The `nuxt.config` file extension can either be `.js`, `.ts` or `.mjs`. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ // My Nuxt config }) ``` <tip> `defineNuxtConfig` helper is globally available without import. </tip> You can explicitly import `defineNuxtConfig` from `nuxt/config` if you prefer: ```ts [nuxt.config.ts]twoslash import { defineNuxtConfig } from 'nuxt/config' export default defineNuxtConfig({ // My Nuxt config }) ``` <read-more to="https://nuxt.com/docs/4.x/api/configuration/nuxt-config"> Discover all the available options in the **Nuxt configuration** documentation. </read-more> To ensure your configuration is up to date, Nuxt will make a full restart when detecting changes in the main configuration file, the [`.env`](https://nuxt.com/docs/4.x/directory-structure/env), [`.nuxtignore`](https://nuxt.com/docs/4.x/directory-structure/nuxtignore) and [`.nuxtrc`](https://nuxt.com/docs/4.x/directory-structure/nuxtrc) dotfiles. # .nuxtignore > The .nuxtignore file lets Nuxt ignore files in your projectโ€™s root directory during the build phase. The `.nuxtignore` file tells Nuxt to ignore files in your projectโ€™s root directory ([`rootDir`](https://nuxt.com/docs/4.x/api/nuxt-config#rootdir)) during the build phase. It is subject to the same specification as [`.gitignore`](https://nuxt.com/docs/4.x/directory-structure/gitignore) and `.eslintignore` files, in which each line is a glob pattern indicating which files should be ignored. <tip> You can also configure [`ignoreOptions`](https://nuxt.com/docs/4.x/api/nuxt-config#ignoreoptions), [`ignorePrefix`](https://nuxt.com/docs/4.x/api/nuxt-config#ignoreprefix) and [`ignore`](https://nuxt.com/docs/4.x/api/nuxt-config#ignore) in your `nuxt.config` file. </tip> ## Usage ```bash [.nuxtignore] # ignore layout foo.vue app/layouts/foo.vue # ignore layout files whose name ends with -ignore.vue app/layouts/*-ignore.vue # ignore page bar.vue app/pages/bar.vue # ignore page inside ignore folder app/pages/ignore/*.vue # ignore route middleware files under foo folder except foo/bar.js app/middleware/foo/*.js !app/middleware/foo/bar.js ``` <read-more icon="i-simple-icons-git" target="_blank" title="the git documentation" to="https://git-scm.com/docs/gitignore"> More details about the spec are in the **gitignore documentation**. </read-more> # .nuxtrc > The .nuxtrc file allows you to define nuxt configurations in a flat syntax. The `.nuxtrc` file can be used to configure Nuxt with a flat syntax. It is based on [`unjs/rc9`](https://github.com/unjs/rc9). <tip> For more advanced configurations, use [`nuxt.config`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config). </tip> ## Usage ```bash [.nuxtrc] # Disable SSR ssr=false # Configuration for `@nuxt/devtools` devtools.enabled=true # Add Nuxt modules modules[]=@nuxt/image modules[]=nuxt-security # Module setups (automatically added by Nuxt) setups.@nuxt/test-utils="3.23.0" ``` If present, the properties in the `nuxt.config` file will overwrite the properties in `.nuxtrc` file. <note> Nuxt automatically adds a `setups` section to track module installation and upgrade state. This is used internally for [module lifecycle hooks](https://nuxt.com/docs/4.x/api/kit/modules#using-lifecycle-hooks-for-module-installation-and-upgrade) and should not be modified manually. </note> <read-more to="https://nuxt.com/docs/4.x/api/configuration/nuxt-config"> Discover all the available options in the **Nuxt configuration** documentation. </read-more> ## Global `.nuxtrc` File You can also create a global `.nuxtrc` file in your home directory to apply configurations globally. - On macOS/Linux, this file is located at:```md ~/.nuxtrc ``` - On Windows, it is located at:```md C:\Users\{username}\.nuxtrc ``` This global `.nuxtrc` file allows you to define default settings that apply to all Nuxt projects on your system. However, project-level `.nuxtrc` files will override these global settings, and `nuxt.config` will take precedence over both. # .output > Nuxt creates the .output/ directory when building your application for production. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/4.x/directory-structure/gitignore) file to avoid pushing the build output to your repository. </important> Use this directory to deploy your Nuxt application to production. <read-more to="https://nuxt.com/docs/4.x/getting-started/deployment"> </read-more> <warning> You should not touch any files inside since the whole directory will be re-created when running [`nuxt build`](https://nuxt.com/docs/4.x/api/commands/build). </warning> # package.json > The package.json file contains all the dependencies and scripts for your application. The minimal `package.json` of your Nuxt application should looks like: ```json [package.json] { "name": "nuxt-app", "private": true, "type": "module", "scripts": { "build": "nuxt build", "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare" }, "dependencies": { "nuxt": "latest", "vue": "latest", "vue-router": "latest" } } ``` <read-more icon="i-simple-icons-npm" target="_blank" to="https://docs.npmjs.com/cli/configuring-npm/package-json/"> Read more about the `package.json` file. </read-more> # public > The public/ directory is used to serve your website's static assets. Files contained within the `public/` directory are served at the root and are not modified by the build process. This is suitable for files that have to keep their names (e.g. `robots.txt`) *or* likely won't change (e.g. `favicon.ico`). ```bash [Directory structure] -| public/ ---| favicon.ico ---| og-image.png ---| robots.txt ``` ```vue [app/app.vue] <script setup lang="ts"> useSeoMeta({ ogImage: '/og-image.png', }) </script> ``` <tip target="_blank" to="https://v2.nuxt.com/docs/directory-structure/static/"> This is known as the <span> `static/` </span> directory in Nuxt 2. </tip> # server > The server/ directory is used to register API and server handlers to your application. Nuxt automatically scans files inside these directories to register API and server handlers with Hot Module Replacement (HMR) support. ```bash [Directory Structure] -| server/ ---| api/ -----| hello.ts # /api/hello ---| routes/ -----| bonjour.ts # /bonjour ---| middleware/ -----| log.ts # log all requests ``` Each file should export a default function defined with `defineEventHandler()` or `eventHandler()` (alias). The handler can directly return JSON data, a `Promise`, or use `event.node.res.end()` to send a response. <important> Do not import Vue app code (components, composables, or other app-only utilities) in your server routes or utilities, and do not import server-only code in your app. </important> <read-more to="https://nuxt.com/docs/4.x/directory-structure/shared#why-you-cannot-mix-vue-and-nitro-code" title="Why You Cannot Mix Vue and Nitro Code"> </read-more> ```ts [server/api/hello.ts]twoslash export default defineEventHandler((event) => { return { hello: 'world', } }) ``` You can now universally call this API in your pages and components: ```vue [app/pages/index.vue] <script setup lang="ts"> const { data } = await useFetch('/api/hello') </script> <template> <pre>{{ data }}</pre> </template> ``` ## Server Routes Files inside the `~~/server/api` are automatically prefixed with `/api` in their route. <video-accordion platform="vimeo" title="Watch a video from Vue School on API routes" video-id="761468863"> </video-accordion> To add server routes without `/api` prefix, put them into `~~/server/routes` directory. **Example:** ```ts [server/routes/hello.ts] export default defineEventHandler(() => 'Hello World!') ``` Given the example above, the `/hello` route will be accessible at [http://localhost:3000/hello](http://localhost:3000/hello). <note> Note that currently server routes do not support the full functionality of dynamic routes as [pages](https://nuxt.com/docs/4.x/directory-structure/app/pages#dynamic-routes) do. </note> ## Server Middleware Nuxt will automatically read in any file in the `~~/server/middleware` to create server middleware for your project. Middleware handlers will run on every request before any other server route to add or check headers, log requests, or extend the event's request object. <note> Middleware handlers should not return anything (nor close or respond to the request) and only inspect or extend the request context or throw an error. </note> **Examples:** ```ts [server/middleware/log.ts] export default defineEventHandler((event) => { console.log('New request: ' + getRequestURL(event)) }) ``` ```ts [server/middleware/auth.ts] export default defineEventHandler((event) => { event.context.auth = { user: 123 } }) ``` ## Server Plugins Nuxt will automatically read any files in the `~~/server/plugins` directory and register them as Nitro plugins. This allows extending Nitro's runtime behavior and hooking into lifecycle events. **Example:** ```ts [server/plugins/nitroPlugin.ts] export default defineNitroPlugin((nitroApp) => { console.log('Nitro plugin', nitroApp) }) ``` <read-more to="https://nitro.build/guide/plugins" target="_blank" title="Nitro Plugins"> </read-more> ## Server Utilities Server routes are powered by [h3js/h3](https://github.com/h3js/h3) which comes with a handy set of helpers. <read-more to="https://www.jsdocs.io/package/h3#package-index-functions" target="_blank" title="Available H3 Request Helpers"> </read-more> You can add more helpers yourself inside the `~~/server/utils` directory. For example, you can define a custom handler utility that wraps the original handler and performs additional operations before returning the final response. **Example:** ```ts [server/utils/handler.ts] export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> ( handler: EventHandler<T, D>, ): EventHandler<T, D> => defineEventHandler<T>(async (event) => { try { // do something before the route handler const response = await handler(event) // do something after the route handler return { response } } catch (err) { // Error handling return { err } } }) ``` ```ts [server/api/hello.get.ts] export default defineWrappedResponseHandler(event => 'hello world') ``` ## Server Alias <badge className="align-middle" color="info" size="xs">v4.3</badge> You can use the `#server` alias to import files from anywhere within the `server/` directory, regardless of the importing file's location. ```ts [server/api/users/[id]/profile.ts] // Instead of relative paths like this: // import { formatUser } from '../../../utils/formatUser' // Use the #server alias: import { formatUser } from '#server/utils/formatUser' ``` This alias ensures consistent imports across your server code, especially useful in deeply nested route handlers. <note> The `#server` alias can only be used within the `server/` directory. Importing from `#server` in client code will result in an error. </note> ## Server Types Auto-imports and other types are different for the `server/` directory, as it is running in a different context from the `app/` directory. By default, Nuxt 4 generates a [`tsconfig.json`](https://nuxt.com/docs/4.x/directory-structure/tsconfig) which includes a project reference covering the `server/` folder which ensures accurate typings. Types placed in `~~/server/types/` are auto-imported in the server context only, so you can reference them in server routes, middleware, plugins, and utilities without importing them. Types that are also needed in the Vue app belong in [`shared/types/`](https://nuxt.com/docs/4.x/directory-structure/shared) instead. ```ts [server/types/todo.ts]twoslash export interface Todo { id: string title: string completed: boolean } ``` ```ts [server/api/todos.get.ts] export default defineEventHandler((): Todo[] => { return [] }) ``` Only files directly in `server/types/` are scanned; files in nested subdirectories are not auto-imported, matching how [`shared/types/`](https://nuxt.com/docs/4.x/directory-structure/shared#how-files-are-scanned) works. ## Recipes ### Route Parameters Server routes can use dynamic parameters within brackets in the file name like `/api/hello/[name].ts` and be accessed via `event.context.params`. ```ts [server/api/hello/[name].ts] export default defineEventHandler((event) => { const name = getRouterParam(event, 'name') return `Hello, ${name}!` }) ``` <tip to="https://h3.dev/examples/validate-data#validate-params"> Alternatively, use `getValidatedRouterParams` with a schema validator such as Zod or Valibot for runtime and type safety. </tip> You can now universally call this API on `/api/hello/nuxt` and get `Hello, nuxt!`. ### Matching HTTP Method Handle file names can be suffixed with `.get`, `.post`, `.put`, `.delete`, ... to match request's [HTTP Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods). ```ts [server/api/test.get.ts] export default defineEventHandler(() => 'Test get handler') ``` ```ts [server/api/test.post.ts] export default defineEventHandler(() => 'Test post handler') ``` Given the example above, fetching `/test` with: - **GET** method: Returns `Test get handler` - **POST** method: Returns `Test post handler` - Any other method: Returns 405 error You can also use `index.[method].ts` inside a directory for structuring your code differently, this is useful to create API namespaces. <code-group> ```ts [server/api/foo/index.get.ts] export default defineEventHandler((event) => { // handle GET requests for the `api/foo` endpoint }) ``` ```ts [server/api/foo/index.post.ts] export default defineEventHandler((event) => { // handle POST requests for the `api/foo` endpoint }) ``` ```ts [server/api/foo/bar.get.ts] export default defineEventHandler((event) => { // handle GET requests for the `api/foo/bar` endpoint }) ``` </code-group> ### Catch-all Route Catch-all routes are helpful for fallback route handling. For example, creating a file named `~~/server/api/foo/[...].ts` will register a catch-all route for all requests that do not match any route handler, such as `/api/foo/bar/baz`. ```ts [server/api/foo/[...].ts] export default defineEventHandler((event) => { // event.context.path to get the route path: '/api/foo/bar/baz' // event.context.params._ to get the route segment: 'bar/baz' return `Default foo handler` }) ``` You can set a name for the catch-all route by using `~~/server/api/foo/[...slug].ts` and access it via `event.context.params.slug`. ```ts [server/api/foo/[...slug].ts] export default defineEventHandler((event) => { // event.context.params.slug to get the route segment: 'bar/baz' return `Default foo handler` }) ``` ### Body Handling ```ts [server/api/submit.post.ts] export default defineEventHandler(async (event) => { const body = await readBody(event) return { body } }) ``` <tip to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web/#runtime-type-safe-request-utils"> Alternatively, use `readValidatedBody` with a schema validator such as Zod or Valibot for runtime and type safety. </tip> You can now universally call this API using: ```vue [app/app.vue] <script setup lang="ts"> async function submit () { const { body } = await $fetch('/api/submit', { method: 'post', body: { test: 123 }, }) } </script> ``` <note> We are using `submit.post.ts` in the filename only to match requests with `POST` method that can accept the request body. When using `readBody` within a GET request, `readBody` will throw a `405 Method Not Allowed` HTTP error. </note> ### Query Parameters Sample query `/api/query?foo=bar&baz=qux` ```ts [server/api/query.get.ts] export default defineEventHandler((event) => { const query = getQuery(event) return { a: query.foo, b: query.baz } }) ``` <tip to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"> Alternatively, use `getValidatedQuery` with a schema validator such as Zod or Valibot for runtime and type safety. </tip> ### Error Handling If no errors are thrown, a status code of `200 OK` will be returned. Any uncaught errors will return a `500 Internal Server Error` HTTP Error. To return other error codes, throw an exception with [`createError`](https://nuxt.com/docs/4.x/api/utils/create-error): ```ts [server/api/validation/[id].ts] export default defineEventHandler((event) => { const id = Number.parseInt(event.context.params.id) as number if (!Number.isInteger(id)) { throw createError({ status: 400, statusText: 'ID should be an integer', }) } return 'All good' }) ``` ### Status Codes To return other status codes, use the [`setResponseStatus`](https://nuxt.com/docs/4.x/api/utils/set-response-status) utility. For example, to return `202 Accepted` ```ts [server/api/validation/[id].ts] export default defineEventHandler((event) => { setResponseStatus(event, 202) }) ``` ### Runtime Config <code-group> ```ts [server/api/foo.ts] export default defineEventHandler(async (event) => { const config = useRuntimeConfig(event) const repo = await $fetch('https://api.github.com/repos/nuxt/nuxt', { headers: { Authorization: `token ${config.githubToken}`, }, }) return repo }) ``` ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { githubToken: '', }, }) ``` ```ini [.env] NUXT_GITHUB_TOKEN='<my-super-token>' ``` </code-group> <note> Giving the `event` as argument to `useRuntimeConfig` is optional, but it is recommended to pass it to get the runtime config overwritten by [environment variables](https://nuxt.com/docs/4.x/guide/going-further/runtime-config#environment-variables) at runtime for server routes. </note> ### Request Cookies ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` ### Forwarding Context & Headers By default, neither the headers from the incoming request nor the request context are forwarded when making fetch requests in server routes. You can use `event.$fetch` to forward the request context and headers when making fetch requests in server routes. ```ts [server/api/forward.ts] export default defineEventHandler((event) => { return event.$fetch('/api/forwarded') }) ``` <note> Headers that are **not meant to be forwarded** will **not be included** in the request. These headers include, for example: `transfer-encoding`, `connection`, `keep-alive`, `upgrade`, `expect`, `host`, `accept` </note> ### Awaiting Promises After Response When handling server requests, you might need to perform asynchronous tasks that shouldn't block the response to the client (for example, caching and logging). You can use `event.waitUntil` to await a promise in the background without delaying the response. The `event.waitUntil` method accepts a promise that will be awaited before the handler terminates, ensuring the task is completed even if the server would otherwise terminate the handler right after the response is sent. This integrates with runtime providers to leverage their native capabilities for handling asynchronous operations after the response is sent. ```ts [server/api/background-task.ts] const timeConsumingBackgroundTask = async () => { await new Promise(resolve => setTimeout(resolve, 1000)) } export default eventHandler((event) => { // schedule a background task without blocking the response event.waitUntil(timeConsumingBackgroundTask()) // immediately send the response to the client return 'done' }) ``` ## Advanced Usage ### Nitro Config You can use `nitro` key in `nuxt.config` to directly set [Nitro configuration](https://nitro.build/config). <warning> This is an advanced option. Custom config can affect production deployments, as the configuration interface might change over time when Nitro is upgraded in semver-minor versions of Nuxt. </warning> ```ts [nuxt.config.ts] export default defineNuxtConfig({ // https://nitro.build/config nitro: {}, }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/concepts/server-engine"> </read-more> ### Nested Router ```ts [server/api/hello/[...slug].ts] import { createRouter, defineEventHandler, useBase } from 'h3' const router = createRouter() router.get('/test', defineEventHandler(() => 'Hello World')) export default useBase('/api/hello', router.handler) ``` ### Sending Streams <tip> This is an experimental feature and is available in all environments. </tip> ```ts [server/api/foo.get.ts] import fs from 'node:fs' import { sendStream } from 'h3' export default defineEventHandler((event) => { return sendStream(event, fs.createReadStream('/path/to/file')) }) ``` ### Sending Redirect ```ts [server/api/foo.get.ts] export default defineEventHandler(async (event) => { await sendRedirect(event, '/path/redirect/to', 302) }) ``` ### Legacy Handler or Middleware ```ts [server/api/legacy.ts] export default fromNodeMiddleware((req, res) => { res.end('Legacy handler') }) ``` <important> Legacy support is possible using [h3js/h3](https://github.com/h3js/h3), but it is advised to avoid legacy handlers as much as you can. </important> ```ts [server/middleware/legacy.ts] export default fromNodeMiddleware((req, res, next) => { console.log('Legacy middleware') next() }) ``` <warning> Never combine `next()` callback with a legacy middleware that is `async` or returns a `Promise`. </warning> ### Server Storage Nitro provides a cross-platform [storage layer](https://nitro.build/guide/storage). In order to configure additional storage mount points, you can use `nitro.storage`, or [server plugins](https://nuxt.com/docs/4.x/directory-structure/server#server-plugins). **Example of adding a Redis storage:** Using `nitro.storage`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { storage: { redis: { driver: 'redis', /* redis connector options */ port: 6379, // Redis port host: '127.0.0.1', // Redis host username: '', // needs Redis >= 6 password: '', db: 0, // Defaults to 0 tls: {}, // tls/ssl }, }, }, }) ``` Then in your API handler: ```ts [server/api/storage/test.ts] export default defineEventHandler(async (event) => { // List all keys with const keys = await useStorage('redis').getKeys() // Set a key with await useStorage('redis').setItem('foo', 'bar') // Remove a key with await useStorage('redis').removeItem('foo') return {} }) ``` <read-more to="https://nitro.build/guide/storage" target="_blank"> Read more about Nitro Storage Layer. </read-more> Alternatively, you can create a storage mount point using a server plugin and runtime config: <code-group> ```ts [server/plugins/storage.ts] import redisDriver from 'unstorage/drivers/redis' export default defineNitroPlugin(() => { const storage = useStorage() // Dynamically pass in credentials from runtime configuration, or other sources const driver = redisDriver({ base: 'redis', host: useRuntimeConfig().redis.host, port: useRuntimeConfig().redis.port, /* other redis connector options */ }) // Mount driver storage.mount('redis', driver) }) ``` ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { redis: { // Default values host: '', port: 0, /* other redis connector options */ }, }, }) ``` </code-group> # shared > Use the shared/ directory to share functionality between the Vue app and the Nitro server. The `shared/` directory allows you to share code that can be used in both the Vue app and the Nitro server. <note> The `shared/` directory is available in Nuxt v3.14+. </note> <important> Code in the `shared/` directory cannot import any Vue or Nitro code. </important> ## Why You Cannot Mix Vue and Nitro Code Nuxt builds two separate bundles: the Vue app (client and server-side rendering) and the Nitro server (API routes, server middleware, server plugins). They are bundled independently and run in different contexts. Code in the `shared/` directory is used in both bundles, so it cannot import from either. ### Vue App Code in Nitro Components and composables need the Vue app runtime and often the Nuxt context (for example `useNuxtApp()` or `useRoute()`), neither of which exists in Nitro. Importing them into server code can cause build or runtime errors, and can pull the Vue app's dependencies into your server bundle. ### Nitro Code in the Vue App Server-only code (such as Node APIs, Nitro utilities, or server route handlers) must not run in the browser. Importing it into your app can break the client build, cause runtime errors in the browser, or leak server logic into the client bundle. ### Type-Only Imports `import type` is erased at compile time and does not pull runtime code into the other bundle, so importing only types across the boundary may appear to work. Even so, keep shared types (such as API response types) in `shared/types/`, where they are auto-imported in both contexts. This keeps the boundary clear, avoids accidentally turning a type import into a value import later, and matches Nuxt's separate [type contexts](https://nuxt.com/docs/4.x/guide/concepts/typescript#project-references) for app, server, and shared code. Types that are only used in one context can live next to that context instead: `app/types/` is auto-imported in the Vue app only, and [`server/types/`](https://nuxt.com/docs/4.x/directory-structure/server#server-types) is auto-imported in the Nitro server only. Use `shared/types/` when a type is needed in both. <video-accordion title="Watch a video from Vue School on sharing utils and types between app and server" video-id="nnAR-MO3q5M"> </video-accordion> ## Usage **Method 1:** Named export ```ts [shared/utils/capitalize.ts]twoslash export const capitalize = (input: string) => { return input[0] ? input[0].toUpperCase() + input.slice(1) : '' } ``` **Method 2:** Default export ```ts [shared/utils/capitalize.ts]twoslash export default function (input: string) { return input[0] ? input[0].toUpperCase() + input.slice(1) : '' } ``` You can now use [auto-imported](https://nuxt.com/docs/4.x/directory-structure/shared) utilities in your Nuxt app and `server/` directory. ```vue [app/app.vue] <script setup lang="ts"> const hello = capitalize('hello') </script> <template> <div> {{ hello }} </div> </template> ``` ```ts [server/api/hello.get.ts] export default defineEventHandler((event) => { return { hello: capitalize('hello'), } }) ``` ## How Files Are Scanned Only files in the `shared/utils/` and `shared/types/` directories will be auto-imported. Files nested within subdirectories of these directories will not be auto-imported unless you add these directories to `imports.dirs` and `nitro.imports.dirs`. <tip> The way `shared/utils` and `shared/types` auto-imports work and are scanned is identical to the [`app/composables/`](https://nuxt.com/docs/4.x/directory-structure/app/composables) and [`app/utils/`](https://nuxt.com/docs/4.x/directory-structure/app/utils) directories. </tip> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/composables#how-files-are-scanned"> </read-more> ```bash [Directory Structure] -| shared/ ---| capitalize.ts # Not auto-imported ---| formatters -----| lower.ts # Not auto-imported ---| utils/ -----| lower.ts # Auto-imported -----| formatters -------| upper.ts # Not auto-imported ---| types/ -----| bar.ts # Auto-imported ``` Any other files you create in the `shared/` folder must be manually imported using the `#shared` alias (automatically configured by Nuxt): ```ts [Importing From #shared] // For files directly in the shared directory import capitalize from '#shared/capitalize' // For files in nested directories import lower from '#shared/formatters/lower' // For files nested in a folder within utils import upper from '#shared/utils/formatters/upper' ``` This alias ensures consistent imports across your application, regardless of the importing file's location. <read-more to="https://nuxt.com/docs/4.x/guide/concepts/auto-imports"> </read-more> # test > Use the test/ directory to organize unit, Nuxt, and end-to-end tests for your application. The `test/` directory is the recommended place for your application tests. Nuxt does not scan it the way it does `app/` or `server/`; you choose the runner and layout yourself (typically with [`@nuxt/test-utils`](https://nuxt.com/docs/4.x/getting-started/testing)). A common layout separates environments: ```bash [Directory structure] -| test/ ---| e2e/ ---| nuxt/ ---| unit/ ``` - `test/unit/` โ€” fast Node tests without the Nuxt runtime - `test/nuxt/` โ€” tests that need the Nuxt runtime environment - `test/e2e/` โ€” end-to-end tests against a running app <read-more to="https://nuxt.com/docs/4.x/getting-started/testing#organizing-your-tests"> See **Organizing Your Tests** for setup, Vitest projects, and TypeScript context. </read-more> # tsconfig.json > Learn how Nuxt manages TypeScript configuration across different parts of your project. Nuxt [automatically generates](https://nuxt.com/docs/4.x/guide/concepts/typescript#auto-generated-types) multiple TypeScript configuration files (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, `.nuxt/tsconfig.node.json` and `.nuxt/tsconfig.shared.json`) that include recommended basic TypeScript configuration for your project, references to [auto-imports](https://nuxt.com/docs/4.x/guide/concepts/auto-imports), [API route types](https://nuxt.com/docs/4.x/guide/concepts/server-engine#typed-api-routes), path aliases, and more. Your Nuxt project should include the following `tsconfig.json` file at the root of the project: ```json [tsconfig.json] { "files": [], "references": [ { "path": "./.nuxt/tsconfig.app.json" }, { "path": "./.nuxt/tsconfig.server.json" }, { "path": "./.nuxt/tsconfig.shared.json" }, { "path": "./.nuxt/tsconfig.node.json" } ] } ``` <warning> We do not recommend modifying the contents of this file directly, as doing so could overwrite important settings that Nuxt or other modules rely on. Instead, extend it via `nuxt.config.ts`. </warning> <read-more to="https://nuxt.com/docs/4.x/guide/concepts/typescript#project-references"> Read more about the different type contexts of a Nuxt project here. </read-more> ## Extending TypeScript Configuration You can customize the TypeScript configuration of your Nuxt project in the `nuxt.config.ts` file: set shared `compilerOptions` for every context at once with `typescript.tsConfig`, and override them for each context (`app`, `shared`, `node`, and `server`) individually. ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ typescript: { // shared compiler options for every generated tsconfig tsConfig: { compilerOptions: { // ... }, }, // customize tsconfig.app.json appTsConfig: { // ... }, // customize tsconfig.shared.json sharedTsConfig: { // ... }, // customize tsconfig.node.json nodeTsConfig: { // ... }, // customize tsconfig.server.json serverTsConfig: { // ... }, }, }) ``` <note> Most `compilerOptions` set in `typescript.tsConfig` are shared with every context, but a few are not. DOM- and Vue-specific options (such as `lib`, `jsx` and `jsxImportSource`) only make sense for your application code, so they are applied to `tsconfig.app.json` alone. Nuxt also manages `types`, `paths` and `noEmit` per context (the `node`, `shared` and `server` configs deliberately emit nothing and scan no ambient types), so setting these in `typescript.tsConfig` will not change them. Use the matching per-context option (`appTsConfig`, `nodeTsConfig`, `sharedTsConfig` or `serverTsConfig`) when you need to override them. </note> <note> `typescript.serverTsConfig` and `nitro.typescript.tsConfig` both extend `tsconfig.server.json` and are kept in sync, so setting either has the same effect. Prefer `typescript.serverTsConfig` to keep all four contexts in one place. </note> # B5001 No `compatibilityDate` is set in your Nuxt configuration. Nuxt uses this date to decide which behaviour defaults to apply, so your project stays stable across Nuxt and Nitro updates instead of silently picking up new defaults. ## Resolution Add `compatibilityDate` to your `nuxt.config`, using today's date so you opt in to the current defaults: ```ts export default defineNuxtConfig({ // use the current date, e.g. the day you add this line compatibilityDate: 'YYYY-MM-DD', }) ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/upgrade"> </read-more> # B5003 You have custom keys under `runtimeConfig.app`, a namespace Nuxt reserves for internal values (such as `baseURL` and `cdnURL`). Custom keys here can collide with Nuxt's own config. ## Resolution Move custom keys to `runtimeConfig.public` (exposed to the client) or to a top-level custom namespace (server-only): ```ts export default defineNuxtConfig({ runtimeConfig: { // instead of runtimeConfig.app.myKey public: { myKey: 'value', }, }, }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> # B5004 Nuxt found a standalone `vite.config` or `webpack.config` file next to your `nuxt.config`. Nuxt manages the bundler internally and ignores these files, so they are usually leftovers from a migration or a copied non-Nuxt project. ## Resolution Move the configuration into `nuxt.config` under the matching key, then delete the external file: - `vite.config`: use the `vite` key - `webpack.config`: use the `webpack` key - `nitro.config`: use the `nitro` key - `postcss.config`: use the `postcss` key ```ts export default defineNuxtConfig({ vite: { // your Vite config here }, }) ``` <read-more to="https://nuxt.com/docs/4.x/getting-started/configuration"> </read-more> # E1001 A composable that needs the Nuxt instance (`useNuxtApp()`, `useRoute()`, `useFetch()`, โ€ฆ) ran outside a plugin, Nuxt hook, route middleware, or Vue `setup()`. The most common trigger is calling it inside an async callback (`setTimeout`, `.then()`, after an `await`) where the context has been lost. ## Resolution Call the composable synchronously at the top of `setup()` / a plugin / middleware and reuse the captured result later. For server-side async work, wrap the call with `nuxtApp.runWithContext()`. <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> # E1006 `onPrehydrate()` ran without being transformed by the Nuxt build pipeline. It needs compile-time processing and only works on the server, so this happens when it is called from a dependency that Nuxt does not transpile. ## Resolution Add the offending library to `build.transpile` in `nuxt.config.ts` so the build pipeline can process its `onPrehydrate()` call. <read-more to="https://nuxt.com/docs/4.x/api/composables/on-prehydrate"> </read-more> # E1007 A compile-time macro such as `definePageMeta()` executed at runtime. These helpers are transformed away by the Nuxt build and must never run dynamically. Usually this means the macro was called inside a composable or a non-page component instead of directly in a page. ## Resolution Call the macro only at the top level of a page component's `<script setup>`. It cannot be used inside composables, conditionals, or non-page components. <read-more to="https://nuxt.com/docs/4.x/api/utils/define-page-meta"> </read-more> # E2001 `navigateTo()` received an external URL but no `{ external: true }` option. Nuxt requires explicit opt-in for external navigation to avoid accidentally redirecting users away from your app. ## Resolution ```ts navigateTo('https://example.com', { external: true }) ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/navigate-to"> </read-more> # E2002 `navigateTo()` was given a URL using a dangerous protocol (`javascript:`, `data:`, `vbscript:`). Nuxt blocks these to prevent XSS. This almost always means unsanitized user input reached `navigateTo()`. ## Resolution Validate and sanitize user-provided URLs before navigating. Allow only `http:`, `https:`, or relative paths. <read-more to="https://nuxt.com/docs/4.x/api/utils/navigate-to"> </read-more> # E2003 `abortNavigation()` was called outside a route middleware. It can only cancel navigation from within a middleware handler, so calling it from a component, plugin, composable, or a callback that lost the middleware context fails. ## Resolution Move the `abortNavigation()` call into the body of a `defineNuxtRouteMiddleware()` handler. <read-more to="https://nuxt.com/docs/4.x/api/utils/abort-navigation"> </read-more> # E2004 A route middleware was referenced (usually via `definePageMeta({ middleware: [...] })`) but no middleware with that name exists. Common causes are a typo in the name, or a middleware file that was renamed or deleted without updating its references. ## Resolution Make sure the name matches a file in `middleware/`. Names are derived from the filename: `middleware/auth.ts` is referenced as `auth`. <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/middleware"> </read-more> # E2005 `useRoute()` was called inside a route middleware (directly or via another composable). At that point the target route is not yet resolved, so `useRoute()` can return unexpected values; middleware receives the `to` and `from` routes as arguments instead. ## Resolution ```ts export default defineNuxtRouteMiddleware((to, from) => { // use `to` / `from` instead of useRoute() }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/middleware"> </read-more> # E2007 `setPageLayout()` was called from a component's `setup()` during SSR. On the server the layout must be decided before the component renders, so changing it here produces incorrect SSR output. ## Resolution Set the layout from route middleware, or statically with `definePageMeta({ layout: '...' })`. <read-more to="https://nuxt.com/docs/4.x/api/utils/set-page-layout"> </read-more> # E3001 The URL passed to `useFetch()` starts with `//`. A protocol-relative URL like this resolves to an external host, which is almost never intended and is rejected to avoid leaking requests to a different origin. ## Resolution Use an absolute URL with an explicit protocol, or a relative path: ```ts useFetch('/api/data') useFetch('https://api.example.com/data') ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-fetch"> </read-more> # E3008 `useAsyncData()` was called without a valid key. The first argument must be a non-empty string so Nuxt can cache and deduplicate the request across components. ## Resolution ```ts const { data } = useAsyncData('users', () => $fetch('/api/users')) ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-async-data"> </read-more> # E3009 `useAsyncData()` was called without a handler function. The handler is the function that performs the fetch and returns the data, so it cannot be omitted or of another type. ## Resolution ```ts const { data } = useAsyncData('users', () => $fetch('/api/users')) ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-async-data"> </read-more> # E4012 Nuxt could not parse the response returned when rendering a server component (island). This usually means the server component endpoint returned something other than the expected island payload, such as an error page or malformed HTML. ## Resolution Check the server component for errors that would prevent it from rendering, and confirm the island endpoint returns a valid response. Inspect the network response for the island request to see what the server actually returned. <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/components#server-components"> </read-more> # E4016 The current route matches a nested page, but the parent page component does not render `<NuxtPage />`. Vue Router can only display a child page inside its parent's `<NuxtPage />` outlet, so the child page is never shown. This happens with a directory structure like the following, when `parent.vue` does not contain `<NuxtPage />`: ```bash [Directory Structure] -| pages/ ---| parent/ ------| child.vue ---| parent.vue ``` ## Resolution Add `<NuxtPage />` to the parent page component so the child route can render inside it. If you did not intend to create a nested route, restructure your `pages/` directory so the page no longer has child routes. <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/pages#nested-routes"> </read-more> # E5001 Code that relies on the app manifest ran while `experimental.appManifest` is disabled. The manifest powers features such as route rules matching and prerendered-payload detection on the client, so it must be enabled for them to work. ## Resolution Enable the app manifest in your `nuxt.config`: ```ts export default defineNuxtConfig({ experimental: { appManifest: true, }, }) ``` <read-more to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#appmanifest"> </read-more> # E6001 A head composable such as `useHead()` was called without an active Unhead instance. This happens when it runs outside a valid Nuxt context, for example in a detached async callback after the Nuxt instance is no longer available. ## Resolution Call head composables synchronously inside a component `setup()`, a Nuxt plugin, or route middleware. If you need them after an `await`, capture the Nuxt context first: ```ts const nuxtApp = useNuxtApp() await someAsyncWork() nuxtApp.runWithContext(() => useHead({ title: 'Late title' })) ``` # E7001 A payload URL was requested with a full URL that includes a hostname. Payloads are always served from the same origin as the app, so a URL with a hostname points outside the app and is rejected. ## Resolution Pass a relative path instead of a full URL: ```ts loadPayload('/some-page') ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload"> </read-more> # E7007 `useState()` received a non-function initial value. The initializer must be a function so that it only runs once, on the server, and its result can be serialized into the payload for hydration. ## Resolution ```ts const counter = useState('counter', () => 0) ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-state"> </read-more> # E7008 `callOnce()` received a non-function `fn` argument. The value to run once must be a function so Nuxt can execute it a single time and skip it on subsequent calls. ## Resolution ```ts await callOnce('setup', () => { // runs once }) ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/call-once"> </read-more> # E7009 `useState()` was called with a key that is not a string. The key identifies the shared state across the app and in the hydration payload, so it must be a non-empty string. ## Resolution ```ts const counter = useState('counter', () => 0) ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-state"> </read-more> # E7010 `callOnce()` was called with a key that is not a string. The key is used to track whether the function has already run, so it must be a non-empty string. ## Resolution ```ts await callOnce('setup', () => { // runs once }) ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/call-once"> </read-more> # E8007 With `features.noScripts: 'production'` (the default when `noScripts` is enabled), scripts are only stripped from rendered HTML in production builds. In development the page still ships JavaScript, so behaviour that depends on it (lazy hydration strategies, `nuxt-client` components inside server components) appears to work in dev and then silently breaks after deployment. This warning is emitted during development when a rendered route uses one of these features. ## Resolution Either remove the client-side dependency from the affected route, or scope script stripping to the routes that are genuinely static using the `noScripts` route rule (which applies in development too, so any breakage is visible immediately): ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/static/**': { noScripts: true }, }, }) ``` Alternatively, set `features.noScripts: 'all'` to strip scripts in development as well, making the production behaviour observable in dev. <read-more to="https://nuxt.com/docs/4.x/guide/going-further/features#noscripts"> </read-more> # Layers > This example shows how to use the extends key in `nuxt.config.ts`. <code-explorer default-value="nuxt.config.ts" path="examples/advanced/config-extends"> </code-explorer> <browser src="https://config-extends.example.nuxt.space"> </browser> This example shows how to use the `extends` key in `nuxt.config.ts` to use the `base/` directory as a base Nuxt application, and use its components, composables or config and override them if necessary. <read-more to="https://nuxt.com/docs/4.x/getting-started/layers"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/config-extends) # Error Handling > This example shows how to handle errors in different contexts: pages, plugins, components and middleware. <code-explorer default-value="error.vue" path="examples/advanced/error-handling"> </code-explorer> <browser src="https://error-handling.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/error-handling) # JSX / TSX > This example shows how to use JSX syntax with typescript in Nuxt pages and components. <code-explorer default-value="app.vue" path="examples/advanced/jsx"> </code-explorer> <browser src="https://jsx.example.nuxt.space"> </browser> <read-more icon="i-simple-icons-vuedotjs" target="_blank" to="https://vuejs.org/guide/extras/render-function.html#jsx-tsx"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/jsx) # Locale > This example shows how to define a locale composable to handle the application's locale, both server and client side. <code-explorer default-value="composables/locale.ts" path="examples/advanced/locale"> </code-explorer> <browser src="https://locale.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/locale) # Module Extend Pages > This example defines a new `test` page using `extendPages` within a module. <code-explorer default-value="modules/pages/index.ts" path="examples/advanced/module-extend-pages"> </code-explorer> <browser src="https://module-extend-pages.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/guide/modules"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/module-extend-pages) # Teleport > This example shows how to use the <Teleport> with client-side and server-side rendering. <code-explorer default-value="app.vue" path="examples/advanced/teleport"> </code-explorer> <browser src="https://teleport.example.nuxt.space"> </browser> Vue 3 provides the [`<Teleport>` component](https://vuejs.org/guide/built-ins/teleport.html) which allows content to be rendered elsewhere in the DOM, outside of the Vue application. This example shows how to use the `<Teleport>` with client-side and server-side rendering. <read-more to="https://nuxt.com/docs/4.x/api/components/teleports"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/teleport) # Testing > This example shows how to test your Nuxt application. <code-explorer default-value="tests/basic.test.ts" path="examples/advanced/testing"> </code-explorer> <browser src="https://testing.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/testing"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/testing) # useCookie > This example shows how to use the useCookie API to persist small amounts of data that both client and server can use. <code-explorer default-value="app.vue" path="examples/advanced/use-cookie"> </code-explorer> <browser src="https://use-cookie.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-cookie"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/use-cookie) # Use Custom Fetch Composable > This example shows a convenient wrapper for the useFetch composable from nuxt. It allows you to customize the fetch request with default values and user authentication token. <code-explorer default-value="plugins/customFetch.ts" path="examples/advanced/use-custom-fetch-composable"> </code-explorer> <browser src="https://use-custom-fetch-composable.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/guide/recipes/custom-usefetch"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/use-custom-fetch-composable) # WASM > This example demonstrates the server-side support of WebAssembly in Nuxt. <code-explorer default-value="app.vue" path="examples/experimental/wasm"> </code-explorer> <browser src="https://wasm.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/experimental/wasm) # Auto Imports > This example demonstrates the auto-imports feature in Nuxt. <code-explorer default-value="app.vue" path="examples/features/auto-imports"> </code-explorer> <browser src="https://auto-imports.example.nuxt.space"> </browser> Example of the auto-imports feature in Nuxt with: - Vue components in the `components/` directory are auto-imported and can be used directly in your templates. - Vue composables in the `composables/` directory are auto-imported and can be used directly in your templates and JS/TS files. - JS/TS variables and functions in the `utils/` directory are auto-imported and can be used directly in your templates and JS/TS files. <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/components"> </read-more> <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/composables"> </read-more> <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/utils"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/auto-imports) # Data Fetching > This example demonstrates data fetching with Nuxt using built-in composables and API routes. <code-explorer default-value="pages/index.vue" path="examples/features/data-fetching"> </code-explorer> <browser src="https://data-fetching.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/data-fetching"> </read-more> <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/server"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/data-fetching) # Layouts > This example shows how to define default and custom layouts. <code-explorer default-value="pages/index.vue" path="examples/features/layouts"> </code-explorer> <browser src="https://layouts.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/views#layouts"> </read-more> <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/layouts"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/layouts) # Meta Tags > This example shows how to use the Nuxt helpers and composables for SEO and meta management. <code-explorer default-value="pages/index.vue" path="examples/features/meta-tags"> </code-explorer> <browser src="https://meta-tags.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/meta-tags) # State Management > This example shows how to use the `useState` composable to create a reactive and SSR-friendly shared state across components. <code-explorer default-value="app.vue" path="examples/features/state-management"> </code-explorer> <browser src="https://state-management.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/state-management"> </read-more> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-state"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/state-management) # Hello World > A minimal Nuxt application only requires the `app.vue` and `nuxt.config.js` files. <code-explorer default-value="app.vue" path="examples/hello-world"> </code-explorer> <browser src="https://hello-world.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/getting-started/introduction"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/hello-world) # Middleware > This example shows how to add route middleware with the middleware/ directory or with a plugin, and how to use them globally or per page. <code-explorer default-value="middleware/redirect-me.ts" path="examples/routing/middleware"> </code-explorer> <browser src="https://middleware.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/middleware"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/middleware) # Pages > This example shows how to use the pages/ directory to create application routes. <code-explorer default-value="pages/index.vue" path="examples/routing/pages"> </code-explorer> <browser src="https://pages.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/4.x/guide/directory-structure/pages"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/pages) # Universal Router > This example demonstrates Nuxt universal routing utilities without depending on `pages/` and `vue-router`. <code-explorer default-value="plugins/add.ts" path="examples/routing/universal-router"> </code-explorer> <browser src="https://universal-router.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/universal-router) # Assets > Nuxt offers two options for your assets. Nuxt uses two directories to handle assets like stylesheets, fonts or images. - The [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory content is served at the server root as-is. - The [`app/assets/`](https://nuxt.com/docs/4.x/directory-structure/app/assets) directory contains by convention every asset that you want the build tool (Vite or webpack) to process. ## Public Directory The [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory is used as a public server for static assets publicly available at a defined URL of your application. You can get a file in the [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory from your application's code or from a browser by the root URL `/`. ### Example For example, referencing an image file in the `public/img/` directory, available at the static URL `/img/nuxt.png`: ```vue [app/app.vue] <template> <img src="/img/nuxt.png" alt="Discover Nuxt" > </template> ``` ## Assets Directory Nuxt uses [Vite](https://vite.dev/guide/assets) (default) or [webpack](https://webpack.js.org/guides/asset-management/) to build and bundle your application. The main function of these build tools is to process JavaScript files, but they can be extended through [plugins](https://vite.dev/plugins/) (for Vite) or [loaders](https://webpack.js.org/loaders/) (for webpack) to process other kinds of assets, like stylesheets, fonts or SVGs. This step transforms the original file, mainly for performance or caching purposes (such as stylesheet minification or browser cache invalidation). By convention, Nuxt uses the [`app/assets/`](https://nuxt.com/docs/4.x/directory-structure/app/assets) directory to store these files but there is no auto-scan functionality for this directory, and you can use any other name for it. In your application's code, you can reference a file located in the [`app/assets/`](https://nuxt.com/docs/4.x/directory-structure/app/assets) directory by using the `~/assets/` path. ### Example For example, referencing an image file that will be processed if a build tool is configured to handle this file extension: ```vue [app/app.vue] <template> <img src="~/assets/img/nuxt.png" alt="Discover Nuxt" > </template> ``` <note> Nuxt won't serve files in the [`app/assets/`](https://nuxt.com/docs/4.x/directory-structure/app/assets) directory at a static URL like `/assets/my-file.png`. If you need a static URL, use the [`public/`](https://nuxt.com/docs/4.x/getting-started/assets#public-directory) directory. </note> ### Static vs. Dynamic `src` When an `src` is a static string literal in your template, the build tool rewrites it into a runtime helper that resolves the final URL. A public path such as `/img/nuxt.png` is wrapped so that your [`app.baseURL`](https://nuxt.com/docs/4.x/api/nuxt-config#baseurl) is applied when the page renders, and a bundled path such as `~/assets/img/nuxt.png` additionally becomes an import that resolves to the hashed output file. ```vue <template> <!-- Static paths are rewritten: app.baseURL is applied at runtime, and the bundled file is hashed. --> <img src="/img/nuxt.png"> <img src="~/assets/img/nuxt.png"> </template> ``` Because `app.baseURL` is applied at runtime, a static public path works even when the base URL is only known at deploy time (for example set via `NUXT_APP_BASE_URL`), and it works whether or not the file is processed by the build. This resolution only happens for literal paths the build tool can see. A bound `:src` whose value is assembled at runtime is opaque to the build tool, so none of that rewriting happens. The string is used exactly as written: ```vue <template> <!-- This does not work: the path is built at runtime, so Vite never sees it as an import. --> <img :src="`~/assets/img/${name}.png`"> </template> ``` A runtime-built public path like `/img/${name}.png` is therefore **not** prefixed with [`app.baseURL`](https://nuxt.com/docs/4.x/api/nuxt-config#baseurl). If your application is deployed below the origin root, prefix it yourself with [`useRuntimeConfig().app.baseURL`](https://nuxt.com/docs/4.x/api/composables/use-runtime-config) (for example via [`joinURL`](https://github.com/unjs/ufo#joinurl)). The sections below cover how to handle each case when the path is only known at runtime. #### Public Assets If the files do not need to be processed or hashed, put them in the [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory and reference them by URL: ```vue [app/app.vue] <script setup lang="ts"> const props = defineProps<{ name: string }>() const imageUrl = computed(() => `/img/${props.name}.png`) </script> <template> <img :src="imageUrl" :alt="props.name" > </template> ``` Files in `public/` keep their original filenames. #### Bundled Assets with Vite The approaches below are specific to Vite, Nuxt's default builder. When the possible files are known, list their imports explicitly: ```vue [app/app.vue] <script setup lang="ts"> const props = defineProps<{ theme: 'light' | 'dark' }>() const logos = { light: () => import('./assets/img/logo-light.png?url'), dark: () => import('./assets/img/logo-dark.png?url'), } const logoUrl = (await logos[props.theme]()).default </script> <template> <img :src="logoUrl" alt="Nuxt" > </template> ``` Each import has a literal path, so Vite can find both files at build time while loading only the selected module at runtime. When many files share a directory and extension, use a [variable dynamic import](https://vite.dev/guide/features.html#dynamic-import) instead of listing every file: ```ts async function getImageUrl (name: string) { const image = await import(`./assets/img/${name}.png?url`) return image.default } ``` Only the filename can be dynamic in this example. Keeping the directory and extension in the import lets Vite find the possible files at build time. For a broader pattern or an explicit map of available files, use [`import.meta.glob`](https://vite.dev/guide/features.html#glob-import): ```ts const images = import.meta.glob<string>('./assets/img/*.{png,jpg,svg}', { query: '?url', import: 'default', }) async function getImageUrl (name: string) { const load = images[`./assets/img/${name}.png`] if (!load) { throw new Error(`Unknown image: ${name}`) } return await load() } ``` Glob imports are lazy by default. Add `eager: true` if the URLs must be available synchronously: ```ts const images = import.meta.glob<string>('./assets/img/*.{png,jpg,svg}', { query: '?url', import: 'default', eager: true, }) ``` Every matching asset is still included in the build output. Lazy imports load each match on demand, while an eager glob loads all matches up front and can increase the initial JavaScript size or inline small assets. <warning> Await a lazy import before using its URL in server-rendered markup. Vite's [`new URL(..., import.meta.url)` pattern](https://vite.dev/guide/assets.html#new-url-url-import-meta-url) does not work with SSR. </warning> # Configuration > Nuxt is configured with sensible defaults to make you productive. By default, Nuxt is configured to cover most use cases. The [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file can override or extend this default configuration. ## Nuxt Configuration The [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file is located at the root of a Nuxt project and can override or extend the application's behavior. A minimal configuration file exports the `defineNuxtConfig` function containing an object with your configuration. The `defineNuxtConfig` helper is globally available without import. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ // My Nuxt config }) ``` This file will often be mentioned in the documentation, for example to add custom scripts, register modules or change rendering modes. <read-more to="https://nuxt.com/docs/4.x/api/configuration/nuxt-config"> Every option is described in the **Configuration Reference**. </read-more> <note> You don't have to use TypeScript to build an application with Nuxt. However, it is strongly recommended to use the `.ts` extension for the `nuxt.config` file. This way you can benefit from hints in your IDE to avoid typos and mistakes while editing your configuration. </note> ### Environment Overrides You can configure fully typed, per-environment overrides in your nuxt.config ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ $production: { routeRules: { '/**': { isr: true }, }, }, $development: { // }, $env: { staging: { // }, }, }) ``` To select an environment when running a Nuxt CLI command, simply pass the name to the `--envName` flag, like so: `nuxt build --envName staging`. To learn more about the mechanism behind these overrides, please refer to the `c12` documentation on [environment-specific configuration](https://github.com/unjs/c12?tab=readme-ov-file#environment-specific-configuration). <video-accordion title="Watch a video from Alexander Lichter about the env-aware nuxt.config.ts" video-id="DFZI2iVCrNc"> </video-accordion> <note> If you're authoring layers, you can also use the `$meta` key to provide metadata that you or the consumers of your layer might use. </note> ### Environment Variables and Private Tokens The `runtimeConfig` API exposes values like environment variables to the rest of your application. By default, these keys are only available server-side. The keys within `runtimeConfig.public` and `runtimeConfig.app` (which is used by Nuxt internally) are also available client-side. Those values should be defined in `nuxt.config` and can be overridden using environment variables. <code-group> ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ runtimeConfig: { // The private keys which are only available server-side apiSecret: '123', // Keys within public are also exposed client-side public: { apiBase: '/api', }, }, }) ``` ```ini [.env] # This will override the value of apiSecret NUXT_API_SECRET=api_secret_token ``` </code-group> These variables are exposed to the rest of your application using the [`useRuntimeConfig()`](https://nuxt.com/docs/4.x/api/composables/use-runtime-config) composable. ```vue [app/pages/index.vue] <script setup lang="ts"> const runtimeConfig = useRuntimeConfig() </script> ``` <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> ## App Configuration The `app.config.ts` file, located in the source directory (by default `app/`), is used to expose public variables that can be determined at build time. Contrary to the `runtimeConfig` option, these cannot be overridden using environment variables. A minimal configuration file exports the `defineAppConfig` function containing an object with your configuration. The `defineAppConfig` helper is globally available without import. ```ts [app/app.config.ts] export default defineAppConfig({ title: 'Hello Nuxt', theme: { dark: true, colors: { primary: '#ff0000', }, }, }) ``` These variables are exposed to the rest of your application using the [`useAppConfig`](https://nuxt.com/docs/4.x/api/composables/use-app-config) composable. ```vue [app/pages/index.vue] <script setup lang="ts"> const appConfig = useAppConfig() </script> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/app-config"> </read-more> ## `runtimeConfig` vs. `app.config` As stated above, `runtimeConfig` and `app.config` are both used to expose variables to the rest of your application. To determine whether you should use one or the other, here are some guidelines: - `runtimeConfig`: Private or public tokens that need to be specified after build using environment variables. - `app.config`: Public tokens that are determined at build time, website configuration such as theme variant, title and any project config that are not sensitive. <table> <thead> <tr> <th> Feature </th> <th> <code> runtimeConfig </code> </th> <th> <code> app.config </code> </th> </tr> </thead> <tbody> <tr> <td> Client-side </td> <td> Hydrated </td> <td> Bundled </td> </tr> <tr> <td> Environment variables </td> <td> โœ… Yes </td> <td> โŒ No </td> </tr> <tr> <td> Reactive </td> <td> โœ… Yes </td> <td> โœ… Yes </td> </tr> <tr> <td> Types support </td> <td> โœ… Partial </td> <td> โœ… Yes </td> </tr> <tr> <td> Configuration per request </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> <tr> <td> Hot module replacement </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> <tr> <td> Non-primitive JS types </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> </tbody> </table> ## External Configuration Files Nuxt uses [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file as the single source of truth for configurations and skips reading external configuration files. During the course of building your project, you may have a need to configure those. The following table highlights common configurations and, where applicable, how they can be configured with Nuxt. <table> <thead> <tr> <th> Name </th> <th> Config File </th> <th> How To Configure </th> </tr> </thead> <tbody> <tr> <td> <a href="https://nitro.build" rel="nofollow"> Nitro </a> </td> <td> <del> <code> nitro.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/4.x/api/nuxt-config#nitro"> <code> nitro </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://postcss.org" rel="nofollow"> PostCSS </a> </td> <td> <del> <code> postcss.config.js </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/4.x/api/nuxt-config#postcss"> <code> postcss </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://vite.dev" rel="nofollow"> Vite </a> </td> <td> <del> <code> vite.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/4.x/api/nuxt-config#vite"> <code> vite </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://webpack.js.org" rel="nofollow"> webpack </a> </td> <td> <del> <code> webpack.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/4.x/api/nuxt-config#webpack-1"> <code> webpack </code> </a> key in <code> nuxt.config </code> </td> </tr> </tbody> </table> Here is a list of other common config files: <table> <thead> <tr> <th> Name </th> <th> Config File </th> <th> How To Configure </th> </tr> </thead> <tbody> <tr> <td> <a href="https://www.typescriptlang.org" rel="nofollow"> TypeScript </a> </td> <td> <code> tsconfig.json </code> </td> <td> <a href="https://nuxt.com/docs/4.x/directory-structure/tsconfig"> More Info </a> </td> </tr> <tr> <td> <a href="https://eslint.org" rel="nofollow"> ESLint </a> </td> <td> <code> eslint.config.js </code> </td> <td> <a href="https://eslint.org/docs/latest/use/configure/configuration-files" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://prettier.io" rel="nofollow"> Prettier </a> </td> <td> <code> prettier.config.js </code> </td> <td> <a href="https://prettier.io/docs/configuration.html" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://stylelint.io" rel="nofollow"> Stylelint </a> </td> <td> <code> stylelint.config.js </code> </td> <td> <a href="https://stylelint.io/user-guide/configure/" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://tailwindcss.com" rel="nofollow"> TailwindCSS </a> </td> <td> <code> tailwind.config.js </code> </td> <td> <a href="https://tailwindcss.nuxtjs.org/tailwindcss/configuration/" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://vitest.dev" rel="nofollow"> Vitest </a> </td> <td> <code> vitest.config.ts </code> </td> <td> <a href="https://vitest.dev/config/" rel="nofollow"> More Info </a> </td> </tr> </tbody> </table> ## Vue Configuration ### With Vite If you need to pass options to `@vitejs/plugin-vue` or `@vitejs/plugin-vue-jsx`, you can do this in your `nuxt.config` file. - `vite.vue` for `@vitejs/plugin-vue`. Check [available options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue). - `vite.vueJsx` for `@vitejs/plugin-vue-jsx`. Check [available options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ vite: { vue: { customElement: true, }, vueJsx: { mergeProps: true, }, }, }) ``` <read-more to="https://nuxt.com/docs/4.x/api/configuration/nuxt-config#vue"> </read-more> ### With webpack If you use webpack and need to configure `vue-loader`, you can do this using `webpack.loaders.vue` key inside your `nuxt.config` file. The available options are [defined here](https://github.com/vuejs/vue-loader/blob/main/src/index.ts#L32-L62). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ webpack: { loaders: { vue: { hotReload: true, }, }, }, }) ``` <read-more to="https://nuxt.com/docs/4.x/api/configuration/nuxt-config#loaders"> </read-more> ### Enabling Experimental Vue Features You may need to enable experimental features in Vue, such as `propsDestructure`. Nuxt provides an easy way to do that in `nuxt.config.ts`, no matter which builder you are using: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ vue: { propsDestructure: true, }, }) ``` #### experimental `reactivityTransform` migration from Vue 3.4 and Nuxt 3.9 Since Nuxt 3.9 and Vue 3.4, `reactivityTransform` has been moved from Vue to Vue Macros which has a [Nuxt integration](https://vue-macros.dev/guide/nuxt-integration.html). <read-more to="https://nuxt.com/docs/4.x/api/configuration/nuxt-config#vue-1"> </read-more> # Data Fetching > Nuxt provides composables to handle data fetching within your application. Nuxt comes with two composables and a built-in library to perform data-fetching in browser or server environments: `useFetch`, [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and `$fetch`. In a nutshell: - [`$fetch`](https://nuxt.com/docs/4.x/api/utils/dollarfetch) is the simplest way to make a network request. - [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) is a wrapper around `$fetch` that fetches data only once in [universal rendering](https://nuxt.com/docs/4.x/guide/concepts/rendering#universal-rendering). - [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) is similar to `useFetch` but offers more fine-grained control. Both `useFetch` and `useAsyncData` share a common set of options and patterns that we will detail in the last sections. ## The Need for `useFetch` and `useAsyncData` Nuxt is a framework which can run isomorphic (or universal) code in both server and client environments. If the [`$fetch` function](https://nuxt.com/docs/4.x/api/utils/dollarfetch) is used to perform data fetching in the setup function of a Vue component, this may cause data to be fetched twice, once on the server (to render the HTML) and once again on the client (when the HTML is hydrated). This can cause hydration issues, increase the time to interactivity and cause unpredictable behavior. The [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) composables solve this problem by ensuring that if an API call is made on the server, the data is forwarded to the client in the payload. The payload is a JavaScript object accessible through [`useNuxtApp().payload`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload). It is used on the client to avoid refetching the same data when the code is executed in the browser [during hydration](https://nuxt.com/docs/4.x/guide/concepts/rendering#universal-rendering). <tip> Use the [Nuxt DevTools](https://devtools.nuxt.com) to inspect this data in the **Payload tab**. </tip> ```vue [app/app.vue] <script setup lang="ts"> const { data } = await useFetch('/api/data') async function handleFormSubmit () { const res = await $fetch('/api/submit', { method: 'POST', body: { // My form data }, }) } </script> <template> <div v-if="data == undefined"> No data </div> <div v-else> <form @submit="handleFormSubmit"> <!-- form input tags --> </form> </div> </template> ``` In the example above, `useFetch` would make sure that the request would occur on the server and is properly forwarded to the browser. `$fetch` has no such mechanism and is a better option to use when the request is solely made from the browser. ### Suspense Nuxt uses Vue's [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense) component under the hood to prevent navigation before every async data is available to the view. The data fetching composables can help you leverage this feature and use what suits best on a per-call basis. <note> You can add the [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/4.x/api/components/nuxt-loading-indicator) to add a progress bar between page navigations. </note> ### A note on `await` Examples in this documentation usually `await` calls to `useFetch` and `useAsyncData`, but this is not always required. The `await` does **not** change the server-rendered HTML. During server rendering, Nuxt waits for the request to resolve before serializing the page either way (`<Suspense>`, and `onServerPrefetch` under the hood), so the fully populated result is always sent to the browser. What the `await` *does* change is what happens next in your own `<script setup>`, and how client-side navigation behaves: - **With await**, execution pauses until the data is ready, so any code after the call can rely on `data` already being populated. On client-side navigation, this blocks navigation until the data resolves: the user stays on the current page (optionally with a [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/4.x/api/components/nuxt-loading-indicator)) and then lands on a fully populated page. This is the default behaviour. - **Without await**, execution continues immediately while the request runs in the background, so `data` starts as its default value and fills in once the request resolves. On client-side navigation, this means navigation happens immediately and you are responsible for handling the loading and error states, typically via the returned `status` and `error` refs. Neither approach is universally better; the right choice depends on the experience you want for that route. Not awaiting has a similar user-visible effect to the [`lazy`](#lazy) option (navigation is not blocked and you handle loading state yourself), but the two are not identical: `lazy` is an explicit flag that defers the request until the component mounts, whereas simply not awaiting starts the request during setup. Prefer `lazy` (or [`useLazyFetch`](https://nuxt.com/docs/4.x/api/composables/use-lazy-fetch) / [`useLazyAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-lazy-async-data)) when you want non-blocking behaviour, since it makes the intent explicit. <warning> The `await` and `lazy` are independent, and on the client awaiting a `lazy` function won't have the effect you expect. If you `await` a `lazy` call (for example `await useLazyFetch(...)` or `await useFetch(..., { lazy: true })`), it still blocks server rendering as usual, but on **client-side navigation** the `await` resolves immediately without waiting for the request. `data` will still be at its default value right after the `await`, and you must handle the loading state via `status`. If you actually want the navigation to wait for the data, drop the `lazy` option rather than relying on `await`. </warning> ## `$fetch` Nuxt includes the [ofetch](https://github.com/unjs/ofetch) library, and is auto-imported as the `$fetch` alias globally across your application. ```vue [pages/todos.vue]twoslash <script setup lang="ts"> async function addTodo () { const todo = await $fetch('/api/todos', { method: 'POST', body: { // My todo data }, }) } </script> ``` <warning> Beware that using only `$fetch` will not provide [network calls de-duplication and navigation prevention](https://nuxt.com/docs/4.x/getting-started/data-fetching#the-need-for-usefetch-and-useasyncdata). <br /> It is recommended to use `$fetch` for client-side interactions (event-based) or combined with [`useAsyncData`](https://nuxt.com/docs/4.x/getting-started/data-fetching#useasyncdata) when fetching the initial component data. </warning> <read-more to="https://nuxt.com/docs/4.x/api/utils/dollarfetch"> Read more about `$fetch`. </read-more> ### Pass Client Headers to the API When calling `useFetch` on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/4.x/api/composables/use-request-fetch) to proxy client headers and cookies (with the exception of headers not meant to be forwarded, like `host`). ```vue <script setup lang="ts"> const { data } = await useFetch('/api/echo') </script> ``` ```ts // /api/echo.ts export default defineEventHandler(event => parseCookies(event)) ``` Alternatively, the example below shows how to use [`useRequestHeaders`](https://nuxt.com/docs/4.x/api/composables/use-request-headers) to access and send cookies to the API from a server-side request (originating on the client). Using an isomorphic `$fetch` call, we ensure that the API endpoint has access to the same `cookie` header originally sent by the user's browser. This is only necessary if you aren't using `useFetch`. ```vue <script setup lang="ts"> const headers = useRequestHeaders(['cookie']) async function getCurrentUser () { return await $fetch('/api/me', { headers }) } </script> ``` <tip> You can also use [`useRequestFetch`](https://nuxt.com/docs/4.x/api/composables/use-request-fetch) to proxy headers to the call automatically. </tip> <caution> Be very careful before proxying headers to an external API and just include headers that you need. Not all headers are safe to be bypassed and might introduce unwanted behavior. Here is a list of common headers that are NOT to be proxied: - `host`, `accept` - `content-length`, `content-md5`, `content-type` - `x-forwarded-host`, `x-forwarded-port`, `x-forwarded-proto` - `cf-connecting-ip`, `cf-ray` </caution> ## `useFetch` The [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) composable uses `$fetch` under-the-hood to make SSR-safe network calls in the setup function. ```vue [app/app.vue]twoslash <script setup lang="ts"> const { data: count } = await useFetch('/api/count') </script> <template> <p>Page visits: {{ count }}</p> </template> ``` This composable is a wrapper around the [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) composable and `$fetch` utility. <video-accordion title="Watch a video from Alexander Lichter to avoid using useFetch the wrong way" video-id="njsGVmcWviY"> </video-accordion> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-fetch"> </read-more> <link-example to="https://nuxt.com/docs/4.x/examples/features/data-fetching"> </link-example> ## `useAsyncData` The `useAsyncData` composable is responsible for wrapping async logic and returning the result once it is resolved. <tip> `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => event.$fetch(url))`. <br /> It's developer experience sugar for the most common use case. (You can find out more about `event.fetch` at [`useRequestFetch`](https://nuxt.com/docs/4.x/api/composables/use-request-fetch).) </tip> <video-accordion title="Watch a video from Alexander Lichter to dig deeper into the difference between useFetch and useAsyncData" video-id="0X-aOpSGabA"> </video-accordion> There are some cases when using the [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) composable is not appropriate, for example when a CMS or a third-party provides their own query layer. In this case, you can use [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) to wrap your calls and still keep the benefits provided by the composable. ```vue [app/pages/users.vue] <script setup lang="ts"> const { data, error } = await useAsyncData('users', () => myGetFunction('users')) // This is also possible: const { data, error } = await useAsyncData(() => myGetFunction('users')) </script> ``` <note> The first argument of [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) is a unique key used to cache the response of the second argument, the querying function. This key can be ignored by directly passing the querying function, the key will be auto-generated. <br /> <br /> Since the autogenerated key only takes into account the location where `useAsyncData` is invoked, it is recommended to always create your own key to avoid unwanted behavior, like when you are creating your own custom composable wrapping `useAsyncData`. <br /> <br /> Setting a key can be useful to share the same data between components using [`useNuxtData`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-data) or to [refresh specific data](https://nuxt.com/docs/4.x/api/utils/refresh-nuxt-data#refresh-specific-data). </note> ```vue [app/pages/users/[id].vue] <script setup lang="ts"> const { id } = useRoute().params const { data, error } = await useAsyncData(`user:${id}`, () => { return myGetFunction('users', { id }) }) </script> ``` The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results. ```vue <script setup lang="ts"> const { data: discounts, status } = await useAsyncData('cart-discount', async (_nuxtApp, { signal }) => { const [coupons, offers] = await Promise.all([ $fetch('/cart/coupons', { signal }), $fetch('/cart/offers', { signal }), ]) return { coupons, offers } }) // discounts.value.coupons // discounts.value.offers </script> ``` <note> `useAsyncData` is for fetching and caching data, not triggering side effects like calling Pinia actions, as this can cause unintended behavior such as repeated executions with nullish values. If you need to trigger side effects, use the [`callOnce`](https://nuxt.com/docs/4.x/api/utils/call-once) utility to do so. ```vue <script setup lang="ts"> const offersStore = useOffersStore() // you can't do this await useAsyncData(() => offersStore.getOffer(route.params.slug)) </script> ``` </note> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-async-data"> Read more about `useAsyncData`. </read-more> ## Return Values `useFetch` and `useAsyncData` have the same return values listed below. - `data`: the result of the asynchronous function that is passed in. - `refresh`/`execute`: a function that can be used to refresh the data returned by the `handler` function. - `clear`: a function that can be used to set `data` to `undefined` (or the value of `options.default()` if provided), set `error` to `undefined`, set `status` to `idle`, and mark any currently pending requests as cancelled. - `error`: an error object if the data fetching failed. - `status`: a string indicating the status of the data request (`"idle"`, `"pending"`, `"success"`, `"error"`). <note> `data`, `error` and `status` are Vue refs accessible with `.value` in `<script setup>` </note> By default, Nuxt waits until a `refresh` is finished before it can be executed again. <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain undefined within `<script setup>`. </note> ## Options [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) return the same object type and accept a common set of options as their last argument. They can help you control the composables behavior, such as navigation blocking, caching or execution. ### Lazy By default, data fetching composables will wait for the resolution of their asynchronous function before navigating to a new page by using Vue's Suspense. This feature can be ignored on client-side navigation with the `lazy` option. In that case, you will have to manually handle loading state using the `status` value. ```vue [app/app.vue]twoslash <script setup lang="ts"> const { status, data: posts } = useFetch('/api/posts', { lazy: true, }) </script> <template> <!-- you will need to handle a loading state --> <div v-if="status === 'pending'"> Loading ... </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` You can alternatively use [`useLazyFetch`](https://nuxt.com/docs/4.x/api/composables/use-lazy-fetch) and `useLazyAsyncData` as convenient methods to perform the same. ```vuetwoslash <script setup lang="ts"> const { status, data: posts } = useLazyFetch('/api/posts') </script> ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-lazy-fetch"> Read more about `useLazyFetch`. </read-more> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-lazy-async-data"> Read more about `useLazyAsyncData`. </read-more> <video-accordion title="Watch a video from Vue School on blocking vs. non-blocking (lazy) requests" video-id="1022000555" platform="vimeo"> </video-accordion> ### Client-only fetching By default, data fetching composables will perform their asynchronous function on both client and server environments. Set the `server` option to `false` to only perform the call on the client-side. On initial load, the data will not be fetched before hydration is complete so you have to handle a pending state, though on subsequent client-side navigation the data will be awaited before loading the page. Combined with the `lazy` option, this can be useful for data that is not needed on the first render (for example, non-SEO sensitive data). ```tstwoslash /* This call is performed before hydration */ const articles = await useFetch('/api/article') /* This call will only be performed on the client */ const { status, data: comments } = useFetch('/api/comments', { lazy: true, server: false, }) ``` The `useFetch` composable is meant to be invoked in setup method or called directly at the top level of a function in lifecycle hooks, otherwise you should use [`$fetch` method](https://nuxt.com/docs/4.x/getting-started/data-fetching#fetch). ### Minimize payload size The `pick` option helps you to minimize the payload size stored in your HTML document by only selecting the fields that you want returned from the composables. ```vue <script setup lang="ts"> /* only pick the fields used in your template */ const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'], }) </script> <template> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </template> ``` If you need more control or map over several objects, you can use the `transform` function to alter the result of the query. ```ts const { data: mountains } = await useFetch('/api/mountains', { transform: (mountains) => { return mountains.map(mountain => ({ title: mountain.title, description: mountain.description })) }, }) ``` <note> Both `pick` and `transform` don't prevent the unwanted data from being fetched initially. But they will prevent unwanted data from being added to the payload transferred from server to client. </note> <video-accordion title="Watch a video from Vue School on minimizing payload size" video-id="1026410430" platform="vimeo"> </video-accordion> ### Caching and refetching #### Keys [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) use keys to prevent refetching the same data. - [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) generates a key from the URL, the fetch options and the location of the call in your source code. This means two `useFetch` calls with the same URL in different components have **different** keys and will each perform their own request. To share the same data between multiple components, provide the same explicit `key` in the `options` object passed as a last argument. - [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) uses its first argument as a key if it is a string. If the first argument is the handler function that performs the query, then a key that is unique to the location of the `useAsyncData` call in your source code will be generated for you. <tip> To get the cached data by key, you can use [`useNuxtData`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-data) </tip> <video-accordion title="Watch a video from Vue School on caching data with the key option" video-id="1026410044" platform="vimeo"> </video-accordion> #### Shared State and Option Consistency When multiple components use the same key with `useAsyncData` or `useFetch`, they will share the same `data`, `error` and `status` refs. This ensures consistency across components but requires some options to be consistent. The following options **must be consistent** across all calls with the same key: - `handler` function - `deep` option - `transform` function - `pick` array - `getCachedData` function - `default` value ```ts // โŒ This will trigger a development warning const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true }) ``` The following options **can safely differ** without triggering warnings: - `server` - `lazy` - `immediate` - `dedupe` - `watch` ```ts // โœ… This is allowed const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false }) ``` If you need independent instances, use different keys: ```ts // These are completely independent instances const { data: users1 } = useAsyncData('users-1', (_nuxtApp, { signal }) => $fetch('/api/users', { signal })) const { data: users2 } = useAsyncData('users-2', (_nuxtApp, { signal }) => $fetch('/api/users', { signal })) ``` #### Reactive Keys You can use computed refs, plain refs or getter functions as keys, allowing for dynamic data fetching that automatically updates when dependencies change: ```ts // Using a computed property as a key const userId = ref('123') const { data: user } = useAsyncData( computed(() => `user-${userId.value}`), () => fetchUser(userId.value), ) // When userId changes, the data will be automatically refetched // and the old data will be cleaned up if no other components use it userId.value = '456' ``` #### Refresh and execute If you want to fetch or refresh data manually, use the `execute` or `refresh` function provided by the composables. ```vuetwoslash <script setup lang="ts"> const { data, error, execute, refresh } = await useFetch('/api/users') </script> <template> <div> <p>{{ data }}</p> <button @click="() => refresh()"> Refresh data </button> </div> </template> ``` The `execute` function is an alias for `refresh` that works in exactly the same way but is more semantic for cases when the fetch is [not immediate](https://nuxt.com/docs/4.x/getting-started/data-fetching#not-immediate). <tip> To globally refetch or invalidate cached data, see [`clearNuxtData`](https://nuxt.com/docs/4.x/api/utils/clear-nuxt-data) and [`refreshNuxtData`](https://nuxt.com/docs/4.x/api/utils/refresh-nuxt-data). </tip> #### Clear If you want to clear the data provided, for whatever reason, without needing to know the specific key to pass to `clearNuxtData`, you can use the `clear` function provided by the composables. ```vuetwoslash <script setup lang="ts"> const { data, clear } = await useFetch('/api/users') const route = useRoute() watch(() => route.path, (path) => { if (path === '/') { clear() } }) </script> ``` #### Watch To re-run your fetching function each time other reactive values in your application change, use the `watch` option. You can use it for one or multiple *watchable* elements. ```vuetwoslash <script setup lang="ts"> const id = ref(1) const { data, error, refresh } = await useFetch('/api/users', { /* Changing the id will trigger a refetch */ watch: [id], }) </script> ``` Note that **watching a reactive value won't change the URL fetched**. For example, this will keep fetching the same initial ID of the user because the URL is constructed at the moment the function is invoked. ```vue <script setup lang="ts"> const id = ref(1) const { data, error, refresh } = await useFetch(`/api/users/${id.value}`, { watch: [id], }) </script> ``` If you need to change the URL based on a reactive value, you may want to use a [computed URL](https://nuxt.com/docs/4.x/getting-started/data-fetching#computed-url) instead. When reactive fetch options are provided, they'll be automatically watched and trigger refetches. In some cases, it can be useful to opt-out of this behavior by specifying `watch: false`. ```ts const id = ref(1) // Won't automatically refetch when id changes const { data, execute } = await useFetch('/api/users', { query: { id }, // id is watched by default watch: false, // disables automatic watching of id }) // doesn't trigger refetch id.value = 2 ``` #### Computed URL Sometimes you may need to compute a URL from reactive values, and refresh the data each time these change. Instead of juggling your way around, you can attach each param as a reactive value. Nuxt will automatically use the reactive value and re-fetch each time it changes. ```vue <script setup lang="ts"> const id = ref(null) const { data, status } = useLazyFetch('/api/user', { query: { user_id: id, }, }) </script> ``` In the case of more complex URL construction, you may use a callback as a [computed getter](https://vuejs.org/guide/essentials/computed) that returns the URL string. Every time a dependency changes, the data will be fetched using the newly constructed URL. Combine this with [not-immediate](https://nuxt.com/docs/4.x/getting-started/data-fetching#not-immediate), and you can wait until the reactive element changes before fetching. ```vue <script setup lang="ts"> const id = ref(null) const { data, status } = useLazyFetch(() => `/api/users/${id.value}`, { immediate: false, }) </script> <template> <div> <!-- disable the input while fetching --> <input v-model="id" type="number" :disabled="status === 'pending'" > <div v-if="status === 'idle'"> Type a user ID </div> <div v-else-if="status === 'pending'"> Loading ... </div> <div v-else> {{ data }} </div> </div> </template> ``` If you need to force a refresh when other reactive values change, you can also [watch other values](https://nuxt.com/docs/4.x/getting-started/data-fetching#watch). ### Not immediate The `useFetch` composable will start fetching data the moment it is invoked. You may prevent this by setting `immediate: false`, for example, to wait for user interaction. With that, you will need both the `status` to handle the fetch lifecycle, and `execute` to start the data fetch. ```vue <script setup lang="ts"> const { data, error, execute, status } = await useLazyFetch('/api/comments', { immediate: false, }) </script> <template> <div v-if="status === 'idle'"> <button @click="execute"> Get data </button> </div> <div v-else-if="status === 'pending'"> Loading comments... </div> <div v-else> {{ data }} </div> </template> ``` For finer control, the `status` variable can be: - `idle` when the fetch hasn't started - `pending` when a fetch has started but not yet completed - `error` when the fetch fails - `success` when the fetch is completed successfully ## Passing Headers and Cookies When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. Normally, during server-side-rendering, due to security considerations, the `$fetch` wouldn't include the user's browser cookies, nor pass on cookies from the fetch response. However, when calling `useFetch` with a relative URL on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/4.x/api/composables/use-request-fetch) to proxy headers and cookies (with the exception of headers not meant to be forwarded, like `host`). ### Pass Cookies From Server-side API Calls on SSR Response If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself. ```ts [app/composables/fetch.ts] import { appendResponseHeader } from 'h3' import type { H3Event } from 'h3' export const fetchWithCookie = async (event: H3Event, url: string) => { /* Get the response from the server endpoint */ const res = await $fetch.raw(url) /* Get the cookies from the response */ const cookies = res.headers.getSetCookie() /* Attach each cookie to our incoming Request */ for (const cookie of cookies) { appendResponseHeader(event, 'set-cookie', cookie) } /* Return the data of the response */ return res._data } ``` ```vue <script setup lang="ts"> // This composable will automatically pass cookies to the client const event = useRequestEvent() const { data: result } = await useAsyncData(() => fetchWithCookie(event!, '/api/with-cookie')) onMounted(() => console.log(document.cookie)) </script> ``` ## Options API Support Nuxt provides a way to perform `asyncData` fetching within the Options API. You must wrap your component definition within `defineNuxtComponent` for this to work. ```vue <script> export default defineNuxtComponent({ /* Use the fetchKey option to provide a unique key */ fetchKey: 'hello', async asyncData () { return { hello: await $fetch('/api/hello'), } }, }) </script> ``` <note> Using `<script setup>` or `<script setup lang="ts">` are the recommended way of declaring Vue components in Nuxt. </note> <read-more to="https://nuxt.com/docs/4.x/api/utils/define-nuxt-component"> </read-more> ## Serializing Data From Server to Client When using `useAsyncData` and `useLazyAsyncData` to transfer data fetched on server to the client (as well as anything else that utilizes [the Nuxt payload](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload)), the payload is serialized with [`devalue`](https://github.com/sveltejs/devalue). This allows us to transfer not just basic JSON but also to serialize and revive/deserialize more advanced kinds of data, such as regular expressions, Dates, Map and Set, `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError` - and more. It is also possible to define your own serializer/deserializer for types that are not supported by Nuxt. You can read more in the [`useNuxtApp`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload) docs. <note> Note that this *does not apply* to data passed from your server routes when fetched with `$fetch` or `useFetch` - see the next section for more information. </note> ## Serializing Data From API Routes When fetching data from the `server` directory, the response is serialized using `JSON.stringify`. However, since serialization is limited to only JavaScript primitive types, Nuxt does its best to convert the return type of `$fetch` and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) to match the actual value. <read-more to="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description" icon="i-simple-icons-mdnwebdocs" target="_blank"> Learn more about `JSON.stringify` limitations. </read-more> ### Example ```ts [server/api/foo.ts] export default defineEventHandler(() => { return new Date() }) ``` ```vue [app/app.vue] <script setup lang="ts"> // Type of `data` is inferred as string even though we returned a Date object const { data } = await useFetch('/api/foo') </script> ``` ### Custom serializer function To customize the serialization behavior, you can define a `toJSON` function on your returned object. If you define a `toJSON` method, Nuxt will respect the return type of the function and will not try to convert the types. ```ts [server/api/bar.ts] export default defineEventHandler(() => { const data = { createdAt: new Date(), toJSON () { return { createdAt: { year: this.createdAt.getFullYear(), month: this.createdAt.getMonth(), day: this.createdAt.getDate(), }, } }, } return data }) ``` ```vue [app/app.vue] <script setup lang="ts"> // Type of `data` is inferred as // { // createdAt: { // year: number // month: number // day: number // } // } const { data } = await useFetch('/api/bar') </script> ``` ### Using an alternative serializer Nuxt does not currently support an alternative serializer to `JSON.stringify`. However, you can return your payload as a normal string and utilize the `toJSON` method to maintain type safety. In the example below, we use [superjson](https://github.com/flightcontrolhq/superjson) as our serializer. ```ts [server/api/superjson.ts] import superjson from 'superjson' export default defineEventHandler(() => { const data = { createdAt: new Date(), // Workaround the type conversion toJSON () { return this }, } // Serialize the output to string, using superjson return superjson.stringify(data) as unknown as typeof data }) ``` ```vue [app/app.vue] <script setup lang="ts"> import superjson from 'superjson' // `date` is inferred as { createdAt: Date } and you can safely use the Date object methods const { data } = await useFetch('/api/superjson', { transform: (value) => { return superjson.parse(value as unknown as string) }, }) </script> ``` ## Recipes ### Consuming SSE (Server-Sent Events) via POST request <tip> If you're consuming SSE via GET request, you can use [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) or VueUse composable [`useEventSource`](https://vueuse.org/core/useeventsource/). </tip> When consuming SSE via POST request, you need to handle the connection manually. Here's how you can do it: ```ts // Make a POST request to the SSE endpoint const response = await $fetch<ReadableStream>('/chats/ask-ai', { method: 'POST', body: { query: 'Hello AI, how are you?', }, responseType: 'stream', }) // Create a new ReadableStream from the response with TextDecoderStream to get the data as text const reader = response.pipeThrough(new TextDecoderStream()).getReader() // Read the chunk of data as we get it while (true) { const { value, done } = await reader.read() if (done) { break } console.log('Received:', value) } ``` ### Making parallel requests When requests don't rely on each other, you can make them in parallel with `Promise.all()` to boost performance. ```ts const { data } = await useAsyncData((_nuxtApp, { signal }) => { return Promise.all([ $fetch('/api/comments/', { signal }), $fetch('/api/author/12', { signal }), ]) }) const comments = computed(() => data.value?.[0]) const author = computed(() => data.value?.[1]) ``` <video-accordion title="Watch a video from Vue School on parallel data fetching" video-id="1024262536" platform="vimeo"> </video-accordion> # Deployment > Learn how to deploy your Nuxt application to any hosting provider. A Nuxt application can be deployed on a Node.js server, pre-rendered for static hosting, or deployed to serverless or edge (CDN) environments. <tip> If you are looking for a list of cloud providers that support Nuxt, see the [Hosting providers](https://nuxt.com/deploy) section. </tip> ## Node.js Server Discover the Node.js server preset with Nitro to deploy on any Node hosting. - **Default output format** if none is specified or auto-detected <br /> - Loads only the required chunks to render the request for optimal cold start timing <br /> - Useful for deploying Nuxt apps to any Node.js hosting ### Entry Point When running `nuxt build` with the Node server preset, the result will be an entry point that launches a ready-to-run Node server. ```bash [Terminal] NODE_ENV=production node .output/server/index.mjs ``` This will launch your production Nuxt server that listens on port 3000 by default. <important> Set `NODE_ENV=production` when running the server. Some dependencies (notably Vue Router) only strip development-only warnings when this is set, so leaving it unset can flood your logs with messages like `[Vue Router warn]: No match found for location with path โ€ฆ` on unmatched routes. </important> It respects the following runtime environment variables: - `NITRO_PORT` or `PORT` (defaults to `3000`) - `NITRO_HOST` or `HOST` (defaults to `'0.0.0.0'`) - `NITRO_SSL_CERT` and `NITRO_SSL_KEY` - if both are present, this will launch the server in HTTPS mode. In the vast majority of cases, this should not be used other than for testing, and the Nitro server should be run behind a reverse proxy like nginx or Cloudflare which terminates SSL. ### Serving the Same Build at Multiple Paths For a normal subpath deployment, set [`app.baseURL`](https://nuxt.com/docs/4.x/api/nuxt-config#baseurl) or the `NUXT_APP_BASE_URL` environment variable. If a reverse proxy deliberately exposes the same rendered page at multiple public paths, Nuxt may replace the browser URL with the path used for server rendering during hydration. You can keep the browser URL by removing the rendered path from the payload in a server plugin: ```ts [app/plugins/preserve-proxy-url.server.ts] export default defineNuxtPlugin((nuxtApp) => { delete nuxtApp.payload.path }) ``` Use this only when the proxy already handles assets and routing for every public path. Without the rendered path, Nuxt cannot correct a genuine mismatch between the requested URL and the server-rendered route. ### PM2 [PM2](https://pm2.keymetrics.io/) (Process Manager 2) is a fast and easy solution for hosting your Nuxt application on your server or VM. To use `pm2`, use an `ecosystem.config.cjs`: ```ts [ecosystem.config.cjs] module.exports = { apps: [ { name: 'NuxtAppName', port: '3000', exec_mode: 'cluster', instances: 'max', script: './.output/server/index.mjs', env: { NODE_ENV: 'production', }, }, ], } ``` ### Cluster Mode You can use `NITRO_PRESET=node_cluster` in order to leverage multi-process performance using Node.js [cluster](https://nodejs.org/dist/latest/docs/api/cluster.html) module. By default, the workload gets distributed to the workers with the round robin strategy. ### Learn More <read-more to="https://nitro.build/deploy/runtimes/node" title="the Nitro documentation for node-server preset"> </read-more> <video-accordion title="Watch Daniel Roe's short video on the topic" video-id="0x1H6K5yOfs"> </video-accordion> ## Static Hosting There are two ways to deploy a Nuxt application to any static hosting services: - Static site generation (SSG) with `ssr: true` pre-renders routes of your application at build time. (This is the default behavior when running `nuxt generate`.) It will also generate `/200.html` and `/404.html` single-page app fallback pages, which can render dynamic routes or 404 errors on the client (though you may need to configure this on your static host). See [What are 200.html and 404.html?](https://nuxt.com/docs/4.x/guide/concepts/rendering#what-are-200html-and-404html). - Alternatively, you can prerender your site with `ssr: false` (static single-page app). This will produce HTML pages with an empty `<div id="__nuxt"></div>` where your Vue app would normally be rendered. You will lose many SEO benefits of prerendering your site, so it is suggested instead to use [`<ClientOnly>`](https://nuxt.com/docs/4.x/api/components/client-only) to wrap the portions of your site that cannot be server rendered (if any). Prerendered routes also emit `_payload.json` files with the data captured at build time, which Nuxt reuses during client-side navigation. Read more about [payload extraction](https://nuxt.com/docs/4.x/getting-started/prerendering#payload-extraction). ### Static Fallback Pages Nuxt can generate two fallback pages for static hosts: - `200.html` is the single-page app fallback. Configure your host to serve it for unmatched routes when you want client-side routing to handle the URL. - `404.html` is the not-found fallback. Configure your host to serve it for routes that should keep a 404 status. `nuxt generate` and `nuxt build --prerender` generate these files automatically. If you use `nuxt build` with route rules to prerender selected routes, add the fallback page explicitly: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { '/200.html': { prerender: true }, }, }) ``` By default both fallbacks are empty shells. Set [`experimental.prerenderErrorPages`](https://nuxt.com/docs/4.x/guide/concepts/rendering#server-rendering-the-error-page) to server-render your `error.vue` into `404.html` at build time. Some providers use `200.html`, some use `404.html`, and some let you configure both. Check your hosting provider's static fallback or rewrite settings after deployment. <read-more to="https://nuxt.com/docs/4.x/getting-started/prerendering" title="Nuxt prerendering"> </read-more> ### Client-side Only Rendering If you don't want to pre-render your routes, another way of using static hosting is to set the `ssr` property to `false` in the `nuxt.config` file. The `nuxt generate` command will then output an `.output/public/index.html` entrypoint and JavaScript bundles like a classic client-side Vue.js application. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ ssr: false, }) ``` ## Hosting Providers Nuxt can be deployed to several cloud providers with a minimal amount of configuration: <read-more to="https://nuxt.com/deploy"> </read-more> ## Presets In addition to Node.js servers and static hosting services, a Nuxt project can be deployed with several well-tested presets and a minimal amount of configuration. You can explicitly set the desired preset in the [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { preset: 'node-server', }, }) ``` ... or use the `NITRO_PRESET` environment variable when running `nuxt build`: ```bash [Terminal] NITRO_PRESET=node-server nuxt build ``` ๐Ÿ”Ž Check [the Nitro deployment](https://nitro.build/deploy) for all possible deployment presets and providers. ## CDN Proxy In most cases, Nuxt can work with third-party content that is not generated or created by Nuxt itself. But sometimes such content can cause problems, especially Cloudflare's "Minification and Security Options". Accordingly, you should make sure that the following options are unchecked / disabled in Cloudflare. Otherwise, unnecessary re-rendering or hydration errors could impact your production application. 1. Speed > Settings > Content Optimization > Disable "Rocket Loaderโ„ข" 2. Security > Settings > Disable "Email Address Obfuscation" With these settings, you can be sure that Cloudflare won't inject scripts into your Nuxt application that may cause unwanted side effects. <tip> Their location on the Cloudflare dashboard sometimes changes so don't hesitate to look around. </tip> # Error Handling > Learn how to catch and handle errors in Nuxt. Nuxt is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts: - Errors during the Vue rendering lifecycle (SSR & CSR) - Server and client startup errors (SSR + CSR) - Errors during Nitro server lifecycle ([`server/`](https://nuxt.com/docs/4.x/directory-structure/server) directory) - Errors downloading JS chunks <tip> **SSR** stands for **Server-Side Rendering** and **CSR** for **Client-Side Rendering**. </tip> ## Vue Errors You can hook into Vue errors using [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured). In addition, Nuxt provides a [`vue:error`](https://nuxt.com/docs/4.x/api/advanced/hooks#app-hooks-runtime) hook that will be called if any errors propagate up to the top level. If you are using an error reporting framework, you can provide a global handler through [`vueApp.config.errorHandler`](https://vuejs.org/api/application#app-config-errorhandler). It will receive all Vue errors, even if they are handled. ```ts [plugins/error-handler.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.config.errorHandler = (error, instance, info) => { // handle error, e.g. report to a service } // Also possible nuxtApp.hook('vue:error', (error, instance, info) => { // handle error, e.g. report to a service }) }) ``` <note> Note that the `vue:error` hook is based on [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) lifecycle hook. </note> ## Startup Errors Nuxt will call the `app:error` hook if there are any errors in starting your Nuxt application. This includes: - running [Nuxt plugins](https://nuxt.com/docs/4.x/directory-structure/app/plugins) - processing `app:created` and `app:beforeMount` hooks - rendering your Vue app to HTML (during SSR) - mounting the app (on client-side), though you should handle this case with `onErrorCaptured` or with `vue:error` - processing the `app:mounted` hook ## Nitro Server Errors You cannot currently define a server-side handler for these errors, but can render an error page, see the [Render an Error Page](https://nuxt.com/docs/4.x/getting-started/error-handling#error-page) section. ## Errors with JS Chunks You might encounter chunk loading errors due to a network connectivity failure or a new deployment (which invalidates your old, hashed JS chunk URLs). Nuxt provides built-in support for handling chunk loading errors by performing a hard reload when a chunk fails to load during route navigation. You can change this behavior by setting `experimental.emitRouteChunkError` to `false` (to disable hooking into these errors at all) or to `manual` if you want to handle them yourself. If you want to handle chunk loading errors manually, you can check out the [automatic implementation](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/plugins/chunk-reload.client.ts) for ideas. ## Error Page <note> When Nuxt encounters a fatal error (any unhandled error on the server, or an error created with `fatal: true` on the client) it will either render a JSON response (if requested with `Accept: application/json` header) or trigger a full-screen error page. </note> An error may occur during the server lifecycle when: - processing your Nuxt plugins - rendering your Vue app into HTML - a server API route throws an error It can also occur on the client side when: - processing your Nuxt plugins - before mounting the application (`app:beforeMount` hook) - mounting your app if the error was not handled with `onErrorCaptured` or `vue:error` hook - the Vue app is initialized and mounted in browser (`app:mounted`). <read-more to="https://nuxt.com/docs/4.x/api/advanced/hooks"> Discover all the Nuxt lifecycle hooks. </read-more> Customize the default error page by adding `~/error.vue` in the source directory of your application, alongside `app.vue`. ```vue [error.vue] <script setup lang="ts"> import type { NuxtError } from '#app' const props = defineProps({ error: Object as () => NuxtError, }) const handleError = () => clearError({ redirect: '/' }) </script> <template> <div> <h2>{{ error?.status }}</h2> <button @click="handleError"> Clear errors </button> </div> </template> ``` <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/error"> Read more about `error.vue` and its uses. </read-more> For custom errors we highly recommend using `onErrorCaptured` composable that can be called in a page/component setup function or `vue:error` runtime nuxt hook that can be configured in a nuxt plugin. ```ts [plugins/error-handler.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('vue:error', (err) => { // }) }) ``` When you are ready to remove the error page, you can call the [`clearError`](https://nuxt.com/docs/4.x/api/utils/clear-error) helper function, which takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page). <important> Make sure to check before using anything dependent on Nuxt plugins, such as `$route` or `useRouter`, as if a plugin threw an error, then it won't be re-run until you clear the error. </important> <note> Rendering an error page is an entirely separate page load, meaning any registered middleware will run again. You can use [`useError`](https://nuxt.com/docs/4.x/getting-started/error-handling#useerror) in middleware to check if an error is being handled. </note> <note> If you are running on Node 16 and you set any cookies when rendering your error page, they will [overwrite cookies previously set](https://github.com/nuxt/nuxt/pull/20585). We recommend using a newer version of Node as Node 16 reached end-of-life in September 2023. </note> ## Error Utils ### `useError` ```ts [TS Signature] function useError (): Ref<Error | { url, status, statusText, message, description, data }> ``` This function will return the global Nuxt error that is being handled. <read-more to="https://nuxt.com/docs/4.x/api/composables/use-error"> Read more about `useError` composable. </read-more> ### `createError` ```ts [TS Signature] function createError (err: string | { cause, data, message, name, stack, status, statusText, fatal }): Error ``` Create an error object with additional metadata. You can pass a string to be set as the error `message` or an object containing error properties. It is usable in both the Vue and Server portions of your app, and is meant to be thrown. If you throw an error created with `createError`: - on server-side, it will trigger a full-screen error page which you can clear with [`clearError`](https://nuxt.com/docs/4.x/getting-started/error-handling#clearerror). - on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`. In development, an error `cause` is preserved and exposed to your error page so you can trace the original error; in production, causes are never included in error responses or the error page payload. ```vue [pages/movies/[slug].vue]twoslash <script setup lang="ts"> const route = useRoute() const { data } = await useFetch(`/api/movies/${route.params.slug}`) if (!data.value) { throw createError({ status: 404, statusText: 'Page Not Found', }) } </script> ``` <tip> The `statusText` property is intended for short, HTTP-compliant status texts (e.g., "Not Found"). It should only contain horizontal tabs, spaces, and visible ASCII characters (`[\t\u0020-\u007E]`). For any detailed descriptions, multi-line messages, or content with non-ASCII characters, you should always use the `message` property instead. </tip> <read-more to="https://nuxt.com/docs/4.x/api/utils/create-error"> Read more about `createError` util. </read-more> ### `showError` ```ts [TS Signature] function showError (err: string | Error | { status, statusText }): Error ``` You can call this function at any point on client-side, or (on server side) directly within middleware, plugins or `setup()` functions. It will trigger a full-screen error page which you can clear with [`clearError`](https://nuxt.com/docs/4.x/getting-started/error-handling#clearerror). It is recommended instead to use `throw createError()`. <read-more to="https://nuxt.com/docs/4.x/api/utils/show-error"> Read more about `showError` util. </read-more> ### `clearError` ```ts [TS Signature] function clearError (options?: { redirect?: string }): Promise<void> ``` This function will clear the currently handled Nuxt error. It also takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page). <read-more to="https://nuxt.com/docs/4.x/api/utils/clear-error"> Read more about `clearError` util. </read-more> ## Render Error in Component Nuxt also provides a [`<NuxtErrorBoundary>`](https://nuxt.com/docs/4.x/api/components/nuxt-error-boundary) component that allows you to handle client-side errors within your app, without replacing your entire site with an error page. This component is responsible for handling errors that occur within its default slot. On client-side, it will prevent the error from bubbling up to the top level, and will render the `#error` slot instead. The `#error` slot will receive `error` as a prop. (If you set `error = null` it will trigger re-rendering the default slot; you'll need to ensure that the error is fully resolved first or the error slot will just be rendered a second time.) <tip> If you navigate to another route, the error will be cleared automatically. </tip> ```vue [app/pages/index.vue] <template> <!-- some content --> <NuxtErrorBoundary @error="someErrorLogger"> <!-- You use the default slot to render your content --> <template #error="{ error, clearError }"> You can display the error locally here: {{ error }} <button @click="clearError"> This will clear the error. </button> </template> </NuxtErrorBoundary> </template> ``` <link-example to="https://nuxt.com/docs/4.x/examples/advanced/error-handling"> </link-example> # Installation > Get started with Nuxt quickly with our online starters or start locally with your terminal. ## Play Online If you just want to play around with Nuxt in your browser without setting up a project, you can use this online sandbox: <card-group> <card color="info" icon="i-simple-icons-stackblitz" target="_blank" title="Open on StackBlitz" to="https://stackblitz.com/github/nuxt/starter?file=app%2Fapp.vue"> Online playground with code editor and terminal access. </card> </card-group> ## New Project <steps> ### Prerequisites - **Node.js** - [`22.x`](https://nodejs.org/en) or newer (but we recommend the [active LTS release](https://github.com/nodejs/release#release-schedule)) - **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box. If you use another editor, such as Neovim, you can configure [Vue Language Server](https://github.com/vuejs/language-tools) support by following the [Vue Language Tools setup guides](https://github.com/vuejs/language-tools/wiki). - **Terminal** - In order to run Nuxt commands <callout> <collapsible name="additional notes for an optimal setup"> - **Node.js**: Make sure to use an even numbered version (22, 24, etc.) - **Neovim**: When configuring the Vue TypeScript plugin, make sure `location` points to the `@vue/language-server` package directory, not its binary. See the [Neovim setup guide](https://github.com/vuejs/language-tools/wiki/Neovim) for a working configuration. - **WSL**: If you are using Windows and experience slow HMR, you may want to try using [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install) which may solve some performance issues. - **Windows slow DNS resolution**: Instead of using `localhost:3000` for local dev server on Windows, use `127.0.0.1` for much faster loading experience on browsers. </collapsible> </callout> ### Create a New Project Open a terminal (if you're using [Visual Studio Code](https://code.visualstudio.com), you can open an [integrated terminal](https://code.visualstudio.com/docs/terminal/basics)) and use the following command to create a new starter project: <code-group sync="pm"> ```bash [npm] npm create nuxt@latest <project-name> ``` ```bash [yarn] yarn create nuxt <project-name> ``` ```bash [pnpm] pnpm create nuxt@latest <project-name> ``` ```bash [bun] bun create nuxt@latest <project-name> ``` ```bash [deno] deno -A npm:create-nuxt@latest <project-name> ``` </code-group> Open your project folder in Visual Studio Code: ```bash [Terminal] code <project-name> ``` Or change directory into your new project from your terminal: ```bash cd <project-name> ``` ### Development Server Now you'll be able to start your Nuxt app in development mode: <code-group sync="pm"> ```bash [npm] npm run dev -- -o ``` ```bash [yarn] yarn dev --open ``` ```bash [pnpm] pnpm dev -o ``` ```bash [bun] bun run dev -o # To use the Bun runtime during development # bun --bun run dev -o ``` ```bash [deno] deno run dev -o ``` </code-group> <tip icon="i-lucide-circle-check"> Well done! A browser window should automatically open for [http://localhost:3000](http://localhost:3000). </tip> <tip icon="i-lucide-container"> If you're using Docker or want a consistent development environment across machines, consider using a dev container. [Learn more about dev containers](https://nuxt.com/docs/4.x/guide/best-practices/devcontainers) </tip> </steps> ## Next Steps Now that you've created your Nuxt project, you are ready to start building your application. <read-more title="Nuxt Concepts" to="https://nuxt.com/docs/4.x/guide/concepts"> </read-more> # Introduction > Nuxt's goal is to make web development intuitive and performant with a great Developer Experience in mind. Nuxt is a free and [open-source framework](https://github.com/nuxt/nuxt) with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with [Vue.js](https://vuejs.org). We made everything so you can start writing `.vue` files from the beginning while enjoying hot module replacement in development and a performant application in production with server-side rendering by default. Nuxt has no vendor lock-in, allowing you to deploy your application [**everywhere, even on the edge**](https://nuxt.com/blog/nuxt-on-the-edge). <tip> If you want to play around with Nuxt in your browser, you can [try it out in one of our online sandboxes](https://nuxt.com/docs/4.x/getting-started/installation#play-online). </tip> ## Automation and Conventions Nuxt uses conventions and an opinionated directory structure to automate repetitive tasks and allow developers to focus on pushing features. The configuration file can still customize and override its default behaviors. - **File-based routing:** define routes based on the structure of your [`app/pages/` directory](https://nuxt.com/docs/4.x/directory-structure/app/pages). This can make it easier to organize your application and avoid the need for manual route configuration. - **Code splitting:** Nuxt automatically splits your code into smaller chunks, which can help reduce the initial load time of your application. - **Server-side rendering out of the box:** Nuxt comes with built-in SSR capabilities, so you don't have to set up a separate server yourself. - **Auto-imports:** write Vue composables and components in their respective directories and use them without having to import them with the benefits of tree-shaking and optimized JS bundles. - **Data-fetching utilities:** Nuxt provides composables to handle SSR-compatible data fetching as well as different strategies. - **Zero-config TypeScript support:** write type-safe code without having to learn TypeScript with our auto-generated types and `tsconfig.json`. - **Configured build tools:** we use [Vite](https://vite.dev) by default to support hot module replacement (HMR) in development and bundling your code for production with best-practices baked-in. Nuxt takes care of these and provides both frontend and backend functionality so you can focus on what matters: **creating your web application**. ## Server-Side Rendering Nuxt comes with built-in server-side rendering (SSR) capabilities by default, without having to configure a server yourself, which has many benefits for web applications: - **Faster initial page load time:** Nuxt sends a fully rendered HTML page to the browser, which can be displayed immediately. This can provide a faster perceived page load time and a better user experience (UX), especially on slower networks or devices. - **Improved SEO:** search engines can better index SSR pages because the HTML content is available immediately, rather than requiring JavaScript to render the content on the client-side. - **Better performance on low-powered devices:** it reduces the amount of JavaScript that needs to be downloaded and executed on the client-side, which can be beneficial for low-powered devices that may struggle with processing heavy JavaScript applications. - **Better accessibility:** the content is immediately available on the initial page load, improving accessibility for users who rely on screen readers or other assistive technologies. - **Easier caching:** pages can be cached on the server-side, which can further improve performance by reducing the amount of time it takes to generate and send the content to the client. Overall, server-side rendering can provide a faster and more efficient user experience, as well as improve search engine optimization and accessibility. As Nuxt is a versatile framework, it gives you the possibility to statically render your whole application to a static hosting with `nuxt generate`, disable SSR globally with the `ssr: false` option or leverage hybrid rendering by setting up the `routeRules` option. <read-more title="Nuxt rendering modes" to="https://nuxt.com/docs/4.x/guide/concepts/rendering"> </read-more> ### Server engine The Nuxt server engine, [Nitro](https://nitro.build/), unlocks new full-stack capabilities. In development, it uses Rollup and Node.js workers for your server code and context isolation. It also generates your server API by reading files from `server/api/` and server middleware from `server/middleware/`. In production, Nitro builds your app and server into one universal `.output` directory. This output is light: minified and removed from any Node.js modules (except polyfills). You can deploy this output on any system supporting JavaScript, from Node.js, Serverless, Workers, Edge-side rendering or purely static. <read-more title="Nuxt server engine" to="https://nuxt.com/docs/4.x/guide/concepts/server-engine"> </read-more> ### Production-ready A Nuxt application can be deployed on a Node or Deno server, pre-rendered to be hosted in static environments, or deployed to serverless and edge providers. <read-more title="Deployment section" to="https://nuxt.com/docs/4.x/getting-started/deployment"> </read-more> ### Modular A module system allows you to extend Nuxt with custom features and integrations with third-party services. <read-more title="Nuxt Modules Concept" to="https://nuxt.com/docs/4.x/guide/concepts/modules"> </read-more> ### Architecture Nuxt is composed of different [core packages](https://github.com/nuxt/nuxt/tree/main/packages): - Core engine: [nuxt](https://github.com/nuxt/nuxt/tree/main/packages/nuxt) - Bundlers: [@nuxt/vite-builder](https://github.com/nuxt/nuxt/tree/main/packages/vite), [@nuxt/rspack-builder](https://github.com/nuxt/nuxt/tree/main/packages/rspack) and [@nuxt/webpack-builder](https://github.com/nuxt/nuxt/tree/main/packages/webpack) - Command line interface: [@nuxt/cli](https://github.com/nuxt/cli) - Server engine: [nitro](https://github.com/nitrojs/nitro) - Development kit: [@nuxt/kit](https://github.com/nuxt/nuxt/tree/main/packages/kit) We recommend reading each concept to have a full vision of Nuxt capabilities and the scope of each package. # Layers > Nuxt provides a powerful system that allows you to extend the default files, configs, and much more. One of the core features of Nuxt is the layers and extending support. You can extend a default Nuxt application to reuse components, utils, and configuration. The layers structure is almost identical to a standard Nuxt application which makes them easy to author and maintain. ## Use Cases - Share reusable configuration presets across projects using `nuxt.config` and `app.config` - Create a component library using [`app/components/`](https://nuxt.com/docs/4.x/directory-structure/app/components) directory - Create utility and composable library using [`app/composables/`](https://nuxt.com/docs/4.x/directory-structure/app/composables) and [`app/utils/`](https://nuxt.com/docs/4.x/directory-structure/app/utils) directories - Create Nuxt module presets - Share standard setup across projects - Create Nuxt themes - Enhance code organization by implementing a modular architecture and support Domain-Driven Design (DDD) pattern in large scale projects. ## Usage By default, any layers within your project in the `~~/layers` directory will be automatically registered as layers in your project. <note> Layer auto-registration was introduced in Nuxt v3.12.0. </note> In addition, named layer aliases to the `srcDir` of each of these layers will automatically be created. For example, you will be able to access the `~~/layers/test` layer via `#layers/test`. <note> Named layer aliases were introduced in Nuxt v3.16.0. </note> In addition, you can extend from a layer by adding the [extends](https://nuxt.com/docs/4.x/api/nuxt-config#extends) property to your [`nuxt.config`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ // Extend from a local layer '../base', // Extend from an installed npm package '@my-themes/awesome', // Extend from a git repository 'github:my-themes/awesome#v1', ], }) ``` You can also pass an authentication token if you are extending from a private GitHub repository: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ // per layer configuration ['github:my-themes/private-awesome', { auth: process.env.GITHUB_TOKEN }], ], }) ``` <note> If a branch is not specified, this will clone `main`. </note> <tip> You can override a layer's alias by specifying it in the options next to the layer source. ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ [ 'github:my-themes/awesome', { meta: { name: 'my-awesome-theme', }, }, ], ], }) ``` </tip> Nuxt uses [unjs/c12](https://github.com/unjs/c12) and [unjs/giget](https://github.com/unjs/giget) for extending remote layers. Check the documentation for more information and all available options. ## Layer Priority When using multiple layers, it's important to understand the override order. Layers with **higher priority** override layers with lower priority when they define the same files or components. ### Priority Order From highest to lowest priority: 1. **Your project files** - always have the highest priority 2. **Auto-scanned layers** from `~~/layers` directory - sorted alphabetically (Z has higher priority than A) 3. **Layers in extends** config - first entry has higher priority than second ### Practical Example Consider multiple layers defining the same component: ```bash [Directory structure] layers/ 1.base/ app/components/Button.vue # Base button style 2.theme/ app/components/Button.vue # Themed button (overrides base) app/ components/Button.vue # Project button (overrides all layers) ``` In this case: - If only layers exist, `2.theme/Button.vue` is used (higher alphabetically) - If `app/components/Button.vue` exists in your project, it overrides all layers ### Controlling Priority You can prefix layer directories with numbers to control the order: ```bash [Directory structure] layers/ 1.base/ # Lowest priority 2.features/ # Medium priority 3.admin/ # Highest priority (among layers) ``` <tip> This pattern is useful for creating base layers with defaults that can be progressively overridden by more specific layers. </tip> Alternatively, you can control the order of your `~~/layers` directories from `nuxt.config` by referencing them in [`extends`](https://nuxt.com/docs/4.x/api/nuxt-config#extends), without renaming your directories. The entries are ordered like any other `extends` layer, with the **first entry having the highest priority**: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ '~~/layers/admin', // highest priority '~~/layers/features', '~~/layers/base', // lowest priority (among the listed layers) ], }) ``` Both `~~/...` (recommended) and `~/...` alias forms as well as relative paths (`./layers/admin`) are supported. Any layer in `~~/layers` that you do not list keeps its alphabetical auto-scan order, ranked below the layers you list in `extends`. ### When to Use Each - **~~/layers directory** - Use for local layers that are part of your project - **extends** - Use for external dependencies (npm packages, remote repositories) or layers outside your project directory ### Full Example with `extends` ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ '../base', // Local layer outside project '@my-themes/awesome', // NPM package 'github:my-themes/awesome#v1', // Remote repository ], }) ``` If you also have `~~/layers/custom`, the priority order is: - Your project files (highest) - `~~/layers/custom` - `../base` - `@my-themes/awesome` - `github:my-themes/awesome#v1` (lowest) <read-more to="https://nuxt.com/docs/4.x/directory-structure/layers"> Learn about the **layers/ directory** to organize and share reusable code, components, composables, and configurations across your Nuxt application. </read-more> <read-more to="https://nuxt.com/docs/4.x/guide/going-further/layers"> Read more about layers in the **Layer Author Guide**. </read-more> <video-accordion title="Watch a video from Learn Vue about Nuxt Layers" video-id="lnFCM7c9f7I"> </video-accordion> <video-accordion title="Watch a video from Alexander Lichter about Nuxt Layers" video-id="fr5yo3aVkfA"> </video-accordion> ## Example <card-group> <card icon="i-simple-icons-github" target="_blank" title="Content Wind" to="https://github.com/Atinux/content-wind"> A lightweight Nuxt theme to build a Markdown driven website. Powered by Nuxt Content, TailwindCSS and Iconify. </card> </card-group> # Prerendering > Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics Nuxt allows for select pages from your application to be rendered at build time. Nuxt will serve the prebuilt pages when requested instead of generating them on the fly. <read-more to="https://nuxt.com/docs/4.x/guide/concepts/rendering" title="Nuxt rendering modes"> </read-more> ## Crawl-based Pre-rendering Use the [`nuxt generate` command](https://nuxt.com/docs/4.x/api/commands/generate) to build and pre-render your application using the [Nitro](https://nuxt.com/docs/4.x/guide/concepts/server-engine) crawler. This command is similar to `nuxt build` with the `nitro.static` option set to `true`, or running `nuxt build --prerender`. This will build your site, stand up a nuxt instance, and, by default, prerender the root page `/` along with any of your site's pages it links to, any of your site's pages they link to, and so on. <code-group sync="pm"> ```bash [npm] npx nuxt generate ``` ```bash [yarn] yarn nuxt generate ``` ```bash [pnpm] pnpm nuxt generate ``` ```bash [bun] bun x nuxt generate ``` ```bash [deno] deno x nuxt generate ``` </code-group> You can now deploy the `.output/public` directory to any static hosting service or preview it locally with `npx serve .output/public`. Static and prerender builds also emit `200.html` and `404.html` SPA fallbacks. See [What are 200.html and 404.html?](https://nuxt.com/docs/4.x/guide/concepts/rendering#what-are-200html-and-404html). How the Nitro crawler works: 1. Load the HTML of your application's root route (`/`), any non-dynamic pages in your `~/pages` directory, and any other routes in the `nitro.prerender.routes` array. 2. Save the HTML and `_payload.json` to the `~/.output/public/` directory to be served statically. 3. Find all anchor tags (`<a href="...">`) in the HTML to navigate to other routes. 4. Repeat steps 1-3 for each anchor tag found until there are no more anchor tags to crawl. This is important to understand since pages that are not linked to a discoverable page can't be pre-rendered automatically. <read-more to="https://nuxt.com/docs/4.x/api/commands/generate#nuxt-generate"> Read more about the `nuxt generate` command. </read-more> ### Selective Pre-rendering You can manually specify routes that [Nitro](https://nuxt.com/docs/4.x/guide/concepts/server-engine) will fetch and pre-render during the build or ignore routes that you don't want to pre-render like `/dynamic` in the `nuxt.config` file: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { prerender: { routes: ['/user/1', '/user/2'], ignore: ['/dynamic'], }, }, }) ``` You can combine this with the `crawlLinks` option to pre-render a set of routes that the crawler can't discover like your `/sitemap.xml` or `/robots.txt`: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { prerender: { crawlLinks: true, routes: ['/sitemap.xml', '/robots.txt'], }, }, }) ``` Setting `nitro.prerender` to `true` is similar to `nitro.prerender.crawlLinks` to `true`. <read-more to="https://nitro.build/config#prerender"> Read more about pre-rendering in the Nitro documentation. </read-more> Lastly, you can manually configure this using routeRules. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Set prerender to true to configure it to be prerendered '/rss.xml': { prerender: true }, // Set it to false to configure it to be skipped for prerendering '/this-DOES-NOT-get-prerendered': { prerender: false }, // Everything under /blog gets prerendered as long as it // is linked to from another page '/blog/**': { prerender: true }, }, }) ``` <read-more to="https://nitro.build/config#routerules"> Read more about Nitro's `routeRules` configuration. </read-more> As a shorthand, you can also configure this in a page file using [`defineRouteRules`](https://nuxt.com/docs/4.x/api/utils/define-route-rules). <read-more to="https://nuxt.com/docs/4.x/guide/going-further/experimental-features#inlinerouterules" icon="i-lucide-star"> This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`. </read-more> ```vue [app/pages/index.vue] <script setup> // Or set at the page level defineRouteRules({ prerender: true, }) </script> <template> <div> <h1>Homepage</h1> <p>Pre-rendered at build time</p> </div> </template> ``` This will be translated to: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, }) ``` ## Payload Extraction When Nuxt renders a page on the server, it serializes the results of your data fetching ([`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch)) and app state ([`useState`](https://nuxt.com/docs/4.x/api/composables/use-state)) into a payload so the client can hydrate without re-fetching. With payload extraction enabled, Nuxt also writes this payload to a `_payload.json` file alongside the route's HTML: - Prerendered routes generate their payload file at build time. - Routes using [ISR or SWR caching](https://nuxt.com/docs/4.x/guide/concepts/rendering#hybrid-rendering) generate their payload file when the route is first rendered, even on a hybrid (non-static) site. During client-side navigation, Nuxt fetches the `_payload.json` file for the destination route and reuses the extracted data instead of running the data fetching again in the browser. You can control this behavior with the [`experimental.payloadExtraction`](https://nuxt.com/docs/4.x/api/nuxt-config#payloadextraction) option: - `'client'` - The payload is inlined in the HTML for the initial render and extracted to `_payload.json` files for client-side navigation. There is no extra network request on first load. - `true` - The payload is extracted to a separate `_payload.json` file for both the initial render and client-side navigation. The HTML is smaller and the payload file can be cached by a CDN, at the cost of one extra request on first load. - `false` - Payload extraction is disabled. The payload is always inlined in the HTML and no `_payload.json` files are generated. The default is `true`, or `'client'` when `compatibilityVersion: 5` is set. It is forced to `false` when `ssr: false` is set. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { payloadExtraction: 'client', }, }) ``` A few practical consequences to be aware of: - On a fully static site, client-side navigation reuses the data captured at build time, so data can be stale until the next rebuild. - For ISR/SWR routes, CDNs can cache payload files alongside the HTML, improving client-side navigation performance for cached routes. Dynamic routes like `pages/[...slug].vue` can opt in with glob patterns such as `'/**': { isr: true }`. - Payloads are serialized with [devalue](https://github.com/Rich-Harris/devalue), so custom types (such as class instances) need payload plugins with custom reducers and revivers to survive the round trip. <read-more to="https://nuxt.com/docs/4.x/api/composables/use-nuxt-app#payload" title="Payload reducers and revivers"> </read-more> ## Runtime Prerender Configuration ### `prerenderRoutes` You can use this at runtime within a [Nuxt context](https://nuxt.com/docs/4.x/guide/going-further/nuxt-app#the-nuxt-context) to add more routes for Nitro to prerender. ```vue [app/pages/index.vue] <script setup> prerenderRoutes(['/some/other/url']) prerenderRoutes('/api/content/article/my-article') </script> <template> <div> <h1>This will register other routes for prerendering when prerendered</h1> </div> </template> ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/prerender-routes" title="prerenderRoutes"> </read-more> ### `prerender:routes` Nuxt hook This is called before prerendering for additional routes to be registered. ```ts [nuxt.config.ts] export default defineNuxtConfig({ hooks: { async 'prerender:routes' (ctx) { const { pages } = await fetch('https://api.some-cms.com/pages').then( res => res.json(), ) for (const page of pages) { ctx.routes.add(`/${page.name}`) } }, }, }) ``` ### `prerender:generate` Nitro hook This is called for each route during prerendering. You can use this for fine-grained handling of each route that gets prerendered. ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { hooks: { 'prerender:generate' (route) { if (route.route?.includes('private')) { route.skip = true } }, }, }, }) ``` # Routing > Nuxt file-system routing creates a route for every file in the pages/ directory. One core feature of Nuxt is the file system router. Every Vue file inside the [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory creates a corresponding URL (or route) that displays the contents of the file. By using dynamic imports for each page, Nuxt leverages code-splitting to ship the minimum amount of JavaScript for the requested route. <note> Code-splitting is enabled by default and is recommended for most apps. If you have a specific reason to ship a single bundle instead, you can disable it in your [`nuxt.config`](https://nuxt.com/docs/4.x/api/nuxt-config): ```ts [nuxt.config.ts] export default defineNuxtConfig({ vite: { $client: { build: { rolldownOptions: { output: { codeSplitting: false, }, }, }, }, }, }) ``` This ships all JavaScript in a single file. It is rarely beneficial โ€” it usually increases the initial download, even on slow connections โ€” so only disable code-splitting if you have measured that it helps your case. </note> ## Pages Nuxt routing is based on [vue-router](https://router.vuejs.org) and generates the routes from every component created in the [`app/pages/` directory](https://nuxt.com/docs/4.x/directory-structure/app/pages), based on their filename. This file system routing uses naming conventions to create dynamic and nested routes: <code-group> ```bash [Directory Structure] -| pages/ ---| about.vue ---| index.vue ---| posts/ -----| [id].vue ``` ```json [Generated Router File] { "routes": [ { "path": "/about", "component": "pages/about.vue" }, { "path": "/", "component": "pages/index.vue" }, { "path": "/posts/:id", "component": "pages/posts/[id].vue" } ] } ``` </code-group> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/pages"> </read-more> ## Navigation The [`<NuxtLink>`](https://nuxt.com/docs/4.x/api/components/nuxt-link) component links pages between them. It renders an `<a>` tag with the `href` attribute set to the route of the page. Once the application is hydrated, page transitions are performed in JavaScript by updating the browser URL. This prevents full-page refreshes and allows for animated transitions. When a [`<NuxtLink>`](https://nuxt.com/docs/4.x/api/components/nuxt-link) enters the viewport on the client side, Nuxt will automatically prefetch components and payload (generated pages) of the linked pages ahead of time, resulting in faster navigation. ```vue [app/pages/index.vue] <template> <header> <nav> <ul> <li><NuxtLink to="/about">About</NuxtLink></li> <li><NuxtLink to="/posts/1">Post 1</NuxtLink></li> <li><NuxtLink to="/posts/2">Post 2</NuxtLink></li> </ul> </nav> </header> </template> ``` <read-more to="https://nuxt.com/docs/4.x/api/components/nuxt-link"> </read-more> ## Route Parameters The [`useRoute()`](https://nuxt.com/docs/4.x/api/composables/use-route) composable can be used in a `<script setup>` block or a `setup()` method of a Vue component to access the current route details. ```vue [pages/posts/[id].vue]twoslash <script setup lang="ts"> const route = useRoute() // When accessing /posts/1, route.params.id will be 1 console.log(route.params.id) </script> ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-route"> </read-more> ## Route Middleware Nuxt provides a customizable route middleware framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route. <note> Route middleware runs within the Vue part of your Nuxt app. Despite the similar name, they are completely different from server middleware, which are run in the Nitro server part of your app. </note> <important> Route middleware does **not** run for server routes (e.g. `/api/*`) or other server requests. To apply middleware to these requests, use [server middleware](https://nuxt.com/docs/4.x/directory-structure/server#server-middleware) instead. </important> There are three kinds of route middleware: 1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used. 2. Named route middleware, which are placed in the [`app/middleware/`](https://nuxt.com/docs/4.x/directory-structure/app/middleware) directory and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.) 3. Global route middleware, which are placed in the [`app/middleware/`](https://nuxt.com/docs/4.x/directory-structure/app/middleware) directory (with a `.global` suffix) and will be automatically run on every route change. Example of an `auth` middleware protecting the `/dashboard` page: <code-group> ```ts [middleware/auth.ts]twoslash function isAuthenticated (): boolean { return false } // ---cut--- export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (isAuthenticated() === false) { return navigateTo('/login') } }) ``` ```vue [pages/dashboard.vue]twoslash <script setup lang="ts"> definePageMeta({ middleware: 'auth', }) </script> <template> <h1>Welcome to your dashboard</h1> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/middleware"> </read-more> ## Route Validation Nuxt offers route validation via the `validate` property in [`definePageMeta()`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) in each page you wish to validate. The `validate` property accepts the `route` as an argument. You can return a boolean value to determine whether or not this is a valid route to be rendered with this page. If you return `false`, this will cause a 404 error. You can also directly return an object with `status`/`statusText` to customize the error returned. If you have a more complex use case, then you can use anonymous route middleware instead. ```vue [pages/posts/[id].vue]twoslash <script setup lang="ts"> definePageMeta({ validate (route) { // Check if the id is made up of digits return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id) }, }) </script> ``` <read-more to="https://nuxt.com/docs/4.x/api/utils/define-page-meta"> </read-more> # SEO and Meta > Improve your Nuxt app's SEO with powerful head config, composables and components. Nuxt head tag management is powered by [Unhead](https://unhead.unjs.io). It provides sensible defaults, several powerful composables and numerous configuration options to manage your app's head and SEO meta tags. ## Nuxt Config Providing an [`app.head`](https://nuxt.com/docs/4.x/api/nuxt-config#head) property in your [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) allows you to statically customize the head for your entire app. <important> This method does not allow you to provide reactive data. We recommend using `useHead()` in `app.vue`. </important> It's good practice to set tags here that won't change such as your site title default, language and favicon. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { title: 'Nuxt', // default fallback title htmlAttrs: { lang: 'en', }, link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, ], }, }, }) ``` <note> When you set [`app.cdnURL`](https://nuxt.com/docs/4.x/api/nuxt-config#cdnurl), assets in your [`public/`](https://nuxt.com/docs/4.x/directory-structure/public) directory (including `favicon.ico`) are served from that CDN. Nuxt resolves public assets against `cdnURL`, falling back to `app.baseURL`. However, a static `app.head` link such as `href: '/favicon.ico'` above is a literal path and is **not** resolved against `cdnURL`. To point the favicon at the resolved location, build the `href` from runtime config with [`useHead()`](https://nuxt.com/docs/4.x/api/composables/use-head) in `app.vue`: ```vue [app/app.vue] <script setup lang="ts"> const { cdnURL, baseURL } = useRuntimeConfig().app useHead({ link: [ { rel: 'icon', type: 'image/x-icon', href: `${cdnURL || baseURL}favicon.ico` }, ], }) </script> ``` </note> You can also provide any of the keys listed below in [Types](https://nuxt.com/docs/4.x/getting-started/seo-meta#types). ### Default Tags Some tags are provided by Nuxt by default to ensure your website works well out of the box. - `viewport`: `width=device-width, initial-scale=1` - `charset`: `utf-8` While most sites won't need to override these defaults, you can update them using the keyed shortcuts. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { // update Nuxt defaults charset: 'utf-16', viewport: 'width=device-width, initial-scale=1, maximum-scale=1', }, }, }) ``` ## `useHead` The [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable function supports reactive input, allowing you to manage your head tags programmatically. ```vue [app/app.vue]twoslash <script setup lang="ts"> useHead({ title: 'My App', meta: [ { name: 'description', content: 'My amazing site.' }, ], bodyAttrs: { class: 'test', }, script: [{ innerHTML: 'console.log(\'Hello world\')' }], }) </script> ``` We recommend taking a look at the [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) and [`useHeadSafe`](https://nuxt.com/docs/4.x/api/composables/use-head-safe) composables. ## `useSeoMeta` The [`useSeoMeta`](https://nuxt.com/docs/4.x/api/composables/use-seo-meta) composable lets you define your site's SEO meta tags as an object with full type safety. This helps you avoid typos and common mistakes, such as using `name` instead of `property`. ```vue [app/app.vue]twoslash <script setup lang="ts"> useSeoMeta({ title: 'My Amazing Site', ogTitle: 'My Amazing Site', description: 'This is my amazing site, let me tell you all about it.', ogDescription: 'This is my amazing site, let me tell you all about it.', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script> ``` <read-more to="https://nuxt.com/docs/4.x/api/composables/use-seo-meta"> </read-more> ## Components While using [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) is recommended in all cases, you may have a personal preference for defining your head tags in your template using components. Nuxt provides the following components for this purpose: `<Title>`, `<Base>`, `<NoScript>`, `<Style>`, `<Meta>`, `<Link>`, `<Body>`, `<Html>` and `<Head>`. Note the capitalization of these components ensuring we don't use invalid native HTML tags. `<Head>` and `<Body>` can accept nested meta tags (for aesthetic reasons) but this does not affect *where* the nested meta tags are rendered in the final HTML. ```vue [app/app.vue] <script setup lang="ts"> const title = ref('Hello World') </script> <template> <div> <Head> <Title>{{ title }}

{{ title }}

``` It's suggested to wrap your components in either a `` or `` component as tags will be deduped more intuitively. If you need to duplicate tags across client-server boundaries, apply a `key` attribute on the `` component. ## Types Below are the non-reactive types used for [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head), [`app.head`](https://nuxt.com/docs/4.x/api/nuxt-config#head) and components. ```ts [Types] interface MetaObject { title?: string titleTemplate?: string | ((title?: string) => string) templateParams?: Record> base?: Base link?: Link[] meta?: Meta[] style?: Style[] script?: Script[] noscript?: Noscript[] htmlAttrs?: HtmlAttributes bodyAttrs?: BodyAttributes } ``` See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types. ## Features ### Reactivity Reactivity is supported on all properties, by providing a computed value, a getter, or a reactive object. ```vue [useHead]twoslash ``` ```vue [useSeoMeta]twoslash ``` ```vue [app/Components] ``` ### Title Template You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site. For example, you could add the name of your site to the title of every page. The `titleTemplate` can either be a string, where `%s` is replaced with the title, or a function. If you want to use a function (for full control), then this cannot be set in your `nuxt.config`. It is recommended instead to set it within your `app.vue` file where it will apply to all pages on your site: ```vue [useHead]twoslash ``` Now, if you set the title to `My Page` with [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to 'Site Title'. ### Template Parameters You can use `templateParams` to provide additional placeholders in your `titleTemplate` besides the default `%s`. This allows for more dynamic title generation. ```vue [useHead]twoslash ``` ### Body Tags You can use the `tagPosition: 'bodyClose'` option on applicable tags to append them to the end of the `` tag. For example: ```vuetwoslash ``` ## Example ### With `definePageMeta` Within your [`app/pages/` directory](https://nuxt.com/docs/4.x/directory-structure/app/pages), you can use `definePageMeta` along with [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) to set metadata based on the current route. For example, you can first set the current page title (this is extracted at build time via a macro, so it can't be set dynamically): ```vue [pages/some-page.vue]twoslash ``` And then in your layout file, you might use the route's metadata you have previously set: ```vue [layouts/default.vue]twoslash ``` ### Dynamic Title In the example below, `titleTemplate` is set either as a string with the `%s` placeholder or as a `function`, which allows greater flexibility in setting the page title dynamically for each route of your Nuxt app: ```vue [app/app.vue]twoslash ``` ```vue [app/app.vue]twoslash ``` `nuxt.config` is also used as an alternative way of setting the page title. However, `nuxt.config` does not allow the page title to be dynamic. Therefore, it is recommended to use `titleTemplate` in the `app.vue` file to add a dynamic title, which is then applied to all routes of your Nuxt app. ### External CSS The example below shows how you might enable Google Fonts using either the `link` property of the [`useHead`](https://nuxt.com/docs/4.x/api/composables/use-head) composable or using the `` component: ```vue [useHead]twoslash ``` ```vue [app/Components] ``` # Server > Build full-stack applications with Nuxt's server framework. You can fetch data from your database or another server, create APIs, or even generate static server-side content like a sitemap or a RSS feed - all from a single codebase. ## Powered by Nitro ![Server engine](https://nuxt.com/assets/docs/getting-started/server.svg) Nuxt's server is [Nitro](https://github.com/nitrojs/nitro). It was originally created for Nuxt but is now part of [UnJS](https://unjs.io) and open for other frameworks - and can even be used on its own. Using Nitro gives Nuxt superpowers: - Full control of the server-side part of your app - Universal deployment on any provider (many zero-config) - Hybrid rendering Nitro is internally using [h3](https://github.com/h3js/h3), a minimal H(TTP) framework built for high performance and portability. ## Server Endpoints & Middleware You can easily manage the server-only part of your Nuxt app, from API endpoints to middleware. Both endpoints and middleware can be defined like this: ```ts [server/api/test.ts]twoslash export default defineEventHandler(async (event) => { // ... Do whatever you want here }) ``` And you can directly return `text`, `json`, `html` or even a `stream`. Out-of-the-box, it supports **hot module replacement** and **auto-import** like the other parts of your Nuxt application. ## Universal Deployment Nitro offers the ability to deploy your Nuxt app anywhere, from a bare metal server to the edge network, with a start time of just a few milliseconds. That's fast! There are more than 15 presets to build your Nuxt app for different cloud providers and servers, including: - [Cloudflare Workers](https://workers.cloudflare.com) - [Netlify Functions](https://www.netlify.com/platform/core/functions/) - [Vercel Cloud](https://vercel.com/home) Or for other runtimes: ## Hybrid Rendering Nitro has a powerful feature called `routeRules` which allows you to define a set of rules to customize how each route of your Nuxt app is rendered (and more). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Generated at build time for SEO purpose '/': { prerender: true }, // Cached for 1 hour '/api/*': { cache: { maxAge: 60 * 60 } }, // Redirection to avoid 404 '/old-page': { redirect: { to: '/new-page', statusCode: 302 }, }, // ... }, }) ``` Learn about all the route rules available to customize the rendering mode of your routes. In addition, there are some route rules (for example, `ssr`, `appMiddleware`, and `noScripts`) that are Nuxt specific to change the behavior when rendering your pages to HTML. Some route rules (`appMiddleware`, `redirect` and `prerender`) also affect client-side behavior. Nitro is used to build the app for server side rendering, as well as pre-rendering. # State Management > Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state. Nuxt provides the [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) composable to create a reactive and SSR-friendly shared state across components. [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) is an SSR-friendly [`ref`](https://vuejs.org/api/reactivity-core#ref) replacement. Its value will be preserved after server-side rendering (during client-side hydration) and shared across all components using a unique key. Because the data inside [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. Read more about `useState` composable. ## Best Practices Never define `const state = ref()` outside of ` ``` To globally invalidate cached state, see [`clearNuxtState`](https://nuxt.com/docs/4.x/api/utils/clear-nuxt-state) util. ### Initializing State Most of the time, you will want to initialize your state with data that resolves asynchronously. You can use the [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) component with the [`callOnce`](https://nuxt.com/docs/4.x/api/utils/call-once) util to do so. ```vue [app/app.vue]twoslash ``` This is similar to the [`nuxtServerInit` action](https://v2.nuxt.com/docs/directory-structure/store/#the-nuxtserverinit-action) in Nuxt 2, which allows filling the initial state of your store server-side before rendering the page. ### Usage with Pinia In this example, we leverage the [Pinia module](https://nuxt.com/modules/pinia) to create a global store and use it across the app. Make sure to install the Pinia module with `npx nuxt module add pinia` or follow the [module's installation steps](https://pinia.vuejs.org/ssr/nuxt.html#Installation). ```ts [app/stores/website.ts] export const useWebsiteStore = defineStore('websiteStore', { state: () => ({ name: '', description: '', }), actions: { async fetch () { const infos = await $fetch('https://api.nuxt.com/modules/pinia') this.name = infos.name this.description = infos.description }, }, }) ``` ```vue [app/app.vue] ``` ## Advanced Usage ```ts [app/composables/locale.ts] import type { Ref } from 'vue' export const useLocale = () => { return useState('locale', () => useDefaultLocale().value) } export const useDefaultLocale = (fallback = 'en-US') => { const locale = ref(fallback) if (import.meta.server) { const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0] if (reqLocale) { locale.value = reqLocale } } else if (import.meta.client) { const navLang = navigator.language if (navLang) { locale.value = navLang } } return locale } export const useLocales = () => { const locale = useLocale() const locales = ref([ 'en-US', 'en-GB', // ..., 'ja-JP-u-ca-japanese', ]) if (!locales.value.includes(locale.value)) { locales.value.unshift(locale.value) } return locales } export const useLocaleDate = (date: Ref | Date, locale = useLocale()) => { return computed(() => new Intl.DateTimeFormat(locale.value, { dateStyle: 'full' }).format(unref(date))) } ``` ```vue [app/app.vue] ``` ## Shared State By using [auto-imported composables](https://nuxt.com/docs/4.x/directory-structure/app/composables) we can define global type-safe states and import them across the app. ```ts [composables/states.ts]twoslash export const useColor = () => useState('color', () => 'pink') ``` ```vue [app/app.vue] ``` ## Using Third-Party Libraries Nuxt **used to rely** on the Vuex library to provide global state management. If you are migrating from Nuxt 2, please head to [the migration guide](https://nuxt.com/docs/4.x/migration/configuration#vuex). Nuxt is not opinionated about state management, so feel free to choose the right solution for your needs. There are multiple integrations with the most popular state management libraries, including: - [Pinia](https://nuxt.com/modules/pinia) - the official Vue recommendation - [Harlem](https://nuxt.com/modules/harlem) - immutable global state management - [XState](https://nuxt.com/modules/xstate) - state machine approach with tools for visualizing and testing your state logic # Styling > Learn how to style your Nuxt application. Nuxt is highly flexible when it comes to styling. Write your own styles, or reference local and external stylesheets. You can use CSS preprocessors, CSS frameworks, UI libraries and Nuxt modules to style your application. ## Local Stylesheets If you're writing local stylesheets, the natural place to put them is the [`app/assets/` directory](https://nuxt.com/docs/4.x/directory-structure/app/assets). ### Importing Within Components You can import stylesheets in your pages, layouts and components directly. You can use a JavaScript import, or a CSS [`@import` statement](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@import). ```vue [app/pages/index.vue] ``` The stylesheets will be inlined in the HTML rendered by Nuxt. ### The CSS Property You can also use the `css` property in the Nuxt configuration. The natural place for your stylesheets is the [`app/assets/` directory](https://nuxt.com/docs/4.x/directory-structure/app/assets). You can then reference its path and Nuxt will include it to all the pages of your application. ```ts [nuxt.config.ts] export default defineNuxtConfig({ css: ['~/assets/css/main.css'], }) ``` The stylesheets will be inlined in the HTML rendered by Nuxt, injected globally and present in all pages. ### Working With Fonts Place your local fonts files in your `public/` directory, for example in `public/fonts`. You can then reference them in your stylesheets using `url()`. ```css [assets/css/main.css] @font-face { font-family: 'FarAwayGalaxy'; src: url('/fonts/FarAwayGalaxy.woff') format('woff'); font-weight: normal; font-style: normal; font-display: swap; } ``` Then reference your fonts by name in your stylesheets, pages or components: ```vue ``` ### Stylesheets Distributed Through NPM You can also reference stylesheets that are distributed through npm. Let's use the popular `animate.css` library as an example. ```bash [npm] npm install animate.css ``` ```bash [yarn] yarn add animate.css ``` ```bash [pnpm] pnpm install animate.css ``` ```bash [bun] bun install animate.css ``` ```bash [deno] deno install npm:animate.css ``` Then you can reference it directly in your pages, layouts and components: ```vue [app/app.vue] ``` The package can also be referenced as a string in the css property of your Nuxt configuration. ```ts [nuxt.config.ts] export default defineNuxtConfig({ css: ['animate.css'], }) ``` ## External Stylesheets You can include external stylesheets in your application by adding a link element in the head section of your nuxt.config file. You can achieve this result using different methods. Note that local stylesheets can also be included this way. You can manipulate the head with the [`app.head`](https://nuxt.com/docs/4.x/api/nuxt-config#head) property of your Nuxt configuration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }], }, }, }) ``` ### Dynamically Adding Stylesheets You can use the useHead composable to dynamically set a value in your head in your code. ```tstwoslash useHead({ link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }], }) ``` Nuxt uses `unhead` under the hood, and you can refer to [its full documentation](https://unhead.unjs.io). ### Modifying The Rendered Head With A Nitro Plugin If you need more advanced control, you can intercept the rendered html with a hook and modify the head programmatically. Create a plugin in `~~/server/plugins/my-plugin.ts` like this: ```ts [server/plugins/my-plugin.ts] export default defineNitroPlugin((nitro) => { nitro.hooks.hook('render:html', (html) => { html.head.push('') }) }) ``` External stylesheets are render-blocking resources: they must be loaded and processed before the browser renders the page. Web pages that contain unnecessarily large styles take longer to render. You can read more about it on [web.dev](https://web.dev/articles/defer-non-critical-css). ## Using Preprocessors To use a preprocessor like SCSS, Sass, Less or Stylus, install it first. ```bash [Sass & SCSS] npm install -D sass ``` ```bash [Less] npm install -D less ``` ```bash [Stylus] npm install -D stylus ``` The natural place to write your stylesheets is the `app/assets` directory. You can then import your source files in your `app.vue` (or layouts files) using your preprocessor's syntax. ```vue [app/pages/app.vue] ``` Alternatively, you can use the `css` property of your Nuxt configuration. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ css: ['~/assets/scss/main.scss'], }) ``` In both cases, the compiled stylesheets will be inlined in the HTML rendered by Nuxt. If you need to inject code in pre-processed files, like a [Sass partial](https://sass-lang.com/documentation/at-rules/use/#partials) with color variables, you can do so with the Vite [preprocessors options](https://vite.dev/config/shared-options#css-preprocessoroptions). Create some partials in your `app/assets` directory: ```scss [assets/_colors.scss] $primary: #49240F; $secondary: #E4A79D; ``` ```sass [assets/_colors.sass] $primary: #49240F $secondary: #E4A79D ``` Then in your `nuxt.config` : ```ts [SCSS]twoslash export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { scss: { additionalData: '@use "~/assets/_colors.scss" as *;', }, }, }, }, }) ``` ```ts [SASS]twoslash export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { sass: { additionalData: '@use "~/assets/_colors.sass" as *\n', }, }, }, }, }) ``` Nuxt uses Vite by default. If you wish to use webpack instead, refer to each preprocessor loader [documentation](https://webpack.js.org/loaders/sass-loader/). ### Preprocessor Workers (Experimental) Vite has made available an [experimental option](https://vite.dev/config/shared-options#css-preprocessormaxworkers) which can speed up using preprocessors. You can enable this in your `nuxt.config`: ```ts export default defineNuxtConfig({ vite: { css: { preprocessorMaxWorkers: true, // number of CPUs minus 1 }, }, }) ``` This is an experimental option and you should refer to the Vite documentation and [provide feedback](https://github.com/vitejs/vite/discussions/15835). ## Single File Components (SFC) Styling One of the best things about Vue and SFC is how great it is at naturally dealing with styling. You can directly write CSS or preprocessor code in the style block of your components file, therefore you will have a fantastic developer experience without having to use something like CSS-in-JS. However if you wish to use CSS-in-JS, you can find 3rd party libraries and modules that support it, such as [pinceau](https://github.com/Tahul/pinceau). You can refer to the [Vue docs](https://vuejs.org/api/sfc-css-features) for a comprehensive reference about styling components in SFC. ### Class And Style Bindings You can leverage Vue SFC features to style your components with class and style attributes. ```vue [Ref and Reactive] ``` ```vue [Computed] ``` ```vue [Array] ``` ```vue [Style] ``` Refer to the [Vue docs](https://vuejs.org/guide/essentials/class-and-style) for more information. ### Dynamic Styles With `v-bind` You can reference JavaScript variables and expressions within your style blocks with the v-bind function. The binding will be dynamic, meaning that if the variable value changes, the style will be updated. ```vue ``` ### Scoped Styles The scoped attribute allows you to style components in isolation. The styles declared with this attribute will only apply to this component. ```vue ``` ### CSS Modules You can use [CSS Modules](https://github.com/css-modules/css-modules) with the module attribute. Access it with the injected `$style` variable. ```vue ``` ### Preprocessors Support SFC style blocks support preprocessor syntax. Vite comes with built-in support for .scss, .sass, .less, .styl and .stylus files without configuration. You just need to install them first, and they will be available directly in SFC with the lang attribute. ```vue [SCSS] ``` ```vue [Sass] ``` ```vue [LESS] ``` ```vue [Stylus] ``` You can refer to the [Vite CSS docs](https://vite.dev/guide/features#css) and the [@vitejs/plugin-vue docs](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue). For webpack users, refer to the [vue loader docs](https://vue-loader.vuejs.org). ## Using PostCSS Nuxt comes with postcss built-in. You can configure it in your `nuxt.config` file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ postcss: { plugins: { 'postcss-nested': {}, 'postcss-custom-media': {}, }, }, }) ``` For proper syntax highlighting in SFC, you can use the postcss lang attribute. ```vue ``` By default, Nuxt comes with the following plugins already pre-configured: - [postcss-import](https://github.com/postcss/postcss-import): Improves the `@import` rule - [postcss-url](https://github.com/postcss/postcss-url): Transforms `url()` statements - [autoprefixer](https://github.com/postcss/autoprefixer): Automatically adds vendor prefixes - [cssnano](https://cssnano.github.io/cssnano/): Minification and purge ## Leveraging Layouts For Multiple Styles If you need to style different parts of your application completely differently, you can use layouts. Use different styles for different layouts. ```vue ``` ## Third Party Libraries And Modules Nuxt isn't opinionated when it comes to styling and provides you with a wide variety of options. You can use any styling tool that you want, such as popular libraries like [UnoCSS](https://unocss.dev) or [Tailwind CSS](https://tailwindcss.com). The community and the Nuxt team have developed plenty of Nuxt modules to make the integration easier. You can discover them on the [modules section](https://nuxt.com/modules) of the website. Here are a few modules to help you get started: - [UnoCSS](https://nuxt.com/modules/unocss): Instant on-demand atomic CSS engine - [Tailwind CSS](https://nuxt.com/modules/tailwindcss): Utility-first CSS framework - [Fontaine](https://github.com/nuxt-modules/fontaine): Font metric fallback - [Pinceau](https://github.com/Tahul/pinceau): Adaptable styling framework - [Nuxt UI](https://ui.nuxt.com): A UI Library for Modern Web Apps - [Panda CSS](https://panda-css.com/docs/installation/nuxt): CSS-in-JS engine that generates atomic CSS at build time Nuxt modules provide you with a good developer experience out of the box, but remember that if your favorite tool doesn't have a module, it doesn't mean that you can't use it with Nuxt! You can configure it yourself for your own project. Depending on the tool, you might need to use a [Nuxt plugin](https://nuxt.com/docs/4.x/directory-structure/app/plugins) and/or [make your own module](https://nuxt.com/docs/4.x/guide/modules). Share them with the [community](https://nuxt.com/modules) if you do! ### Easily Load Webfonts You can use [the Nuxt Google Fonts module](https://github.com/nuxt-modules/google-fonts) to load Google Fonts. If you are using [UnoCSS](https://unocss.dev/integrations/nuxt), note that it comes with a [web fonts presets](https://unocss.dev/presets/web-fonts) to conveniently load fonts from common providers, including Google Fonts and more. ## Advanced ### Transitions Nuxt comes with the same `` element that Vue has, and also has support for the experimental [View Transitions API](https://nuxt.com/docs/4.x/getting-started/transitions#view-transitions-api-experimental). ### Font Advanced Optimization We would recommend using [Fontaine](https://github.com/nuxt-modules/fontaine) to reduce your [CLS](https://web.dev/articles/cls). If you need something more advanced, consider creating a Nuxt module to extend the build process or the Nuxt runtime. Always remember to take advantage of the various tools and techniques available in the Web ecosystem at large to make styling your application easier and more efficient. Whether you're using native CSS, a preprocessor, postcss, a UI library or a module, Nuxt has got you covered. Happy styling! ### LCP Advanced Optimizations You can do the following to speed-up the download of your global CSS files: - Use a CDN so the files are physically closer to your users - Compress your assets, ideally using Brotli - Use HTTP2/HTTP3 for delivery - Host your assets on the same domain (do not use a different subdomain) Most of these things should be done for you automatically if you're using modern platforms like Cloudflare, Netlify or Vercel. You can find an LCP optimization guide on [web.dev](https://web.dev/articles/optimize-lcp). If all of your CSS is inlined by Nuxt, you can (experimentally) completely stop external CSS files from being referenced in your rendered HTML. You can achieve that with a hook, that you can place in a module, or in your Nuxt configuration file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ hooks: { 'build:manifest': (manifest) => { // find the app entry, css list const css = Object.values(manifest).find(options => options.isEntry)?.css if (css) { // start from the end of the array and go to the beginning for (let i = css.length - 1; i >= 0; i--) { // if it starts with 'entry', remove it from the list if (css[i].startsWith('entry')) { css.splice(i, 1) } } } }, }, }) ``` # Testing > How to test your Nuxt application. If you are a module author, you can find more specific information in the [Module Author's guide](https://nuxt.com/docs/4.x/guide/modules/testing). Nuxt offers first-class support for end-to-end and unit testing of your Nuxt application via `@nuxt/test-utils`, a library of test utilities and configuration that currently powers the [tests we use on Nuxt itself](https://github.com/nuxt/nuxt/tree/main/test) and tests throughout the module ecosystem. ## Installation In order to allow you to manage your other testing dependencies, `@nuxt/test-utils` ships with various optional peer dependencies. For example: - you can choose between `happy-dom` and `jsdom` for a runtime Nuxt environment - you can choose between `vitest`, `cucumber`, `jest` and `playwright` for end-to-end test runners - `playwright-core` is only required if you wish to use the built-in browser testing utilities (and are not using `@playwright/test` as your test runner) ```bash [npm] npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [yarn] yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [pnpm] pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [bun] bun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ## Unit Testing We currently ship an environment for unit testing code that needs a [Nuxt](https://nuxt.com) runtime environment. It currently *only has support for vitest* (although contribution to add other runtimes would be welcome). ### Setup 1. Add `@nuxt/test-utils/module` to your `nuxt.config` file (optional). It adds a Vitest integration to your Nuxt DevTools which supports running your unit tests in development.```tstwoslash export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], }) ``` 2. Create a `vitest.config.ts` with the following content:```tstwoslash import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/unit/*.{test,spec}.ts'], environment: 'node', }, }, { test: { name: 'e2e', include: ['test/e2e/*.{test,spec}.ts'], environment: 'node', }, }, await defineVitestProject({ test: { name: 'nuxt', include: ['test/nuxt/*.{test,spec}.ts'], environment: 'nuxt', }, }), ], }, }) ``` `defineVitestProject` is only for Nuxt-environment tests. End-to-end tests should be configured as a regular `test.environment: 'node'` project. 3. If your Nuxt-environment tests live outside `test/nuxt/`, see [TypeScript Support in Tests](#typescript-support-in-tests) to add them to the TypeScript context. When importing `@nuxt/test-utils` in your vitest config, it is necessary to have `"type": "module"` specified in your `package.json` or rename your vitest config file appropriately. > i.e., `vitest.config.m{ts,js}`. It is possible to set environment variables for testing by using the `.env.test` file. ### Using a Nuxt Runtime Environment Using [Vitest projects](https://vitest.dev/guide/projects.html#test-projects), you have fine-grained control over which tests run in which environment: - **Unit tests**: Place regular unit tests in `test/unit/` - these run in a Node environment for speed - **Nuxt tests**: Place tests that rely on the Nuxt runtime environment in `test/nuxt/` - these will run within a Nuxt runtime environment #### Alternative: Simple Setup If you prefer a simpler setup and want all tests to run in the Nuxt environment, you can use the basic configuration: ```tstwoslash import { defineVitestConfig } from '@nuxt/test-utils/config' import { fileURLToPath } from 'node:url' export default defineVitestConfig({ test: { environment: 'nuxt', // you can optionally set Nuxt-specific environment options // environmentOptions: { // nuxt: { // rootDir: fileURLToPath(new URL('./playground', import.meta.url)), // domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom' // overrides: { // // other Nuxt config you want to pass // } // } // } }, }) ``` If you're using the simple setup with `environment: 'nuxt'` by default, you can opt *out* of the [Nuxt environment](https://vitest.dev/guide/environment.html#test-environment) per test file as needed. ```tstwoslash // @vitest-environment node import { test } from 'vitest' test('my test', () => { // ... test without Nuxt environment! }) ``` This approach is not recommended as it creates a hybrid environment where Nuxt Vite plugins run but the Nuxt entry and `nuxtApp` are not initialized. This can lead to hard-to-debug errors. ### Organizing Your Tests With the project-based setup, you might organize your tests as follows: ```bash [Directory structure] test/ โ”œโ”€โ”€ e2e/ โ”‚ โ””โ”€โ”€ ssr.test.ts โ”œโ”€โ”€ nuxt/ โ”‚ โ”œโ”€โ”€ components.test.ts โ”‚ โ””โ”€โ”€ composables.test.ts โ”œโ”€โ”€ unit/ โ”‚ โ””โ”€โ”€ utils.test.ts ``` You can of course opt for any test structure, but keeping the Nuxt runtime environment separated from Nuxt end-to-end tests is important for test stability. #### TypeScript Support in Tests By default, test files in `test/nuxt/` and `tests/nuxt/` directories are included in the [Nuxt app TypeScript context](https://nuxt.com/docs/4.x/guide/concepts/typescript#how-nuxt-uses-project-references). That means they will recognise Nuxt aliases (like `~/`, `@/`, `#imports`) and TypeScript will be aware of auto-imports that work in your Nuxt app. This matches the recommended structure where only tests that need the Nuxt runtime environment are placed in these directories. Unit tests in other directories like `test/unit/` can be added manually if needed. ##### Adding other test directories If you have tests in other directories that you will be running in the Nuxt Vitest environment, you can include them in the Nuxt app TypeScript context by adding them to your configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ typescript: { tsConfig: { include: [ // this path is relative to the generated .nuxt/tsconfig.json '../test/other-nuxt-context/**/*', ], }, }, }) ``` Unit tests should not depend on Nuxt runtime features like auto-imports or composables. Only add TypeScript path alias support if your tests import from your source files (e.g., `~/utils/helpers`), not for Nuxt-specific features. #### Running Tests With the project setup, you can run different test suites: ```bash # Run all tests npx vitest # Run only unit tests npx vitest --project unit # Run only Nuxt tests npx vitest --project nuxt # Run tests in watch mode npx vitest --watch ``` When you run your tests within the Nuxt environment, they will be running in a [`happy-dom`](https://github.com/capricorn86/happy-dom) or [`jsdom`](https://github.com/jsdom/jsdom) environment. Before your tests run, a global Nuxt app will be initialized (including, for example, running any plugins or code you've defined in your `app.vue`). This means you should take particular care not to mutate the global state in your tests (or, if you need to, to reset it afterwards). ### ๐ŸŽญ Built-In Mocks `@nuxt/test-utils` provides some built-in mocks for the DOM environment. #### `intersectionObserver` Default `true`, creates a dummy class without any functionality for the IntersectionObserver API #### `indexedDB` Default `false`, uses [`fake-indexeddb`](https://github.com/dumbmatter/fakeIndexedDB) to create a functional mock of the IndexedDB API These can be configured in the `environmentOptions` section of your `vitest.config.ts` file: ```tstwoslash import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ test: { environmentOptions: { nuxt: { mock: { intersectionObserver: true, indexedDb: true, }, }, }, }, }) ``` ### ๐Ÿ› ๏ธ Helpers `@nuxt/test-utils` provides a number of helpers to make testing Nuxt apps easier. #### `mountSuspended` `mountSuspended` allows you to mount any Vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins. Under the hood, `mountSuspended` wraps `mount` from `@vue/test-utils`, so you can check out [the Vue Test Utils documentation](https://test-utils.vuejs.org/guide/) for more on the options you can pass, and how to use this utility. For example: ```ts [tests/components/SomeComponents.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- import { expect, it } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' it('can mount some component', async () => { const component = await mountSuspended(SomeComponent) expect(component.text()).toMatchInlineSnapshot( '"This is an auto-imported component"', ) }) ``` ```ts [tests/App.nuxt.spec.ts]twoslash import { expect, it } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import App from '~/app.vue' it('can also mount an app', async () => { const component = await mountSuspended(App, { route: '/test' }) expect(component.html()).toMatchInlineSnapshot(` "
This is an auto-imported component
I am a global component
/
Test link " `) }) ``` If you need to spy on component setup state, you can set the `spy` option to `true` and access the return value of the setup via `setupState`. ```ts [tests/components/SomeComponents.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- import { expect, it, vi } from 'vitest' import { mountSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' it('can spy on setup state', async () => { const component = await mountSuspended(SomeComponent, { spy: true }) vi.mocked(component.setupState.someMethod).mockImplementation(() => 'mocked') }) ``` The options object accepts `@vue/test-utils` mount options and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). - `spy`: enable spy component setup state (default `false`). The return object includes the `@vue/test-utils` mount result and the following properties: - `setupState`: the return value of the component setup. #### `renderSuspended` `renderSuspended` allows you to render any Vue component within the Nuxt environment using `@testing-library/vue`, allowing async setup and access to injections from your Nuxt plugins. This should be used together with utilities from Testing Library, e.g. `screen` and `fireEvent`. Install [@testing-library/vue](https://testing-library.com/docs/vue-testing-library/intro/) in your project to use these. Additionally, Testing Library also relies on testing globals for cleanup. You should turn these on in your [Vitest config](https://vitest.dev/config/globals). The passed in component will be rendered inside a `
`. Examples: ```ts [tests/components/SomeComponents.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- import { expect, it } from 'vitest' import { renderSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' import { screen } from '@testing-library/vue' it('can render some component', async () => { await renderSuspended(SomeComponent) expect(screen.getByText('This is an auto-imported component')).toBeDefined() }) ``` ```ts [tests/App.nuxt.spec.ts]twoslash import { expect, it } from 'vitest' import { renderSuspended } from '@nuxt/test-utils/runtime' import App from '~/app.vue' it('can also render an app', async () => { const html = await renderSuspended(App, { route: '/test' }) expect(html).toMatchInlineSnapshot(` "
This is an auto-imported component
I am a global component
Index page
Test link
" `) }) ``` The options object accepts `@testing-library/vue` render options and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). - `spy`: enable spy component setup state (default `false`). See the [`mountSuspended`](#mountsuspended) example above. The return object includes the `@testing-library/vue` render result and the following properties: - `setupState`: the return value of the component setup. #### `mockNuxtImport` `mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useState`, you can do so like this: ```tstwoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', () => { return () => { return { value: 'mocked storage' } } }) // your tests here ``` You can explicitly type the mock for type safety, and use the original implementation passed to the factory function when mocking complex functionality. ```ts [test/nuxt/import.test.ts]twoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', (original) => { return (...args) => { return { ...original('some-key'), value: 'mocked state' } } }) // or specify the target to mock mockNuxtImport(useState, (original) => { return (...args) => { return { ...original('some-key'), value: 'mocked state' } } }) // your tests here ``` `mockNuxtImport` can only be used once per mocked import per test file. It is actually a macro that gets transformed to `vi.mock` and `vi.mock` is hoisted, as described [in the Vitest docs](https://vitest.dev/api/vi#vi-mock). If you need to mock a Nuxt import and provide different implementations between tests, you can do it by creating and exposing your mocks using [`vi.hoisted`](https://vitest.dev/api/vi#vi-hoisted), and then use those mocks in `mockNuxtImport`. You then have access to the mocked imports, and can change the implementation between tests. Be careful to [restore mocks](https://vitest.dev/api/mock#mockrestore) before or after each test to undo mock state changes between runs. ```tstwoslash import { vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' const { useStateMock } = vi.hoisted(() => { return { useStateMock: vi.fn(() => { return { value: 'mocked storage' } }), } }) mockNuxtImport('useState', () => { return useStateMock }) // Then, inside a test useStateMock.mockImplementation(() => { return { value: 'something else' } }) ``` If you need to mock behavior only inside a test, you can also use the following approach. ```tstwoslash import { beforeEach, vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport(useRoute, original => vi.fn(original)) beforeEach(() => { vi.resetAllMocks() }) // Then, inside a test const useRouteOriginal = vi.mocked(useRoute).getMockImplementation()! vi.mocked(useRoute).mockImplementation( (...args) => ({ ...useRouteOriginal(...args), path: '/mocked' }), ) ``` #### `mockComponent` `mockComponent` allows you to mock Nuxt's component. The first argument can be the component name in PascalCase, or the relative path of the component. The second argument is a factory function that returns the mocked component. For example, to mock `MyComponent`, you can: ```tstwoslash import { mockComponent } from '@nuxt/test-utils/runtime' mockComponent('MyComponent', { props: { value: String, }, setup (props) { // ... }, }) // relative path or alias also works mockComponent('~/components/my-component.vue', () => { // or a factory function return defineComponent({ setup (props) { // ... }, }) }) // or you can use SFC for redirecting to a mock component mockComponent('MyComponent', () => import('./MockComponent.vue')) // your tests here ``` > **Note**: You can't reference local variables in the factory function since they are hoisted. If you need to access Vue APIs or other variables, you need to import them in your factory function. ```tstwoslash import { mockComponent } from '@nuxt/test-utils/runtime' mockComponent('MyComponent', async () => { const { ref, h } = await import('vue') return defineComponent({ setup (props) { const counter = ref(0) return () => h('div', null, counter.value) }, }) }) ``` #### `registerEndpoint` `registerEndpoint` allows you create Nitro endpoint that returns mocked data. It can come in handy if you want to test a component that makes requests to API to display some data. The first argument is the endpoint name (e.g. `/test/`). The second argument is a factory function that returns the mocked data. For example, to mock `/test/` endpoint, you can do: ```tstwoslash import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', () => ({ test: 'test-field', })) ``` By default, your request will be made using the `GET` method. You may use another method by setting an object as the second argument instead of a function. ```tstwoslash import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', { method: 'POST', handler: () => ({ test: 'test-field' }), }) ``` This object accepts the following properties: - `handler`: the event handler function - `method`: (optional) HTTP method to match (e.g., 'GET', 'POST') - `once`: (optional) if true, the handler will only be used for the first matching request and then automatically removed > **Note**: If your requests in a component go to an external API, you can use `baseURL` and then make it empty using [Nuxt Environment Override Config](https://nuxt.com/docs/4.x/getting-started/configuration#environment-overrides) (`$test`) so all your requests will go to Nitro server. #### Conflict with End-To-End Testing `@nuxt/test-utils/runtime` and `@nuxt/test-utils/e2e` need to run in different testing environments and so can't be used in the same file. If you would like to use both the end-to-end and unit testing functionality of `@nuxt/test-utils`, you can split your tests into separate files. You then either specify a test environment per-file with the special `// @vitest-environment nuxt` comment, or name your runtime unit test files with the `.nuxt.spec.ts` extension. `app.nuxt.spec.ts` ```tstwoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', () => { return () => { return { value: 'mocked storage' } } }) ``` `app.e2e.spec.ts` ```tstwoslash import { $fetch, setup } from '@nuxt/test-utils/e2e' await setup({ setupTimeout: 10000, }) // ... ``` ### Using `@vue/test-utils` If you prefer to use `@vue/test-utils` on its own for unit testing in Nuxt, and you are only testing components which do not rely on Nuxt composables, auto-imports or context, you can follow these steps to set it up. 1. Install the needed dependencies ```bash [npm] npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [yarn] yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [pnpm] pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [bun] bun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` 2. Create a `vitest.config.ts` with the following content:```ts import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom', }, }) ``` 3. Add a new command for test in your `package.json````json "scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" }, ``` 4. Create a simple `` component `app/components/HelloWorld.vue` with the following content:```vue ``` 5. Create a simple unit test for this newly created component `~/components/HelloWorld.spec.ts````tstwoslash import { describe, expect, it } from 'vitest' import { mount } from '@vue/test-utils' import HelloWorld from './HelloWorld.vue' describe('HelloWorld', () => { it('component renders Hello world properly', () => { const wrapper = mount(HelloWorld) expect(wrapper.text()).toContain('Hello world') }) }) ``` 6. Run vitest command ```bash [npm] npm run test ``` ```bash [yarn] yarn test ``` ```bash [pnpm] pnpm run test ``` ```bash [bun] bun run test ``` Congratulations, you're all set to start unit testing with `@vue/test-utils` in Nuxt! Happy testing! ### Vitest Browser Mode `@nuxt/test-utils` provides helpers for testing in [Vitest Browser Mode](https://vitest.dev/guide/browser/) via `@nuxt/test-utils/browser`. #### Setup 1. Install Vitest browser packages and a browser provider: ```bash [npm] npm i --save-dev @vitest/browser-playwright ``` ```bash [yarn] yarn add --dev @vitest/browser-playwright ``` ```bash [pnpm] pnpm add -D @vitest/browser-playwright ``` ```bash [bun] bun add --dev @vitest/browser-playwright ``` 2. Configure browser mode in your `vitest.config.ts`:```tstwoslash // @errors: 2307 // ---cut--- import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { projects: [ await defineVitestProject({ test: { name: 'browser', include: ['test/browser/**/*.{test,spec}.ts'], browser: { enabled: true, provider: playwright(), instances: [{ browser: 'chromium' }], }, // If you want to enable `page.render` and automatic cleanup, add this setup file setupFiles: ['@nuxt/test-utils/browser'], }, }), ], }, }) ``` When adding `@nuxt/test-utils/browser` to `setupFiles`, if TypeScript does not automatically recognize the types for `page.render`, you can add `@nuxt/test-utils/browser` via `typescript.tsConfig.compilerOptions.types` in your `nuxt.config.ts`. If your Vitest browser mode tests live outside `test/nuxt/` (such as in `test/browser/`), see [Adding other test directories](#adding-other-test-directories) to add them to the TypeScript context. #### Usage You can use `page.render` from `vitest/browser`: ```ts [test/browser/components/MyCounter.nuxt.spec.ts]twoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const MyCounter: Component } // ---cut--- import { expect, it } from 'vitest' import { page } from 'vitest/browser' // If you added the setup file, the following import is not needed import '@nuxt/test-utils/browser' import { MyCounter } from '#components' it('counter button increments the count', async () => { const screen = await page.render(MyCounter) await screen.getByRole('button', { name: 'Increment' }).click() await expect.element(screen.getByText('Count: 1')).toBeVisible() }) ``` You can also import `render` directly from `@nuxt/test-utils/browser`: ```tstwoslash // @noErrors import type { Component } from 'vue' declare module '#components' { export const MyCounter: Component } // ---cut--- import { expect, it } from 'vitest' import { render } from '@nuxt/test-utils/browser' import { MyCounter } from '#components' it('can render using the render helper', async () => { const screen = await render(MyCounter) await screen.getByRole('button', { name: 'Increment' }).click() await expect.element(screen.getByText('Count: 1')).toBeVisible() }) ``` The options object accepts `@vue/test-utils` mount options (use `container` instead of `attachTo`) and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). - `spy`: enable spy component setup state (default `false`). See the [`mountSuspended`](#mountsuspended) example above. - `container`: custom `HTMLElement` container to render into (use this option instead of `@vue/test-utils` `attachTo`). - `baseElement`: custom base `HTMLElement` (default `document.body`). The return object includes the following properties: - `container`: the container `HTMLElement` the component is rendered into. - `baseElement`: the base `HTMLElement` (default `document.body`). - `locator`: root element `Locator`. - `setupState`: the return value of the component setup, mocked when the `spy` option is enabled. - `debug()`: print formatted DOM to console. - `unmount()`: unmount the component. Also records a `nuxt.unmount` trace mark. - `emitted()`: get emitted events. - `rerender(props)`: re-render the component with new props. Also records a `nuxt.rerender` trace mark. ## End-To-End Testing For end-to-end testing, we support [Vitest](https://github.com/vitest-dev/vitest), [Jest](https://jestjs.io), [Cucumber](https://cucumber.io/) and [Playwright](https://playwright.dev/) as test runners. ### Setup In each `describe` block where you are taking advantage of the `@nuxt/test-utils/e2e` helper methods, you will need to set up the test context before beginning. ```ts [test/my-test.spec.ts]twoslash import { describe, test } from 'vitest' import { $fetch, setup } from '@nuxt/test-utils/e2e' describe('My test', async () => { await setup({ // test context options }) test('my test', () => { // ... }) }) ``` Behind the scenes, `setup` performs a number of tasks in `beforeAll`, `beforeEach`, `afterEach` and `afterAll` to set up the Nuxt test environment correctly. Please use the options below for the `setup` method. #### Nuxt Config - `rootDir`: Path to a directory with a Nuxt app to be put under test. - Type: `string` - Default: `'.'` - `configFile`: Name of the configuration file. - Type: `string` - Default: `'nuxt.config'` #### Timings - `setupTimeout`: The amount of time (in milliseconds) to allow for `setupTest` to complete its work (which could include building or generating files for a Nuxt application, depending on the options that are passed). - Type: `number` - Default: `120000` or `240000` on windows - `teardownTimeout`: The amount of time (in milliseconds) to allow tearing down the test environment, such as closing the browser. - Type: `number` - Default: `30000` #### Features - `build`: Whether to run a separate build step. - Type: `boolean` - Default: `true` (`false` if `browser` or `server` is disabled, or if a `host` is provided) - `server`: Whether to launch a server to respond to requests in the test suite. - Type: `boolean` - Default: `true` (`false` if a `host` is provided) - `port`: If provided, set the launched test server port to the value. - Type: `number | undefined` - Default: `undefined` - `host`: If provided, a URL to use as the test target instead of building and running a new server. Useful for running "real" end-to-end tests against a deployed version of your application, or against an already running local server (which may provide a significant reduction in test execution timings). See the [target host end-to-end example below](https://nuxt.com/docs/4.x/getting-started/testing#target-host-end-to-end-example). - Type: `string` - Default: `undefined` - `browser`: Under the hood, Nuxt test utils uses [`playwright`](https://playwright.dev) to carry out browser testing. If this option is set, a browser will be launched and can be controlled in the subsequent test suite. - Type: `boolean` - Default: `false` - `browserOptions` - Type: `object` with the following properties - `type`: The type of browser to launch - either `chromium`, `firefox` or `webkit` - `launch`: `object` of options that will be passed to playwright when launching the browser. See [full API reference](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). - `runner`: Specify the runner for the test suite. Currently, [Vitest](https://vitest.dev) is recommended. - Type: `'vitest' | 'jest' | 'cucumber'` - Default: `'vitest'` - `logLevel`: Overrides the consola log level for the server subprocess. (use NUXT_TEST_LOG_LEVEL environment variable to override) - Type: `number` - Default: `1` - `captureServerLogs`: Whether to capture server process output instead of inheriting stdio. When `true` (default), server stdout/stderr is suppressed from the console and accessible via `getServerLogs()`. Set to `false` to restore the old inherit-stdio behaviour (useful when debugging a test locally). - Type: `boolean` - Default: `true` ##### Target `host` end-to-end example A common use-case for end-to-end testing is running the tests against a deployed application running in the same environment typically used for Production. For local development or automated deploy pipelines, testing against a separate local server can be more efficient and is typically faster than allowing the test framework to rebuild between tests. To utilize a separate target host for end-to-end tests, simply provide the `host` property of the `setup` function with the desired URL. ```ts import { createPage, setup } from '@nuxt/test-utils/e2e' import { describe, expect, it } from 'vitest' describe('login page', async () => { await setup({ host: 'http://localhost:8787', }) it('displays the email and password fields', async () => { const page = await createPage('/login') expect(await page.getByTestId('email').isVisible()).toBe(true) expect(await page.getByTestId('password').isVisible()).toBe(true) }) }) ``` ### APIs #### `$fetch(url)` Get the HTML of a server-rendered page. ```tstwoslash import { $fetch } from '@nuxt/test-utils/e2e' const html = await $fetch('/') ``` #### `fetch(url)` Get the response of a server-rendered page. ```tstwoslash import { fetch } from '@nuxt/test-utils/e2e' const res = await fetch('/') const { body, headers } = res ``` #### `url(path)` Get the full URL for a given page (including the port the test server is running on.) ```tstwoslash import { url } from '@nuxt/test-utils/e2e' const pageUrl = url('/page') // 'http://localhost:6840/page' ``` #### `getServerLogs()` Returns the lines captured from the server subprocess's stdout/stderr since the last `startServer()` call (or `clearServerLogs()`). Only populated when `captureServerLogs` is `true` (the default). ```tstwoslash import { expect, it, vi } from 'vitest' import { $fetch, clearServerLogs, getServerLogs } from '@nuxt/test-utils/e2e' it('captures console.log output from a server route', async () => { clearServerLogs() await $fetch('/api/log-test') await vi.waitFor(() => { expect(getServerLogs().some(line => line.includes('[test] server-log-marker'))).toBe(true) }) }) ``` #### `clearServerLogs()` Clears the captured server log lines. Useful between requests when you want to assert only on the logs produced by a specific operation. ### Testing in a Browser We provide built-in support using Playwright within `@nuxt/test-utils`, either programmatically or via the Playwright test runner. #### `createPage(url)` Within `vitest`, `jest` or `cucumber`, you can create a configured Playwright browser instance with `createPage`, and (optionally) point it at a path from the running server. You can find out more about the API methods available in the [Playwright documentation](https://playwright.dev/docs/api/class-page). ```tstwoslash import { createPage } from '@nuxt/test-utils/e2e' const page = await createPage('/page') // you can access all the Playwright APIs from the `page` variable ``` #### Testing with Playwright Test Runner We also provide first-class support for testing Nuxt within [the Playwright test runner](https://playwright.dev/docs/intro). ```bash [npm] npm i --save-dev @playwright/test @nuxt/test-utils ``` ```bash [yarn] yarn add --dev @playwright/test @nuxt/test-utils ``` ```bash [pnpm] pnpm add -D @playwright/test @nuxt/test-utils ``` ```bash [bun] bun add --dev @playwright/test @nuxt/test-utils ``` ```bash [deno] deno add --dev npm:@playwright/test npm:@nuxt/test-utils ``` You can provide global Nuxt configuration, with the same configuration details as the `setup()` function mentioned earlier in this section. ```ts [playwright.config.ts] import { fileURLToPath } from 'node:url' import { defineConfig, devices } from '@playwright/test' import type { ConfigOptions } from '@nuxt/test-utils/playwright' export default defineConfig({ use: { nuxt: { rootDir: fileURLToPath(new URL('.', import.meta.url)), }, }, // ... }) ``` Your test file should then use `expect` and `test` directly from `@nuxt/test-utils/playwright`: ```ts [tests/example.test.ts] import { expect, test } from '@nuxt/test-utils/playwright' test('test', async ({ page, goto }) => { await goto('/', { waitUntil: 'hydration' }) await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!') }) ``` You can alternatively configure your Nuxt server directly within your test file: ```ts [tests/example.test.ts] import { expect, test } from '@nuxt/test-utils/playwright' test.use({ nuxt: { rootDir: fileURLToPath(new URL('..', import.meta.url)), }, }) test('test', async ({ page, goto }) => { await goto('/', { waitUntil: 'hydration' }) await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!') }) ``` # Transitions > Apply transitions between pages and layouts with Vue or native browser View Transitions. Nuxt leverages Vue's [``](https://vuejs.org/guide/built-ins/transition#the-transition-component) component to apply transitions between pages and layouts. Because Nuxt uses Vue's `` component, a page or layout you want to animate must have a **single root element**. A page or layout with multiple root elements (a fragment) cannot be animated, so the transition will not run and navigating between routes may error. Nuxt warns about this in development. Wrap the template in a single root element (for example a `
`). ## Page Transitions You can enable page transitions to apply an automatic transition for all your [pages](https://nuxt.com/docs/4.x/directory-structure/app/pages). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: { name: 'page', mode: 'out-in' }, }, }) ``` If you are changing layouts as well as pages, the page transition you set here will not run. Instead, you should set a [layout transition](https://nuxt.com/docs/4.x/getting-started/transitions#layout-transitions). To start adding transition between your pages, add the following CSS to your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app): ```vue [app/app.vue] ``` ```vue [app/pages/index.vue] ``` ```vue [app/pages/about.vue] ``` This produces the following result when navigating between pages: To set a different transition for a page, set the `pageTransition` key in [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) of the page: ```vue [pages/about.vue]twoslash ``` ```vue [app/app.vue] ``` Moving to the about page will add the 3d rotation effect: ## Layout Transitions You can enable layout transitions to apply an automatic transition for all your [layouts](https://nuxt.com/docs/4.x/directory-structure/app/layouts). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { layoutTransition: { name: 'layout', mode: 'out-in' }, }, }) ``` To start adding transition between your pages and layouts, add the following CSS to your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app): ```vue [app/app.vue] ``` ```vue [app/layouts/default.vue] ``` ```vue [app/layouts/orange.vue] ``` ```vue [app/pages/index.vue] ``` ```vue [app/pages/about.vue] ``` This produces the following result when navigating between pages: Similar to `pageTransition`, you can apply a custom `layoutTransition` to the page component using `definePageMeta`: ```vue [pages/about.vue]twoslash ``` ## Global Settings You can customize these default transition names globally using `nuxt.config`. Both `pageTransition` and `layoutTransition` keys accept [`TransitionProps`](https://vuejs.org/api/built-in-components#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: { name: 'fade', mode: 'out-in', // default }, layoutTransition: { name: 'slide', mode: 'out-in', // default }, }, }) ``` If you change the `name` property, you also have to rename the CSS classes accordingly. To override the global transition property, use the `definePageMeta` to define page or layout transitions for a single Nuxt page and override any page or layout transitions that are defined globally in `nuxt.config` file. ```vue [pages/some-page.vue]twoslash ``` ## Disable Transitions `pageTransition` and `layoutTransition` can be disabled for a specific route: ```vue [pages/some-page.vue]twoslash ``` Or globally in the `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: false, layoutTransition: false, }, }) ``` ## JavaScript Hooks For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt pages. This way presents perfect use-cases for JavaScript animation libraries such as [GSAP](https://gsap.com). ```vue [pages/some-page.vue]twoslash ``` Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition#javascript-hooks) available in the `Transition` component. ## Dynamic Transitions To apply dynamic transitions using conditional logic, you can leverage inline [middleware](https://nuxt.com/docs/4.x/directory-structure/app/middleware) to assign a different transition name to `to.meta.pageTransition`. ```vue [pages/[id].vue]twoslash ``` ```vue [app/layouts/default.vue] ``` The page now applies the `slide-left` transition when going to the next id and `slide-right` for the previous one: ## Transition with NuxtPage When `` is used in `app.vue`, transitions can be configured with the `transition` prop to activate transitions globally. ```vue [app/app.vue] ``` Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. ## View Transitions API (Experimental) Nuxt ships with an experimental implementation of the [**View Transitions API**](https://developer.chrome.com/docs/web-platform/view-transitions) (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API)). This is an exciting new way to implement native browser transitions which (among other things) have the ability to transition between unrelated elements on different pages. You can check a demo [on StackBlitz](https://stackblitz.com/edit/nuxt-view-transitions). The Nuxt integration can be enabled with the `experimental.viewTransition` option in your configuration file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { viewTransition: true, }, }) ``` The possible values are: `false`, `true`, or `'always'`. If set to true, Nuxt will not apply transitions if the user's browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition and it is up to you to respect the user's preference. By default, view transitions are enabled for all [pages](https://nuxt.com/docs/4.x/directory-structure/app/pages), but you can set a different global default. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { // Disable view transitions globally, and opt-in on a per page basis viewTransition: false, }, }) ``` It is possible to override the default `viewTransition` value for a page by setting the `viewTransition` key in [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) of the page: ```vue [pages/about.vue]twoslash ``` Overriding view transitions on a per-page basis will only have an effect if you have enabled the `experimental.viewTransition` option. ### View Transition Types v4.4 [View transition types](https://developer.chrome.com/blog/view-transitions-update-io24#view-transition-types) allow you to apply different CSS animations depending on the type of navigation. This is useful for creating asymmetric transitions (e.g., a different animation when navigating forward vs. backward). Types are set on the [`ViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) and can be targeted in CSS using the [`:active-view-transition-type()`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:active-view-transition-type) pseudo-class selector. You can set default types globally in your `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { viewTransition: { enabled: true, types: ['slide'], }, }, }) ``` Or configure types per-page using `definePageMeta`. Per-page types support both static arrays and functions for dynamic behavior: ```vue [pages/detail.vue]twoslash ``` You can also use functions for `types`, `toTypes`, and `fromTypes` in `definePageMeta` to determine types dynamically based on the route: ```vue [pages/[id].vue]twoslash ``` Then target these types in your CSS: ```css /* Default crossfade */ ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.3s; } /* Slide left animation */ html:active-view-transition-type(slide-left) { &::view-transition-old(root) { animation: slide-out-left 0.3s ease-in-out; } &::view-transition-new(root) { animation: slide-in-right 0.3s ease-in-out; } } /* Slide right animation */ html:active-view-transition-type(slide-right) { &::view-transition-old(root) { animation: slide-out-right 0.3s ease-in-out; } &::view-transition-new(root) { animation: slide-in-left 0.3s ease-in-out; } } ``` Function values for `types`, `toTypes`, and `fromTypes` only work in `definePageMeta`, not in `nuxt.config.ts` (where only static `string[]` is supported). The `page:view-transition:start` hook provides access to the [`ViewTransition`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition) object, which includes a [`types`](https://developer.mozilla.org/en-US/docs/Web/API/ViewTransition/types) property (`ViewTransitionTypeSet`) that can be read or modified at runtime: ```ts [plugins/view-transition.client.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:view-transition:start', (transition) => { // Read or modify types at runtime console.log([...transition.types]) }) }) ``` If you are also using Vue transitions like `pageTransition` and `layoutTransition` (see above) to achieve the same result as the new View Transitions API, then you may wish to *disable* Vue transitions if the user's browser supports the newer, native web API. You can do this by creating `~/middleware/disable-vue-transitions.global.ts` with the following contents: ```ts export default defineNuxtRouteMiddleware((to) => { if (import.meta.server || !document.startViewTransition) { return } // Disable built-in Vue transitions to.meta.pageTransition = false to.meta.layoutTransition = false }) ``` ### Known Issues - If you perform data fetching within your page setup functions, you may wish to reconsider using this feature for the moment. (By design, View Transitions completely freeze DOM updates whilst they are taking place.) We're looking at restricting the View Transition to the final moments before `` resolves, but in the interim you may want to consider carefully whether to adopt this feature if this describes you. # Upgrade Guide > Learn how to upgrade to the latest Nuxt version. ## Upgrading Nuxt ### Latest release To upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases), use the `nuxt upgrade` command. ```bash [npm] npx nuxt upgrade ``` ```bash [yarn] yarn nuxt upgrade ``` ```bash [pnpm] pnpm nuxt upgrade ``` ```bash [bun] bun x nuxt upgrade ``` ```bash [deno] deno x nuxt upgrade ``` ### Nightly Release Channel To use the latest Nuxt build and test features before their release, read about the [nightly release channel](https://nuxt.com/docs/4.x/guide/going-further/nightly-release-channel) guide. ## Testing Nuxt 5 Nuxt 5 is **currently in development**. Until the release, it is possible to test many of Nuxt 5's breaking changes from Nuxt version 4.2+. ### Opting in to Nuxt 5 First, upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases). Then you can set your `future.compatibilityVersion` to match Nuxt 5 behavior: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ future: { compatibilityVersion: 5, }, }) ``` When you set your `future.compatibilityVersion` to `5`, defaults throughout your Nuxt configuration will change to opt in to Nuxt v5 behavior, including: - **Vite Environment API**: Automatically enables the new [Vite Environment API](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-to-vite-environment-api) for improved build configuration - **Case-sensitive routing**: Page routes [match URL casing exactly](https://nuxt.com/docs/4.x/getting-started/upgrade#case-sensitive-routing), consistent with Nitro - **Normalized Page Names**: Page component names will [match their route names](https://nuxt.com/docs/4.x/getting-started/upgrade#normalized-page-component-names) for consistent `` behavior - **clearNuxtState resets to defaults**: `clearNuxtState` will [reset state to its initial value](https://nuxt.com/docs/4.x/getting-started/upgrade#respect-defaults-when-clearing-usestate) instead of setting it to `undefined` - **Non-async callHook**: [`callHook` may return `void`](https://nuxt.com/docs/4.x/getting-started/upgrade#non-async-callhook) instead of always returning a `Promise` - **Comment node placeholders**: Client-only components use [comment nodes instead of `
`](https://nuxt.com/docs/4.x/getting-started/upgrade#client-only-comment-placeholders) as SSR placeholders, fixing a scoped styles hydration issue - **Stricter side-effect imports**: The generated `tsconfig.json` enables [`noUncheckedSideEffectImports`](https://nuxt.com/docs/4.x/getting-started/upgrade#stricter-side-effect-imports) to match the TypeScript 7 default - **Vue Options API disabled**: The [Options API is compiled out of the client bundle](https://nuxt.com/docs/4.x/getting-started/upgrade#vue-options-api-disabled-by-default) to reduce its size - **Typed pages**: [`experimental.typedPages`](https://nuxt.com/docs/4.x/getting-started/upgrade#typed-pages-enabled-by-default) is enabled by default for type-checked routing - **TypeScript baseUrl ignored**: Generated TypeScript configurations [no longer use `compilerOptions.baseUrl`](https://nuxt.com/docs/4.x/getting-started/upgrade#typescript-baseurl-is-ignored) to resolve Nuxt aliases - Other Nuxt 5 improvements and changes as they become available This section is subject to change until the final release, so please check back here regularly if you are testing Nuxt 5 using `future.compatibilityVersion: 5`. Breaking or significant changes will be noted below along with migration steps for backward/forward compatibility. ### Case-Sensitive Routing ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, page routes match URLs case-sensitively, consistent with Nitro. For example, `/About` no longer matches `pages/about.vue`. #### Migration Steps Update links to use the same casing as their page routes. To keep case-insensitive matching: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ router: { options: { sensitive: false, }, }, }) ``` ### `jiti` Is No Longer Bundled ๐Ÿšฆ **Impact Level**: Medium #### What Changed Nuxt no longer depends on [`jiti`](https://github.com/unjs/jiti). Files loaded outside the bundler (`nuxt.config.ts`, files in `modules/`, and layer configs) are now imported by the runtime itself. **You can still write your config in TypeScript.** Nuxt 5 requires Node `22.19` or later, where type stripping is on by default, so `nuxt.config.ts` and TypeScript modules load natively. Two things the runtime does not do, which `jiti` used to paper over, are guess file extensions and compile TypeScript syntax that emits code. Both would otherwise only surface when Nuxt loads the file, so the generated `node` tsconfig now describes the environment the way the runtime sees it (`module` and `moduleResolution` set to `nodenext`, plus [`erasableSyntaxOnly`](https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly)) and TypeScript reports both up front. That covers `nuxt.config`, `modules/` and layer configs only. Your app and `shared/` code goes through Vite and resolves the way it always has. If you need the previous behaviour, override it: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { nodeTsConfig: { compilerOptions: { module: 'preserve', moduleResolution: 'bundler', erasableSyntaxOnly: false, }, }, }, }) ``` #### Reasons for Change `jiti` was pulled into every Nuxt install to load a handful of files, most of which the runtime can now load unaided. Removing it makes a default install smaller. #### Migration Steps **1. Add file extensions to relative imports.** Relative imports in `nuxt.config.ts`, `modules/`, and layer configs need an explicit extension: ```diff [nuxt.config.ts] - import { myPlugin } from './build/my-plugin' + import { myPlugin } from './build/my-plugin.ts' ``` TypeScript reports a missing extension as `TS2835`. Note that its quick fix suggests `./build/my-plugin.js`; write the extension the file actually has (`.ts`), which Node resolves directly. Bare package imports (`import { defu } from 'defu'`) are unaffected. **2. Use erasable TypeScript syntax.** Type annotations are erased, but syntax that emits runtime code cannot be. In config and module files, replace: - `enum Foo {}` with a `const` object - `namespace` / `module` blocks with plain exports - constructor parameter properties (`constructor(private x: string) {}`) with an explicit assignment - experimental decorators TypeScript reports all of these for you as `TS1294`. **3. If you publish a layer or module, ship compiled JavaScript.** This one is specific to packages. The runtime refuses to strip types from any file inside `node_modules`, whatever the configuration, so a published entrypoint written in TypeScript cannot be loaded natively however new the Node version is. Build to JavaScript before publishing, and if your package ships a `nuxt.config`, emit it as `nuxt.config.mjs`. Otherwise every consuming project has to install `jiti`. This does not apply to layers inside your own project: `layers/*/nuxt.config.ts` loads natively. **4. Install jiti if you still need it.** `jiti` is now an optional peer dependency. Install it and Nuxt will pick it up automatically as a fallback whenever the runtime cannot load a file on its own: ```bash [npm] npm i -D jiti ``` ```bash [yarn] yarn add -D jiti ``` ```bash [pnpm] pnpm add -D jiti ``` ```bash [bun] bun add -D jiti ``` A `nuxt.schema` file always needs `jiti`, whatever Node version you are on: its JSDoc annotations are read by an import-time transform rather than by importing the file. One smaller change comes with this: PostCSS plugins named in `postcss.plugins` are now resolved by the runtime, so a plugin name that only resolves through a Nuxt `alias` entry no longer loads. Use the package name, or a path. ### Migration to Vite Environment API ๐Ÿšฆ **Impact Level**: Medium #### What Changed Nuxt 5 migrates to Vite 6's new [Environment API](https://vite.dev/guide/api-environment), which formalizes the concept of environments and provides better control over configuration per environment. Previously, Nuxt used separate client and server Vite configurations. Now, Nuxt uses a shared Vite configuration with environment-specific plugins that use the `applyToEnvironment()` method to target specific environments. You can test this feature early by setting `future.compatibilityVersion: 5` (see [Testing Nuxt 5](https://nuxt.com/docs/4.x/getting-started/upgrade#testing-nuxt-5)) or by enabling it explicitly with `experimental.viteEnvironmentApi: true`. **Key changes:** 1. **Deprecated environment-specific extendViteConfig()**: The `server` and `client` options in `extendViteConfig()` are deprecated and will show warnings when used. 2. **Changed plugin registration**: Vite plugins registered with `addVitePlugin()` and only targeting one environment (by passing `server: false` or `client: false`) will not have their `config` or `configResolved` hooks called. 3. **Shared configuration**: The `vite:extendConfig` and `vite:configResolved` hooks now work with a shared configuration rather than separate client/server configs. #### Reasons for Change The Vite Environment API provides: - Better consistency between development and production builds - More granular control over environment-specific configuration - Improved performance and plugin architecture - Support for custom environments beyond just client and server #### Migration Steps ##### 1. Migrate to use Vite plugins We would recommend you use a Vite plugin instead of `extendViteConfig`, `vite:configResolved` and `vite:extendConfig`. ```ts // Before extendViteConfig((config) => { config.optimizeDeps.include.push('my-package') }, { server: false }) nuxt.hook('vite:extendConfig' /* or vite:configResolved */, (config, { isClient }) => { if (isClient) { config.optimizeDeps.include.push('my-package') } }) // After addVitePlugin(() => ({ name: 'my-plugin', config (config) { // you can set global vite configuration here }, configResolved (config) { // you can access the fully resolved vite configuration here }, configEnvironment (name, config) { // you can set environment-specific vite configuration here if (name === 'client') { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('my-package') } }, applyToEnvironment (environment) { return environment.name === 'client' }, })) ``` ##### 2. Migrate Vite plugins to use environments Instead of using `addVitePlugin` with `server: false` or `client: false`, you can instead use the new `applyToEnvironment` hook within your plugin. ```ts // Before addVitePlugin(() => ({ name: 'my-plugin', config (config) { config.optimizeDeps.include.push('my-package') }, }), { client: false }) // After addVitePlugin(() => ({ name: 'my-plugin', config (config) { // you can set global vite configuration here }, configResolved (config) { // you can access the fully resolved vite configuration here }, configEnvironment (name, config) { // you can set environment-specific vite configuration here if (name === 'client') { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('my-package') } }, applyToEnvironment (environment) { return environment.name === 'client' }, })) ``` Learn more about Vite's Environment API ### `giget` Is Now Optional (Remote Layers) ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `giget` is no longer installed by default. It is now an optional peer dependency of `@nuxt/kit`, needed only to download a layer that `extends` names by remote URL: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: ['github:my-org/my-theme'], }) ``` Local layers, layers in `~~/layers/`, and layers installed as packages are unaffected. #### Reasons for Change Most projects never extend from a remote source, so the downloader was being installed for everyone to serve a small minority. Downloading a layer at config-resolution time is also the least reproducible way to consume one: the fetch happens outside your package manager, so it is not in your lockfile and, unless you pin it yourself, not pinned to a revision. #### Migration Steps **Preferred: move the layer into package.json.** Every major package manager understands git URLs, so a remote layer can be a normal dependency. This puts it in your lockfile, pins it to an exact commit, and installs it alongside everything else: ```json [package.json] { "devDependencies": { "my-theme": "github:my-org/my-theme#4a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b" } } ``` Then extend from it by package name: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: ['my-theme'], }) ``` The part after `#` is any commit-ish, so a tag (`#v1.2.0`) or `#semver:^1.2.0` works too; a full commit SHA is the only form that is genuinely immutable. **Otherwise, install giget** and keep using a remote `extends` entry: ```bash [npm] npm install -D giget ``` ```bash [yarn] yarn add -D giget ``` ```bash [pnpm] pnpm add -D giget ``` ```bash [bun] bun add -D giget ``` If a remote layer is resolved without `giget` present, Nuxt reports which `extends` entry needs it. ### Non-Async `callHook` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With the upgrade to [hookable v6](https://github.com/unjs/hookable), `callHook` may now return `void` instead of always returning `Promise`. This is a significant performance improvement that avoids unnecessary `Promise` allocations when there are no registered hooks or all hooks are synchronous. By default (with `compatibilityVersion: 4`), Nuxt wraps `callHook` with `Promise.resolve()` so that existing `.then()` and `.catch()` chaining continues to work. With `compatibilityVersion: 5`, this wrapper is removed. This affects both build-time Nuxt hooks (used by Nuxt modules) and runtime Nuxt hooks (which you might use in your application code). #### Reasons for Change Hookable v6's `callHook` is 20-40x faster because it avoids creating a `Promise` when one is not needed. This benefits applications with many hook call sites. #### Migration Steps If you or your modules use `callHook` with `.then()` or `.catch()` chaining, switch to `await`: ```diff - nuxtApp.callHook('my:hook', data).then(() => { ... }) + await nuxtApp.callHook('my:hook', data) ``` ```diff - nuxtApp.hooks.callHook('my:hook', data).catch(err => { ... }) + try { await nuxtApp.hooks.callHook('my:hook', data) } catch (err) { ... } ``` You can test this feature early by setting `future.compatibilityVersion: 5` (see [Testing Nuxt 5](https://nuxt.com/docs/4.x/getting-started/upgrade#testing-nuxt-5)) or by enabling it explicitly with `experimental.asyncCallHook: false`. Alternatively, you can ensure `callHook` always returns a `Promise` with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { asyncCallHook: true, }, }) ``` ### Client-Only Comment Placeholders ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, client-only components (`.client.vue` files and `createClientOnly()` wrappers) now render an HTML comment (``) on the server instead of an empty `
` element. #### Reasons for Change When the placeholder `
` and the actual component root share the same tag name, Vue's runtime skips re-applying `setScopeId` during hydration. This causes scoped styles to be missing after the component mounts. Using a comment node avoids the tag name collision entirely. #### Migration Steps If you rely on the placeholder `
` to inherit attributes (`class`, `style`, etc.) for layout purposes (e.g., reserving space to prevent layout shift), wrap the component in `` with a `#fallback` slot instead: ```diff - + + + + ``` You can test this feature early by setting `future.compatibilityVersion: 5` (see [Testing Nuxt 5](https://nuxt.com/docs/4.x/getting-started/upgrade#testing-nuxt-5)) or by enabling it explicitly with `experimental.clientNodePlaceholder: true`. Alternatively, you can revert to the previous `
` placeholder behavior with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { clientNodePlaceholder: false, }, }) ``` ### Stricter Side-Effect Imports ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, Nuxt's generated `tsconfig.json` enables [`noUncheckedSideEffectImports`](https://www.typescriptlang.org/tsconfig/#noUncheckedSideEffectImports). This is a default in TypeScript 7, so adopting it early keeps your project aligned ahead of that upgrade. With this option on, a side-effect-only import (`import './setup'`) that TypeScript cannot resolve to a module is now a type error, whereas it was previously ignored. This only affects type-checking (`nuxt typecheck` and your editor), not runtime behavior. #### Reasons for Change Unresolved side-effect imports were silently ignored, so a typo or a deleted file could pass type-checking. Flagging them catches these mistakes and matches the TypeScript 7 default. #### Migration Steps If type-checking now errors on a side-effect import of a non-code asset (for example `import '~/assets/styles.css'`), add an ambient module declaration so TypeScript knows the import is valid: ```ts [types.d.ts] declare module '*.css' {} ``` You can revert to the previous behavior by disabling the option in your `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedSideEffectImports: false, }, }, }, }) ``` ### Vue Options API Disabled by Default ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, Nuxt sets Vue's [`__VUE_OPTIONS_API__`](https://vuejs.org/api/compile-time-flags#VUE_OPTIONS_API) feature flag to `false`, which compiles Vue's Options API runtime out of the client bundle. #### Reasons for Change The Options API runtime ships in every client bundle even though most Nuxt applications are written with the Composition API and ` ``` ### More Granular Inline Styles ๐Ÿšฆ **Impact Level**: Moderate Nuxt will now only inline styles for Vue components, not global CSS. #### What Changed Previously, Nuxt would inline all CSS, including global styles, and remove `` elements to separate CSS files. Now, Nuxt will only do this for Vue components (which previously produced separate chunks of CSS). We think this is a better balance of reducing separate network requests (just as before, there will not be separate requests for individual `.css` files per-page or per-component on the initial load), as well as allowing caching of a single global CSS file and reducing the document download size of the initial request. #### Migration Steps This feature is fully configurable and you can revert to the previous behavior by setting `inlineStyles: true` to inline global CSS as well as per-component CSS. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ features: { inlineStyles: true, }, }) ``` ### Scan Page Meta After Resolution ๐Ÿšฆ **Impact Level**: Minimal #### What Changed We now scan page metadata (defined in `definePageMeta`) *after* calling the `pages:extend` hook rather than before. #### Reasons for Change This was to allow scanning metadata for pages that users wanted to add in `pages:extend`. We still offer an opportunity to change or override page metadata in a new `pages:resolved` hook. #### Migration Steps If you want to override page metadata, do that in `pages:resolved` rather than in `pages:extend`. ```diff export default defineNuxtConfig({ hooks: { - 'pages:extend'(pages) { + 'pages:resolved'(pages) { const myPage = pages.find(page => page.path === '/') myPage.meta ||= {} myPage.meta.layout = 'overridden-layout' } } }) ``` Alternatively, you can revert to the previous behaviour with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { scanPageMeta: true, }, }) ``` ### Shared Prerender Data ๐Ÿšฆ **Impact Level**: Medium #### What Changed We enabled a previously experimental feature to share data from `useAsyncData` and `useFetch` calls, across different pages. See [original PR](https://github.com/nuxt/nuxt/pull/24894). #### Reasons for Change This feature 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. For example, if your site requires a `useFetch` call for every page (for example, to get navigation data for a menu, or site settings from a CMS), this data would only be fetched once when prerendering the first page that uses it, and then cached for use when prerendering other pages. #### Migration Steps 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.) ```ts [app/pages/test/[slug].vue] // 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}`) }) ``` Alternatively, you can disable this feature with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { sharedPrerenderData: false, }, }) ``` ### Default `data` and `error` values in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `data` and `error` objects returned from `useAsyncData` will now default to `undefined`. #### Reasons for Change Previously `data` was initialized to `null` but reset in `clearNuxtData` to `undefined`. `error` was initialized to `null`. This change is to bring greater consistency. #### Migration Steps If you were checking if `data.value` or `error.value` were `null`, you can update these checks to check for `undefined` instead. You can automate this step by running `npx codemod@latest nuxt/4/default-data-error-value` ### Removal of deprecated `boolean` values for `dedupe` option when calling `refresh` in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`). ```ts [app/app.vue]twoslash // @errors: 2322 const { refresh } = await useAsyncData(() => Promise.resolve({ message: 'Hello, Nuxt!' })) async function refreshData () { await refresh({ dedupe: true }) } ``` #### Reasons for Change These aliases were removed, for greater clarity. The issue came up when adding `dedupe` as an option to `useAsyncData`, and we removed the boolean values as they ended up being *opposites*. `refresh({ dedupe: false })` meant **do not cancel existing requests in favour of this new one**. But passing `dedupe: true` within the options of `useAsyncData` means **do not make any new requests if there is an existing pending request.** (See [PR](https://github.com/nuxt/nuxt/pull/24564#pullrequestreview-1764584361).) #### Migration Steps The migration should be straightforward: ```diff const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' })) async function refreshData () { - await refresh({ dedupe: true }) + await refresh({ dedupe: 'cancel' }) - await refresh({ dedupe: false }) + await refresh({ dedupe: 'defer' }) } ``` You can automate this step by running `npx codemod@latest nuxt/4/deprecated-dedupe-value` ### Respect defaults when clearing `data` in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed If you provide a custom `default` value for `useAsyncData`, this will now be used when calling `clear` or `clearNuxtData` and it will be reset to its default value rather than simply unset. #### Reasons for Change Often users set an appropriately empty value, such as an empty array, to avoid the need to check for `null`/`undefined` when iterating over it. This should be respected when resetting/clearing the data. ### Respect defaults when clearing `useState` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed With `compatibilityVersion: 5`, `clearNuxtState` will reset state to its initial value (provided by the `init` function of `useState`) instead of setting it to `undefined`. This aligns `clearNuxtState` behavior with `clearNuxtData`, which already resets to defaults. #### Reasons for Change When `clearNuxtState` sets state to `undefined`, composables that depend on that state can crash because they expect the state to always have a valid shape (e.g., accessing properties on `undefined`). Resetting to the `init` value ensures state always has a usable default. #### Migration Steps If you rely on `clearNuxtState` setting state to `undefined`, you can explicitly pass `{ reset: false }`: ```diff - clearNuxtState('myKey') + clearNuxtState('myKey', { reset: false }) ``` Alternatively, you can revert to the previous behavior with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { defaults: { useState: { resetOnClear: false, }, }, }, }) ``` You can also opt in to this behavior today without setting `compatibilityVersion: 5`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { defaults: { useState: { resetOnClear: true, }, }, }, }) ``` ### Alignment of `pending` value in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Medium The `pending` object returned from `useAsyncData`, `useFetch`, `useLazyAsyncData` and `useLazyFetch` is now a computed property that is `true` only when `status` is also pending. #### What Changed Now, when `immediate: false` is passed, `pending` will be `false` until the first request is made. This is a change from the previous behavior, where `pending` was always `true` until the first request was made. #### Reasons for Change This aligns the meaning of `pending` with the `status` property, which is also `pending` when the request is in progress. #### Migration Steps If you rely on the `pending` property, ensure that your logic accounts for the new behavior where `pending` will only be `true` when the status is also pending. ```diff ``` Alternatively, you can temporarily revert to the previous behavior with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { pendingWhenIdle: true, }, }) ``` ### Key Change Behavior in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Medium #### What Changed When using reactive keys in `useAsyncData` or `useFetch`, Nuxt automatically refetches data when the key changes. When `immediate: false` is set, `useAsyncData` will only fetch data when the key changes if the data has already been fetched once. Previously, `useFetch` had slightly different behavior. It would always fetch data when the key changed. Now, `useFetch` and `useAsyncData` behave consistently - by only fetch data when the key changes if the data has already been fetched once. #### Reasons for Change This ensures consistent behavior between `useAsyncData` and `useFetch`, and prevents unexpected fetches. If you have set `immediate: false`, then you must call `refresh` or `execute` or data will never be fetched in `useFetch` or `useAsyncData`. #### Migration Steps This change should generally improve the expected behavior, but if you were expecting changing the key or options of a non-immediate `useFetch`, you now will need to trigger it manually the first time. ```diff const id = ref('123') const { data, execute } = await useFetch('/api/test', { query: { id }, immediate: false ) + watch(id, () => execute(), { once: true }) ``` To opt out of this behavior: ```ts // Or globally in your Nuxt config export default defineNuxtConfig({ experimental: { alwaysRunFetchOnKeyChange: true, }, }) ``` ### Shallow Data Reactivity in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal The `data` object returned from `useAsyncData`, `useFetch`, `useLazyAsyncData` and `useLazyFetch` is now a `shallowRef` rather than a `ref`. #### What Changed When new data is fetched, anything depending on `data` will still be reactive because the entire object is replaced. But if your code changes a property *within* that data structure, this will not trigger any reactivity in your app. #### Reasons for Change This brings a **significant** performance improvement for deeply nested objects and arrays because Vue does not need to watch every single property/array for modification. In most cases, `data` should also be immutable. #### Migration Steps In most cases, no migration steps are required, but if you rely on the reactivity of the data object then you have two options: 1. You can granularly opt in to deep reactivity on a per-composable basis: ```diff - const { data } = useFetch('/api/test') + const { data } = useFetch('/api/test', { deep: true }) ``` 2. You can change the default behavior on a project-wide basis (not recommended): ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { defaults: { useAsyncData: { deep: true, }, }, }, }) ``` If you need to, you can automate this step by running `npx codemod@latest nuxt/4/shallow-function-reactivity` ### Absolute Watch Paths in `builder:watch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The Nuxt `builder:watch` hook now emits a path which is absolute rather than relative to your project `srcDir`. #### Reasons for Change This allows us to support watching paths which are outside your `srcDir`, and offers better support for layers and other more complex patterns. #### Migration Steps We have already proactively migrated the public Nuxt modules which we are aware use this hook. See [issue #25339](https://github.com/nuxt/nuxt/issues/25339). However, if you are a module author using the `builder:watch` hook and wishing to remain backwards/forwards compatible, you can use the following code to ensure that your code works the same in both Nuxt v3 and Nuxt v4: ```diff + import { relative, resolve } from 'node:fs' // ... nuxt.hook('builder:watch', async (event, path) => { + path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path)) // ... }) ``` You can automate this step by running `npx codemod@latest nuxt/4/absolute-watch-path` ### Removal of `window.__NUXT__` object #### What Changed We are removing the global `window.__NUXT__` object after the app finishes hydration. #### Reasons for Change This opens the way to multi-app patterns ([#21635](https://github.com/nuxt/nuxt/issues/21635)) and enables us to focus on a single way to access Nuxt app data - `useNuxtApp()`. #### Migration Steps The data is still available, but can be accessed with `useNuxtApp().payload`: ```diff - console.log(window.__NUXT__) + console.log(useNuxtApp().payload) ``` ### Directory index scanning ๐Ÿšฆ **Impact Level**: Medium #### What Changed Child folders in your `app/middleware/` folder are also scanned for `index` files and these are now also registered as middleware in your project. #### Reasons for Change Nuxt scans a number of folders automatically, including `app/middleware/` and `app/plugins/`. Child folders in your `app/plugins/` folder are scanned for `index` files and we wanted to make this behavior consistent between scanned directories. #### Migration Steps Probably no migration is necessary but if you wish to revert to previous behavior you can add a hook to filter out these middleware: ```ts export default defineNuxtConfig({ hooks: { 'app:resolve' (app) { app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path)) }, }, }) ``` ### Template Compilation Changes ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Previously, Nuxt used `lodash/template` to compile templates located on the file system using the `.ejs` file format/syntax. In addition, we provided some template utilities (`serialize`, `importName`, `importSources`) which could be used for code-generation within these templates, which are now being removed. #### Reasons for Change In Nuxt v3 we moved to a 'virtual' syntax with a `getContents()` function which is much more flexible and performant. In addition, `lodash/template` has had a succession of security issues. These do not really apply to Nuxt projects because it is being used at build-time, not runtime, and by trusted code. However, they still appear in security audits. Moreover, `lodash` is a hefty dependency and is unused by most projects. Finally, providing code serialization functions directly within Nuxt is not ideal. Instead, we maintain projects like [unjs/knitwork](https://github.com/unjs/knitwork) which can be dependencies of your project, and where security issues can be reported/resolved directly without requiring an upgrade of Nuxt itself. #### Migration Steps We have raised PRs to update modules using EJS syntax, but if you need to do this yourself, you have three backwards/forwards-compatible alternatives: - Moving your string interpolation logic directly into `getContents()`. - Using a custom function to handle the replacement, such as in [https://github.com/nuxt-modules/color-mode/pull/240](https://github.com/nuxt-modules/color-mode/pull/240). - Use `es-toolkit/compat` (a drop-in replacement for lodash template), as a dependency of *your* project rather than Nuxt: ```diff + import { readFileSync } from 'node:fs' + import { template } from 'es-toolkit/compat' // ... addTemplate({ fileName: 'appinsights-vue.js' options: { /* some options */ }, - src: resolver.resolve('./runtime/plugin.ejs'), + getContents({ options }) { + const contents = readFileSync(resolver.resolve('./runtime/plugin.ejs'), 'utf-8') + return template(contents)({ options }) + }, }) ``` Finally, if you are using the template utilities (`serialize`, `importName`, `importSources`), you can replace them as follows with utilities from `knitwork`: ```ts import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork' const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"\{(.+)\}"(?=,?$)/gm, r => JSON.parse(r).replace(/^\{(.*)\}$/, '$1')) const importSources = (sources: string | string[], { lazy = false } = {}) => { return toArray(sources).map((src) => { if (lazy) { return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}` } return genImport(src, genSafeVariableName(src)) }).join('\n') } const importName = genSafeVariableName ``` You can automate this step by running `npx codemod@latest nuxt/4/template-compilation-changes` ### Default TypeScript Configuration Changes ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `compilerOptions.noUncheckedIndexedAccess` is now `true` instead of `false`. #### Reasons for Change This change is a follow up to a prior [3.12 config update](https://github.com/nuxt/nuxt/pull/27485) where we improved our defaults, mostly adhering to [TotalTypeScript's recommendations](https://www.totaltypescript.com/tsconfig-cheat-sheet). #### Migration Steps There are two approaches: 1. Run a typecheck on your app and fix any new errors (recommended). 2. Override the new default in your `nuxt.config.ts`:```ts export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedIndexedAccess: false, }, }, }, }) ``` ### TypeScript Configuration Splitting ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Nuxt now generates separate TypeScript configurations for different contexts to provide better type-checking experiences: 1. **New TypeScript configuration files**: Nuxt now generates additional TypeScript configurations: - `.nuxt/tsconfig.app.json` - For your app code (Vue components, composables, etc.) - `.nuxt/tsconfig.server.json` - For your server-side code (Nitro/server directory) - `.nuxt/tsconfig.node.json` - For your build-time code (modules, `nuxt.config.ts`, etc.) - `.nuxt/tsconfig.shared.json` - For code shared between app and server contexts (like types and non-environment specific utilities) - `.nuxt/tsconfig.json` - Legacy configuration for backward compatibility 2. **Backward compatibility**: Existing projects that extend `.nuxt/tsconfig.json` will continue to work as before. 3. **Opt-in project references**: New projects or those wanting better type checking can adopt TypeScript's project references feature. 4. **Context-specific type checking**: Each context now has appropriate compiler options and includes/excludes for its specific environment. 5. **New typescript.nodeTsConfig option**: You can now customize the TypeScript configuration for Node.js build-time code. #### Reasons for Change This change provides several benefits: 1. **Better type safety**: Each context (app, server, build-time) gets appropriate type checking with context-specific globals and APIs. 2. **Improved IDE experience**: Better IntelliSense and error reporting for different parts of your codebase. 3. **Cleaner separation**: Server code won't incorrectly suggest client-side APIs and vice versa. 4. **Performance**: TypeScript can more efficiently check code with properly scoped configurations. For example, auto-imports are not available in your `nuxt.config.ts` (but previously this was not flagged by TypeScript). And while IDEs recognized the separate context hinted by `tsconfig.json` in your `server/` directory, this was not reflected in type-checking (requiring a separate step). #### Migration Steps **No migration is required** - existing projects will continue to work as before. However, to take advantage of improved type checking, you can opt in to the new project references approach: 1. **Update your root tsconfig.json** to use project references: If your `tsconfig.json` currently has an `"extends": "./.nuxt/tsconfig.json"` line, **remove it** before adding the references. Project references and extends are mutually exclusive. ```json { // Remove "extends": "./.nuxt/tsconfig.json" if present "files": [], "references": [ { "path": "./.nuxt/tsconfig.app.json" }, { "path": "./.nuxt/tsconfig.server.json" }, { "path": "./.nuxt/tsconfig.shared.json" }, { "path": "./.nuxt/tsconfig.node.json" } ] } ``` 2. **Remove any manual server tsconfig.json** files (like `server/tsconfig.json`) that extended `.nuxt/tsconfig.server.json`. 3. **Update your type checking scripts** to use the build flag for project references:```diff - "typecheck": "nuxt prepare && vue-tsc --noEmit" + "typecheck": "nuxt prepare && vue-tsc -b --noEmit" ``` 4. **Move all type augmentations into their appropriate context**: - If you are augmenting types for the app context, move the files to the `app/` directory. - If you are augmenting types for the server context, move the files to the `server/` directory. - If you are augmenting types that are **shared between the app and server**, move the files to the `shared/` directory. Augmenting types from outside the `app/`, `server/`, or `shared/` directories will not work with the new project references setup. 5. **Configure TypeScript options** if needed:```ts export default defineNuxtConfig({ typescript: { // customize tsconfig.app.json tsConfig: { // ... }, // customize tsconfig.shared.json sharedTsConfig: { // ... }, // customize tsconfig.node.json nodeTsConfig: { // ... }, }, nitro: { typescript: { // customize tsconfig.server.json tsConfig: { // ... }, }, }, }) ``` 6. **Update any CI/build scripts** that run TypeScript checking to ensure they use the new project references approach. The new configuration provides better type safety and IntelliSense for projects that opt in, while maintaining full backward compatibility for existing setups. ### Removal of Experimental Features ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Four experimental features are no longer configurable in Nuxt 4: - `experimental.treeshakeClientOnly` will be `true` (default since v3.0) - `experimental.configSchema` will be `true` (default since v3.3) - `experimental.polyfillVueUseHead` will be `false` (default since v3.4) - `experimental.respectNoSSRHeader` will be `false` (default since v3.4) - `vite.devBundler` is no longer configurable - it will use `vite-node` by default #### Reasons for Change These options have been set to their current values for some time and we do not have a reason to believe that they need to remain configurable. #### Migration Steps - `polyfillVueUseHead` is implementable in user-land with [this plugin](https://github.com/nuxt/nuxt/blob/f209158352b09d1986aa320e29ff36353b91c358/packages/nuxt/src/head/runtime/plugins/vueuse-head-polyfill.ts#L10-L11) - `respectNoSSRHeader`is implementable in user-land with [server middleware](https://github.com/nuxt/nuxt/blob/c660b39447f0d5b8790c0826092638d321cd6821/packages/nuxt/src/core/runtime/nitro/no-ssr.ts#L8-L9) ### Removal of Top-Level `generate` Configuration ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The top-level `generate` configuration option is no longer available in Nuxt 4. This includes all of its properties: - `generate.exclude` - for excluding routes from prerendering - `generate.routes` - for specifying routes to prerender #### Reasons for Change The top level `generate` configuration was a holdover from Nuxt 2. We've supported `nitro.prerender` for a while now, and it is the preferred way to configure prerendering in Nuxt 3+. #### Migration Steps Replace `generate` configuration with the corresponding `nitro.prerender` options: ```diff export default defineNuxtConfig({ - generate: { - exclude: ['/admin', '/private'], - routes: ['/sitemap.xml', '/robots.txt'] - } + nitro: { + prerender: { + ignore: ['/admin', '/private'], + routes: ['/sitemap.xml', '/robots.txt'] + } + } }) ``` Read more about Nitro's prerender configuration options. ### Normalized Page Component Names ๐Ÿšฆ **Impact Level**: Minimal #### What Changed When `future.compatibilityVersion` is set to `5` (or `experimental.normalizePageNames` is enabled), page component names match their route names instead of using the filename. For example, `pages/foo/index.vue` will have the component name `foo` instead of `index`. #### Reasons for Change Previously, Vue assigned component names based on the filename. This meant multiple pages like `pages/foo/index.vue` and `pages/bar/index.vue` would both have the component name `index`. This made `` with `include`/`exclude` filters unreliable and required manually adding `defineOptions({ name: '...' })` to each page. #### Migration Steps If you rely on the current component names (e.g. in `` `include`/`exclude` lists), update them to use route names instead of filenames. ```diff ``` To disable this behavior: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { normalizePageNames: false, }, }) ``` ## Nuxt 2 vs. Nuxt 3+ In the table below, there is a quick comparison between 3 versions of Nuxt:
Feature / Version Nuxt 2 Nuxt Bridge Nuxt 3+
Vue 2 2 3
Stability ๐Ÿ˜Š Stable ๐Ÿ˜Š Stable ๐Ÿ˜Š Stable
Performance ๐ŸŽ Fast โœˆ๏ธ Faster ๐Ÿš€ Fastest
Nitro Engine โŒ โœ… โœ…
ESM support ๐ŸŒ™ Partial ๐Ÿ‘ Better โœ…
TypeScript โ˜‘๏ธ Opt-in ๐Ÿšง Partial โœ…
Composition API โŒ ๐Ÿšง Partial โœ…
Options API โœ… โœ… โœ…
Components Auto Import โœ… โœ… โœ…
``` For in-page updates that are not navigations, such as form validation or toasts, use [``](https://nuxt.com/docs/4.x/api/components/nuxt-announcer) with [`useAnnouncer`](https://nuxt.com/docs/4.x/api/composables/use-announcer) instead. ## Page Titles Because the route announcer follows the document title, giving every route a distinct title is the single most valuable thing you can do. Set a global template in `app.vue` and let each page fill in its own part: ```vue [app.vue] ``` ```vue [app/pages/about.vue] ``` If your titles come from route metadata rather than from the page itself, you can read [`definePageMeta`](https://nuxt.com/docs/4.x/directory-structure/app/pages#page-metadata) values from [`useRoute`](https://nuxt.com/docs/4.x/api/composables/use-route) in a layout. ## Links Use [``](https://nuxt.com/docs/4.x/api/components/nuxt-link) for in-app navigation. It renders a real ``, which means it is focusable, appears in the tab order, and works with middle-click and "open in new tab", all of which you would have to reimplement on a `
` with a `@click` handler calling `navigateTo`. ```vue ``` In a menu or a set of breadcrumbs, the link matching the current route already exposes `aria-current="page"`, so assistive technology can tell which item you are on. Where a different token describes the relationship better, such as a step in a multi-page form, set [`ariaCurrentValue`](https://nuxt.com/docs/4.x/api/components/nuxt-link#routerlink): ```vue ``` Links to files in your `public/` directory, or to another app on the same origin, are not routes that Vue Router knows about. Mark them as [`external`](https://nuxt.com/docs/4.x/api/components/nuxt-link#handling-static-file-and-cross-app-links) so the browser performs a real navigation instead of failing to match a route. ## Focus Management After a client-side navigation, focus stays where it was, which is usually the link the user just activated. Vue Router does not move it and neither does Nuxt, so a keyboard user can end up tabbing through the whole header again to reach the content that just changed. A skip link as the first tab stop of your app is the conventional fix, and it helps on the initial page load too: ```vue [app.vue] ``` `
` is not focusable on its own, so it needs `tabindex="-1"` to accept focus from the skip link or from a script. Use `-1` rather than a positive value, which would move the element in the tab order and surprise everyone else. If it suits your app, you can go further and move focus to the main region after every navigation from a plugin: ```ts [app/plugins/focus-main.client.ts] export default defineNuxtPlugin(() => { useRouter().afterEach((to, from) => { if (to.path === from.path) { return } nextTick(() => document.getElementById('main')?.focus()) }) }) ``` Navigate around your app with the keyboard alone. Tabbing from the skip link into `
` after a couple of navigations will surface most focus problems quickly. ## Scroll Behavior Nuxt scrolls to the top on a new route, restores the previous position when the user goes back, and scrolls to hash targets. If you need something different, such as smooth scrolling or a different offset, configure [`scrollBehaviorType`](https://nuxt.com/docs/4.x/guide/recipes/custom-routing#scroll-behavior-for-hash-links) or write your own `scrollBehavior` in [`router.options.ts`](https://nuxt.com/docs/4.x/guide/recipes/custom-routing#router-options). Bear in mind that smooth scrolling should respect the user's `prefers-reduced-motion` setting. ## Useful Resources - [Web Accessibility Initiative (WAI)](https://www.w3.org/WAI/) - [MDN: Accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility) - [Understanding WCAG 2.1](https://www.w3.org/WAI/WCAG21/Understanding/) # Dev Containers > Set up or open a Nuxt project in a dev container for a consistent development environment. ## Setting Up a Dev Container If you're starting a new Nuxt project and want to develop inside a dev container, you can add the configuration yourself. Read more about dev containers ### Prerequisites - [Visual Studio Code](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) - [Docker Desktop](https://www.docker.com/products/docker-desktop/) or [Docker Engine](https://docs.docker.com/engine/) ### Create the Configuration Create a `.devcontainer/` folder in your project root with these two files: ```json [devcontainer.json] { "name": "nuxt-devcontainer", "build": { "dockerfile": "Dockerfile", "context": "../" }, "forwardPorts": [3000], "portsAttributes": { "3000": { "label": "Application", "onAutoForward": "openPreview" } }, "mounts": [ "type=volume,target=${containerWorkspaceFolder}/node_modules" ], "postStartCommand": "pnpm install && pnpm dev:prepare" } ``` ```dockerfile [Dockerfile] FROM node:lts WORKDIR /app RUN npm i -g corepack && corepack enable COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ RUN pnpm install --frozen-lockfile COPY . . ``` This configuration uses Node.js LTS and enables pnpm via corepack. It forwards port 3000 for the Nuxt dev server and persists `node_modules` in a Docker volume to avoid reinstallation on container restarts. To use a different package manager, replace `corepack enable` with your preferred manager (for example, `npm install -g yarn`) and update the `postStartCommand` accordingly. ## Opening an Existing Dev Container If a project already includes a dev container configuration, you can open it using any of these methods: ### 1. VS Code Prompt When you open the project in VS Code, you should see a notification in the bottom right corner: > "Reopen in Dev Containers" Click this button to build and open the project in a dev container. ### 2. Command Palette If you dismiss the prompt or want to manually trigger it: 1. Open the Command Palette (`Cmd+Shift+P` on Mac, `Ctrl+Shift+P` on Windows/Linux) 2. Search for **"Dev Containers: Reopen in Container"** 3. Select it VS Code will build the container and reopen your project. ### 3. Dev Containers CLI For advanced users or CI workflows, you can use the Dev Containers CLI directly: ```bash # Install the CLI (if not already installed) npm install -g @devcontainers/cli # Build and open the project in a container devcontainer up --workspace-folder . # After making changes to .devcontainer, rebuild devcontainer build ``` ## Next Steps Once the container is running: ```bash pnpm dev ``` Your Nuxt app will be available at [http://localhost:3000](http://localhost:3000). # Nuxt and Hydration > Why fixing hydration issues is important When developing, you may face hydration issues. Don't ignore those warnings. ## Why Is It Important to Fix Them? Hydration mismatches are not just warnings - they are indicators of serious problems that can break your application: ### Performance Impact - **Increased time to interactive**: Hydration errors force Vue to re-render the entire component tree, which will increase the time for your Nuxt app to become interactive - **Poor user experience**: Users may see content flashing or unexpected layout shifts ### Functionality Issues - **Broken interactivity**: Event listeners may not attach properly, leaving buttons and forms non-functional - **State inconsistencies**: Application state can become out of sync between what the user sees and what the application thinks is rendered - **SEO problems**: Search engines may index different content than what users actually see ## How to Detect Them ### Development Console Warnings Vue will log hydration mismatch warnings in the browser console during development: ![Screenshot of Vue hydration mismatch warning in the browser console](https://nuxt.com/assets/docs/best-practices/vue-console-hydration.png) ## Common Reasons ### Browser-only APIs in Server Context **Problem**: Using browser-specific APIs during server-side rendering. ```html ``` **Solution**: You can use [`useCookie`](https://nuxt.com/docs/4.x/api/composables/use-cookie): ```html ``` ### Inconsistent Data **Problem**: Different data between server and client. ```html ``` **Solution**: Use SSR-friendly state: ```html ``` ### Conditional Rendering Based on Client State **Problem**: Using client-only conditions during SSR. ```html ``` **Solution**: Use media queries or handle it client-side: ```html ``` ### Third-party Libraries with Side Effects **Problem**: Libraries that modify the DOM or have browser dependencies (this happens a LOT with tag managers). ```html ``` **Solution**: Initialise libraries after hydration has completed: ```html ``` ### Dynamic Content Based on Time **Problem**: Content that changes based on current time. ```html ``` **Solution**: Use [`NuxtTime`](https://nuxt.com/docs/4.x/api/components/nuxt-time) component or handle it client-side: ```html ``` ```html ``` ## In Summary 1. **Use SSR-friendly composables**: [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch), [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data), [`useState`](https://nuxt.com/docs/4.x/api/composables/use-state) 2. **Wrap client-only code**: Use [`ClientOnly`](https://nuxt.com/docs/4.x/api/components/client-only) component for browser-specific content 3. **Consistent data sources**: Ensure server and client uses the same data 4. **Avoid side effects in setup**: Move browser-dependent code to `onMounted` You can read the [Vue documentation on SSR hydration mismatch](https://vuejs.org/guide/scaling-up/ssr#hydration-mismatch) for a better understanding of hydration. # Nuxt performance > Best practices for improving performance of Nuxt apps. Nuxt comes with built-in features designed to improve your application's performance and contribute to better [Core Web Vitals](https://web.dev/articles/vitals). There are also multiple Nuxt core modules that assist in improving performance in specific areas. This guide outlines best practices to optimize performance of your Nuxt application. ## Built-in Features Nuxt offers several built-in features that help you optimize performance of your website. Understanding how these features work is crucial for achieving blazingly-fast performance. ### Links [``](https://nuxt.com/docs/4.x/api/components/nuxt-link) is a drop-in replacement for both Vue Router's `` component and HTML's `` tag. It intelligently determines whether the link is internal or external and renders it accordingly with available optimizations (prefetching, default attributes, etc.) ```html About page ``` Nuxt automatically includes smart prefetching. That means it detects when a link is visible (by default), either in the viewport or when scrolling and prefetches the JavaScript for those pages so that they are ready when the user clicks the link. You can also opt for prefetching on interaction instead: ```ts export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { prefetchOn: { interaction: true, visibility: false, }, }, }, }, }) ``` ### Hybrid Rendering In more complex applications, we may need a full control over how our application is rendered to support cases where some pages could be generated at build time, while others should be client-side rendered Hybrid rendering allows different caching rules per route using Route Rules and decides how the server should respond to a new request on a given URL: ```ts export default defineNuxtConfig({ routeRules: { '/': { prerender: true, }, '/products/**': { swr: 3600, }, '/blog': { isr: 3600, }, '/admin/**': { ssr: false, }, }, }) ``` Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using Nitro caching layer. ### Lazy Loading Components To dynamically import a component (also known as lazy-loading a component) all you need to do is add the Lazy prefix to the component's name. This is useful if the component is not always needed. ```html ``` By using the Lazy prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size. ### Lazy Hydration It is not always necessary to hydrate (or make interactive) all the components of your site on the initial load. Using lazy hydration, you can control when components can have their code loaded, which can improve the time-to-interactive metric for your app. Nuxt allows you to control when components become interactive with lazy hydration (added in Nuxt v3.16). ```html ``` To optimize your app, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks. For content and marketing sites that need little or no client-side interactivity, you can go further and combine prerendering, the `noScripts` route rule, [server components](https://nuxt.com/docs/4.x/guide/concepts/server-components) and lazy hydration to ship near-zero JavaScript. ### Fetching data To avoid fetching same data twice (once on the server and once on client) Nuxt provides [`useFetch`](https://nuxt.com/docs/4.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data). They ensure that if an API call is made on the server, the data is forwarded to the client in the payload instead of being fetched again. ## Core Nuxt Modules Apart from Nuxt's built-in features, there are also core modules maintained by the Nuxt team which help improve performance even further. These modules help handle assets such as images, custom fonts, or third party scripts. ### Images Unoptimized images can have a significant negative impact on your website performance, specifically the [Largest Contentful Paint (LCP)](https://web.dev/articles/lcp) score. In Nuxt we can use [Nuxt Image](https://image.nuxt.com/) module that is a plug-and-play image optimization for Nuxt apps. It allows resizing and transforming your images using built-in optimizer or your favorite images CDN. [``](https://nuxt.com/docs/4.x/api/components/nuxt-img) is a drop-in replacement for the native `` tag that comes with following enhancements: - Uses built-in provider to optimize local and remote images - Converts `src` to provider optimized URLs with modern formats such as WebP or Avif - Automatically resizes images based on `width` and `height` - Generates responsive `sizes` when providing sizes option - Supports native `lazy loading` as well as other `` attributes Images in your website can usually be separated by importance; the ones that are needed to be delivered first at initial load (i.e. `Largest Contentful Paint`), and the ones that can be loaded later or when specifically needed. For that, we could use the following optimizations: ```html ``` ### Fonts [Nuxt Fonts](https://fonts.nuxt.com/) will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance. It includes built-in automatic self-hosting for any font file which means you can optimally load web fonts with reduced layout shift, thanks to the underlying package [fontaine](https://github.com/unjs/fontaine). Nuxt Fonts processes all your CSS and does the following things automatically when it encounters a font-family declaration. 1. **Resolves fonts** โ€“ Looks for font files in public/, then checks web providers like Google, Bunny, and Fontshare. 2. **Generates @font-face rules** โ€“ Injects CSS rules to load fonts from the correct sources. 3. **Proxies & caches fonts** โ€“ Rewrites URLs to `/_fonts`, downloads and caches fonts locally. 4. **Creates fallback metrics** โ€“ Adjusts local system fonts to match web fonts, reducing layout shift ([CLS](https://web.dev/articles/cls)). 5. **Includes fonts in build** โ€“ Bundles fonts with your project, hashing file names and setting long-lived cache headers. It supports multiple providers that are designed to be pluggable and extensible, so no matter your setup you should be able to use an existing provider or write your own. ### Scripts Third-party resources like analytics tools, video embeds, maps, and social media integrations enhance website functionality but can significantly degrade user experience and negatively impact [Interaction to Next Paint (INP)](https://web.dev/articles/inp) and Largest Contentful Paint (LCP) scores. [Nuxt Scripts](https://scripts.nuxt.com/) lets you load third-party scripts with better performance, privacy, security and DX. Nuxt Scripts provides an abstraction layer on top of third-party scripts, providing SSR support and type-safety and while still giving you full low-level control over how a script is loaded. ```ts const { onLoaded, proxy } = useScriptGoogleAnalytics( { id: 'G-1234567', scriptOptions: { trigger: 'manual', }, }, ) // queue events to be sent when ga loads proxy.gtag('config', 'UA-123456789-1') // or wait until ga is loaded onLoaded((gtag) => { // script loaded }) ``` ## Profiling Tools To improve performance, we need to first know how to measure it, starting with measuring performance during development - on local environment, and then moving to auditing application that are deployed on production. ### Nuxi Analyze [This](https://nuxt.com/docs/4.x/api/commands/analyze) command of `nuxt` allows you to analyze the production bundle of your Nuxt application. It leverages `vite-bundle-visualizer` (similar to `webpack-bundle-analyzer`) to generate a visual representation of your application's bundle, making it easier to identify which components take up the most space. When you see a large block in the visualization, it often signals an opportunity for optimizationโ€”whether by splitting it into smaller parts, implementing lazy loading, or replacing it with a more efficient alternative, especially for third-party libraries. Large blocks containing multiple elements can often be reduced by importing only the necessary components rather than entire modules while large standalone blocks may be better suited for lazy loading rather than being included in the main bundle. ### Nuxt DevTools The [Nuxt DevTools](https://devtools.nuxt.com/) gives you insights and transparency about your Nuxt App to identify performance gaps and seamlessly manage your app configurations. ![Nuxt DevTools example](https://user-images.githubusercontent.com/11247099/217670806-fb39aeff-3881-44e5-b9c8-6c757f5925fc.png) It comes with several features we can use to measure performance of Nuxt apps: 1. **Timeline** โ€“ Tracks time spent on rendering, updating, and initializing components to identify performance bottlenecks. 2. **Assets** โ€“ Displays file sizes (e.g., images) without transformations. 3. **Render Tree** โ€“ Shows connections between Vue components, scripts, and styles to optimize dynamic loading. 4. **Inspect** โ€“ Lists all files used in the Vue app with their size and evaluation time. ### Chrome DevTools Chrome DevTools come with two useful tabs for measuring performance; `Performance` and `Lighthouse`. When you open the [Performance](https://developer.chrome.com/docs/devtools/performance/overview) panel, it instantly shows your local **Largest Contentful Paint (LCP)** and **Cumulative Layout Shift (CLS)** scores (good, needs improvement, or bad). If you interact with the page, it also captures **Interaction to Next Paint (INP)**, giving you a full view of your Core Web Vitals based on your device and network. ![Chrome DevTools Performance Panel](https://developer.chrome.com/static/docs/devtools/performance/image/cpu-throttling_856.png) [Lighthouse](https://developer.chrome.com/docs/devtools/lighthouse) audits performance, accessibility, SEO, progressive web apps, and best practices. It runs tests on your page and generates a report. Use failing audits as a guide to improve your site. ![Lighthouse](https://developer.chrome.com/static/docs/lighthouse/images/lighthouse-overview_720.png) Each audit has a reference document explaining why the audit is important, as well as how to fix it. ### PageSpeed Insights [PageSpeed Insights (PSI)](https://developers.google.com/speed/docs/insights/v5/about) reports on the user experience of a page on both mobile and desktop devices, and provides suggestions on how that page may be improved. It provides both lab and field data about a page. Lab data is useful for debugging issues, as it is collected in a controlled environment while field data is useful for capturing true, real-world user experience. ### Web Page Test [WebPageTest](https://www.webpagetest.org/) is a web performance tool providing deep diagnostic information about how a page performs under a variety of conditions. Each test can be run from different locations around the world, on real browsers, over any number of customizable network conditions. ## Common Problems When building more complex Nuxt applications, you will probably encounter some of the problems listed below. Understanding these problems and fixing them will help you improve performance of your website. ### Overusing plugins **Problem**: A large number of plugins can cause performance issues, especially if they require expensive computations or take too long to initialize. Since plugins run during the hydration phase, inefficient setups can block rendering and degrade the user experience. **Solution**: Inspect your plugins and see if some of them could be implemented rather as a composable or utility function instead. ### Unused code / dependencies **Problem**: With the development of the project, there can be a case where there will be some unused code or a dependency. This additional functionality may not be used or needed while it will be increase the bundle size of our project. **Solution**: Inspect your `package.json` for unused dependencies and analyze your code for unused utils/composables/functions. ### Not using Vue Performance tips **Problem**: [Vue documentation](https://vuejs.org/guide/best-practices/performance) lists several Performance improvements we can use in our Nuxt projects as well but as they are part of Vue documentation, developers tend to forget about it and focus on Nuxt specific improvements only - while Nuxt application is still a Vue project. **Solution**: Use concepts such as `shallowRef`, `v-memo`, `v-once`, etc to improve performance. ### Not following patterns **Problem**: The more people are currently working on the project, the more difficult it will be to maintain the stable codebase. Developers have a tendency to introduce new concepts they've seen in another project which can cause conflicts and problems with performance. **Solution**: Establish rules and patterns in the project such as [Good practices and Design Patterns for Vue Composables](https://dev.to/jacobandrewsky/good-practices-and-design-patterns-for-vue-composables-24lk) ### Trying to load everything at the same time **Problem**: When a page is loaded and it is not correctly instructed about the order of loading elements it will result in fetching everything at the same time - which can be slow and result in bad User Experience. **Solution**: Use concepts such as Progressive Enhancement where core webpage content is set first, then more nuanced and technically rigorous layers of presentation and features are added on top as the browser/internet connection allow. ## Useful Resources To learn more about various techniques for improving performance, take a look at the following resources: 1. [Apply instant loading with the PRPL pattern](https://web.dev/articles/apply-instant-loading-with-prpl) 2. [Perceived performance](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance) 3. [Understanding Critical Rendering Path](https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Critical_rendering_path) # Nuxt Plugins > Best practices when using Nuxt plugins. Plugins in Nuxt allow you to extend your application with additional functionality. However, improper use can lead to performance bottlenecks. This guide outlines best practices to optimize your Nuxt plugins. ## Avoid Costly Plugin Setup A large number of plugins can cause performance issues, especially if they require expensive computations or take too long to initialize. Since plugins run during the hydration phase, inefficient setups can block rendering and degrade the user experience. ## Use Composition Whenever Possible Whenever possible, favor composition over plugins. Just like in Vue, many utilities and composables can be used directly without the need for a plugin. This keeps your project lightweight and improves maintainability. ## If `async`, Enable `parallel` By default, all plugins loads synchronously. When defining asynchronous plugins, setting `parallel: true` allows multiple plugins to load concurrently, improving performance by preventing blocking operations. # Auto-imports > Nuxt auto-imports components, composables, helper functions and Vue APIs. Nuxt auto-imports components, composables and [Vue.js APIs](https://vuejs.org/api/) to use across your application without explicitly importing them. ```vue [app/app.vue]twoslash ``` Thanks to its opinionated directory structure, Nuxt can auto-import your [`app/components/`](https://nuxt.com/docs/4.x/directory-structure/app/components), [`app/composables/`](https://nuxt.com/docs/4.x/directory-structure/app/composables) and [`app/utils/`](https://nuxt.com/docs/4.x/directory-structure/app/utils). Contrary to a classic global declaration, Nuxt preserves typings, IDEs completions and hints, and **only includes what is used in your production code**. In the docs, every function that is not explicitly imported is auto-imported by Nuxt and can be used as-is in your code. You can find a reference for auto-imported components, composables and utilities in the [API section](https://nuxt.com/docs/4.x/api). In the [`server`](https://nuxt.com/docs/4.x/directory-structure/server) directory, Nuxt auto-imports exported functions and variables from `server/utils/`. You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports`](https://nuxt.com/docs/4.x/api/nuxt-config#imports) section of your `nuxt.config` file. ## Built-in Auto-imports Nuxt auto-imports functions and composables to perform [data fetching](https://nuxt.com/docs/4.x/getting-started/data-fetching), get access to the [app context](https://nuxt.com/docs/4.x/api/composables/use-nuxt-app) and [runtime config](https://nuxt.com/docs/4.x/guide/going-further/runtime-config), manage [state](https://nuxt.com/docs/4.x/getting-started/state-management) or define components and plugins. ```vuetwoslash ``` Vue exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt. ```vuetwoslash ``` ### Vue and Nuxt Composables When you are using the built-in Composition API composables provided by Vue and Nuxt, be aware that many of them rely on being called in the right *context*. During a component lifecycle, Vue tracks the temporary instance of the current component (and similarly, Nuxt tracks a temporary instance of `nuxtApp`) via a global variable, and then unsets it in the same tick. This is essential when server rendering, both to avoid cross-request state pollution (leaking a shared reference between two users) and to avoid leakage between different components. That means that (with very few exceptions) you cannot use them outside a Nuxt plugin, Nuxt route middleware or Vue setup function. On top of that, you must use them synchronously - that is, you cannot use `await` before calling a composable, except within ` ``` ### Disabling Auto-imports If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { autoImport: false, }, }) ``` This will disable auto-imports completely but it's still possible to use [explicit imports](https://nuxt.com/docs/4.x/guide/concepts/auto-imports#explicit-imports) from `#imports`. ### Partially Disabling Auto-imports If you want framework-specific functions like `ref` to remain auto-imported but wish to disable auto-imports for your own code (e.g., custom composables), you can set the `imports.scan` option to `false` in your `nuxt.config.ts` file: ```ts export default defineNuxtConfig({ imports: { scan: false, }, }) ``` With this configuration: - Framework functions like `ref`, `computed`, or `watch` will still work without needing manual imports. - Custom code, such as composables, will need to be manually imported in your files. **Caution:** This setup has certain limitations: - If you structure your project with layers, you will need to explicitly import the composables from each layer, rather than relying on auto-imports. - This breaks the layer systemโ€™s override feature. If you use `imports.scan: false`, ensure you understand this side-effect and adjust your architecture accordingly. ## Auto-imported Components Nuxt also automatically imports components from your `~/components` directory, although this is configured separately from auto-importing composables and utility functions. To disable auto-importing components from your own `~/components` directory, you can set `components.dirs` to an empty array (though note that this will not affect components added by modules). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: { dirs: [], }, }) ``` ## Auto-Import from Third-Party Packages Nuxt also allows auto-importing from third-party packages. If you are using the Nuxt module for that package, it is likely that the module has already configured auto-imports for that package. For example, you could enable the auto-import of the `useI18n` composable from the `vue-i18n` package like this: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { presets: [ { from: 'vue-i18n', imports: ['useI18n'], }, ], }, }) ``` # Code Style > Nuxt supports ESLint out of the box ## ESLint The recommended approach for Nuxt is to enable ESLint support using the [`@nuxt/eslint`](https://eslint.nuxt.com/packages/module) module, that will setup project-aware ESLint configuration for you. The module is designed for the [new ESLint flat config format](https://eslint.org/docs/latest/use/configure/configuration-files) which is the [default format since ESLint v9](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/). If you are using the legacy `.eslintrc` config, you will need to [configure manually with `@nuxt/eslint-config`](https://eslint.nuxt.com/packages/config#customizing-the-config). We highly recommend you to migrate over the flat config to be future-proof. ## Quick Setup ```bash npx nuxt module add eslint ``` Start your Nuxt app, a `eslint.config.mjs` file will be generated under your project root. You can customize it as needed. You can learn more about the module and customizations in [Nuxt ESLint's documentation](https://eslint.nuxt.com/packages/module). # ES Modules > Nuxt uses native ES modules. This guide helps explain what ES Modules are and how to make a Nuxt app (or upstream library) compatible with ESM. ## Background ### CommonJS Modules CommonJS (CJS) is a format introduced by Node.js that allows sharing functionality between isolated JavaScript modules ([read more](https://nodejs.org/api/modules.html)). You might be already familiar with this syntax: ```js const a = require('./a') module.exports.a = a ``` Bundlers like webpack and Rollup support this syntax and allow you to use modules written in CommonJS in the browser. ### ESM Syntax Most of the time, when people talk about ESM vs. CJS, they are talking about a different syntax for writing [modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ```js import a from './a' export { a } ``` Before ECMAScript Modules (ESM) became a standard (it took more than 10 years!), tooling like [webpack](https://webpack.js.org/guides/ecma-script-modules/) and even languages like TypeScript started supporting so-called **ESM syntax**. However, there are some key differences with actual spec; here's [a helpful explainer](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/). ### What is 'Native' ESM? You may have been writing your app using ESM syntax for a long time. After all, it's natively supported by the browser, and in Nuxt 2 we compiled all the code you wrote to the appropriate format (CJS for server, ESM for browser). When adding modules to your package, things were a little different. A sample library might expose both CJS and ESM versions, and let us pick which one we wanted: ```json { "name": "sample-library", "main": "dist/sample-library.cjs.js", "module": "dist/sample-library.esm.js" } ``` So in Nuxt 2, the bundler (webpack) would pull in the CJS file ('main') for the server build and use the ESM file ('module') for the client build. The `module` field is a convention used by bundlers like webpack and Rollup, but is not recognized by Node.js itself. Node.js only uses the [`exports`](https://nodejs.org/api/packages.html#exports) and [`main`](https://nodejs.org/api/packages.html#main) fields for module resolution. However, in recent Node.js LTS releases, it is now possible to [use native ESM module](https://nodejs.org/api/esm.html) within Node.js. That means that Node.js itself can process JavaScript using ESM syntax, although it doesn't do it by default. The two most common ways to enable ESM syntax are: - set `"type": "module"` within your `package.json` and keep using `.js` extension - use the `.mjs` file extensions (recommended) This is what we do for Nuxt Nitro; we output a `.output/server/index.mjs` file. That tells Node.js to treat this file as a native ES module. ### What Are Valid Imports in a Node.js Context? When you `import` a module rather than `require` it, Node.js resolves it differently. For example, when you import `sample-library`, Node.js will look for the `exports` entry in that library's `package.json`, or fall back to the `main` entry if `exports` is not defined. This is also true of dynamic imports, like `const b = await import('sample-library')`. Node supports the following kinds of imports (see [docs](https://nodejs.org/api/packages.html#determining-module-system)): 1. files ending in `.mjs` - these are expected to use ESM syntax 2. files ending in `.cjs` - these are expected to use CJS syntax 3. files ending in `.js` - these are expected to use CJS syntax unless their `package.json` has `"type": "module"` ### What Kinds of Problems Can There Be? For a long time module authors have been producing ESM-syntax builds but using conventions like `.esm.js` or `.es.js`, which they have added to the `module` field in their `package.json`. This hasn't been a problem until now because they have only been used by bundlers like webpack, which don't especially care about the file extension. However, if you try to import a package with an `.esm.js` file in a Node.js ESM context, it won't work, and you'll get an error like: ```bash [Terminal] (node:22145) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. /path/to/index.js:1 export default {} ^^^^^^ SyntaxError: Unexpected token 'export' at wrapSafe (internal/modules/cjs/loader.js:1001:16) at Module._compile (internal/modules/cjs/loader.js:1049:27) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10) .... at async Object.loadESM (internal/process/esm_loader.js:68:5) ``` You might also get this error if you have a named import from an ESM-syntax build that Node.js thinks is CJS: ```bash [Terminal] file:///path/to/index.mjs:5 import { named } from 'sample-library' ^^^^^ SyntaxError: Named export 'named' not found. The requested module 'sample-library' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using: import pkg from 'sample-library'; const { named } = pkg; at ModuleJob._instantiate (internal/modules/esm/module_job.js:120:21) at async ModuleJob.run (internal/modules/esm/module_job.js:165:5) at async Loader.import (internal/modules/esm/loader.js:177:24) at async Object.loadESM (internal/process/esm_loader.js:68:5) ``` ## Troubleshooting ESM Issues If you encounter these errors, the issue is almost certainly with the upstream library. They need to [fix their library](https://nuxt.com/docs/4.x/guide/concepts/esm#library-author-guide) to support being imported by Node. ### Transpiling Libraries In the meantime, you can tell Nuxt not to try to import these libraries by adding them to `build.transpile`: ```tstwoslash export default defineNuxtConfig({ build: { transpile: ['sample-library'], }, }) ``` You may find that you *also* need to add other packages that are being imported by these libraries. ### Aliasing Libraries In some cases, you may also need to manually alias the library to the CJS version, for example: ```tstwoslash export default defineNuxtConfig({ alias: { 'sample-library': 'sample-library/dist/sample-library.cjs.js', }, }) ``` ### Default Exports A dependency with CommonJS format, can use `module.exports` or `exports` to provide a default export: ```js [node_modules/cjs-pkg/index.js] module.exports = { test: 123 } // or exports.test = 123 ``` This normally works well if we `require` such dependency: ```js [test.cjs] const pkg = require('cjs-pkg') console.log(pkg) // { test: 123 } ``` [Node.js in native ESM mode](https://nodejs.org/api/esm.html#interoperability-with-commonjs), [typescript with `esModuleInterop` enabled](https://www.typescriptlang.org/tsconfig/#esModuleInterop) and bundlers such as webpack, provide a compatibility mechanism so that we can default import such library. This mechanism is often referred to as "interop require default": ```js import pkg from 'cjs-pkg' console.log(pkg) // { test: 123 } ``` However, because of the complexities of syntax detection and different bundle formats, there is always a chance that the interop default fails and we end up with something like this: ```js import pkg from 'cjs-pkg' console.log(pkg) // { default: { test: 123 } } ``` Also when using dynamic import syntax (in both CJS and ESM files), we always have this situation: ```js import('cjs-pkg').then(console.log) // [Module: null prototype] { default: { test: '123' } } ``` In this case, we need to manually interop the default export: ```js // Static import import { default as pkg } from 'cjs-pkg' // Dynamic import import('cjs-pkg').then(m => m.default || m).then(console.log) ``` For handling more complex situations and more safety, we recommend [mlly](https://github.com/unjs/mlly), which can preserve named exports. ```js import { interopDefault } from 'mlly' // Assuming the shape is { default: { foo: 'bar' }, baz: 'qux' } import myModule from 'my-module' console.log(interopDefault(myModule)) // { foo: 'bar', baz: 'qux' } ``` ## Library Author Guide The good news is that it's relatively simple to fix issues of ESM compatibility. There are two main options: 1. **You can rename your ESM files to end with .mjs.**
*This is the recommended and simplest approach.* You may have to sort out issues with your library's dependencies and possibly with your build system, but in most cases, this should fix the problem for you. It's also recommended to rename your CJS files to end with `.cjs`, for the greatest explicitness. 2. **You can opt to make your entire library ESM-only**.
This would mean setting `"type": "module"` in your `package.json` and ensuring that your built library uses ESM syntax. However, you may face issues with your dependencies - and this approach means your library can *only* be consumed in an ESM context. ### Migration The initial step from CJS to ESM is updating any usage of `require` to use `import` instead: ```ts [Before] module.exports = function () { /* ... */ } exports.hello = 'world' ``` ```ts [After] export default function () { /* ... */ } export const hello = 'world' ``` ```js [Before] const myLib = require('my-lib') ``` ```js [After] import myLib from 'my-lib' // or const dynamicMyLib = await import('my-lib').then(lib => lib.default || lib) ``` In ESM Modules, unlike CJS, `require`, `require.resolve`, `__filename` and `__dirname` globals are not available and should be replaced with `import()` and `import.meta.filename`. ```js [Before] const { join } = require('node:path') const newDir = join(__dirname, 'new-dir') ``` ```js [After] import { fileURLToPath } from 'node:url' const newDir = fileURLToPath(new URL('./new-dir', import.meta.url)) ``` ```js [Before] const someFile = require.resolve('./lib/foo.js') ``` ```js [After] import { resolveModulePath } from 'exsolve' const someFile = resolveModulePath('my-lib', { from: import.meta.url }) ``` ### Best Practices - Prefer named exports rather than default export. This helps reduce CJS conflicts. (see [Default exports](https://nuxt.com/docs/4.x/guide/concepts/esm#default-exports) section) - Avoid depending on Node.js built-ins and CommonJS or Node.js-only dependencies as much as possible to make your library usable in Browsers and Edge Workers without needing Nitro polyfills. - Use new `exports` field with conditional exports. ([read more](https://nodejs.org/api/packages.html#conditional-exports)). ```json { "exports": { ".": { "import": "./dist/mymodule.mjs" } } } ``` # Modules > Nuxt provides a module system to extend the framework core and simplify integrations. ## Exploring Nuxt Modules When developing production-grade applications with Nuxt you might find that the framework's core functionality is not enough. Nuxt can be extended with configuration options and plugins, but maintaining these customizations across multiple projects can be tedious, repetitive and time-consuming. On the other hand, supporting every project's needs out of the box would make Nuxt very complex and hard to use. This is one of the reasons why Nuxt provides a module system that makes it possible to extend the core. Nuxt modules are async functions that sequentially run when starting Nuxt in development mode using [`nuxt dev`](https://nuxt.com/docs/4.x/api/commands/dev) or building a project for production with [`nuxt build`](https://nuxt.com/docs/4.x/api/commands/build). They can override templates, configure webpack loaders, add CSS libraries, and perform many other useful tasks. Best of all, Nuxt modules can be distributed in npm packages. This makes it possible for them to be reused across projects and shared with the community, helping create an ecosystem of high-quality add-ons. Explore Nuxt Modules ## Add Nuxt Modules Once you have installed the modules you can add them to your [`nuxt.config.ts`](https://nuxt.com/docs/4.x/directory-structure/nuxt-config) file under the `modules` property. Module developers usually provide additional steps and details for usage. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ modules: [ // Using package name (recommended usage) '@nuxtjs/example', // Load a local module './modules/example', // Add module with inline-options ['./modules/example', { token: '123' }], // Inline module definition async (inlineOptions, nuxt) => { }, ], }) ``` Nuxt modules are now build-time-only, and the `buildModules` property used in Nuxt 2 is deprecated in favor of `modules`. ## Disabling Modules v4.3 You can disable a module by setting its config key to `false` in your Nuxt config. This is particularly useful when you want to disable modules inherited from layers. ```ts [nuxt.config.ts] export default defineNuxtConfig({ // Disable `@nuxt/image` module image: false, }) ``` ## Create a Nuxt Module Everyone has the opportunity to develop modules and we cannot wait to see what you will build. # Nuxt Lifecycle > Understanding the lifecycle of Nuxt applications can help you gain deeper insights into how the framework operates, especially for both server-side and client-side rendering. The goal of this chapter is to provide a high-level overview of the different parts of the framework, their execution order, and how they work together. ## Server Lifecycle On the server, the following steps are executed for every initial request to your application: ### Server plugins once Nuxt is powered by [Nitro](https://nitro.build/), a modern server engine. When Nitro starts, it initializes and executes the plugins under the [`/server/plugins`](https://nuxt.com/docs/4.x/directory-structure/server#server-plugins) directory. These plugins can: - Capture and handle application-wide errors. - Register hooks that execute when Nitro shuts down. - Register hooks for request lifecycle events, such as modifying responses. Nitro plugins are executed only once when the server starts. In a serverless environment, the server boots on each incoming request, and so do the Nitro plugins. However, they are not awaited. ### Server middleware After initializing the Nitro server, middleware under `server/middleware/` is executed for every request. Middleware can be used for tasks such as authentication, logging, or request transformation. Returning a value from middleware will terminate the request and send the returned value as the response. This behavior should generally be avoided to ensure proper request handling! ### App plugins The Vue and Nuxt instances are created first. Afterward, Nuxt executes its app plugins. This includes: - Built-in plugins, such as Vue Router and `unhead`. - Custom plugins located in the `app/plugins/` directory, including those without a suffix (e.g., `myPlugin.ts`) and those with the `.server` suffix (e.g., `myServerPlugin.server.ts`). Plugins execute in a specific order and may have dependencies on one another. For more details, including execution order and parallelism, refer to the [Plugins documentation](https://nuxt.com/docs/4.x/directory-structure/app/plugins). After this step, Nuxt calls the [`app:created`](https://nuxt.com/docs/4.x/api/advanced/hooks#app-hooks-runtime) hook, which can be used to execute additional logic. ### Route validation After initializing plugins and before executing middleware, Nuxt calls the `validate` method if it is defined in the `definePageMeta` function. The `validate` method, which can be synchronous or asynchronous, is often used to validate dynamic route parameters. - The `validate` function should return `true` if the parameters are valid. - If validation fails, it should return `false` or an object containing a `status` and/or `statusText` to terminate the request. For more information, see the [Route Validation documentation](https://nuxt.com/docs/4.x/getting-started/routing#route-validation). ### App middleware Middleware allows you to run code before navigating to a particular route. It is often used for tasks such as authentication, redirection, or logging. In Nuxt, there are three types of middleware: - **Global route middleware** - **Named route middleware** - **Anonymous (or inline) route middleware** Nuxt executes all global middleware on the initial page load (both on server and client) and then again before any client-side navigation. Named and anonymous middleware are executed only on the routes specified in the middleware property of the page(route) meta defined in the corresponding page components. For details about each type and examples, see the [Middleware documentation](https://nuxt.com/docs/4.x/directory-structure/app/middleware). Any redirection on the server will result in a `Location:` header being sent to the browser; the browser then makes a fresh request to this new location. All application state will be reset when this happens, unless persisted in a cookie. ### Page and components Nuxt renders the page and its components and fetches any required data with `useFetch` and `useAsyncData` during this step. Since there are no dynamic updates and no DOM operations occur on the server, Vue lifecycle hooks such as `onBeforeMount`, `onMounted`, and subsequent hooks are **NOT** executed during SSR. By default, Vue pauses dependency tracking during SSR for better performance. There is no reactivity on the server side because Vue SSR renders the app top-down as static HTML, making it impossible to go back and modify content that has already been rendered. You should avoid code that produces side effects that need cleanup in root scope of ` ``` On the initial request, the `counter` ref is initialized in the server since it is rendered inside the `

` tag. The contents of `handleClick` is never executed here. During hydration in the browser, the `counter` ref is re-initialized. The `handleClick` finally binds itself to the button; Therefore it is reasonable to deduce that the body of `handleClick` will always run in a browser environment. [Middlewares](https://nuxt.com/docs/4.x/directory-structure/app/middleware) and [pages](https://nuxt.com/docs/4.x/directory-structure/app/pages) run in the server and on the client during hydration. [Plugins](https://nuxt.com/docs/4.x/directory-structure/app/plugins) can be rendered on the server or client or both. [Components](https://nuxt.com/docs/4.x/directory-structure/app/components) can be forced to run on the client only as well. [Composables](https://nuxt.com/docs/4.x/directory-structure/app/composables) and [utilities](https://nuxt.com/docs/4.x/directory-structure/app/utils) are rendered based on the context of their usage. **Benefits of server-side rendering:** - **Performance**: Users can get immediate access to the page's content because browsers can display static content much faster than JavaScript-generated content. At the same time, Nuxt preserves the interactivity of a web application during the hydration process. - **Search Engine Optimization**: Universal rendering delivers the entire HTML content of the page to the browser as a classic server application. Web crawlers can directly index the page's content, which makes Universal rendering a great choice for any content that you want to index quickly. **Downsides of server-side rendering:** - **Development constraints:** Server and browser environments don't provide the same APIs, and it can be tricky to write code that can run on both sides seamlessly. Fortunately, Nuxt provides guidelines and specific variables to help you determine where a piece of code is executed. - **Cost:** A server needs to be running in order to render pages on the fly. This adds a monthly cost like any traditional server. However, the server calls are highly reduced thanks to universal rendering with the browser taking over on client-side navigation. A cost reduction is possible by leveraging [edge-side-rendering](https://nuxt.com/docs/4.x/guide/concepts/rendering#edge-side-rendering). Universal rendering is very versatile and can fit almost any use case, and is especially appropriate for any content-oriented websites: **blogs, marketing websites, portfolios, e-commerce sites, and marketplaces.** For more examples about writing Vue code without hydration mismatch, see [the Vue docs](https://vuejs.org/guide/scaling-up/ssr#hydration-mismatch). When importing a library that relies on browser APIs and has side effects, make sure the component importing it is only called client-side. Bundlers do not treeshake imports of modules containing side effects. ## Client-Side Rendering Out of the box, a traditional Vue.js application is rendered in the browser (or **client**). Then, Vue.js generates HTML elements after the browser downloads and parses all the JavaScript code containing the instructions to create the current interface. ![Users have to wait for the browser to download, parse and execute the JavaScript before seeing the page's content](https://nuxt.com/assets/docs/concepts/rendering/csr.svg) **Benefits of client-side rendering:** - **Development speed**: When working entirely on the client-side, we don't have to worry about the server compatibility of the code, for example, by using browser-only APIs like the `window` object. - **Cheaper:** Running a server adds a cost of infrastructure as you would need to run on a platform that supports JavaScript. We can host client-only applications on any static server with HTML, CSS, and JavaScript files. - **Offline:** Because code entirely runs in the browser, it can nicely keep working while the internet is unavailable. **Downsides of client-side rendering:** - **Performance**: The user has to wait for the browser to download, parse and run JavaScript files. Depending on the network for the download part and the user's device for the parsing and execution, this can take some time and impact the user's experience. - **Search Engine Optimization**: Indexing and updating the content delivered via client-side rendering takes more time than with a server-rendered HTML document. This is related to the performance drawback we discussed, as search engine crawlers won't wait for the interface to be fully rendered on their first try to index the page. Your content will take more time to show and update in search results pages with pure client-side rendering. Client-side rendering is a good choice for heavily interactive **web applications** that don't need indexing or whose users visit frequently. It can leverage browser caching to skip the download phase on subsequent visits, such as **SaaS, back-office applications, or online games**. You can enable client-side only rendering with Nuxt in your `nuxt.config.ts`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ ssr: false, }) ``` If you do use `ssr: false`, you should also place an HTML file in `~/spa-loading-template.html` with some HTML you would like to use to render a loading screen that will be rendered until your app is hydrated. ### Deploying a Static Client-Rendered App If you deploy your app to [static hosting](https://nuxt.com/docs/4.x/getting-started/deployment#static-hosting) with the `nuxt generate` or `nuxt build --prerender` commands, then by default, Nuxt will render every page as a separate static HTML file. If you prerender your app with the `nuxt generate` or `nuxt build --prerender` commands, then you will not be able to use any server endpoints as no server will be included in your output folder. If you need server functionality, use `nuxt build` instead. If you are using purely client-side rendering, then this might be unnecessary. You might only need a single `index.html` file, plus `200.html` and `404.html` fallbacks, which you can tell your static web host to serve up for all requests. In order to achieve this we can change how the routes are prerendered. Just add this to [your hooks](https://nuxt.com/docs/4.x/api/advanced/hooks#nuxt-hooks-build-time) in your `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ hooks: { 'prerender:routes' ({ routes }) { routes.clear() // Do not generate any routes (except the defaults) }, }, }) ``` This will produce three files: - `index.html` - `200.html` - `404.html` #### What are 200.html and 404.html? Static hosts need an HTML shell for client-side routes and missing paths. Nuxt emits two SPA fallbacks for that: - **200.html**. Serve this for unmatched paths when you want the client router to handle the URL. - **404.html**. Serve this when the host should keep a 404 status and still load your app. `nuxt generate` and `nuxt build --prerender` write these into `.output/public/`. A plain `nuxt build` without prerender does not. With hybrid route rules, add the fallbacks with route rules or run a prerender build if you need them. Point your host at the file your provider expects. #### Server-rendering the Error Page By default `404.html` is an empty shell, so your `error.vue` (and its layout and data) only appear once the client app has booted. You can prerender it instead: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { prerenderErrorPages: true, }, }) ``` Nuxt then renders `error.vue` at build time with a synthetic 404 error and writes the result to `404.html`, which hydrates in place at whatever URL your host served it from. Pass an array of status codes between 400 and 599 (`[404, 500]`) to emit additional pages, if your host can serve them. Because a single file is served for every missing path, the error page cannot depend on the request: `useRoute()`, `useRequestURL()` and data fetched with the current path will hold the build-time values in the prerendered HTML and be corrected on hydration. Wrap request-specific markup in [``](https://nuxt.com/docs/4.x/api/components/client-only), and skip request-specific data fetching with `import.meta.prerender`: ```vue [error.vue] ``` `import.meta.prerender` is only `true` while the page is being generated, so the same `error.vue` still server-renders its data when the app is deployed with a server. #### Skipping Client Fallback Generation When prerendering a client-rendered app, Nuxt will generate `index.html`, `200.html` and `404.html` files by default. However, if you need to prevent any (or all) of these files from being generated in your build, you can use the `'prerender:generate'` hook from [Nitro](https://nuxt.com/docs/4.x/getting-started/prerendering#prerendergenerate-nitro-hook). ```ts [nuxt.config.ts]twoslash // @errors: 2353 7006 export default defineNuxtConfig({ ssr: false, nitro: { hooks: { 'prerender:generate' (route) { const routesToSkip = ['/index.html', '/200.html', '/404.html'] if (routesToSkip.includes(route.route)) { route.skip = true } }, }, }, }) ``` ## Hybrid Rendering Hybrid rendering allows different caching rules per route using **Route Rules** and decides how the server should respond to a new request on a given URL. Previously every route/page of a Nuxt application and server must use the same rendering mode, universal or client-side. In various cases, some pages could be generated at build time, while others should be client-side rendered. For example, think of a content website with an admin section. Every content page should be primarily static and generated once, but the admin section requires registration and behaves more like a dynamic application. Nuxt includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route! Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using [Nitro caching layer](https://nitro.build/guide/cache). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Homepage pre-rendered at build time '/': { prerender: true }, // Products page generated on demand, revalidates in background, cached until API response changes '/products': { swr: true }, // Product pages generated on demand, revalidates in background, cached for 1 hour (3600 seconds) '/products/**': { swr: 3600 }, // Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds) '/blog': { isr: 3600 }, // Blog post page generated on demand once until next deployment, cached on CDN '/blog/**': { isr: true }, // Admin dashboard renders only on client-side '/admin/**': { ssr: false }, // Add cors headers on API routes '/api/**': { cors: true }, // Redirects legacy urls '/old-page': { redirect: '/new-page' }, }, }) ``` ### Route Rules The different properties you can use are the following: - `redirect: string` - Define server-side redirects. - `ssr: boolean` - Disables server-side rendering of the HTML for sections of your app and make them render only in the browser with `ssr: false` - `cors: boolean` - Automatically adds cors headers with `cors: true` - you can customize the output by overriding with `headers` - `headers: object` - Add specific headers to sections of your site - for example, your assets - `swr: number | boolean` - Add cache headers to the server response and cache it on the server or reverse proxy for a configurable TTL (time to live). The `node-server` preset of Nitro is able to cache the full response. When the TTL expired, the cached response will be sent while the page will be regenerated in the background. If true is used, a `stale-while-revalidate` header is added without a MaxAge. - `isr: number | boolean` - The behavior is the same as `swr` except that we are able to add the response to the CDN cache on platforms that support this (currently Netlify or Vercel). If `true` is used, the content persists until the next deploy inside the CDN. - `prerender: boolean` - Prerenders routes at build time and includes them in your build as static assets - `noScripts: boolean` - Disables rendering of Nuxt scripts and JS resource hints for sections of your site. Read more about [`noScripts`](https://nuxt.com/docs/4.x/guide/going-further/features#noscripts). - `appMiddleware: string | string[] | Record` - Allows you to define middleware that should or should not run for page paths within the Vue app part of your application (that is, not your Nitro routes) Routes using `isr` or `swr` also generate `_payload.json` files alongside HTML. Client-side navigation loads these cached payloads instead of re-fetching data. Read more about [payload extraction](https://nuxt.com/docs/4.x/getting-started/prerendering#payload-extraction). ### Server Bundle Size with `ssr: false` A route covered by `ssr: false` is only ever rendered in the browser, so Nuxt excludes its page component from the server bundle. This applies whenever the rules covering every path that reaches the page can be resolved at build time, including dynamic routes such as `pages/products/[id].vue` under a `/products/**` rule. A page is kept in the server bundle when any path that reaches it might still be rendered on the server: - a more specific rule re-enables SSR somewhere below the client-only one (`'/admin/**': { ssr: false }` with `'/admin/report': { ssr: true }`) - the page has an alias, or a child declared with an absolute path, that falls outside the client-only region - the page is a parent shell rendering a child that is still server-rendered This is a build-time optimization only; it does not change what the server sends to the browser. Whenever possible, route rules will be automatically applied to the deployment platform's native rules for optimal performances (Netlify and Vercel are currently supported). Note that Hybrid Rendering is not available when using [`nuxt generate`](https://nuxt.com/docs/4.x/api/commands/generate). **Examples:** Example of a Nuxt application with hybrid rendering deployed on Vercel. ## Edge-Side Rendering Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience. With ESR, the rendering process is pushed to the 'edge' of the network - the CDN's edge servers. Note that ESR is more a deployment target than an actual rendering mode. When a request for a page is made, instead of going all the way to the original server, it's intercepted by the nearest edge server. This server generates the HTML for the page and sends it back to the user. This process minimizes the physical distance the data has to travel, **reducing latency and loading the page faster**. Edge-side rendering is possible thanks to [Nitro](https://nitro.build/), the [server engine](https://nuxt.com/docs/4.x/guide/concepts/server-engine) that powers Nuxt. It offers cross-platform support for Node.js, Deno, Cloudflare Workers, and more. The current platforms where you can leverage ESR are: - [Cloudflare Pages](https://pages.cloudflare.com) with zero configuration using the git integration and the `nuxt build` command - [Vercel Cloud](https://vercel.com/home) using the `nuxt build` command and `NITRO_PRESET=vercel-edge` environment variable - [Netlify Edge Functions](https://www.netlify.com/platform/#netlify-edge-functions) using the `nuxt build` command and `NITRO_PRESET=netlify-edge` environment variable Note that **Hybrid Rendering** can be used when using Edge-Side Rendering with route rules. # Server Components > Render individual components on the server only, keeping their JavaScript out of your client bundle. Nuxt renders your app on the server by default, but then it ships the JavaScript for every component to the browser and hydrates the whole page. For content-heavy components (markdown rendering, syntax highlighting, CMS output) that never change on the client, this is wasted work: the user downloads, parses and executes code whose only job is to reproduce HTML that is already on the page. Server components (also called island components) invert this. A server component is rendered on the server, its HTML is embedded in the page, and none of its JavaScript is sent to the client. Its dependencies (a markdown parser, a highlighting library) stay on the server too. Read Daniel Roe's guide to Nuxt Server Components. ## Enabling Server Components Component islands are controlled by [`experimental.componentIslands`](https://nuxt.com/docs/4.x/guide/going-further/experimental-features#componentislands). The default value is `'auto'`, which enables the feature automatically as soon as your app contains a server component or island, so in most cases you do not need any configuration. Set the option explicitly if you want remote islands or selective client hydration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { componentIslands: { selectiveClient: true, // or 'deep', to enable `nuxt-client` remoteIsland: false, // allow rendering islands from a remote source }, }, }) ``` Server components are still marked experimental. You can follow the roadmap on GitHub. ## `.server.vue` Components Add the `.server` suffix to a component to make it a standalone server component: ```bash [Directory Structure] -| app/ ---| components/ -----| HighlightedMarkdown.server.vue ``` Use it like any other component: ```vue [app/pages/example.vue] ``` Components inside `~/components/islands/` are also registered as islands and can be rendered with [``](https://nuxt.com/docs/4.x/api/components/nuxt-island) directly, for example `` for `~/components/islands/MyIsland.vue`. You can also pair a `.server.vue` component with a `.client.vue` component of the same name for [separate server and client implementations](https://nuxt.com/docs/4.x/directory-structure/app/components#paired-with-a-client-component). In that case the component is not an island: the client half hydrates normally. Server components (and islands) must have a single root element. (HTML comments are considered elements as well.) ## How Islands Are Rendered Server components use [``](https://nuxt.com/docs/4.x/api/components/nuxt-island) under the hood. Rendering an island issues a request to a dedicated island endpoint, which: - creates a **new, isolated Vue app** on the server to render just that component - creates an 'island context' that you can access via `nuxtApp.ssrContext.islandContext` inside the island - runs your plugins again, unless they set `env: { islands: false }` (object-syntax plugins) Because the island is isolated from the rest of your app: - you cannot share state (provide/inject, Pinia, `useState`) between the page and the island; pass data via props instead - [`useRoute()`](https://nuxt.com/docs/4.x/api/composables/use-route) inside an island reflects the island's own request, not the page the user is on. If an island needs route information, pass it in explicitly, either as props or via the `context` prop on `` (read inside the island from `nuxtApp.ssrContext.islandContext`) - route middleware does not run when rendering islands Props are serialized and sent as **GET query parameters**. This makes island responses cacheable, but it also means: - props must be JSON-serializable - props are limited by URL length, so avoid passing large amounts of data - props may be visible in server access logs, CDN caches and `Referer` headers Because props come from the request (URL query or body), treat them as untrusted input. Nuxt rejects the props most likely to leak through unintentionally: a top-level `as` that the island does not declare (an undeclared prop falls through as an attribute onto the island's root), and, with `vue.runtimeCompiler` enabled, a `template` anywhere in the props. Beyond that, avoid feeding props you have not validated into dynamic component resolution (``, `h()`, `resolveDynamicComponent()`, or a polymorphic `as` / `asChild` prop), since a string can resolve to any registered component or HTML element. Props a component does not declare fall through as attributes onto its single root element, so an island whose root is a polymorphic component (e.g. from `reka-ui` / `@nuxt/ui`) can receive attributes you did not bind. Set `defineOptions({ inheritAttrs: false })` on such islands, or declare the props you accept. To switch components based on caller input, map a discriminator through an allowlist of imported components rather than passing the raw prop: ```vue ``` Changing an island's props triggers a network request that re-renders the component on the server and updates its HTML in place. Read the full `` API documentation, including props, slots, events and known limitations. ## Selective Hydration with `nuxt-client` An island is static by default, but you can hydrate individual components inside it by adding the `nuxt-client` attribute. This requires `experimental.componentIslands.selectiveClient` to be enabled. ```vue [app/components/ServerWithClient.server.vue] ``` The component marked with `nuxt-client` is server-rendered as part of the island, then hydrated by the main client app. Only its chunk is shipped to the client; the rest of the island remains static. Setting `selectiveClient: 'deep'` additionally allows passing slots to `nuxt-client` components. Those slots are rendered on the server and are **not interactive** on the client. Use `nuxt-client` only on local `.vue` SFCs. Built-ins like [``](https://nuxt.com/docs/4.x/api/components/nuxt-link) skip the islands transform. After client navigation you may see `Failed to locate Teleport target`, or the link disappears with no error. Wrap the built-in in your own `.vue` file and put `nuxt-client` on that wrapper. See [#29251](https://github.com/nuxt/nuxt/issues/29251) and [#26002](https://github.com/nuxt/nuxt/issues/26002). ## Slots Slots can be passed to an island component if declared in the island. Slot content is provided by the parent, so it belongs to the main client app and **is** interactive (it is wrapped in a `

` with `display: contents;`). `` reserves the `#fallback` slot to specify content rendered before the island loads (when `lazy` is set) or when fetching the island fails. ## The Client Navigation Round Trip On the initial server-rendered page load, islands are rendered inline and there is no extra request. On **client-side navigation**, however, each island on the destination page must be fetched from the server (you can see these requests in the network tab). This has real costs: - islands block on a network round trip during navigation, unless you pass the `lazy` prop (with a `#fallback` slot) to render them non-blockingly - an app with many islands per page makes many requests per navigation Islands work best on pages that are reached by full page loads (content and marketing pages) or when their number per page is small. If a component needs to update frequently on the client, an island is probably the wrong tool. ## Prerendering and Caching Islands play well with static and cached rendering: - during prerendering (`nuxt generate` or `prerender` route rules), island responses are cached, so identical islands (same name, props and context) are rendered once and reused - because props travel as GET query parameters, island responses can also be cached by your server or CDN at the island endpoint level - two instances of the same island with the same props share a single server render and payload entry Note that island responses being keyed only on name, props and context is exactly what keeps them cacheable independently of the page they appear on; this is also why they cannot see the current route (see above). If you are building a mostly-static site, islands combine well with `prerender` and `noScripts` route rules. See the mostly-static site recipe for combining prerendering, `noScripts`, islands and lazy hydration. One interaction to be aware of: island slots and `nuxt-client` components rely on a small inline script to relocate teleported content into place before hydration. On routes rendered with [`noScripts`](https://nuxt.com/docs/4.x/guide/going-further/features#noscripts), that script is omitted, so fully interactive `nuxt-client` components will not hydrate there. Plain static islands are unaffected. ## Current Limitations Server components are experimental, and some rough edges are tracked in open issues: - Most features for server-only and island components, such as slots and `nuxt-client` components, are only available for single file components. - Using islands can significantly increase the number of chunks generated at build time ([#34855](https://github.com/nuxt/nuxt/issues/34855)). - With webpack and Rspack, scoped `:slotted()` styles in server component slots can fail because server and client builds may generate different scope IDs ([#31510](https://github.com/nuxt/nuxt/issues/31510)). - Template refs cannot reference elements inside a server component from the parent ([#31512](https://github.com/nuxt/nuxt/issues/31512)). - `inject`/`provide` does not cross the island boundary, so injecting from the page into a standalone server component does not work ([#22751](https://github.com/nuxt/nuxt/issues/22751)). - Server components rendered via the auto-generated wrapper do not expose load and error events; use `` directly if you need its `error` event and `refresh()` method ([#25744](https://github.com/nuxt/nuxt/issues/25744)). - [`useId`](https://vuejs.org/api/composition-api-helpers#useid) has known limitations inside islands; see the [`` documentation](https://nuxt.com/docs/4.x/api/components/nuxt-island#known-limitations). - Each nested island adds extra overhead, so be careful when nesting islands within other islands. Read more about server component file conventions in the components directory documentation. # Server Engine > Nuxt is powered by a new server engine: Nitro. While building Nuxt, we created a new server engine: [Nitro](https://nitro.build/). It is shipped with many features: - Cross-platform support for Node.js, browsers, service workers and more. - Serverless support out-of-the-box. - API routes support. - Automatic code-splitting and async-loaded chunks. - Hybrid mode for static + serverless sites. - Development server with hot module reloading. ## API Layer Server [API endpoints](https://nuxt.com/docs/4.x/directory-structure/server#server-routes) and [Middleware](https://nuxt.com/docs/4.x/directory-structure/server#server-middleware) are added by Nitro that internally uses [h3](https://github.com/h3js/h3). Key features include: - Handlers can directly return objects/arrays for an automatically-handled JSON response - Handlers can return promises, which will be awaited (`res.end()` and `next()` are also supported) - Helper functions for body parsing, cookie handling, redirects, headers and more Check out [the h3 docs](https://github.com/h3js/h3) for more information. Learn more about the API layer in the `server/` directory. ## Direct API Calls Nitro allows 'direct' calling of routes via the globally-available [`$fetch`](https://nuxt.com/docs/4.x/api/utils/dollarfetch) helper. This will make an API call to the server if run on the browser, but will directly call the relevant function if run on the server, **saving an additional API call**. [`$fetch`](https://nuxt.com/docs/4.x/api/utils/dollarfetch) API is using [ofetch](https://github.com/unjs/ofetch), with key features including: - Automatic parsing of JSON responses (with access to raw response if needed) - Request body and params are automatically handled, with correct `Content-Type` headers For more information on `$fetch` features, check out [ofetch](https://github.com/unjs/ofetch). ## Typed API Routes When using API routes (or middleware), Nitro will generate typings for these routes as long as you are returning a value instead of using `res.end()` to send a response. You can access these types when using [`$fetch()`](https://nuxt.com/docs/4.x/api/utils/dollarfetch) or [`useFetch()`](https://nuxt.com/docs/4.x/api/composables/use-fetch). ## Standalone Server Nitro produces a standalone server dist that is independent of `node_modules`. The server in Nuxt 2 is not standalone and requires part of Nuxt core to be involved by running `nuxt start` (with the [`nuxt-start`](https://www.npmjs.com/package/nuxt-start) or [`nuxt`](https://www.npmjs.com/package/nuxt) distributions) or custom programmatic usage, which is fragile and prone to breakage and not suitable for serverless and service worker environments. Nuxt generates this dist when running `nuxt build` into a [`.output`](https://nuxt.com/docs/4.x/directory-structure/output) directory. The output contains runtime code to run your Nuxt server in any environment (including experimental browser service workers!) and serve your static files, making it a true hybrid framework for the JAMstack. In addition, Nuxt implements a native storage layer, supporting multi-source drivers and local assets. Read more about Nitro engine on GitHub. # TypeScript > Nuxt is fully typed and provides helpful shortcuts to ensure you have access to accurate type information when you are coding. ## Type-checking By default, Nuxt doesn't check types when you run [`nuxt dev`](https://nuxt.com/docs/4.x/api/commands/dev) or [`nuxt build`](https://nuxt.com/docs/4.x/api/commands/build), for performance reasons. To enable type-checking at build or development time, install `vue-tsc` and `typescript` as development dependency: ```bash [npm] npm install --save-dev vue-tsc typescript ``` ```bash [yarn] yarn add --dev vue-tsc typescript ``` ```bash [pnpm] pnpm add -D vue-tsc typescript ``` ```bash [bun] bun add -D vue-tsc typescript ``` ```bash [deno] deno add -D npm:vue-tsc npm:typescript ``` Then, run [`nuxt typecheck`](https://nuxt.com/docs/4.x/api/commands/typecheck) command to check your types: ```bash [Terminal] npx nuxt typecheck ``` To enable type-checking at build or development time, you can also use the [`typescript.typeCheck`](https://nuxt.com/docs/4.x/api/nuxt-config#typecheck) option in your `nuxt.config` file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { typeCheck: true, }, }) ``` ## Auto-generated Types Nuxt projects rely on auto-generated types to work properly. These types are stored in the [`.nuxt`](https://nuxt.com/docs/4.x/directory-structure/nuxt) directory and are generated when you run the dev server or build your application. You can also generate these files manually by running `nuxt prepare`. The generated `tsconfig.json` files inside the [`.nuxt`](https://nuxt.com/docs/4.x/directory-structure/nuxt) directory include **recommended basic TypeScript configuration** for your project, references to [auto-imports](https://nuxt.com/docs/4.x/guide/concepts/auto-imports), [API route types](https://nuxt.com/docs/4.x/guide/concepts/server-engine#typed-api-routes), path aliases like `#imports`, `~/file`, or `#build/file`, and more. Nuxt relies on this configuration, and [Nuxt modules](https://nuxt.com/docs/4.x/guide/modules) can extend it as well. For this reason, it is not recommended to modify your `tsconfig.json` file directly, as doing so could overwrite important settings. Instead, extend it via `nuxt.config.ts`. [Learn more about extending the configuration here](https://nuxt.com/docs/4.x/directory-structure/tsconfig). Watch a video from Daniel Roe explaining built-in Nuxt aliases. ## Project References Nuxt uses [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html) to improve type-checking performance and provide better IDE support. This feature allows TypeScript to break up your codebase into smaller, more manageable pieces. ### How Nuxt Uses Project References When you run `nuxt dev`, `nuxt build` or `nuxt prepare`, Nuxt will generate multiple `tsconfig.json` files for different parts of your application. - **.nuxt/tsconfig.app.json** - Configuration for your application code within the `app/` directory - **.nuxt/tsconfig.node.json** - Configuration for your `nuxt.config.ts` and files outside the other contexts - **.nuxt/tsconfig.server.json** - Configuration for server-side code (when applicable) - **.nuxt/tsconfig.shared.json** - For code shared between app and server contexts (like types and non-environment specific utilities) Each of these files is configured to reference the appropriate dependencies and provide optimal type-checking for their specific context. For backward compatibility, Nuxt still generates `.nuxt/tsconfig.json`. However, we recommend using [TypeScript project references](https://nuxt.com/docs/4.x/directory-structure/tsconfig) with the new configuration files (`.nuxt/tsconfig.app.json`, `.nuxt/tsconfig.server.json`, etc.) for better type safety and performance. This legacy file will be removed in a future version of Nuxt. ### Benefits of Project References - **Faster builds**: TypeScript can skip rebuilding unchanged projects - **Better IDE performance**: Your IDE can provide faster IntelliSense and error checking - **Isolated compilation**: Errors in one part of your application don't prevent compilation of other parts - **Clearer dependency management**: Each project explicitly declares its dependencies ### Augmenting Types with Project References Since the project is divided into **multiple type contexts**, it's important to **augment types within the correct context** to ensure they're properly recognized. TypeScript will not recognize augmentations placed outside these directories unless they are explicitly included in the appropriate context. For example, if you want to augment types for the `app` context, the augmentation file should be placed in the `app/` directory. Similarly: - For the `server` context, place the augmentation file in the `server/` directory. - For types that are **shared between the app and server**, place the file in the `shared/` directory. Read more about augmenting specific type contexts from **files outside those contexts** in the Module Author Guide. ## Strict Checks TypeScript comes with certain checks to give you more safety and analysis of your program. [Strict checks](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) are enabled by default in Nuxt when the [`typescript.typeCheck`](https://nuxt.com/docs/4.x/guide/concepts/typescript#type-checking) option is enabled to give you greater type safety. If you are currently converting your codebase to TypeScript, you may want to temporarily disable strict checks by setting `strict` to `false` in your `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { strict: false, }, }) ``` # Vue.js Development > Nuxt uses Vue.js and adds features such as component auto-imports, file-based routing and composables for an SSR-friendly usage. Nuxt integrates Vue 3, the new major release of Vue that enables new patterns for Nuxt users. While an in-depth knowledge of Vue is not required to use Nuxt, we recommend that you read the documentation and go through some of the examples on [vuejs.org](https://vuejs.org). Nuxt has always used Vue as a frontend framework. We chose to build Nuxt on top of Vue for these reasons: - The reactivity model of Vue, where a change in data automatically triggers a change in the interface. - The component-based templating, while keeping HTML as the common language of the web, enables intuitive patterns to keep your interface consistent, yet powerful. - From small projects to large web applications, Vue keeps performing well at scale to ensure that your application keeps delivering value to your users. ## Vue with Nuxt ### Single File Components [Vueโ€™s single-file components](https://vuejs.org/guide/scaling-up/sfc) (SFC or `*.vue` files) encapsulate the markup (` ``` 1. Make sure you use capital letters for these component names to distinguish them from native HTML elements (`` rather than `<title>`). 2. You can place these components anywhere in your template for your page. </important> ### Options API ```vue [Nuxt 3 (Options API)] <script> // if using options API `head` method you must use `defineNuxtComponent` export default defineNuxtComponent({ head (nuxtApp) { // `head` receives the nuxt app but cannot access the component instance return { meta: [{ name: 'description', content: 'This is my page description.', }], } }, }) </script> ``` # Modules > Learn how to migrate from Nuxt 2 to Nuxt 3 modules. ## Module Compatibility Nuxt 3 has a basic backward compatibility layer for Nuxt 2 modules using `@nuxt/kit` auto wrappers. But there are usually steps to follow to make modules compatible with Nuxt 3 and sometimes, using Nuxt Bridge is required for cross-version compatibility. We have prepared a [Dedicated Guide](https://nuxt.com/docs/4.x/guide/modules) for authoring Nuxt 3 ready modules using `@nuxt/kit`. Currently best migration path is to follow it and rewrite your modules. Rest of this guide includes preparation steps if you prefer to avoid a full rewrite yet making modules compatible with Nuxt 3. <tip icon="i-lucide-puzzle" to="https://nuxt.com/modules"> Explore Nuxt 3 compatible modules. </tip> ### Plugin Compatibility Nuxt 3 plugins are **not** fully backward compatible with Nuxt 2. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/plugins"> </read-more> ### Vue Compatibility Plugins or components using the Composition API need exclusive Vue 2 or Vue 3 support. By using [vue-demi](https://github.com/vueuse/vue-demi) they should be compatible with both Nuxt 2 and 3. ## Module Migration When Nuxt 3 users add your module, you will not have access to the module container (`this.*`) so you will need to use utilities from `@nuxt/kit` to access the container functionality. ### Test with `@nuxt/bridge` Migrating to `@nuxt/bridge` is the first and most important step for supporting Nuxt 3. If you have a fixture or example in your module, add `@nuxt/bridge` package to its config (see [example](https://nuxt.com/docs/4.x/bridge/overview#update-nuxtconfig)) ### Migrate from CommonJS to ESM Nuxt 3 natively supports TypeScript and ECMAScript Modules. Please check [Native ES Modules](https://nuxt.com/docs/4.x/guide/concepts/esm) for more info and upgrading. ### Ensure Plugins Default Export If you inject a Nuxt plugin that does not have `export default` (such as global Vue plugins), ensure you add `export default () => { }` to the end of it. <code-group> ```js [Before] // ~/plugins/vuelidate.js import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate) ``` ```js [After] // ~/plugins/vuelidate.js import Vue from 'vue' import Vuelidate from 'vuelidate' Vue.use(Vuelidate) export default () => { } ``` </code-group> ### Avoid Runtime Modules With Nuxt 3, Nuxt is now a build-time-only dependency, which means that modules shouldn't attempt to hook into the Nuxt runtime. Your module should work even if it's only added to [`buildModules`](https://nuxt.com/docs/4.x/api/nuxt-config#runtimeconfig) (instead of `modules`). For example: - Avoid updating `process.env` within a Nuxt module and reading by a Nuxt plugin; use [`runtimeConfig`](https://nuxt.com/docs/4.x/api/nuxt-config#runtimeconfig) instead. - (*) Avoid depending on runtime hooks like `vue-renderer:*` for production - (*) Avoid adding `serverMiddleware` by importing them inside the module. Instead, add them by referencing a file path so that they are independent of the module's context (*) Unless it is for `nuxt dev` purpose only and guarded with `if (nuxt.options.dev) { }`. <tip> Continue reading about Nuxt 3 modules in the [Modules Author Guide](https://nuxt.com/docs/4.x/guide/modules). </tip> ### Use TypeScript (Optional) While it is not essential, most of the Nuxt ecosystem is shifting to use TypeScript, so it is highly recommended to consider migration. <tip> You can start migration by renaming `.js` files, to `.ts`. TypeScript is designed to be progressive! </tip> <tip> You can use TypeScript syntax for Nuxt 2 and 3 modules and plugins without any extra dependencies. </tip> # Overview > Nuxt 3 is a complete rewrite of Nuxt 2, and also based on a new set of underlying technologies. There are significant changes when migrating a Nuxt 2 app to Nuxt 3, although you can expect migration to become more straightforward as we move toward a stable release. <note> This migration guide is under progress to align with the development of Nuxt 3. </note> Some of these significant changes include: 1. Moving from Vue 2 to Vue 3, including defaulting to the Composition API and script setup. 2. Moving from webpack 4 and Babel to Vite or webpack 5 and esbuild. 3. Moving from a runtime Nuxt dependency to a minimal, standalone server compiled with nitropack. <tip> If you need to remain on Nuxt 2, but want to benefit from Nuxt 3 features in Nuxt 2, you can alternatively check out [how to get started with Bridge](https://nuxt.com/docs/4.x/bridge/overview). </tip> ## Next Steps - Learn about differences in [configuration](https://nuxt.com/docs/4.x/migration/configuration) # Pages and Layouts > Learn how to migrate from Nuxt 2 to Nuxt 3 pages and layouts. ## `app.vue` Nuxt 3 provides a central entry point to your app via `~/app.vue`. <note> If you don't have an `app.vue` file in your source directory, Nuxt will use its own default version. </note> This file is a great place to put any custom code that needs to be run once when your app starts up, as well as any components that are present on every page of your app. For example, if you only have one layout, you can move this to `app.vue` instead. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/app"> </read-more> <link-example to="https://nuxt.com/docs/4.x/examples/hello-world"> </link-example> ### Migration Consider creating an `app.vue` file and including any logic that needs to run once at the top-level of your app. You can check out [an example here](https://nuxt.com/docs/4.x/directory-structure/app/app). ## Layouts If you are using layouts in your app for multiple pages, there is only a slight change required. In Nuxt 2, the `<Nuxt>` component is used within a layout to render the current page. In Nuxt 3, layouts use slots instead, so you will have to replace that component with a `<slot />`. This also allows advanced use cases with named and scoped slots. [Read more about layouts](https://nuxt.com/docs/4.x/directory-structure/app/layouts). You will also need to change how you define the layout used by a page using the `definePageMeta` compiler macro. Layouts will be kebab-cased. So `app/layouts/customLayout.vue` becomes `custom-layout` when referenced in your page. ### Migration 1. Replace `<Nuxt />` with `<slot />````diff [app/layouts/custom.vue] <template> <div id="app-layout"> <main> - <Nuxt /> + <slot /> </main> </div> </template> ``` 2. Use [`definePageMeta`](https://nuxt.com/docs/4.x/api/utils/define-page-meta) to select the layout used by your page. ```diff [app/pages/index.vue] + <script setup> + definePageMeta({ + layout: 'custom' + }) - <script> - export default { - layout: 'custom' - } </script> ``` 3. Move `~/layouts/_error.vue` to `~/error.vue`. See [the error handling docs](https://nuxt.com/docs/4.x/getting-started/error-handling). If you want to ensure that this page uses a layout, you can use [`<NuxtLayout>`](https://nuxt.com/docs/4.x/directory-structure/app/layouts) directly within `error.vue`: ```vue [error.vue] <template> <div> <NuxtLayout name="default"> <!-- --> </NuxtLayout> </div> </template> ``` ## Pages Nuxt 3 ships with an optional `vue-router` integration triggered by the existence of a [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory in your source directory. If you only have a single page, you may consider instead moving it to `app.vue` for a lighter build. ### Dynamic Routes The format for defining dynamic routes in Nuxt 3 is slightly different from Nuxt 2, so you may need to rename some of the files within `app/pages/`. 1. Where you previously used `_id` to define a dynamic route parameter you now use `[id]`. 2. Where you previously used `_.vue` to define a catch-all route, you now use `[...slug].vue`. ### Nested Routes In Nuxt 2, you will have defined any nested routes (with parent and child components) using `<Nuxt>` and `<NuxtChild>`. In Nuxt 3, these have been replaced with a single `<NuxtPage>` component. ### Page Keys and Keep-alive Props If you were passing a custom page key or keep-alive props to `<Nuxt>`, you will now use `definePageMeta` to set these options. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/pages#special-metadata"> </read-more> ### Page and Layout Transitions If you have been defining transitions for your page or layout directly in your component options, you will now need to use `definePageMeta` to set the transition. Since Vue 3, [-enter and -leave CSS classes have been renamed](https://v3-migration.vuejs.org/breaking-changes/transition.html). The `style` prop from `<Nuxt>` no longer applies to transition when used on `<slot>`, so move the styles to your `-active` class. <read-more to="https://nuxt.com/docs/4.x/getting-started/transitions"> </read-more> ### Migration 1. Rename any pages with dynamic parameters to match the new format. 2. Update `<Nuxt>` and `<NuxtChild>` to be `<NuxtPage>`. 3. If you're using the Composition API, you can also migrate `this.$route` and `this.$router` to use [`useRoute`](https://nuxt.com/docs/4.x/api/composables/use-route) and [`useRouter`](https://nuxt.com/docs/4.x/api/composables/use-router) composables. #### Example: Dynamic Routes <code-group> ```text [Nuxt 2] - URL: /users - Page: /pages/users/index.vue - URL: /users/some-user-name - Page: /pages/users/_user.vue - Usage: params.user - URL: /users/some-user-name/edit - Page: /pages/users/_user/edit.vue - Usage: params.user - URL: /users/anything-else - Page: /pages/users/_.vue - Usage: params.pathMatch ``` ```text [Nuxt 3] - URL: /users - Page: /pages/users/index.vue - URL: /users/some-user-name - Page: /pages/users/[user].vue - Usage: params.user - URL: /users/some-user-name/edit - Page: /pages/users/[user]/edit.vue - Usage: params.user - URL: /users/anything-else - Page: /pages/users/[...slug].vue - Usage: params.slug ``` </code-group> #### Example: Nested Routes and `definePageMeta` <code-group> ```vue [Nuxt 2] <template> <div> <NuxtChild keep-alive :keep-alive-props="{ exclude: ['modal'] }" :nuxt-child-key="$route.slug" /> </div> </template> <script> export default { transition: 'page', // or { name: 'page' } } </script> ``` ```vue [Nuxt 3] <template> <div> <NuxtPage /> </div> </template> <script setup lang="ts"> // This compiler macro works in both <script> and <script setup> definePageMeta({ // you can also pass a string or a computed property key: route => route.slug, transition: { name: 'page', }, keepalive: { exclude: ['modal'], }, }) </script> ``` </code-group> ## `<NuxtLink>` Component Most of the syntax and functionality are the same for the global [NuxtLink](https://nuxt.com/docs/4.x/api/components/nuxt-link) component. If you have been using the shortcut `<NLink>` format, you should update this to use `<NuxtLink>`. `<NuxtLink>` is now a drop-in replacement for *all* links, even external ones. You can read more about it, and how to extend it to provide your own link component. <read-more to="https://nuxt.com/docs/4.x/api/components/nuxt-link"> </read-more> ## Programmatic Navigation When migrating from Nuxt 2 to Nuxt 3, you will have to update how you programmatically navigate your users. In Nuxt 2, you had access to the underlying Vue Router with `this.$router`. In Nuxt 3, you can use the `navigateTo()` utility method which allows you to pass a route and parameters to Vue Router. <warning> Make sure to always `await` on [`navigateTo`](https://nuxt.com/docs/4.x/api/utils/navigate-to) or chain its result by returning from functions. </warning> <code-group> ```vue [Nuxt 2] <script> export default { methods: { navigate () { this.$router.push({ path: '/search', query: { name: 'first name', type: '1', }, }) }, }, } </script> ``` ```vue [Nuxt 3] <script setup lang="ts"> function navigate () { return navigateTo({ path: '/search', query: { name: 'first name', type: '1', }, }) } </script> ``` </code-group> # Plugins and Middleware > Learn how to migrate from Nuxt 2 to Nuxt 3 plugins and middleware. ## Plugins Plugins now have a different format, and take only one argument (`nuxtApp`). <code-group> ```ts [Nuxt 2] export default (ctx, inject) => { inject('injected', () => 'my injected function') } ``` ```ts [Nuxt 3] export default defineNuxtPlugin((nuxtApp) => { // now available on `nuxtApp.$injected` nuxtApp.provide('injected', () => 'my injected function') // You can alternatively use this format, which comes with automatic type support return { provide: { injected: () => 'my injected function', }, } }) ``` </code-group> <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/plugins"> </read-more> <read-more to="https://nuxt.com/docs/4.x/api/composables/use-nuxt-app"> Read more about the format of `nuxtApp`. </read-more> ### Migration 1. Migrate your plugins to use the `defineNuxtPlugin` helper function. 2. Remove any entries in your `nuxt.config` plugins array that are located in your `app/plugins/` folder. All files in this directory at the top level (and any index files in any subdirectories) will be automatically registered. Instead of setting `mode` to `client` or `server`, you can indicate this in the file name. For example, `~/plugins/my-plugin.client.ts` will only be loaded on client-side. ## Route Middleware Route middleware has a different format. <code-group> ```js [Nuxt 2] export default function ({ store, redirect }) { // If the user is not authenticated if (!store.state.authenticated) { return redirect('/login') } } ``` ```ts [Nuxt 3] export default defineNuxtRouteMiddleware((to, from) => { const auth = useState('auth') if (!auth.value.authenticated) { return navigateTo('/login') } }) ``` </code-group> Much like Nuxt 2, route middleware placed in your `~/middleware` folder is automatically registered. You can then specify it by name in a component. However, this is done with `definePageMeta` rather than as a component option. `navigateTo` is one of a number of route helper functions. <read-more to="https://nuxt.com/docs/4.x/directory-structure/app/middleware"> </read-more> ### Migration 1. Migrate your route middleware to use the `defineNuxtRouteMiddleware` helper function. 2. Any global middleware (such as in your `nuxt.config`) can be placed in your `~/middleware` folder with a `.global` extension, for example `~/middleware/auth.global.ts`. # Runtime Config > Learn how to migrate from Nuxt 2 to Nuxt 3 runtime config. If you wish to reference environment variables within your Nuxt 3 app, you will need to use runtime config. When referencing these variables within your components, you will have to use the [`useRuntimeConfig`](https://nuxt.com/docs/4.x/api/composables/use-runtime-config) composable in your setup method (or Nuxt plugin). In the `server/` portion of your app, you can use [`useRuntimeConfig`](https://nuxt.com/docs/4.x/api/composables/use-runtime-config) without any import. <read-more to="https://nuxt.com/docs/4.x/guide/going-further/runtime-config"> </read-more> ## Migration 1. Add any environment variables that you use in your app to the `runtimeConfig` property of the `nuxt.config` file. 2. Migrate `process.env` to [`useRuntimeConfig`](https://nuxt.com/docs/4.x/api/composables/use-runtime-config) throughout the Vue part of your app. <code-group> ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { // Private config that is only available on the server apiSecret: '123', // Config within public will be also exposed to the client public: { apiBase: '/api', }, }, }) ``` ```vue [app/pages/index.vue] <script setup lang="ts"> const config = useRuntimeConfig() // instead of process.env you will now access config.public.apiBase console.log(config.public.apiBase) </script> ``` ```ts [server/api/hello.ts] export default defineEventhandler((event) => { const config = useRuntimeConfig(event) // In server, you can now access config.apiSecret, in addition to config.public console.log(config.apiSecret) console.log(config.public.apiBase) }) ``` ```ini [.env] # Runtime config values are automatically replaced by matching environment variables at runtime NUXT_API_SECRET=api_secret_token NUXT_PUBLIC_API_BASE=https://nuxtjs.org ``` </code-group> # Server > Learn how to migrate from Nuxt 2 to Nuxt 3 server. In a built Nuxt 3 application, there is no runtime Nuxt dependency. That means your site will be highly performant, and ultra-slim. But it also means you can no longer hook into runtime Nuxt server hooks. <read-more to="https://nuxt.com/docs/4.x/guide/concepts/server-engine"> </read-more> ## Steps 1. Remove the `render` key in your `nuxt.config`. 2. Any files in `~~/server/api` and `~~/server/middleware` will be automatically registered; you can remove them from your `serverMiddleware` array. 3. Update any other items in your `serverMiddleware` array to point to files or npm packages directly, rather than using inline functions. <read-more to="https://nuxt.com/docs/4.x/directory-structure/server"> </read-more> <read-more to="https://nuxt.com/docs/4.x/guide/going-further/hooks#server-hooks-runtime"> </read-more> # Nuxt Docs This repository contains the documentation of Nuxt, hosted on [https://nuxt.com/docs](https://nuxt.com/docs) ## Contributing Have a look at [https://github.com/nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) to run the website locally. # AWS Amplify > Deploy your Nuxt Application to AWS Amplify infrastructure. <tip> **Zero Configuration โœจ** <br /> Integration with AWS Amplify is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> ## Setup 1. Login to the [AWS Amplify Hosting Console](https://console.aws.amazon.com/amplify/?trk=01c5a476-5997-4e6a-88b9-fd0a0a5bbe34&sc_channel=el) 2. Click on "Get Started" > Amplify Hosting (Host your web app) 3. Select and authorize access to your Git repository provider and select the main branch 4. Choose a name for your app, make sure build settings are auto-detected and optionally set requirement environment variables under the advanced section 5. Optionally, select Enable SSR logging to enable server-side logging to your Amazon CloudWatch account 6. Confirm configuration and click on "Save and Deploy" ## Learn more <read-more target="_blank" to="https://www.youtube.com/watch?v=CAk5_XGkOG4"> Watch an Amplify Hosting tutorial with Nuxt </read-more> <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/aws-amplify"> Head over **Nitro documentation** to learn more about the aws-amplify deployment preset. </read-more> # Azure > Deploy your Nuxt Application to Azure infrastructure. ## Azure Static Web Apps <tip> **Zero Configuration โœจ** <br /> Integration with Azure Static Web Apps provider is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> Azure Static Web Apps are designed to be deployed continuously in a [GitHub Actions workflow](https://docs.microsoft.com/en-us/azure/static-web-apps/github-actions-workflow). By default, Nuxt will detect this deployment environment to enable the `azure` preset. ### Local preview Install [Azure Functions Core Tools](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local) if you want to test locally. You can invoke a development environment to preview before deploying. ```bash [Terminal] npx nuxi build --preset=azure npx @azure/static-web-apps-cli start .output/public --api-location .output/server ``` ### Configuration Azure Static Web Apps are [configured](https://learn.microsoft.com/en-us/azure/static-web-apps/configuration) using the `staticwebapp.config.json` file. Nuxt automatically generates this configuration file whenever the application is built with the `azure` preset. It adds the following properties based on the following criteria: <table> <thead> <tr> <th> Property </th> <th> Criteria </th> <th> Default </th> </tr> </thead> <tbody> <tr> <td> <strong> <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#platform" rel="nofollow"> platform.apiRuntime </a> </strong> </td> <td> Will automatically set to <code> node:16 </code> or <code> node:14 </code> depending on your package configuration. </td> <td> <code> node:16 </code> </td> </tr> <tr> <td> <strong> <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#fallback-routes" rel="nofollow"> navigationFallback.rewrite </a> </strong> </td> <td> Is always <code> /api/server </code> </td> <td> <code> /api/server </code> </td> </tr> <tr> <td> <strong> <a href="https://learn.microsoft.com/en-us/azure/static-web-apps/configuration#routes" rel="nofollow"> routes </a> </strong> </td> <td> All prerendered routes are added. Additionally, if you do not have an <code> index.html </code> file an empty one is created for you for compatibility purposes and also requests to <code> /index.html </code> are redirected to the root directory which is handled by <code> /api/server </code> . </td> <td> <code> [] </code> </td> </tr> </tbody> </table> ### Custom Configuration You can alter the generated configuration using `azure.config` option. For instance, if you wanted to specify a Node runtime for your Azure Functions, edit your `nuxt.config.ts` file to the following: ```ts [nuxt.config.ts] export default defineNuxtConfig({ // ... nitro: { azure: { config: { // ... platform: { apiRuntime: 'node:18' } } } } }) ``` Custom routes will be added and matched first. In the case of a conflict (determined if an object has the same route property), custom routes will override generated ones. ### Deploy from CI/CD via GitHub Actions When you link your GitHub repository to Azure Static Web Apps, a workflow file is added to the repository. When you are asked to select your framework, select custom and provide the following information: <table> <thead> <tr> <th> Input </th> <th> Value </th> </tr> </thead> <tbody> <tr> <td> <strong> app_location </strong> </td> <td> '/' </td> </tr> <tr> <td> <strong> api_location </strong> </td> <td> '.output/server' </td> </tr> <tr> <td> <strong> output_location </strong> </td> <td> '.output/public' </td> </tr> </tbody> </table> If you miss this step, you can always find the build configuration section in your workflow and update the build configuration: ```yaml [.github/workflows/azure-static-web-apps-<RANDOM_NAME>.yml] ###### Repository/Build Configurations ###### app_location: '/' api_location: '.output/server' output_location: '.output/public' ###### End of Repository/Build Configurations ###### ``` <callout> That's it! Now Azure Static Web Apps will automatically deploy your Nitro-powered application on push. </callout> If you are using `runtimeConfig`, you will likely want to configure the corresponding [environment variables on Azure](https://docs.microsoft.com/en-us/azure/static-web-apps/application-settings). ## More options <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/azure"> Learn about the other Azure deployment presets on Nitro documentation. </read-more> # Cleavr > Deploy your Nuxt Application to Cleavr infrastructure. <tip> **Zero Configuration โœจ** <br /> Integration with this provider is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> ## Setup **In your Cleavr.io panel:** 1. Provision a new server 2. Add a website, selecting **Nuxt 3** as the app type 3. In web app > settings > Code Repo, point to your project's code repository 4. In web app > settings > Environment variables, set `SERVER_PRESET=cleavr` You're now all set to deploy your project! ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/cleavr"> Head over **Nitro documentation** to learn more about the cleavr deployment preset. </read-more> # Clever Cloud > Deploy your Nuxt Application to Clever Cloud infrastructure. Nuxt supports deploying on [Clever Cloud](https://www.clever-cloud.com/) with minimal configuration. ## Deploy Clever Cloud from the Console To deploy your Nuxt project to Clever Cloud, you will need to create a **new application**. The application wizard will walk you through the necessary configuration steps. 1. From the lateral menubar, click **Create > An application** 2. Choose how to deploy: **Create an application from a local repository** or **Create an application from a GitHub repository** 3. Select a **Node.js** application, or a **static one**. 4. Set up the minimal size for your instance and scalability options. Nuxt app must be deployed with a minimum size of **XS** instance for **Node.js** application and **nano** instance for **static one**. The build process, however, will need to be configured later with at least an M instance size to ensure it can handle the resource requirements. Depending on your projectโ€™s specifications and dependencies, you may need to adjust further as you monitor the metrics from the **Overview** page. 5. Select a **region** to deploy your instance. 6. Skip connecting **Add-ons** to your Clever application unless youโ€™re using a database. 7. Inject **environment variables**: - For **Node.js** <code-group sync="pm"> ```ini [npm] CC_POST_BUILD_HOOK="npm run build" CC_RUN_COMMAND="node .output/server/index.mjs" ``` ```ini [yarn] CC_POST_BUILD_HOOK="yarn build" CC_RUN_COMMAND="node .output/server/index.mjs" ``` ```ini [pnpm] CC_POST_BUILD_HOOK="pnpm build" CC_RUN_COMMAND="node .output/server/index.mjs" ``` ```ini [bun] CC_POST_BUILD_HOOK="bun build" CC_RUN_COMMAND="node .output/server/index.mjs" ``` </code-group> - For a **static application** <note> If [`ssr: false` is set in `nuxt.config.ts`](https://nuxt.com/docs/4.x/getting-started/deployment#static-hosting) **or** if your project contains dynamic routes that cannot be pre-rendered, you should : 1. Use a **Static Apache** application 2. Create a [`.htaccess`](https://www.clever.cloud/developers/doc/applications/static-apache/#serving-indexhtml-for-spa-single-page-application-routers) file that redirects all routes to `index.html` to ensure proper routing for your SPA. Otherwise, you can use the default **Static HTML** application. </note> <code-group sync="pm"> ```ini [npm] CC_WEBROOT=/.output/public CC_OVERRIDE_BUILDCACHE=/.output/public CC_PRE_BUILD_HOOK=npm install CC_POST_BUILD_HOOK=npm run generate ``` ```ini [yarn] CC_WEBROOT=/.output/public CC_OVERRIDE_BUILDCACHE=/.output/public CC_PRE_BUILD_HOOK=yarn install CC_POST_BUILD_HOOK=yarn generate ``` ```ini [pnpm] CC_WEBROOT=/.output/public CC_OVERRIDE_BUILDCACHE=/.output/public CC_PRE_BUILD_HOOK=pnpm install CC_POST_BUILD_HOOK=pnpm generate ``` ```ini [bun] CC_WEBROOT=/.output/public CC_OVERRIDE_BUILDCACHE=/.output/public CC_PRE_BUILD_HOOK=bun install CC_POST_BUILD_HOOK=bun generate ``` </code-group> 1. Navigate to the application **Information** menu and enable the **enable dedicated build instance** option on a minimal instance of type **M**. 2. **Deploy!** If youโ€™re deploying from **GitHub**, your deployment should start automatically. If youโ€™re using **Git**, show [this docs](https://www.clever-cloud.com/developers/doc/quickstart/#choose-how-to-deploy). ## Learn more <read-more target="_blank" to="https://developers.clever-cloud.com/guides/nuxt"> Clever Cloud documentation for deploying Nuxt </read-more> # Cloudflare > Deploy your Nuxt Application to Cloudflare infrastructure. ## Cloudflare Pages <tip> **Zero Configuration โœจ** <br /> Integration with Cloudflare Pages is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> <important> Use [@nuxthub/core](https://nuxt.com/modules/hub) to add database, KV, blob storage, and cache to your Nuxt application. NuxtHub works on Vercel, Cloudflare, Netlify, and more. Learn more on [hub.nuxt.com](https://hub.nuxt.com). </important> ### Git Integration If you use the GitHub/GitLab integration with Cloudflare Pages, **no configuration is required**. Pushing to your repository will automatically build your project and deploy it. <note> Nuxt will detect the environment to set the correct [Server/Nitro preset](https://nitro.unjs.io/deploy/providers/cloudflare). </note> To leverage server-side rendering on the edge, set the build command to: `nuxt build` To statically generate your website, set the build command to: `nuxt generate` ### Route matching On CloudFlare Pages, if an HTML file is found with a matching path to the current route requested, it will serve it. It will also redirect HTML pages to their extension-less counterparts: for instance, `/contact.html` will be redirected to `/contact`, and `/about/index.html` will be redirected to `/about/`. To match Cloudflare [route matching](https://developers.cloudflare.com/pages/configuration/serving-pages/#route-matching) rules, set the nitro option `autoSubfolderIndex` to `false`. ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { prerender: { autoSubfolderIndex: false } } }) ``` ### Direct Upload Alternatively, you can use [wrangler](https://github.com/cloudflare/workers-sdk) to upload your project to Cloudflare. In this case, you will have to set the preset manually. 1. Build your project for Cloudflare Pages: ```bash [Terminal] npx nuxi build --preset=cloudflare_pages ``` 1. Deploy, it will ask you to create a project for the first time: ```bash [Terminal] npx wrangler pages deploy dist/ ``` ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/cloudflare"> Head over **Nitro documentation** to learn more about the Cloudflare deployment preset. </read-more> <read-more target="_blank" to="https://developers.cloudflare.com/pages/framework-guides/deploy-a-nuxt-site/#use-bindings-in-your-nuxt-application"> Head over **CloudFlare Pages** documentation to learn more about it. </read-more> ## Templates <card-group> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Atidone" to="https://github.com/atinux/atidone"> A todos application with user authentication, SSR and Cloudflare D1. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Atinotes" to="https://github.com/atinux/atinotes"> An editable website with universal rendering based on Cloudflare KV. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Atidraw" to="https://github.com/atinux/atidraw"> Web application that lets you to draw and share your drawings with the world, with Cloudflare R2 & AI. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Nuxt Image Gallery" to="https://github.com/flosciante/nuxt-image-gallery"> An image gallery to upload, edit and share your images to the world, with Cloudflare R2. </card> </card-group> ## Learn more <read-more target="_blank" to="https://v2.nitro.build/deploy/providers/cloudflare"> Head over **Nitro documentation** to learn more about the cloudflare deployment preset. </read-more> # Deno Deploy > Deploy your Nuxt Application to Deno Deploy infrastructure. <important> Deno deploy preset is experimental. </important> ## Deploy with the CLI You can use [deployctl](https://deno.com/deploy/docs/deployctl) to deploy your app. Login to [Deno Deploy](https://dash.deno.com/account#access-tokens) to obtain a `DENO_DEPLOY_TOKEN` access token, and set it as an environment variable. ```bash # Build with the deno_deploy preset npm run build --preset=deno_deploy # Make sure to run the deployctl command from the output directory cd .output deployctl deploy --project=my-project server/index.ts --token=<DENO_DEPLOY_TOKEN> ``` ## Deploy within CI/CD using GitHub Actions Link your GitHub repository to your Deno Deploy project and choose the "GitHub Actions" deployment mode. You can do this in your project settings on [https://dash.deno.com](https://dash.deno.com). Create a GitHub action file in your repository: ```yaml [.github/workflows/deno_deploy.yml] name: deno-deploy on: push: branches: - main pull_request: branches: - main jobs: deploy: steps: - uses: actions/checkout@v3 - run: corepack enable - uses: actions/setup-node@v3 with: node-version: 18 cache: pnpm - run: pnpm install - run: pnpm build env: NITRO_PRESET: deno_deploy - name: Deploy to Deno Deploy uses: denoland/deployctl@v1 with: project: <my-project> entrypoint: server/index.ts root: .output ``` <important> Make sure to rename `<my-project>` with your project name. </important> ## Templates <card-group> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Nuxt Deno KV" to="https://github.com/Atinux/nuxt-deno-kv"> A collaborative todo-list app built with Deno KV and Nuxt. </card> </card-group> ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/deno-deploy"> Head over **Nitro documentation** to learn more about the deno-deploy deployment preset. </read-more> # DigitalOcean > Deploy your Nuxt Application to DigitalOcean infrastructure. Nuxt supports deploying on the [DigitalOcean App Platform](https://docs.digitalocean.com/products/app-platform/) with minimal configuration. ## Setup 1. Create a new DigitalOcean app following the [guide](https://docs.digitalocean.com/products/app-platform/how-to/create-apps/). 2. Next, you'll need to configure environment variables. In your app settings, ensure the following [app-level environment variables](https://docs.digitalocean.com/products/app-platform/how-to/use-environment-variables/):```bash SERVER_PRESET=digital-ocean ``` 3. You will need to ensure you set an `engines.node` field in your app's `package.json` to ensure DigitalOcean uses a supported version of Node.js:```json [package.json] { "engines": { "node": "20.x" } } ``` 4. You'll also need to add a run command so DigitalOcean knows what command to run after a build. You can do so by adding a start script to your `package.json`:```json [package.json] { "scripts": { "start": "node .output/server/index.mjs" } } ``` 5. Finally, you'll need to add this start script to your DigitalOcean app's run command. Go to `Components > Settings > Commands`, click "Edit", then add `npm run start` <tip> Your Nuxt app should be live at a DigitalOcean generated URL and you can now follow [the rest of the DigitalOcean deployment guide](https://docs.digitalocean.com/products/app-platform/how-to/manage-deployments/). </tip> ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/digitalocean"> Head over **Nitro documentation** to learn more about the digitalocean deployment preset. </read-more> # Firebase > Deploy your Nuxt Application to Firebase infrastructure. ## Firebase App Hosting (recommended) <note> You will need to be on the [**Blaze plan**](https://firebase.google.com/pricing) (Pay as you go) to get started. </note> <read-more to="https://firebase.google.com/docs/app-hosting" title="Firebase App Hosting"> </read-more> ### Project Setup 1. Go to the Firebase [console](https://console.firebase.google.com/) and set up a new project. 2. Select **Build > App Hosting** from the sidebar. - You may need to upgrade your billing plan at this step. 3. Click **Get Started**. - Choose a region. - Import a GitHub repository (youโ€™ll need to link your GitHub account). - Configure deployment settings (project root directory and branch), and enable automatic rollouts. - Choose a unique ID for your backend. 4. Click Finish & Deploy to create your first rollout. When you deploy with Firebase App Hosting, the App Hosting preset will be run automatically at build time. ## Firebase Functions (deprecated) <important> This deployment method is deprecated and is not recommended. Firebase App Hosting is the recommended way to deploy Nuxt apps on Firebase. </important> To use the more recent and recommended generation of Firebase functions, set the `firebase.gen` option to `2`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { firebase: { gen: 2 } } }) ``` <note> If you cannot use configuration for any reason, alternatively you can use `NITRO_FIREBASE_GEN=2` environment variable. </note> If you already have a deployed version of your website and want to upgrade to 2nd gen, [see the Migration process on Firebase docs](https://firebase.google.com/docs/functions/2nd-gen-upgrade). Namely, the CLI will ask you to delete your existing functions before deploying the new ones. <tip target="_blank" to="https://firebase.google.com/docs/functions/version-comparison"> Comparison between 1st and 2nd generation functions </tip> ## Project Setup You may instead prefer to set up your project with the Firebase CLI, which will fetch your project ID for you, add required dependencies (see above) and even set up automated deployments via GitHub Actions (for hosting only). [Learn about installing the firebase CLI](https://firebase.google.com/docs/cli#windows-npm). 1. Install the latest version of the Firebase CLI. ```bash [Terminal] npm install -g firebase-tools@latest ``` 1. Initialize your Firebase Project ```bash [Terminal] firebase login firebase init hosting ``` <note> When prompted, you can enter `.output/public` as the public directory. In the next step, **do not** configure your project as a single-page app. </note> Once complete, add the following to your `firebase.json` to enable server rendering in Cloud Functions: ```json [firebase.json] { "functions": { "source": ".output/server" }, "hosting": [ { "site": "<your_project_id>", "public": ".output/public", "cleanUrls": true, "rewrites": [{ "source": "**", "function": "server" }] } ] } ``` ## Local Preview You can preview a local version of your site if you need to test things out without deploying. ```bash npm run build -- --preset=firebase firebase emulators:start ``` ## Build and Deploy Deploy to Firebase Hosting by running a Nuxt build and then running the `firebase deploy` command. ```bash npm run build -- --preset=firebase firebase deploy ``` ## Options You can set options for Firebase functions in your `nuxt.config.ts` file: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { firebase: { gen: 2, httpsOptions: { region: 'europe-west1', maxInstances: 3, }, }, }, }); ``` ### Runtime Node.js Version You can set a custom Node.js version in configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { firebase: { nodeVersion: '18' // Can be '16' or '18' or '20' }, }, }); ``` Firebase tools use the `engines.node` version in `package.json` to determine which node version to use for your functions. Nuxt automatically writes to the `.output/server/package.json` with configured Node.js version. You might also need to add a runtime key to your `firebase.json` file: ```json [firebase.json] { "functions": { "source": ".output/server", "runtime": "nodejs20" } } ``` <read-more to="https://firebase.google.com/docs/functions/manage-functions?gen=2nd#set_nodejs_version" target="_blank"> You can read more about this in **Firebase Docs**. </read-more> ## Other Cloud Functions Firebase may warn that other Cloud Functions will be deleted when you deploy. That warning depends on `codebase` identifiers, not on how many function sources you list. Without a unique `codebase`, the CLI treats functions outside the current deploy as candidates for deletion. A single functions source can coexist with other functions if you give it a unique `codebase` (for example in a separate repository that deploys to the same Firebase project). Use a different `codebase` in each repository's `firebase.json`. In one repository, configure multiple function sources with distinct `codebase` values: ```json [firebase.json] { "functions": [ { "source": "functions", "codebase": "default" }, { "source": ".output/server", "codebase": "nuxt" } ], "hosting": [ { "site": "<your_project_id>", "public": ".output/public", "cleanUrls": true, "rewrites": [{ "source": "**", "function": "server" }] } ] } ``` <read-more to="https://firebase.google.com/docs/functions/organize-functions?gen=2nd#managing_multiple_source_packages_monorepo" target="_blank"> See **Managing multiple source packages** in the Firebase docs. </read-more> To deploy only the Nuxt codebase and hosting: ```bash firebase deploy --only functions:nuxt,hosting ``` With a single functions source (no separate `codebase`), target the `server` function instead: ```bash firebase deploy --only functions:server,hosting ``` <read-more to="https://nitro.unjs.io/deploy/providers/firebase" target="_blank"> Head over to the **Nitro documentation** to learn more about the Firebase deployment preset. </read-more> ## Using Cookies in Production When using Firebase Hosting together with Cloud Functions or Cloud Run, cookies are generally stripped from incoming requests to allow for efficient CDN cache behavior. Only the specially-named `__session` cookie is permitted to pass through to your app. <read-more to="https://firebase.google.com/docs/hosting/manage-cache#using_cookies" target="\_blank"> For more information, refer to the **Firebase documentation**. </read-more> ## Working with Environment Variables To set environment variables for your Firebase functions, you need to copy the `.env` file to the `.output/server` directory. You can do this by adding a `postbuild` script to your `package.json`, that will automatically run after the build command: ```json [package.json] { "scripts": { "postbuild": "cp .env .output/server/.env" } } ``` <read-more to="https://firebase.google.com/docs/functions/config-env?gen=2nd#env-variables" target="\_blank"> For more information, refer to the **Firebase documentation**. </read-more> # Flightcontrol > Deploy your Nuxt Application to Flightcontrol infrastructure. Nitro supports deploying to [AWS via Flightcontrol](https://flightcontrol.dev?ref=nuxt) with minimal configuration. <tip> **Zero Configuration โœจ** <br /> Integration with Flightcontrol is possible with zero configuration. </tip> ## Set Up your Flightcontrol account On a high level, the steps you will need to follow to deploy a project for the first time are: 1. Create an account at [Flightcontrol](https://app.flightcontrol.dev/signup?ref=nuxt) 2. Create an account at [AWS](https://portal.aws.amazon.com/billing/signup) (if you don't already have one) 3. Link your AWS account to the Flightcontrol 4. Authorize the Flightcontrol GitHub App to access your chosen repositories, public or private. 5. Create a Flightcontrol project with configuration via the Dashboard or with configuration via `flightcontrol.json`. ## Create a Project with Configuration via the Dashboard 1. Create a Flightcontrol project from the Dashboard. Select a repository for the source. 2. Select the `GUI` config type. 3. Select the Nuxt preset. 4. Select your preferred AWS server size. 5. Submit the new project form. ## Create a Project with Configuration via `flightcontrol.json` 1. Create a Flightcontrol project from your dashboard. Select a repository for the source. 2. Select the `flightcontrol.json` config type. 3. Add a new file at the root of your repository called `flightcontrol.json`. Here is an example configuration that creates an AWS fargate service for your app: ```json [flightcontrol.json] { "$schema": "https://app.flightcontrol.dev/schema.json", "environments": [ { "id": "production", "name": "Production", "region": "us-west-2", "source": { "branch": "main" }, "services": [ { "id": "nitro", "buildType": "nixpacks", "name": "My Nitro site", "type": "fargate", "domain": "www.yourdomain.com", "outputDirectory": ".output", "startCommand": "node .output/server/index.mjs", "cpu": 0.25, "memory": 0.5 } ] } ] } ``` 1. Submit the new project form. <read-more target="_blank" to="https://www.flightcontrol.dev/docs?ref=nuxt"> Learn more about Flightcontrol's configuration. </read-more> <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/flightcontrol"> Head over **Nitro documentation** to learn more about the flightcontrol deployment preset. </read-more> # GitHub Pages > Deploy your Nuxt Application to GitHub Pages infrastructure. Nuxt supports deploying to [GitHub Pages](https://pages.github.com/) with minimal configuration. <caution> GitHub Pages only support static sites, Nuxt will pre-render your application to static HTML files. </caution> <caution> If you are **not** using a custom domain, you need to set `NUXT_APP_BASE_URL` to your repository-slug for your build step. **Example**: `https://<user>.github.io/<repository>/`: `NUXT_APP_BASE_URL=/<repository>/ npx nuxt build --preset github_pages` </caution> ## Setup Follow the steps to [create a GitHub Pages site](https://docs.github.com/en/pages/getting-started-with-github-pages/creating-a-github-pages-site). ## Deployment Here is an example GitHub Actions workflow to deploy your site to GitHub Pages using the `github_pages` preset: ```yaml [.github/workflows/deploy.yml] # https://github.com/actions/deploy-pages#usage name: Deploy to GitHub Pages on: workflow_dispatch: push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: corepack enable - uses: actions/setup-node@v4 with: node-version: "20" # Pick your own package manager and build script - run: npm install - run: npx nuxt build --preset github_pages - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: ./.output/public # Deployment job deploy: # Add a dependency to the build job needs: build # Grant GITHUB_TOKEN the permissions required to make a Pages deployment permissions: pages: write # to deploy to Pages id-token: write # to verify the deployment originates from an appropriate source # Deploy to the github_pages environment environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} # Specify runner + deployment step runs-on: ubuntu-latest steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 ``` <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/github-pages"> Head over **Nitro documentation** to learn more about the github-pages deployment preset. </read-more> # GitLab Pages > Deploy your Nuxt Application to GitLab Pages. Nuxt supports deploying on the [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages) with minimal configuration. <caution> GitLab Pages only support static sites, Nuxt will pre-render your application to static HTML files. </caution> <caution> If you are **not** using a custom domain, you need to set `NUXT_APP_BASE_URL` to your repository-slug for your build step. **Example**: `https://<group/user>.gitlab.io/<repository>/`: `NUXT_APP_BASE_URL=/<repository>/ npm run generate` </caution> ## Deployment 1. Here is an example GitLab Pages workflow to deploy your site to GitLab Pages: ```yaml [.gitlab-ci.yml] # Job name has to be `pages`. See https://docs.gitlab.com/ee/user/project/pages/#how-it-works pages: image: node before_script: - npm ci --cache .npm --prefer-offline script: # Specify the steps involved to build your app here - npm run generate cache: # https://docs.gitlab.com/ee/ci/caching/#cache-nodejs-dependencies key: files: - package-lock.json paths: - .npm/ artifacts: paths: # The directory that contains the built files to be published - .output/public # The directory that contains the built files to be published publish: .output/public rules: # This ensures that only pushes to the default branch # will trigger a pages deploy - if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH ``` ## Learn more <read-more target="_blank" to="https://docs.gitlab.com/ee/user/project/pages/getting_started_part_one.html#project-website-examples"> Head over **GitLab Pages default domain names and URLs** to learn more about the GitLab Pages default domain names. </read-more> # Heroku > Deploy your Nuxt Application to Heroku infrastructure. Nuxt supports deploying on [Heroku](https://heroku.com/) with minimal configuration. ## Using the Heroku CLI 1. Create a new Heroku app.```bash [Terminal] heroku create myapp ``` 2. Configure Heroku to use the nodejs buildpack.```bash [Terminal] heroku buildpacks:set heroku/nodejs ``` 3. Configure your app.```bash [Terminal] heroku config:set SERVER_PRESET=heroku ``` 4. Ensure you have `start` and `build` commands in your `package.json` file.```json [package.json] { "scripts": { "build": "nuxt build", "start": "node .output/server/index.mjs" } } ``` ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/heroku"> Head over **Nitro documentation** to learn more about the Heroku deployment preset. </read-more> # Hostinger > Deploy your Nuxt Application to Hostinger Node.js Hosting. ## Deploy using Git 1. Push your code to a GitHub repository. 2. Log in to [hPanel](https://hpanel.hostinger.com), go to **Websites** and click **Add Website**. 3. Select **Node.js Apps**, then choose **Import Git Repository**. 4. Authorize Hostinger to access your GitHub account and select your repository. 5. Hostinger will automatically detect your Nuxt app and suggest build settings. 6. Click **Deploy** โ€” your application will be built and go live automatically. After deployment, every push to your repository will trigger a new build and redeploy your application automatically. ## Deploy by uploading files 1. Compress your project files into a `.zip` archive. 2. In hPanel, go to **Websites โ†’ Add Website โ†’ Node.js Apps**, then select **Upload your website files**. 3. Upload the `.zip` file and confirm the build settings. 4. Click **Deploy**. Learn more about [Node.js deployments](https://www.hostinger.com/support/how-to-deploy-a-nodejs-website-in-hostinger/) on Hostinger. # IIS > Deploy your Nuxt Application to IIS infrastructure. ## Using IISnode 1. Install the latest LTS version of [Node.js](https://nodejs.org/en/) on your Windows Server. 2. Install [IISnode](https://github.com/azure/iisnode/releases) 3. Install [IIS `URLRewrite` Module](https://www.iis.net/downloads/microsoft/url-rewrite). 4. In IIS, add `.mjs` as a new mime type and set its content type to `application/javascript`. 5. Build you application with the following command: ```bash [Terminal] npx nuxi build --preset=iis_node ``` 6. Deploy the contents of your `.output` folder to your website in IIS. ## More options <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/iis"> Head over **Nitro documentation** to learn more about the IIS deployment presets. </read-more> # Koyeb > Deploy your Nuxt Application to Koyeb infrastructure. Nuxt supports deploying on the [Koyeb serverless platform](https://www.koyeb.com/docs) with minimal configuration. ## Setup 1. Create a new Koyeb app for Nuxt following the [guide](https://www.koyeb.com/docs/deploy/nuxt). 2. Set the `engines.node` field in your project's `package.json` file to a [Koyeb-supported version of Node.js](https://www.koyeb.com/docs/build-and-deploy/build-from-git/nodejs#runtime):```json [package.json] { "engines": { "node": "20.x" } } ``` 3. Ensure that `build` and `start` scripts are defined within the project's `package.json` file to define how to build and run the application:```json [package.json] { "scripts": { "build": "nuxt build", "start": "node .output/server/index.mjs" } } ``` 4. During deployment, you'll need to configure environment variables. In your service settings, set the following [environment variable](https://www.koyeb.com/docs/build-and-deploy/environment-variables):```bash SERVER_PRESET=koyeb ``` 5. Click "Deploy" to build and deploy your Nuxt app. ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/koyeb"> Head over **Nitro documentation** to learn more about the Koyeb deployment preset. </read-more> # Netlify > Deploy your Nuxt Application to Netlify infrastructure. <tip> **Zero Configuration โœจ** <br /> Integration with Netlify is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> ## Setup Nuxt will auto-detect that you are in a [Netlify](https://www.netlify.com) build environment and build an optimized version of your server. For new sites, Netlify will detect that you are using Nuxt 3 and set the publish directory to `dist` and build command to `npm run build`. <note> If you are upgrading an existing site from Nuxt 2 you should check these and update them if needed. </note> If you want to add custom redirects, you can do so with [`routeRules`](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering) or by adding a [`_redirects`](https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file) file to your `public` directory. <tip color="green" icon="i-lucide-check-circle"> For deployment, just push to your git repository [as you would normally do for Netlify](https://docs.netlify.com/configure-builds/get-started/). </tip> ## Netlify Edge Functions <read-more target="_blank" to="https://www.netlify.com/blog/announcing-serverless-compute-with-edge-functions"> Netlify Edge Functions use Deno and the powerful V8 JavaScript runtime to let you run globally distributed functions for the fastest possible response times. </read-more> Set the following environment variable to run Nuxt on Edge Functions: ```bash SERVER_PRESET=netlify_edge ``` ## On-demand Builders On-demand Builders are serverless functions used to generate web content as needed thatโ€™s automatically cached on Netlifyโ€™s Edge CDN. They enable you to build pages for your site when a user visits them for the first time and then cache them at the edge for subsequent visits until the next deployment. <read-more target="_blank" to="https://docs.netlify.com/configure-builds/on-demand-builders/"> Read More about Netlify on-demand builders </read-more> Set the following environment variable to enable on-demand builders: ```bash SERVER_PRESET=netlify_builder ``` <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/netlify"> Head over **Nitro documentation** to learn more about the netlify deployment preset. </read-more> # Northflank > Deploy your Nuxt Application to Northflank infrastructure. Nuxt supports deploying on [Northflank](https://www.northflank.com) with minimal configuration. ## Setup 1. Link your [Git provider](https://northflank.com/docs/v1/application/getting-started/link-your-git-account) and [create a new project](https://northflank.com/docs/v1/application/getting-started/create-a-project) in Northflank. 2. In your project, create a [Service](https://northflank.com/docs/v1/application/getting-started/build-and-deploy-your-code) and connect it to your Nuxt repository. 3. Ensure your package.json includes a start script that runs the Nuxt production server. ```json [package.json] { "scripts": { "start": "node .output/server/index.mjs" } } ``` 1. Click "Create Service" to build and deploy your Nuxt app. <read-more target="_blank" to="https://northflank.com/docs"> For more information, refer to the **Northflank documentation**. </read-more> # Render > Deploy your Nuxt Application to Render infrastructure. Nuxt supports deploying on [Render](https://render.com/) with minimal configuration. ## Set up application 1. [Create a new Web Service](https://dashboard.render.com/select-repo?type=web) and select the repository that contains your code. 2. Ensure the 'Node' environment is selected. 3. Depending on your package manager, set the build command to `yarn && yarn build`, `npm install && npm run build`, or `pnpm i --shamefully-hoist && pnpm build`. 4. Update the start command to `node .output/server/index.mjs` 5. Click 'Advanced' and add the following environment variables ```bash SERVER_PRESET=render_com NODE_VERSION=20 ``` 6. Click on `Create Web Service`. ## More options <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/render"> Head over **Nitro documentation** to learn more about the Render deployment presets. </read-more> # SST > Deploy your Nuxt Application to AWS with SST. Nuxt supports deploying on [SST](https://sst.dev/) with minimal configuration. ## Quick start 1. Create a Nuxt project. 2. Init SST in your project. ```bash npx sst@latest init ``` 3. It should detect that your are using Nuxt and ask you to update your `nuxt.config.ts` file. ```ts nitro: { preset: 'aws-lambda' } ``` 4. Once you are ready to deploy, run. ```bash npx sst deploy --stage production ``` You can [read the full Nuxt on SST tutorial here](https://sst.dev/docs/start/aws/nuxt). ## More options You can also deploy Nuxt to a container using SST. Head over to the [SST docs to learn more](https://sst.dev/docs/start/aws/nuxt). # Stormkit > Deploy your Nuxt Application to Stormkit infrastructure. <tip> **Zero Configuration โœจ** <br /> Integration with [Stormkit](https://www.stormkit.io/) is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> ## Setup Follow the steps to [create a new app](https://app.stormkit.io/apps/new) on Stormkit. ## Deployment By default, Stormkit will deploy your apps automatically when you push changes to your main branch. But to trigger a manual deploy (for example, you might do this for the very first deployment), you may click `Deploy now`. <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/stormkit"> Head over **Nitro documentation** to learn more about the stormkit deployment preset. </read-more> # Vercel > Deploy your Nuxt Application to Vercel infrastructure. <tip> **Zero Configuration โœจ** <br /> Integration with Vercel is possible with zero configuration, [learn more](https://nitro.unjs.io/deploy#zero-config-providers). </tip> <important> Use [@nuxthub/core](https://nuxt.com/modules/hub) to add database, KV, blob storage, and cache to your Nuxt application. NuxtHub works on Vercel, Cloudflare, Netlify, and more. Learn more on [hub.nuxt.com](https://hub.nuxt.com). </important> ## Deploy using Git 1. Push your code to your git repository (GitHub, GitLab, Bitbucket). 2. [Import your project](https://vercel.com/new) into Vercel. 3. Vercel will detect that you are using Nitro and will enable the correct settings for your deployment. 4. Your application is deployed! After your project has been imported and deployed, all subsequent pushes to branches will generate [Preview Deployments](https://vercel.com/docs/deployments/environments#preview-environment-pre-production), and all changes made to the Production Branch (commonly โ€œmainโ€) will result in a [Production Deployment](https://vercel.com/docs/deployments/environments#production-environment). Learn more about Vercelโ€™s [Git Integration](https://vercel.com/docs/git). ## Custom Build Output Configuration You can provide additional [build output configuration](https://vercel.com/docs/build-output-api) using `nitro.vercel.config` key inside `nuxt.config.ts`. It will be merged with built-in auto generated config. ## Templates <card-group> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Nuxt Vercel ISR" to="https://github.com/danielroe/nuxt-vercel-isr"> Example of a Nuxt application with hybrid rendering deployed on Vercel. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="Nuxt on the Edge on Vercel" to="https://github.com/pi0/nuxt-on-the-edge"> Example of a Nuxt application running on Vercel Edge Functions. </card> </card-group> ## Learn More <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/vercel"> Head over **Nitro documentation** to learn more about On-Demand Incremental Static Regeneration or more advanced options. </read-more> # Zeabur > Deploy your Nuxt Application to Zeabur. Nuxt supports deploying on [Zeabur](https://zeabur.com) with minimal configuration. ## Setup 1. Create a new Zeabur app for Nuxt following the [guide](https://zeabur.com/docs/guides/nodejs/nuxt). 2. During the deployment process, you can configure environment variables in Zeabur dashboard. In your service page, open the variables tab set the following [environment variable](https://zeabur.com/docs/deploy/variables):```bash SERVER_PRESET=zeabur ``` ## Learn more <read-more target="_blank" to="https://nitro.unjs.io/deploy/providers/zeabur"> Head over **Nitro documentation** to learn more about the Zeabur deployment preset. </read-more> # Zerops > Deploy your Nuxt Application to Zerops infrastructure. **Nodejs Preset**: `SERVER_PRESET: zerops`**Static Preset**: `SERVER_PRESET: zerops-static` <read-more title="Zerops" to="https://zerops.io"> </read-more> <tip> **Nuxt x Zerops Quickrun โœจ** <br /> Want to test running Nuxt on Zerops without installing or setting up anything? Using repositories [Zerops x Nuxt - Static](https://github.com/zeropsio/recipe-nuxt-static) or [Zerops x Nuxt - SSR on Node.js](https://github.com/zeropsio/recipe-nuxt-nodejs) you can deploy example Nuxt app with a single click. </tip> Zerops supports deploying both static and server-side rendered apps with a simple configuration file in your project root. ## Static Projects and services can be added either through a [Project add wizard](https://app.zerops.io/dashboard/project-add) or imported using a YAML structure: ### Creating a Project ```yml [zerops-project-import.yml] project: name: recipe-nuxt services: - hostname: app type: static ``` This will create a project called `recipe-nuxt` with a Zerops Static service called `app`. ### Setting up Zerops YAML To tell Zerops how to build and run your app, add a `zerops.yml` to your root: ```yml [zerops.yml] zerops: - setup: app build: base: nodejs@20 buildCommands: - yarn - yarn nuxi generate deployFiles: - .output/public/~ run: base: static ``` Now you can trigger the [build & deploy pipeline using the Zerops CLI](#building-deploying-your-app) or by connecting the app service with your [GitHub](https://docs.zerops.io/references/github-integration/) / [GitLab](https://docs.zerops.io/references/gitlab-integration) repository from inside the service detail. ## SSR Node.js Projects and services can be added either through a [Project add wizard](https://app.zerops.io/dashboard/project-add) or imported using a YAML structure: ```yml [zerops-project-import.yml] project: name: recipe-nuxt services: - hostname: app type: nodejs@20 ``` This will create a project called `recipe-nuxt` with a Zerops Node.js service called `app`. ### Setting up Zerops YAML To tell Zerops how to build and run your app, add a `zerops.yml` to your root: ```yml [zerops.yml] zerops: - setup: nuxt build: base: nodejs@20 buildCommands: - yarn - yarn build deployFiles: - .output/~ run: base: nodejs@20 ports: - port: 3000 httpSupport: true start: node server/index.mjs ``` Now you can trigger the [build & deploy pipeline using the Zerops CLI](#building-deploying-your-app) or by connecting the app service with your [GitHub](https://docs.zerops.io/references/github-integration/) / [GitLab](https://docs.zerops.io/references/gitlab-integration) repository from inside the service detail. ## Building & Deploying your App - Install the [Zerops CLI](https://github.com/zeropsio/zcli). ```sh npm i -g @zerops/zcli ``` - Open [Settings > Access Token Management](https://app.zerops.io/settings/token-management) in the Zerops app and generate a new access token. - Log in using your access token with the following command: ```sh zcli login <token> ``` - Navigate to the root of your app (where `zerops.yml` is located) and run the following command to trigger the deploy: ```sh zcli push ``` Your code can be deployed automatically on each commit or a new tag by connecting the service with your [GitHub](https://docs.zerops.io/references/gitlab-integration) / [GitLab](https://docs.zerops.io/references/gitlab-integration) repository. This connection can be set up in the service detail. <read-more title="Zerops Documentation" to="https://docs.zerops.io/"> </read-more> # Nuxt API Reference > Explore all Nuxt Internals: Components, Composables, Utils, Commands and more. <card-group> <card icon="i-lucide-box" title="Components" to="https://nuxt.com/docs/3.x/api/components/client-only"> Explore Nuxt built-in components for pages, layouts, head, and more. </card> <card icon="i-lucide-arrow-left-right" title="Composables" to="https://nuxt.com/docs/3.x/api/composables/use-app-config"> Discover Nuxt composable functions for data-fetching, head management and more. </card> <card icon="i-lucide-square-function" title="Utils" to="https://nuxt.com/docs/3.x/api/utils/dollarfetch"> Learn about Nuxt utility functions for navigation, error handling and more. </card> <card icon="i-lucide-square-terminal" title="Commands" to="https://nuxt.com/docs/3.x/api/commands/add"> List of Nuxt CLI commands to init, analyze, build, and preview your application. </card> <card icon="i-lucide-package" title="Nuxt Kit" to="https://nuxt.com/docs/3.x/api/kit/modules"> Understand Nuxt Kit utilities to create modules and control Nuxt. </card> <card icon="i-lucide-brain" title="Advanced" to="https://nuxt.com/docs/3.x/api/advanced/hooks"> Go deep in Nuxt internals with Nuxt lifecycle hooks. </card> <card icon="i-lucide-cog" title="Nuxt Configuration" to="https://nuxt.com/docs/3.x/api/nuxt-config"> Explore all Nuxt configuration options to customize your application. </card> </card-group> # Lifecycle Hooks > Nuxt provides a powerful hooking system to expand almost every aspect using hooks. <read-more to="https://nuxt.com/docs/3.x/guide/going-further/hooks"> </read-more> ## App Hooks (runtime) Check the [app source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts#L37) for all available hooks. <table> <thead> <tr> <th> Hook </th> <th> Arguments </th> <th> Environment </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> app:created </code> </td> <td> <code> vueApp </code> </td> <td> Server & Client </td> <td> Called when initial <code> vueApp </code> instance is created. </td> </tr> <tr> <td> <code> app:error </code> </td> <td> <code> err </code> </td> <td> Server & Client </td> <td> Called when a fatal error occurs. </td> </tr> <tr> <td> <code> app:error:cleared </code> </td> <td> <code> { redirect? } </code> </td> <td> Server & Client </td> <td> Called when a fatal error occurs. </td> </tr> <tr> <td> <code> vue:setup </code> </td> <td> - </td> <td> Server & Client </td> <td> Called when the setup of Nuxt root is initialized. This callback must be synchronous. </td> </tr> <tr> <td> <code> vue:error </code> </td> <td> <code> err, target, info </code> </td> <td> Server & Client </td> <td> Called when a vue error propagates to the root component. <a href="https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured" rel="nofollow"> Learn More </a> . </td> </tr> <tr> <td> <code> app:rendered </code> </td> <td> <code> renderContext </code> </td> <td> Server </td> <td> Called when SSR rendering is done. </td> </tr> <tr> <td> <code> app:redirected </code> </td> <td> - </td> <td> Server </td> <td> Called before SSR redirection. </td> </tr> <tr> <td> <code> app:beforeMount </code> </td> <td> <code> vueApp </code> </td> <td> Client </td> <td> Called before mounting the app, called only on client side. </td> </tr> <tr> <td> <code> app:mounted </code> </td> <td> <code> vueApp </code> </td> <td> Client </td> <td> Called when Vue app is initialized and mounted in browser. </td> </tr> <tr> <td> <code> app:suspense:resolve </code> </td> <td> <code> appComponent </code> </td> <td> Client </td> <td> On <a href="https://vuejs.org/guide/built-ins/suspense#suspense" rel="nofollow"> Suspense </a> resolved event. </td> </tr> <tr> <td> <code> app:manifest:update </code> </td> <td> <code> { id, timestamp } </code> </td> <td> Client </td> <td> Called when there is a newer version of your app detected. </td> </tr> <tr> <td> <code> app:data:refresh </code> </td> <td> <code> keys? </code> </td> <td> Client </td> <td> Called when <code> refreshNuxtData </code> is called. </td> </tr> <tr> <td> <code> link:prefetch </code> </td> <td> <code> to </code> </td> <td> Client </td> <td> Called when a <code> <NuxtLink> </code> is observed to be prefetched. </td> </tr> <tr> <td> <code> page:start </code> </td> <td> <code> pageComponent? </code> </td> <td> Client </td> <td> Called on <a href="https://vuejs.org/guide/built-ins/suspense#suspense" rel="nofollow"> Suspense </a> inside of <code> NuxtPage </code> pending event. </td> </tr> <tr> <td> <code> page:finish </code> </td> <td> <code> pageComponent? </code> </td> <td> Client </td> <td> Called on <a href="https://vuejs.org/guide/built-ins/suspense#suspense" rel="nofollow"> Suspense </a> inside of <code> NuxtPage </code> resolved event. </td> </tr> <tr> <td> <code> page:loading:start </code> </td> <td> - </td> <td> Client </td> <td> Called when a route navigation begins (before resolution) or when the page key changes. May fire without the page component's <code> setup() </code> re-running if the page is reused (e.g. with a static <code> key </code> in <code> definePageMeta </code> ). </td> </tr> <tr> <td> <code> page:loading:end </code> </td> <td> - </td> <td> Client </td> <td> Called after <code> page:finish </code> </td> </tr> <tr> <td> <code> page:transition:finish </code> </td> <td> <code> pageComponent? </code> </td> <td> Client </td> <td> After page transition <a href="https://vuejs.org/guide/built-ins/transition#javascript-hooks" rel="nofollow"> onAfterLeave </a> event. </td> </tr> <tr> <td> <code> dev:ssr-logs </code> </td> <td> <code> logs </code> </td> <td> Client </td> <td> Called with an array of server-side logs that have been passed to the client (if <code> features.devLogs </code> is enabled). </td> </tr> <tr> <td> <code> page:view-transition:start </code> </td> <td> <code> transition </code> </td> <td> Client </td> <td> Called after <code> document.startViewTransition </code> is called when <a href="https://nuxt.com/docs/3.x/getting-started/transitions#view-transitions-api-experimental"> experimental viewTransition support is enabled </a> . </td> </tr> </tbody> </table> ## Nuxt Hooks (build time) Check the [schema source code](https://github.com/nuxt/nuxt/blob/main/packages/schema/src/types/hooks.ts#L83) for all available hooks. <table> <thead> <tr> <th> Hook </th> <th> Arguments </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> kit:compatibility </code> </td> <td> <code> compatibility, issues </code> </td> <td> Allows extending compatibility checks. </td> </tr> <tr> <td> <code> ready </code> </td> <td> <code> nuxt </code> </td> <td> Called after Nuxt initialization, when the Nuxt instance is ready to work. </td> </tr> <tr> <td> <code> close </code> </td> <td> <code> nuxt </code> </td> <td> Called when Nuxt instance is gracefully closing. </td> </tr> <tr> <td> <code> restart </code> </td> <td> <code> { hard?: boolean } </code> </td> <td> To be called to restart the current Nuxt instance. </td> </tr> <tr> <td> <code> modules:before </code> </td> <td> - </td> <td> Called during Nuxt initialization, before installing user modules. </td> </tr> <tr> <td> <code> modules:done </code> </td> <td> - </td> <td> Called during Nuxt initialization, after installing user modules. </td> </tr> <tr> <td> <code> app:resolve </code> </td> <td> <code> app </code> </td> <td> Called after resolving the <code> app </code> instance. </td> </tr> <tr> <td> <code> app:templates </code> </td> <td> <code> app </code> </td> <td> Called during <code> NuxtApp </code> generation, to allow customizing, modifying or adding new files to the build directory (either virtually or to written to <code> .nuxt </code> ). </td> </tr> <tr> <td> <code> app:templatesGenerated </code> </td> <td> <code> app </code> </td> <td> Called after templates are compiled into the <a href="https://nuxt.com/docs/3.x/directory-structure/nuxt"> virtual file system </a> (vfs). </td> </tr> <tr> <td> <code> build:before </code> </td> <td> - </td> <td> Called before Nuxt bundle builder. </td> </tr> <tr> <td> <code> build:done </code> </td> <td> - </td> <td> Called after Nuxt bundle builder is complete. </td> </tr> <tr> <td> <code> build:manifest </code> </td> <td> <code> manifest </code> </td> <td> Called during the manifest build by Vite and webpack. This allows customizing the manifest that Nitro will use to render <code> <script> </code> and <code> <link> </code> tags in the final HTML. </td> </tr> <tr> <td> <code> builder:generateApp </code> </td> <td> <code> options </code> </td> <td> Called before generating the app. </td> </tr> <tr> <td> <code> builder:watch </code> </td> <td> <code> event, path </code> </td> <td> Called at build time in development when the watcher spots a change to a file or directory in the project. </td> </tr> <tr> <td> <code> pages:extend </code> </td> <td> <code> pages </code> </td> <td> Called after page routes are scanned from the file system. </td> </tr> <tr> <td> <code> pages:resolved </code> </td> <td> <code> pages </code> </td> <td> Called after page routes have been augmented with scanned metadata. </td> </tr> <tr> <td> <code> pages:routerOptions </code> </td> <td> <code> { files: Array<{ path: string, optional?: boolean }> } </code> </td> <td> Called when resolving <code> router.options </code> files. Later items in the array override earlier ones. </td> </tr> <tr> <td> <code> server:devHandler </code> </td> <td> <code> handler </code> </td> <td> Called when the dev middleware is being registered on the Nitro dev server. </td> </tr> <tr> <td> <code> imports:sources </code> </td> <td> <code> presets </code> </td> <td> Called at setup allowing modules to extend sources. </td> </tr> <tr> <td> <code> imports:extend </code> </td> <td> <code> imports </code> </td> <td> Called at setup allowing modules to extend imports. </td> </tr> <tr> <td> <code> imports:context </code> </td> <td> <code> context </code> </td> <td> Called when the <a href="https://github.com/unjs/unimport" rel="nofollow"> unimport </a> context is created. </td> </tr> <tr> <td> <code> imports:dirs </code> </td> <td> <code> dirs </code> </td> <td> Allows extending import directories. </td> </tr> <tr> <td> <code> components:dirs </code> </td> <td> <code> dirs </code> </td> <td> Called within <code> app:resolve </code> allowing to extend the directories that are scanned for auto-importable components. </td> </tr> <tr> <td> <code> components:extend </code> </td> <td> <code> components </code> </td> <td> Allows extending new components. </td> </tr> <tr> <td> <code> nitro:config </code> </td> <td> <code> nitroConfig </code> </td> <td> Called before initializing Nitro, allowing customization of Nitro's configuration. </td> </tr> <tr> <td> <code> nitro:init </code> </td> <td> <code> nitro </code> </td> <td> Called after Nitro is initialized, which allows registering Nitro hooks and interacting directly with Nitro. </td> </tr> <tr> <td> <code> nitro:build:before </code> </td> <td> <code> nitro </code> </td> <td> Called before building the Nitro instance. </td> </tr> <tr> <td> <code> nitro:build:public-assets </code> </td> <td> <code> nitro </code> </td> <td> Called after copying public assets. Allows modifying public assets before Nitro server is built. </td> </tr> <tr> <td> <code> prerender:routes </code> </td> <td> <code> ctx </code> </td> <td> Allows extending the routes to be pre-rendered. </td> </tr> <tr> <td> <code> build:error </code> </td> <td> <code> error </code> </td> <td> Called when an error occurs at build time. </td> </tr> <tr> <td> <code> prepare:types </code> </td> <td> <code> options </code> </td> <td> Called before <code> @nuxt/cli </code> writes TypeScript configuration files (<code> .nuxt/tsconfig.app.json </code> , <code> .nuxt/tsconfig.server.json </code> , etc.) and <code> .nuxt/nuxt.d.ts </code> , allowing addition of custom references and declarations in <code> nuxt.d.ts </code> , or directly modifying the options in generated configurations </td> </tr> <tr> <td> <code> listen </code> </td> <td> <code> listenerServer, listener </code> </td> <td> Called when the dev server is loading. </td> </tr> <tr> <td> <code> schema:extend </code> </td> <td> <code> schemas </code> </td> <td> Allows extending default schemas. </td> </tr> <tr> <td> <code> schema:resolved </code> </td> <td> <code> schema </code> </td> <td> Allows extending resolved schema. </td> </tr> <tr> <td> <code> schema:beforeWrite </code> </td> <td> <code> schema </code> </td> <td> Called before writing the given schema. </td> </tr> <tr> <td> <code> schema:written </code> </td> <td> - </td> <td> Called after the schema is written. </td> </tr> <tr> <td> <code> vite:extend </code> </td> <td> <code> viteBuildContext </code> </td> <td> Allows extending Vite default context. </td> </tr> <tr> <td> <code> vite:extendConfig </code> </td> <td> <code> viteInlineConfig, env </code> </td> <td> Allows extending Vite default config. <strong> Deprecated in Nuxt 5+. </strong> In Nuxt 5, this operates on a shared configuration rather than separate client/server configs. </td> </tr> <tr> <td> <code> vite:configResolved </code> </td> <td> <code> viteInlineConfig, env </code> </td> <td> Allows reading the resolved Vite config. <strong> Deprecated in Nuxt 5+. </strong> In Nuxt 5, this operates on a shared configuration rather than separate client/server configs. </td> </tr> <tr> <td> <code> vite:serverCreated </code> </td> <td> <code> viteServer, env </code> </td> <td> Called when the Vite server is created. </td> </tr> <tr> <td> <code> vite:compiled </code> </td> <td> - </td> <td> Called after Vite server is compiled. </td> </tr> <tr> <td> <code> webpack:config </code> </td> <td> <code> webpackConfigs </code> </td> <td> Called before configuring the webpack compiler. </td> </tr> <tr> <td> <code> webpack:configResolved </code> </td> <td> <code> webpackConfigs </code> </td> <td> Allows reading the resolved webpack config. </td> </tr> <tr> <td> <code> webpack:compile </code> </td> <td> <code> options </code> </td> <td> Called right before compilation. </td> </tr> <tr> <td> <code> webpack:compiled </code> </td> <td> <code> options </code> </td> <td> Called after resources are loaded. </td> </tr> <tr> <td> <code> webpack:change </code> </td> <td> <code> shortPath </code> </td> <td> Called on <code> change </code> on WebpackBar. </td> </tr> <tr> <td> <code> webpack:error </code> </td> <td> - </td> <td> Called on <code> done </code> if has errors on WebpackBar. </td> </tr> <tr> <td> <code> webpack:done </code> </td> <td> - </td> <td> Called on <code> allDone </code> on WebpackBar. </td> </tr> <tr> <td> <code> webpack:progress </code> </td> <td> <code> statesArray </code> </td> <td> Called on <code> progress </code> on WebpackBar. </td> </tr> </tbody> </table> ## Nitro App Hooks (runtime, server-side) See [Nitro](https://nitro.build/guide/plugins#available-hooks) for all available hooks. <table> <thead> <tr> <th> Hook </th> <th> Arguments </th> <th> Description </th> <th> Types </th> </tr> </thead> <tbody> <tr> <td> <code> dev:ssr-logs </code> </td> <td> <code> { path, logs } </code> </td> <td> Server </td> <td> Called at the end of a request cycle with an array of server-side logs. </td> </tr> <tr> <td> <code> render:response </code> </td> <td> <code> response, { event } </code> </td> <td> Called before sending the response. </td> <td> <a href="https://github.com/nuxt/nuxt/blob/71ef8bd3ff207fd51c2ca18d5a8c7140476780c7/packages/nuxt/src/core/runtime/nitro/renderer.ts#L24" rel="nofollow"> response </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> render:html </code> </td> <td> <code> html, { event } </code> </td> <td> Called before constructing the HTML. </td> <td> <a href="https://github.com/nuxt/nuxt/blob/71ef8bd3ff207fd51c2ca18d5a8c7140476780c7/packages/nuxt/src/core/runtime/nitro/renderer.ts#L15" rel="nofollow"> html </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> render:island </code> </td> <td> <code> islandResponse, { event, islandContext } </code> </td> <td> Called before constructing the island HTML. </td> <td> <a href="https://github.com/nuxt/nuxt/blob/e50cabfed1984c341af0d0c056a325a8aec26980/packages/nuxt/src/core/runtime/nitro/renderer.ts#L28" rel="nofollow"> islandResponse </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> , <a href="https://github.com/nuxt/nuxt/blob/e50cabfed1984c341af0d0c056a325a8aec26980/packages/nuxt/src/core/runtime/nitro/renderer.ts#L38" rel="nofollow"> islandContext </a> </td> </tr> <tr> <td> <code> close </code> </td> <td> - </td> <td> Called when Nitro is closed. </td> <td> - </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> error, { event? } </code> </td> <td> Called when an error occurs. </td> <td> <a href="https://github.com/nitrojs/nitro/blob/d20ffcbd16fc4003b774445e1a01e698c2bb078a/src/types/runtime/nitro.ts#L48" rel="nofollow"> error </a> , <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> request </code> </td> <td> <code> event </code> </td> <td> Called when a request is received. </td> <td> <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> </td> </tr> <tr> <td> <code> beforeResponse </code> </td> <td> <code> event, { body } </code> </td> <td> Called before sending the response. </td> <td> <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> , unknown </td> </tr> <tr> <td> <code> afterResponse </code> </td> <td> <code> event, { body } </code> </td> <td> Called after sending the response. </td> <td> <a href="https://github.com/h3js/h3/blob/f6ceb5581043dc4d8b6eab91e9be4531e0c30f8e/src/types.ts#L38" rel="nofollow"> event </a> , unknown </td> </tr> </tbody> </table> # Import meta > Understand where your code is running using `import.meta`. ## The `import.meta` object With ES modules you can obtain some metadata from the code that imports or compiles your ES-module. This is done through `import.meta`, which is an object that provides your code with this information. Throughout the Nuxt documentation you may see snippets that use this already to figure out whether the code is currently running on the client or server side. <read-more to="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta"> Read more about `import.meta`. </read-more> ## Runtime (App) Properties These values are statically injected and can be used for tree-shaking your runtime code. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> import.meta.client </code> </td> <td> boolean </td> <td> True when evaluated on the client side. </td> </tr> <tr> <td> <code> import.meta.browser </code> </td> <td> boolean </td> <td> True when evaluated on the client side. </td> </tr> <tr> <td> <code> import.meta.server </code> </td> <td> boolean </td> <td> True when evaluated on the server side. </td> </tr> <tr> <td> <code> import.meta.nitro </code> </td> <td> boolean </td> <td> True when evaluated on the server side. </td> </tr> <tr> <td> <code> import.meta.dev </code> </td> <td> boolean </td> <td> True when running the Nuxt dev server. </td> </tr> <tr> <td> <code> import.meta.test </code> </td> <td> boolean </td> <td> True when running in a test context. </td> </tr> <tr> <td> <code> import.meta.prerender </code> </td> <td> boolean </td> <td> True when rendering HTML on the server in the prerender stage of your build. </td> </tr> </tbody> </table> ## Builder Properties These values are available both in modules and in your `nuxt.config`. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> import.meta.env </code> </td> <td> object </td> <td> Equals <code> process.env </code> </td> </tr> <tr> <td> <code> import.meta.url </code> </td> <td> string </td> <td> Resolvable path for the current file. </td> </tr> </tbody> </table> ## Examples ### Using `import.meta.url` to resolve files within modules ```ts [modules/my-module/index.ts] import { createResolver } from 'nuxt/kit' // Resolve relative from the current file const resolver = createResolver(import.meta.url) export default defineNuxtModule({ meta: { name: 'myModule' }, setup () { addComponent({ name: 'MyModuleComponent', // Resolves to '/modules/my-module/components/MyModuleComponent.vue' filePath: resolver.resolve('./components/MyModuleComponent.vue'), }) }, }) ``` # nuxt add > Add modules to your Nuxt application with the command line. ```bash [Terminal] npx nuxt add <MODULENAME> [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--skipInstall] [--skipConfig] [--dev] ``` ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> MODULENAME </code> </td> <td> Specify one or more modules to install by name, separated by spaces </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --skipInstall </code> </td> <td> </td> <td> Skip npm install </td> </tr> <tr> <td> <code> --skipConfig </code> </td> <td> </td> <td> Skip nuxt.config.ts update </td> </tr> <tr> <td> <code> --dev </code> </td> <td> </td> <td> Install modules as dev dependencies </td> </tr> </tbody> </table> The command lets you install [Nuxt modules](https://nuxt.com/modules) in your application with no manual work. When running the command, it will: - install the module as a dependency using your package manager (unless `--skipInstall` is set) - add it to your [package.json](https://nuxt.com/docs/3.x/directory-structure/package) file (unless `--skipInstall` is set) - update your [`nuxt.config`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file (unless `--skipConfig` is set) If no module name is passed, you will be prompted to search for and select modules to add. **Example:** Installing the [`Pinia`](https://nuxt.com/modules/pinia) module ```bash [Terminal] npx nuxt add pinia ``` <note> `nuxt module add` is an alias for `nuxt add`. </note> <read-more to="https://nuxt.com/docs/3.x/api/commands/module"> Read more about the other `nuxt module` commands. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/module/add.ts) # nuxt add-template > Scaffold an entity into your Nuxt application. ```bash [Terminal] npx nuxt add-template <TEMPLATE> <NAME> [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--force] ``` <note> `nuxt add <TEMPLATE> <NAME>` still works but is deprecated in favour of `nuxt add-template`. </note> <read-more to="https://nuxt.com/docs/3.x/api/commands/add"> Read more about `nuxt add`, which adds Nuxt modules to your application. </read-more> ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> TEMPLATE </code> </td> <td> Specify which template to generate (options: <api|app|app-config|component|composable|error|layer|layout|middleware|module|page|plugin|server-middleware|server-plugin|server-route|server-util>) </td> </tr> <tr> <td> <code> NAME </code> </td> <td> Specify name of the generated file </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --force </code> </td> <td> <code> false </code> </td> <td> Force override file if it already exists </td> </tr> </tbody> </table> **Modifiers:** Some templates support additional modifier flags to add a suffix (like `.client` or `.get`) to their name. Generated files are written relative to your [`srcDir`](https://nuxt.com/docs/3.x/api/nuxt-config#srcdir), which defaults to the root of your project. The paths below assume that default. ```bash [Terminal] # Generates `/plugins/sockets.client.ts` npx nuxt add-template plugin sockets --client ``` ## `nuxt add-template component` - Modifier flags: `--mode client|server` or `--client` or `--server` ```bash [Terminal] # Generates `components/TheHeader.vue` npx nuxt add-template component TheHeader ``` ## `nuxt add-template composable` ```bash [Terminal] # Generates `composables/foo.ts` npx nuxt add-template composable foo ``` ## `nuxt add-template layout` ```bash [Terminal] # Generates `layouts/custom.vue` npx nuxt add-template layout custom ``` ## `nuxt add-template plugin` - Modifier flags: `--mode client|server` or `--client` or `--server` ```bash [Terminal] # Generates `plugins/analytics.ts` npx nuxt add-template plugin analytics ``` ## `nuxt add-template page` ```bash [Terminal] # Generates `pages/about.vue` npx nuxt add-template page about ``` ```bash [Terminal] # Generates `pages/category/[id].vue` npx nuxt add-template page "category/[id]" ``` ## `nuxt add-template middleware` - Modifier flags: `--global` ```bash [Terminal] # Generates `middleware/auth.ts` npx nuxt add-template middleware auth ``` ## `nuxt add-template api` - Modifier flags: `--method` (can accept `connect`, `delete`, `get`, `head`, `options`, `patch`, `post`, `put` or `trace`) or alternatively you can directly use `--get`, `--post`, etc. ```bash [Terminal] # Generates `server/api/hello.ts` npx nuxt add-template api hello ``` ## `nuxt add-template layer` ```bash [Terminal] # Generates `layers/subscribe/nuxt.config.ts` npx nuxt add-template layer subscribe ``` --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/add-template.ts) # nuxt analyze > Analyze the production bundle or your Nuxt application. ```bash [Terminal] npx nuxt analyze [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dotenv] [-e, --extends=<layer-name>] [--name=<name>] [--no-serve] ``` The `analyze` command builds Nuxt and analyzes the production bundle (experimental). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --name=<name> </code> </td> <td> <code> default </code> </td> <td> Name of the analysis </td> </tr> <tr> <td> <code> --no-serve </code> </td> <td> </td> <td> Skip serving the analysis results </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/analyze.ts) # nuxt build > Build your Nuxt application. ```bash [Terminal] npx nuxt build [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--prerender] [--preset] [--dotenv] [--envName] [-e, --extends=<layer-name>] [--profile[=verbose]] ``` The `build` command creates a `.output` directory with all your application, server and dependencies ready for production. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --prerender </code> </td> <td> </td> <td> Build Nuxt and prerender static routes </td> </tr> <tr> <td> <code> --preset </code> </td> <td> </td> <td> Nitro server preset </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --profile[=verbose] </code> </td> <td> </td> <td> Profile performance. Use <code> --profile </code> for CPU only, <code> --profile=verbose </code> for full report. </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. </note> <note> `--prerender` will always set the `preset` to `static` </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/build.ts) # nuxt build-module > Nuxt command to build your Nuxt module before publishing. ```bash [Terminal] npx nuxt build-module [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--build] [--stub] [--sourcemap] [--prepare] ``` The `build-module` command runs `@nuxt/module-builder` to generate `dist` directory within your `rootDir` that contains the full build for your **nuxt-module**. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --build </code> </td> <td> <code> false </code> </td> <td> Build module for distribution </td> </tr> <tr> <td> <code> --stub </code> </td> <td> <code> false </code> </td> <td> Stub dist instead of actually building it for development </td> </tr> <tr> <td> <code> --sourcemap </code> </td> <td> <code> false </code> </td> <td> Generate sourcemaps </td> </tr> <tr> <td> <code> --prepare </code> </td> <td> <code> false </code> </td> <td> Prepare module for local development </td> </tr> </tbody> </table> <read-more icon="i-simple-icons-github" target="\_blank" to="https://github.com/nuxt/module-builder"> Read more about `@nuxt/module-builder`. </read-more> --- - [Source](https://github.com/nuxt/module-builder/blob/main/src/cli.ts) # nuxt cleanup > Remove common generated Nuxt files and caches. ```bash [Terminal] npx nuxt cleanup [ROOTDIR] [--cwd=<directory>] ``` The `cleanup` command removes common generated Nuxt files and caches, including: - `.nuxt` - `.output` - `dist` - `node_modules/.vite` - `node_modules/.cache` ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/cleanup.ts) # nuxt dev > The dev command starts a development server with hot module replacement at http://localhost:3000 ```bash [Terminal] npx nuxt dev [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dotenv] [--envName] [-e, --extends=<layer-name>] [--clear] [--no-f, --no-fork] [-p, --port] [-h, --host] [--clipboard] [-o, --open] [--https] [--publicURL] [--qr] [--public] [--tunnel] [--profile[=verbose]] [--sslCert] [--sslKey] ``` The `dev` command starts a development server with hot module replacement at [http://localhost:3000](https://localhost:3000) ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --clear </code> </td> <td> <code> false </code> </td> <td> Clear console on restart </td> </tr> <tr> <td> <code> --no-f, --no-fork </code> </td> <td> </td> <td> Disable forked mode </td> </tr> <tr> <td> <code> -p, --port </code> </td> <td> </td> <td> Port to listen on (default: <code> NUXT_PORT || NITRO_PORT || PORT || nuxtOptions.devServer.port </code> ) </td> </tr> <tr> <td> <code> -h, --host </code> </td> <td> </td> <td> Host to listen on (default: <code> NUXT_HOST || NITRO_HOST || HOST || nuxtOptions.devServer?.host </code> ) </td> </tr> <tr> <td> <code> --clipboard </code> </td> <td> <code> false </code> </td> <td> Copy the URL to the clipboard </td> </tr> <tr> <td> <code> -o, --open </code> </td> <td> <code> false </code> </td> <td> Open the URL in the browser </td> </tr> <tr> <td> <code> --https </code> </td> <td> </td> <td> Enable HTTPS </td> </tr> <tr> <td> <code> --publicURL </code> </td> <td> </td> <td> Displayed public URL (used for QR code) </td> </tr> <tr> <td> <code> --qr </code> </td> <td> </td> <td> Display The QR code of public URL when available </td> </tr> <tr> <td> <code> --public </code> </td> <td> </td> <td> Listen to all network interfaces </td> </tr> <tr> <td> <code> --tunnel </code> </td> <td> </td> <td> Open a tunnel using <a href="https://github.com/unjs/untun" rel="nofollow"> https://github.com/unjs/untun </a> </td> </tr> <tr> <td> <code> --profile[=verbose] </code> </td> <td> </td> <td> Profile performance. Use <code> --profile </code> for CPU only, <code> --profile=verbose </code> for full report. </td> </tr> <tr> <td> <code> --sslCert </code> </td> <td> </td> <td> (DEPRECATED) Use <code> --https.cert </code> instead. </td> </tr> <tr> <td> <code> --sslKey </code> </td> <td> </td> <td> (DEPRECATED) Use <code> --https.key </code> instead. </td> </tr> </tbody> </table> The port and host can also be set via NUXT_PORT, PORT, NUXT_HOST or HOST environment variables. Additionally to the above options, `@nuxt/cli` can pass options through to `listhen`, e.g. `--no-qr` to turn off the dev server QR code. You can find the list of `listhen` options in the [unjs/listhen](https://github.com/unjs/listhen) docs. This command sets `process.env.NODE_ENV` to `development`. <note> If you are using a self-signed certificate in development, you will need to set `NODE_TLS_REJECT_UNAUTHORIZED=0` in your environment. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/dev.ts) # nuxt devtools > The devtools command allows you to enable or disable Nuxt DevTools on a per-project basis. ```bash [Terminal] npx nuxt devtools <COMMAND> [ROOTDIR] [--cwd=<directory>] ``` Running `nuxt devtools enable` will install the Nuxt DevTools globally, and also enable it within the particular project you are using. It is saved as a preference in your user-level `.nuxtrc`. If you want to remove devtools support for a particular project, you can run `nuxt devtools disable`. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> COMMAND </code> </td> <td> Command to run (options: <enable|disable>) </td> </tr> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> </tbody> </table> <read-more icon="i-simple-icons-nuxtdotjs" target="\_blank" to="https://devtools.nuxt.com"> Read more about the **Nuxt DevTools**. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/devtools.ts) # nuxt generate > Pre-renders every route of the application and stores the result in plain HTML files. ```bash [Terminal] npx nuxt generate [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--preset] [--dotenv] [--envName] [-e, --extends=<layer-name>] [--profile[=verbose]] ``` The `generate` command pre-renders every route of your application and stores the result in plain HTML files that you can deploy on any static hosting services. The command triggers the `nuxt build` command with the `prerender` argument set to `true` ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --preset </code> </td> <td> </td> <td> Nitro server preset </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --profile[=verbose] </code> </td> <td> </td> <td> Profile performance. Use <code> --profile </code> for CPU only, <code> --profile=verbose </code> for full report. </td> </tr> </tbody> </table> <read-more to="https://nuxt.com/docs/3.x/getting-started/deployment#static-hosting"> Read more about pre-rendering and static hosting. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/generate.ts) # nuxt info > The info command logs information about the current or specified Nuxt project. ```bash [Terminal] npx nuxt info [ROOTDIR] [--cwd=<directory>] ``` The `info` command logs information about the current or specified Nuxt project. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/info.ts) # create nuxt > The init command initializes a fresh Nuxt project. ```bash [Terminal] npm create nuxt@latest [DIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [-t, --template] [-f, --force] [--offline] [--preferOffline] [--no-install] [--gitInit] [--shell] [--packageManager] [-M, --modules] [--no-modules] [--nightly] ``` The `create-nuxt` command initializes a fresh Nuxt project using [unjs/giget](https://github.com/unjs/giget). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> DIR="" </code> </td> <td> Project directory </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> -t, --template </code> </td> <td> </td> <td> Template name </td> </tr> <tr> <td> <code> -f, --force </code> </td> <td> </td> <td> Override existing directory </td> </tr> <tr> <td> <code> --offline </code> </td> <td> </td> <td> Force offline mode </td> </tr> <tr> <td> <code> --preferOffline </code> </td> <td> </td> <td> Prefer offline mode </td> </tr> <tr> <td> <code> --no-install </code> </td> <td> </td> <td> Skip installing dependencies </td> </tr> <tr> <td> <code> --gitInit </code> </td> <td> </td> <td> Initialize git repository </td> </tr> <tr> <td> <code> --shell </code> </td> <td> </td> <td> Start shell after installation in project directory </td> </tr> <tr> <td> <code> --packageManager </code> </td> <td> </td> <td> Package manager choice (npm, pnpm, yarn, bun) </td> </tr> <tr> <td> <code> -M, --modules </code> </td> <td> </td> <td> Nuxt modules to install (comma separated without spaces) </td> </tr> <tr> <td> <code> --no-modules </code> </td> <td> </td> <td> Skip module installation prompt </td> </tr> <tr> <td> <code> --nightly </code> </td> <td> </td> <td> Use Nuxt nightly release channel (3x or latest) </td> </tr> </tbody> </table> ## Environment Variables - `NUXI_INIT_REGISTRY`: Set to a custom template registry. ([learn more](https://github.com/unjs/giget#custom-registry)). - Default registry is loaded from [nuxt/starter/templates](https://github.com/nuxt/starter/tree/templates/templates) --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/init.ts) # nuxt module > Search and remove modules in your Nuxt application with the command line. Nuxt provides a few utilities to work with [Nuxt modules](https://nuxt.com/modules) seamlessly. <read-more to="https://nuxt.com/docs/3.x/api/commands/add"> Read more about `nuxt add`, which installs modules into your application. </read-more> ## `nuxt module remove` ```bash [Terminal] npx nuxt module remove [MODULENAME] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--skipInstall] [--skipConfig] ``` ### Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> MODULENAME </code> </td> <td> Specify one or more modules to remove by name, separated by spaces </td> </tr> </tbody> </table> ### Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --skipInstall </code> </td> <td> </td> <td> Skip dependency uninstall </td> </tr> <tr> <td> <code> --skipConfig </code> </td> <td> </td> <td> Skip nuxt.config.ts update </td> </tr> </tbody> </table> The command uninstalls the module (unless `--skipInstall` is set) and removes it from your [`nuxt.config`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file (unless `--skipConfig` is set). If no module name is passed, you will be prompted to select from the modules registered in your `nuxt.config`. A module name is required when `--skipConfig` is set. **Example:** ```bash [Terminal] npx nuxt module remove pinia ``` ## `nuxt module search` ```bash [Terminal] npx nuxt module search <QUERY> [--cwd=<directory>] [--nuxtVersion=<2|3>] ``` ### Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> QUERY </code> </td> <td> keywords to search for </td> </tr> </tbody> </table> ### Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> <code> . </code> </td> <td> Specify the working directory </td> </tr> <tr> <td> <code> --nuxtVersion=<2|3> </code> </td> <td> </td> <td> Filter by Nuxt version and list compatible modules only (auto detected by default) </td> </tr> </tbody> </table> The command searches for Nuxt modules matching your query that are compatible with your Nuxt version. **Example:** ```bash [Terminal] npx nuxt module search pinia ``` --- - [Source](https://github.com/nuxt/cli/tree/3.x/packages/nuxi/src/commands/module) # Nuxt CLI > The Nuxt CLI runs, builds and inspects your Nuxt application from the command line. `@nuxt/cli` is the `nuxt` command: it runs the dev server, builds your application for production, scaffolds files, manages modules and answers questions about your project. It is a dependency of `nuxt`, so a Nuxt project already has it. ```bash [Terminal] npx nuxt dev ``` The binary is installed as `nuxt`, and also as `nuxi`, `nuxi-ng` and `nuxt-cli` for compatibility with older setups. Two other packages ship the same commands for different situations. `nuxi` is a standalone build with no runtime dependencies, for running commands outside a project or installing globally. Scaffolding a new project is [`create-nuxt`](https://nuxt.com/docs/3.x/api/commands/init), a separate package so that it can be run without a project to install into. ## Running commands Inside a project, your package manager runs the version the project depends on: ```bash [Terminal] pnpm nuxt dev npm exec nuxt dev yarn nuxt dev bun nuxt dev ``` Outside a project, `npx nuxi` runs the same commands from its own bundled copy. ## Global options `--cwd` may be passed before the command name as well as after it, which is useful in a monorepo: ```bash [Terminal] npx nuxt --cwd apps/web dev ``` Commands that take a `ROOTDIR` positional treat an explicit `--cwd` as an override of it. `--help` on any command prints its arguments and options, and `--version` prints the CLI version. Node.js 18 or newer is required. Older versions still run, with a warning that they are unsupported. ## Project commands A command the CLI does not provide is looked up as a `nuxt-<command>` binary in your project, so a dependency can add a command of its own. This is how [`nuxt build-module`](https://nuxt.com/docs/3.x/api/commands/build-module) works: it runs the `nuxt-build-module` binary that `@nuxt/module-builder` installs. ## Shell completions `nuxt complete <shell>` prints a completion script, powered by [`@bomb.sh/tab`](https://github.com/bombshell-dev/tab). It completes commands, flags and some flag values: ports and hosts for `nuxt dev`, Nitro presets for `nuxt build --preset`, starter templates for `nuxt init --template`, and log levels. <code-group> ```bash [zsh] npx nuxt complete zsh > "${fpath[1]}/_nuxt" ``` ```bash [bash] npx nuxt complete bash > /etc/bash_completion.d/nuxt ``` ```bash [fish] npx nuxt complete fish > ~/.config/fish/completions/nuxt.fish ``` </code-group> `powershell` is also supported, and `create-nuxt complete <shell>` has its own script which completes starter template names. <note> Completions work through your package manager too (`pnpm nuxt <Tab>`), if you install [tab's package manager completions](https://github.com/bombshell-dev/tab?tab=readme-ov-file#package-manager-completions). </note> ## Debugging the CLI Set `DEBUG=nuxi` for extra diagnostics from the CLI itself, such as dev server startup timings and the paths it removes during cleanup. ## Prereleases Every commit is published to the nightly channel: ```bash [Terminal] npm install -D @nuxt/cli-nightly npx @nuxt/cli-nightly dev ``` `create-nuxt-nightly` scaffolds with it, and `npm create nuxt@latest --nightly` scaffolds a project against the Nuxt nightly channel. Builds for an individual pull request are published by [pkg.pr.new](https://pkg.pr.new) and linked from the pull request itself, which is the quickest way to check whether a fix works before it is released. --- - [Source](https://github.com/nuxt/cli) # nuxt prepare > The prepare command creates a .nuxt directory in your application and generates types. ```bash [Terminal] npx nuxt prepare [ROOTDIR] [--dotenv] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--envName] [-e, --extends=<layer-name>] ``` The `prepare` command creates a [`.nuxt`](https://nuxt.com/docs/3.x/directory-structure/nuxt) directory in your application and generates types. This can be useful in a CI environment or as a `postinstall` command in your [`package.json`](https://nuxt.com/docs/3.x/directory-structure/package). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/prepare.ts) # nuxt preview > The preview command starts a server to preview your application after the build command. ```bash [Terminal] npx nuxt preview [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--envName] [-e, --extends=<layer-name>] [-p, --port] [--dotenv] ``` The `preview` command starts a server to preview your Nuxt application after running the `build` command. The `start` command is an alias for `preview`. When running your application in production refer to the [Deployment section](https://nuxt.com/docs/3.x/getting-started/deployment). ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --envName </code> </td> <td> </td> <td> The environment to use when resolving configuration overrides (default is <code> production </code> when building, and <code> development </code> when running the dev server) </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> -p, --port </code> </td> <td> </td> <td> Port to listen on </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> </tbody> </table> If `--port` is not provided, the `NUXT_PORT`, `NITRO_PORT` and `PORT` environment variables are used, in that order. This command sets `process.env.NODE_ENV` to `production`. To override, define `NODE_ENV` in a `.env` file or as command-line argument. <note> For convenience, in preview mode, your [`.env`](https://nuxt.com/docs/3.x/directory-structure/env) file will be loaded into `process.env`. (However, in production you will need to ensure your environment variables are set yourself. For example, with Node.js 20+ you could do this by running `NODE_ENV=production node --env-file .env .output/server/index.mjs` to start your server.) </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/preview.ts) # nuxt test > The test command runs tests using @nuxt/test-utils. ```bash [Terminal] npx nuxt test [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dev] [--watch] ``` The `test` command runs tests using [`@nuxt/test-utils`](https://nuxt.com/docs/3.x/getting-started/testing). This command sets `process.env.NODE_ENV` to `test` if not already set. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dev </code> </td> <td> </td> <td> Run in dev mode </td> </tr> <tr> <td> <code> --watch </code> </td> <td> </td> <td> Watch mode </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `test`. </note> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/test.ts) # nuxt typecheck > The typecheck command runs vue-tsc or Golar to check types throughout your app. ```bash [Terminal] npx nuxt typecheck [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dotenv] [-e, --extends=<layer-name>] [--checker] ``` The `typecheck` command runs [`vue-tsc`](https://github.com/vuejs/language-tools/tree/master/packages/tsc) or [Golar](https://golar.dev/languages/vue/) to check types throughout your app. If neither is installed, you will be prompted to install one, or shown installation instructions when running in a non-interactive terminal. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dotenv </code> </td> <td> </td> <td> Path to <code> .env </code> file to load, relative to the root directory </td> </tr> <tr> <td> <code> -e, --extends=<layer-name> </code> </td> <td> </td> <td> Extend from a Nuxt layer </td> </tr> <tr> <td> <code> --checker </code> </td> <td> </td> <td> Type checker to use (<code> vue-tsc </code> or <code> golar </code> ) </td> </tr> </tbody> </table> <note> This command sets `process.env.NODE_ENV` to `production`. To override, define `NODE_ENV` in a [`.env`](https://nuxt.com/docs/3.x/directory-structure/env) file or as a command-line argument. </note> <read-more to="https://nuxt.com/docs/3.x/guide/concepts/typescript#type-checking"> Read more on how to enable type-checking at build or development time. </read-more> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/typecheck.ts) # nuxt upgrade > The upgrade command upgrades Nuxt to the latest version. ```bash [Terminal] npx nuxt upgrade [ROOTDIR] [--cwd=<directory>] [--logLevel=<silent|info|verbose>] [--dedupe] [-f, --force] [-ch, --channel=<stable|nightly|v3|v4|v4-nightly|v3-nightly>] ``` The `upgrade` command upgrades Nuxt to the latest version. ## Arguments <table> <thead> <tr> <th> Argument </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> ROOTDIR="." </code> </td> <td> Specifies the working directory (default: <code> . </code> ) </td> </tr> </tbody> </table> ## Options <table> <thead> <tr> <th> Option </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> --cwd=<directory> </code> </td> <td> </td> <td> Specify the working directory, this takes precedence over ROOTDIR (default: <code> . </code> ) </td> </tr> <tr> <td> <code> --logLevel=<silent|info|verbose> </code> </td> <td> </td> <td> Specify build-time log level </td> </tr> <tr> <td> <code> --dedupe </code> </td> <td> </td> <td> Dedupe dependencies after upgrading </td> </tr> <tr> <td> <code> -f, --force </code> </td> <td> </td> <td> Force upgrade to recreate lockfile and node_modules </td> </tr> <tr> <td> <code> -ch, --channel=<stable|nightly|v3|v4|v4-nightly|v3-nightly> </code> </td> <td> <code> stable </code> </td> <td> Specify a channel to install from (default: stable) </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/cli/blob/3.x/packages/nuxi/src/commands/upgrade.ts) # <ClientOnly> > Render components only in client-side with the <ClientOnly> component. The `<ClientOnly>` component is used for purposely rendering a component only on client side. <note> The content of the default slot will be tree-shaken out of the server build. (This does mean that any CSS used by components within it may not be inlined when rendering the initial HTML.) </note> ## Props - `placeholderTag` | `fallbackTag`: specify a tag to be rendered server-side. - `placeholder` | `fallback`: specify a content to be rendered server-side. ```vue <template> <div> <Sidebar /> <!-- The <Comment> component will only be rendered on client-side --> <ClientOnly fallback-tag="span" fallback="Loading comments..." > <Comment /> </ClientOnly> </div> </template> ``` ## Slots - `#fallback`: specify a content to be rendered on the server and displayed until `<ClientOnly>` is mounted in the browser. ```vue [pages/example.vue] <template> <div> <Sidebar /> <!-- This renders the "span" element on the server side --> <ClientOnly fallback-tag="span"> <!-- this component will only be rendered on client side --> <Comments /> <template #fallback> <!-- this will be rendered on server side --> <p>Loading comments...</p> </template> </ClientOnly> </div> </template> ``` ## Examples ### Accessing HTML Elements Components inside `<ClientOnly>` are rendered only after being mounted. To access the rendered elements in the DOM, you can watch a template ref: ```vue [pages/example.vue] <script setup lang="ts"> const nuxtWelcomeRef = useTemplateRef('nuxtWelcomeRef') // The watch will be triggered when the component is available watch(nuxtWelcomeRef, () => { console.log('<NuxtWelcome /> mounted') }, { once: true }) </script> <template> <ClientOnly> <NuxtWelcome ref="nuxtWelcomeRef" /> </ClientOnly> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-only.ts) # <DevOnly> > Render components only during development with the <DevOnly> component. Nuxt provides the `<DevOnly>` component to render a component only during development. The content will not be included in production builds. ```vue [pages/example.vue] <template> <div> <Sidebar /> <DevOnly> <!-- this component will only be rendered during development --> <LazyDebugBar /> <!-- if you ever require to have a replacement during production --> <!-- be sure to test these using `nuxt preview` --> <template #fallback> <div><!-- empty div for flex.justify-between --></div> </template> </DevOnly> </div> </template> ``` ## Slots - `#fallback`: if you ever require to have a replacement during production. ```vue <template> <div> <Sidebar /> <DevOnly> <!-- this component will only be rendered during development --> <LazyDebugBar /> <!-- be sure to test these using `nuxt preview` --> <template #fallback> <div><!-- empty div for flex.justify-between --></div> </template> </DevOnly> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/dev-only.ts) # <NuxtClientFallback> > Nuxt provides the <NuxtClientFallback> component to render its content on the client if any of its children trigger an error in SSR Nuxt provides the `<NuxtClientFallback>` component to render its content on the client if any of its children trigger an error in SSR. <note to="https://nuxt.com/docs/3.x/guide/going-further/experimental-features#clientfallback"> This component is experimental and in order to use it you must enable the `experimental.clientFallback` option in your `nuxt.config`. </note> ```vue [pages/example.vue] <template> <div> <Sidebar /> <!-- this component will be rendered on client-side --> <NuxtClientFallback fallback-tag="span"> <Comments /> <BrokeInSSR /> </NuxtClientFallback> </div> </template> ``` ## Events - `@ssr-error`: Event emitted when a child triggers an error in SSR. Note that this will only be triggered on the server.```vue <template> <NuxtClientFallback @ssr-error="logSomeError"> <!-- ... --> </NuxtClientFallback> </template> ``` ## Props - `placeholderTag` | `fallbackTag`: Specify a fallback tag to be rendered if the slot fails to render on the server. - **type**: `string` - **default**: `div` - `placeholder` | `fallback`: Specify fallback content to be rendered if the slot fails to render. - **type**: `string` - `keepFallback`: Keep the fallback content if it failed to render server-side. - **type**: `boolean` - **default**: `false` <warning icon="i-ph-warning-duotone"> The `placeholder` and `fallback` props render content as raw HTML. Do not pass untrusted user input to these props as it may lead to XSS vulnerabilities. Use the `#fallback` or `#placeholder` slots instead for dynamic content that needs proper escaping. </warning> ```vue <template> <!-- render <span>Hello world</span> server-side if the default slot fails to render --> <NuxtClientFallback fallback-tag="span" fallback="Hello world" > <BrokeInSSR /> </NuxtClientFallback> </template> ``` ## Slots - `#fallback`: specify content to be displayed server-side if the slot fails to render. ```vue <template> <NuxtClientFallback> <!-- ... --> <template #fallback> <!-- this will be rendered on server side if the default slot fails to render in ssr --> <p>Hello world</p> </template> </NuxtClientFallback> </template> ``` --- - [Source (client)](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.client.ts) - [Source (server)](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/client-fallback.server.ts) # <NuxtErrorBoundary> > The <NuxtErrorBoundary> component handles client-side errors happening in its default slot. <tip> The `<NuxtErrorBoundary>` uses Vue's [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) hook under the hood. </tip> ## Events - `@error`: Event emitted when the default slot of the component throws an error.```vue <template> <NuxtErrorBoundary @error="logSomeError"> <!-- ... --> </NuxtErrorBoundary> </template> ``` ## Slots - `#error`: Specify a fallback content to display in case of error.```vue <template> <NuxtErrorBoundary> <!-- ... --> <template #error="{ error, clearError }"> <p>An error occurred: {{ error }}</p> <button @click="clearError"> Clear error </button> </template> </NuxtErrorBoundary> </template> ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> ## Examples ### Accessing `error` and `clearError` in script You can access `error` and `clearError` properties within the component's script as below: ```vue <template> <NuxtErrorBoundary ref="errorBoundary"> <!-- ... --> </NuxtErrorBoundary> </template> <script setup lang="ts"> const errorBoundary = useTemplateRef('errorBoundary') // errorBoundary.value?.error // errorBoundary.value?.clearError() </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-error-boundary.vue) # <NuxtImg> > Nuxt provides a <NuxtImg> component to handle automatic image optimization. `<NuxtImg>` is a drop-in replacement for the native `<img>` tag. - Uses built-in provider to optimize local and remote images - Converts `src` to provider-optimized URLs - Automatically resizes images based on `width` and `height` - Generates responsive sizes when providing `sizes` option - Supports native lazy loading as well as other `<img>` attributes ## Setup In order to use `<NuxtImg>` you should install and enable the Nuxt Image module: ```bash [Terminal] npx nuxt module add image ``` ## Usage `<NuxtImg>` outputs a native `img` tag directly (without any wrapper around it). Use it like you would use the `<img>` tag: ```html <NuxtImg src="/nuxt-icon.png" /> ``` Will result in: ```html <img src="/nuxt-icon.png" /> ``` <read-more target="_blank" to="https://image.nuxt.com/usage/nuxt-img"> Read more about the `<NuxtImg>` component. </read-more> --- - [Source](https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtImg.vue) # <NuxtIsland> > Nuxt provides the <NuxtIsland> component to render a non-interactive component without any client JS. When rendering an island component, the content of the island component is static, thus no JS is downloaded client-side. Changing the island component props triggers a refetch of the island component to re-render it again. <note> Global styles of your application are sent with the response. </note> <tip> Server only components use `<NuxtIsland>` under the hood </tip> ## Props - `name` : Name of the component to render. - **type**: `string` - **required** - `lazy`: Make the component non-blocking. - **type**: `boolean` - **default**: `false` - `props`: Props to send to the component to render. - **type**: `Record<string, any>` - `source`: Remote source to call the island to render. - **type**: `string` - **dangerouslyLoadClientComponents**: Required to load client components from a remote source. - **type**: `boolean` - **default**: `false` <note> Remote islands need `experimental.componentIslands` to be `'local+remote'` in your `nuxt.config`. </note> <warning icon="i-ph-warning-duotone"> Using the `source` prop to render content from a remote server is inherently dangerous. When you specify a remote `source`, you are fully trusting that server to provide safe HTML content that will be rendered directly in your application. This is similar to using `v-html` with external content - the remote server can inject any HTML, including potentially malicious content. **Only use source with servers you fully trust and control.** The `dangerouslyLoadClientComponents` prop controls an additional layer of risk: whether to also download and execute client components from the remote source. Even with `dangerouslyLoadClientComponents` disabled (the default), you are still trusting the remote server's HTML output. </warning> <note> Component props and context are sent as GET query parameters to enable caching. Query parameters may be visible in server access logs, CDN caches, and HTTP `Referer` headers. </note> <note> By default, component islands are scanned from the `~/components/islands/` directory. So the `~/components/islands/MyIsland.vue` component could be rendered with `<NuxtIsland name="MyIsland" />`. </note> ## Slots Slots can be passed to an island component if declared. Every slot is interactive since the parent component is the one providing it. Some slots are reserved to `NuxtIsland` for special cases. - `#fallback`: Specify the content to be rendered before the island loads (if the component is lazy) or if `NuxtIsland` fails to fetch the component. ## Ref - `refresh()` - **type**: `() => Promise<void>` - **description**: force refetch the server component by refetching it. ## Events - `error` - **parameters**: - **error**: - **type**: `unknown` - **description**: emitted when `NuxtIsland` fails to fetch the new island. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-island.ts) # <NuxtLayout> > Nuxt provides the <NuxtLayout> component to show layouts on pages and error pages. You can use `<NuxtLayout />` component to activate the `default` layout on `app.vue` or `error.vue`. ```vue [app.vue] <template> <NuxtLayout> some page content </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/layouts"> </read-more> ## Props - `name`: Specify a layout name to be rendered, can be a string, reactive reference or a computed property. It **must** match the name of the corresponding layout file in the [`layouts/`](https://nuxt.com/docs/3.x/directory-structure/layouts) directory, or `false` to disable the layout. - **type**: `string | false` - **default**: `default` ```vue [pages/index.vue] <script setup lang="ts"> // layouts/custom.vue const layout = 'custom' </script> <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> ``` <note> Please note the layout name is normalized to kebab-case, so if your layout file is named `errorLayout.vue`, it will become `error-layout` when passed as a `name` property to `<NuxtLayout />`. </note> ```vue [error.vue] <template> <NuxtLayout name="error-layout"> <NuxtPage /> </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/layouts"> Read more about dynamic layouts. </read-more> - `fallback`: If an invalid layout is passed to the `name` prop, no layout will be rendered. Specify a `fallback` layout to be rendered in this scenario. It **must** match the name of the corresponding layout file in the [`layouts/`](https://nuxt.com/docs/3.x/directory-structure/layouts) directory. - **type**: `string` - **default**: `null` ## Additional Props `NuxtLayout` also accepts any additional props that you may need to pass to the layout. These custom props are then made accessible as attributes. ```vue [pages/some-page.vue] <template> <div> <NuxtLayout name="custom" title="I am a custom layout" > <!-- ... --> </NuxtLayout> </div> </template> ``` In the above example, the value of `title` will be available using `$attrs.title` in the template or `useAttrs().title` in `<script setup>` at custom.vue. ```vue [layouts/custom.vue] <script setup lang="ts"> const layoutCustomProps = useAttrs() console.log(layoutCustomProps.title) // I am a custom layout </script> ``` ## Transitions `<NuxtLayout />` renders incoming content via `<slot />`, which is then wrapped around Vueโ€™s `<Transition />` component to activate layout transition. For this to work as expected, it is recommended that `<NuxtLayout />` is **not** the root element of the page component. <code-group> ```vue [pages/index.vue] <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> </NuxtLayout> </div> </template> ``` ```vue [layouts/custom.vue] <template> <div> <!-- named slot --> <slot name="header" /> <slot /> </div> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/3.x/getting-started/transitions"> </read-more> ## Layout's Ref To get the ref of a layout component, access it through `ref.value.layoutRef`. <code-group> ```vue [app.vue] <script setup lang="ts"> const layout = ref() function logFoo () { layout.value.layoutRef.foo() } </script> <template> <NuxtLayout ref="layout"> default layout </NuxtLayout> </template> ``` ```vue [layouts/default.vue] <script setup lang="ts"> const foo = () => console.log('foo') defineExpose({ foo, }) </script> <template> <div> default layout <slot /> </div> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/3.x/directory-structure/layouts"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-layout.ts) # <NuxtLink> > Nuxt provides <NuxtLink> component to handle any kind of links within your application. <note> `<NuxtLink>` is a drop-in replacement for both Vue Router's `<RouterLink>` component and HTML's `<a>` tag. It intelligently determines whether the link is *internal* or *external* and renders it accordingly with available optimizations (prefetching, default attributes, etc.) </note> ## Internal Routing In this example, we use `<NuxtLink>` component to link to another page of the application. <code-group> ```vue [pages/index.vue] <template> <NuxtLink to="/about">About page</NuxtLink> </template> ``` ```html [(Renders as) index.html] <!-- (Vue Router & Smart Prefetching) --> <a href="/about">About page</a> ``` </code-group> ### Passing Params to Dynamic Routes In this example, we pass the `id` param to link to the route `~/pages/posts/[id].vue`. <code-group> ```vue [pages/index.vue] <template> <NuxtLink :to="{ name: 'posts-id', params: { id: 123 } }"> Post 123 </NuxtLink> </template> ``` ```html [(Renders as) index.html] <a href="/posts/123">Post 123</a> ``` </code-group> <tip> Check out the Pages panel in Nuxt DevTools to see the route name and the params it might take. </tip> <tip> When you pass an object into the `to` prop, `<NuxtLink>` will inherit Vue Routerโ€™s handling of query parameters. Keys and values will be automatically encoded, so you donโ€™t need to call `encodeURI` or `encodeURIComponent` manually. </tip> ### Handling Static File and Cross-App Links By default, `<NuxtLink>` uses Vue Router's client side navigation for relative route. When linking to static files in the `/public` directory or to another application hosted on the same domain, it might result in unexpected 404 errors because they are not part of the client routes. In such cases, you can use the `external` prop with `<NuxtLink>` to bypass Vue Router's internal routing mechanism. The `external` prop explicitly indicates that the link is external. `<NuxtLink>` will render the link as a standard HTML `<a>` tag. This ensures the link behaves correctly, bypassing Vue Routerโ€™s logic and directly pointing to the resource. #### Linking to Static Files For static files in the `/public` directory, such as PDFs or images, use the `external` prop to ensure the link resolves correctly. ```vue [pages/index.vue] <template> <NuxtLink to="/example-report.pdf" external > Download Report </NuxtLink> </template> ``` #### Linking to a Cross-App URL When pointing to a different application on the same domain, using the `external` prop ensures the correct behavior. ```vue [pages/index.vue] <template> <NuxtLink to="/another-app" external > Go to Another App </NuxtLink> </template> ``` Using the `external` prop or relying on automatic handling ensures proper navigation, avoids unexpected routing issues, and improves compatibility with static resources or cross-application scenarios. ## External Routing In this example, we use `<NuxtLink>` component to link to a website. ```vue [app.vue] <template> <NuxtLink to="https://nuxtjs.org"> Nuxt website </NuxtLink> <!-- <a href="https://nuxtjs.org" rel="noopener noreferrer">...</a> --> </template> ``` ## `rel` and `noRel` Attributes A `rel` attribute of `noopener noreferrer` is applied by default to links with a `target` attribute or to absolute links (e.g., links starting with `http://`, `https://`, or `//`). - `noopener` solves a [security bug](https://mathiasbynens.github.io/rel-noopener/) in older browsers. - `noreferrer` improves privacy for your users by not sending the `Referer` header to the linked site. These defaults have no negative impact on SEO and are considered [best practice](https://developer.chrome.com/docs/lighthouse/best-practices/external-anchors-use-rel-noopener). When you need to overwrite this behavior you can use the `rel` or `noRel` props. ```vue [app.vue] <template> <NuxtLink to="https://twitter.com/nuxt_js"> Nuxt Twitter </NuxtLink> <!-- <a href="https://twitter.com/nuxt_js" rel="noopener noreferrer">...</a> --> <NuxtLink to="https://discord.nuxtjs.org" rel="noopener" > Nuxt Discord </NuxtLink> <!-- <a href="https://discord.nuxtjs.org" rel="noopener">...</a> --> <NuxtLink to="/about" target="_blank" >About page</NuxtLink> <!-- <a href="/about" target="_blank" rel="noopener noreferrer">...</a> --> </template> ``` A `noRel` prop can be used to prevent the default `rel` attribute from being added to the absolute links. ```vue [app.vue] <template> <NuxtLink to="https://github.com/nuxt" no-rel > Nuxt GitHub </NuxtLink> <!-- <a href="https://github.com/nuxt">...</a> --> </template> ``` <note> `noRel` and `rel` cannot be used together. `rel` will be ignored. </note> ## Prefetch Links Nuxt automatically includes smart prefetching. That means it detects when a link is visible (by default), either in the viewport or when scrolling and prefetches the JavaScript for those pages so that they are ready when the user clicks the link. Nuxt only loads the resources when the browser isn't busy and skips prefetching if your connection is offline or if you only have 2g connection. ```vue [pages/index.vue] <NuxtLink to="/about" no-prefetch> About page not pre-fetched </NuxtLink> <NuxtLink to="/about" :prefetch="false"> About page not pre-fetched </NuxtLink> ``` ### Custom Prefetch Triggers We now support custom prefetch triggers for `<NuxtLink>` after `v3.13.0`. You can use the `prefetchOn` prop to control when to prefetch links. ```vue <template> <NuxtLink prefetch-on="visibility"> This will prefetch when it becomes visible (default) </NuxtLink> <NuxtLink prefetch-on="interaction"> This will prefetch when hovered or when it gains focus </NuxtLink> </template> ``` - `visibility`: Prefetches when the link becomes visible in the viewport. Monitors the element's intersection with the viewport using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Prefetching is triggered when the element is scrolled into view. - `interaction`: Prefetches when the link is hovered or focused. This approach listens for `pointerenter` and `focus` events, proactively prefetching resources when the user indicates intent to interact. You can also use an object to configure `prefetchOn`: ```vue <template> <NuxtLink :prefetch-on="{ interaction: true }"> This will prefetch when hovered or when it gains focus </NuxtLink> </template> ``` That you probably don't want both enabled! ```vue <template> <NuxtLink :prefetch-on="{ visibility: true, interaction: true }"> This will prefetch when hovered/focus - or when it becomes visible </NuxtLink> </template> ``` This configuration will observe when the element enters the viewport and also listen for `pointerenter` and `focus` events. This may result in unnecessary resource usage or redundant prefetching, as both triggers can prefetch the same resource under different conditions. ### Enable Cross-origin Prefetch To enable cross-origin prefetching, you can set the `crossOriginPrefetch` option in your `nuxt.config`. This will enable cross-origin prefetching using the [Speculation Rules API](https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API). ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { crossOriginPrefetch: true, }, }) ``` ### Disable prefetch globally It's also possible to enable/disable prefetching all links globally for your app. ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { prefetch: false, }, }, }, }) ``` ## Props ### RouterLink When not using `external`, `<NuxtLink>` supports all Vue Router's [`RouterLink` props](https://router.vuejs.org/api/interfaces/routerlinkprops) - `to`: Any URL or a [route location object](https://router.vuejs.org/api/type-aliases/routelocation) from Vue Router - `custom`: Whether `<NuxtLink>` should wrap its content in an `<a>` element. It allows taking full control of how a link is rendered and how navigation works when it is clicked. Works the same as [Vue Router's `custom` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#custom-) - `exactActiveClass`: A class to apply on exact active links. Works the same as [Vue Router's `exactActiveClass` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#exactActiveClass-) on internal links. Defaults to Vue Router's default (`"router-link-exact-active"`) - `activeClass`: A class to apply on active links. Works the same as [Vue Router's `activeClass` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#activeClass-) on internal links. Defaults to Vue Router's default (`"router-link-active"`) - `replace`: Works the same as [Vue Router's `replace` prop](https://router.vuejs.org/api/interfaces/routelocationoptions#replace-) on internal links - `ariaCurrentValue`: An `aria-current` attribute value to apply on exact active links. Works the same as [Vue Router's `ariaCurrentValue` prop](https://router.vuejs.org/api/interfaces/routerlinkprops#ariaCurrentValue-) on internal links ### NuxtLink - `href`: An alias for `to`. If used with `to`, `href` will be ignored - `noRel`: If set to `true`, no `rel` attribute will be added to the external link - `external`: Forces the link to be rendered as an `<a>` tag instead of a Vue Router `RouterLink`. - `prefetch`: When enabled will prefetch middleware, layouts and payloads (when using [payloadExtraction](https://nuxt.com/docs/3.x/guide/going-further/experimental-features#payloadextraction)) of links in the viewport. Used by the experimental [crossOriginPrefetch](https://nuxt.com/docs/3.x/guide/going-further/experimental-features#crossoriginprefetch) config. - `prefetchOn`: Allows custom control of when to prefetch links. Possible options are `interaction` and `visibility` (default). You can also pass an object for full control, for example: `{ interaction: true, visibility: true }`. This prop is only used when `prefetch` is enabled (default) and `noPrefetch` is not set. - `noPrefetch`: Disables prefetching. - `prefetchedClass`: A class to apply to links that have been prefetched. ### Anchor - `target`: A `target` attribute value to apply on the link - `rel`: A `rel` attribute value to apply on the link. Defaults to `"noopener noreferrer"` for external links. <tip> Defaults can be overwritten, see [overwriting defaults](https://nuxt.com/docs/3.x/api/components/nuxt-link#overwriting-defaults) if you want to change them. </tip> ## Overwriting Defaults ### In Nuxt Config You can overwrite some `<NuxtLink>` defaults in your [`nuxt.config`](https://nuxt.com/docs/3.x/guide/going-further/experimental-features#defaults) <important> These options will likely be moved elsewhere in the future, such as into `app.config` or into the `app/` directory. </important> ```ts [nuxt.config.ts] export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { // default values componentName: 'NuxtLink', externalRelAttribute: 'noopener noreferrer', activeClass: 'router-link-active', exactActiveClass: 'router-link-exact-active', prefetchedClass: undefined, // can be any valid string class name trailingSlash: undefined, // can be 'append' or 'remove' prefetch: true, prefetchOn: { visibility: true }, }, }, }, }) ``` ### Custom Link Component You can overwrite `<NuxtLink>` defaults by creating your own link component using `defineNuxtLink`. ```ts [components/MyNuxtLink.ts] export default defineNuxtLink({ componentName: 'MyNuxtLink', /* see signature below for more */ }) ``` You can then use `<MyNuxtLink />` component as usual with your new defaults. ### `defineNuxtLink` Signature ```ts interface NuxtLinkOptions { componentName?: string externalRelAttribute?: string activeClass?: string exactActiveClass?: string trailingSlash?: 'append' | 'remove' prefetch?: boolean prefetchedClass?: string prefetchOn?: Partial<{ visibility: boolean interaction: boolean }> } function defineNuxtLink (options: NuxtLinkOptions): Component {} ``` - `componentName`: A name for the component. Default is `NuxtLink`. - `externalRelAttribute`: A default `rel` attribute value applied on external links. Defaults to `"noopener noreferrer"`. Set it to `""` to disable - `activeClass`: A default class to apply on active links. Works the same as [Vue Router's `linkActiveClass` option](https://router.vuejs.org/api/interfaces/routeroptions#linkActiveClass-). Defaults to Vue Router's default (`"router-link-active"`) - `exactActiveClass`: A default class to apply on exact active links. Works the same as [Vue Router's `linkExactActiveClass` option](https://router.vuejs.org/api/interfaces/routeroptions#linkExactActiveClass-). Defaults to Vue Router's default (`"router-link-exact-active"`) - `trailingSlash`: An option to either add or remove trailing slashes in the `href`. If unset or not matching the valid values `append` or `remove`, it will be ignored. - `prefetch`: Whether or not to prefetch links by default. - `prefetchOn`: Granular control of which prefetch strategies to apply by default. - `prefetchedClass`: A default class to apply to links that have been prefetched. <link-example to="https://nuxt.com/docs/3.x/examples/routing/pages"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-link.ts) # <NuxtLoadingIndicator> > Display a progress bar between page navigations. ## Usage Add `<NuxtLoadingIndicator/>` in your [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app) or [`layouts/`](https://nuxt.com/docs/3.x/directory-structure/layouts). ```vue [app.vue] <template> <NuxtLoadingIndicator /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` <link-example to="https://nuxt.com/docs/3.x/examples/routing/pages"> </link-example> ## Slots You can pass custom HTML or components through the loading indicator's default slot. ## Props - `color`: The color of the loading bar. It can be set to `false` to turn off explicit color styling. - `errorColor`: The color of the loading bar when `error` is set to `true`. - `height`: Height of the loading bar, in pixels (default `3`). - `duration`: Duration of the loading bar, in milliseconds (default `2000`). - `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`). - `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100. <note> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts). </note> <note> You can hook into the underlying indicator instance using [the `useLoadingIndicator` composable](https://nuxt.com/docs/3.x/api/composables/use-loading-indicator), which will allow you to trigger start/finish events yourself. </note> <tip> The loading indicator's speed gradually decreases after reaching a specific point controlled by `estimatedProgress`. This adjustment provides a more accurate reflection of longer page loading times and prevents the indicator from prematurely showing 100% completion. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-loading-indicator.ts) # <NuxtPage> > The <NuxtPage> component is required to display pages located in the pages/ directory. `<NuxtPage>` is a built-in component that comes with Nuxt. It lets you display top-level or nested pages located in the [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory. <note> `<NuxtPage>` is a wrapper around [`<RouterView>`](https://router.vuejs.org/api/interfaces/routerviewprops) from Vue Router. It should be used instead of `<RouterView>` because the former takes additional care of internal states. Otherwise, `useRoute()` may return incorrect paths. </note> `<NuxtPage>` includes the following components: ```vue <template> <RouterView v-slot="{ Component }"> <!-- Optional, when using transitions --> <Transition> <!-- Optional, when using keep-alive --> <KeepAlive> <Suspense> <component :is="Component" /> </Suspense> </KeepAlive> </Transition> </RouterView> </template> ``` By default, Nuxt does not enable `<Transition>` and `<KeepAlive>`. You can enable them in the nuxt.config file or by setting the `transition` and `keepalive` properties on `<NuxtPage>`. If you want to define a specific page, you can set it in `definePageMeta` in the page component. <warning> If you enable `<Transition>` in your page component, ensure that the page has a single root element. </warning> Since `<NuxtPage>` uses `<Suspense>` under the hood, the component lifecycle behavior during page changes differs from that of a typical Vue application. In a typical Vue application, a new page component is mounted **only after** the previous one has been fully unmounted. However, in Nuxt, due to how Vue `<Suspense>` is implemented, the new page component is mounted **before** the previous one is unmounted. ## Props - `name`: tells `<RouterView>` to render the component with the corresponding name in the matched route record's components option. - type: `string` - `route`: route location that has all of its components resolved. - type: `RouteLocationNormalized` - `pageKey`: control when the `NuxtPage` component is re-rendered. - type: `string` or `function` - `transition`: define global transitions for all pages rendered with the `NuxtPage` component. - type: `boolean` or [`TransitionProps`](https://vuejs.org/api/built-in-components#transition) - `keepalive`: control state preservation of pages rendered with the `NuxtPage` component. - type: `boolean` or [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive) <tip> Nuxt automatically resolves the `name` and `route` by scanning and rendering all Vue component files found in the `/pages` directory. </tip> ## Example For example, if you pass a key that never changes, the `<NuxtPage>` component will be rendered only once - when it is first mounted. ```vue [app.vue] <template> <NuxtPage page-key="static" /> </template> ``` You can also use a dynamic key based on the current route: ```html <NuxtPage :page-key="route => route.fullPath" /> ``` <warning> Don't use `$route` object here as it can cause problems with how `<NuxtPage>` renders pages with `<Suspense>`. </warning> Alternatively, `pageKey` can be passed as a `key` value via [`definePageMeta`](https://nuxt.com/docs/3.x/api/utils/define-page-meta) from the `<script>` section of your Vue component in the `/pages` directory. ```vue [pages/my-page.vue] <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, }) </script> ``` <link-example to="https://nuxt.com/docs/3.x/examples/routing/pages"> </link-example> ## Page's Ref To get the `ref` of a page component, access it through `ref.value.pageRef` ```vue [app.vue] <script setup lang="ts"> const page = ref() function logFoo () { page.value.pageRef.foo() } </script> <template> <NuxtPage ref="page" /> </template> ``` ```vue [my-page.vue] <script setup lang="ts"> const foo = () => { console.log('foo method called') } defineExpose({ foo, }) </script> ``` ## Custom Props `<NuxtPage>` also accepts custom props that you may need to pass further down the hierarchy. For example, in the below example, the value of `foobar` will be passed to the `NuxtPage` component and then to the page components. ```vue [app.vue] <template> <NuxtPage :foobar="123" /> </template> ``` We can access the `foobar` prop in the page component: ```vue [pages/page.vue] <script setup lang="ts"> const props = defineProps<{ foobar: number }>() console.log(props.foobar) // Outputs: 123 ``` If you have not defined the prop with `defineProps`, any props passed down to `NuxtPage` can still be accessed directly from the page `attrs`: ```vue [pages/page.vue] <script setup lang="ts"> const attrs = useAttrs() console.log(attrs.foobar) // Outputs: 123 </script> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/pages"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/page.ts) # <NuxtPicture> > Nuxt provides a <NuxtPicture> component to handle automatic image optimization. `<NuxtPicture>` is a drop-in replacement for the native `<picture>` tag. Usage of `<NuxtPicture>` is almost identical to [`<NuxtImg>`](https://nuxt.com/docs/3.x/api/components/nuxt-img) but it also allows serving modern formats like `webp` when possible. Learn more about the [`<picture>` tag on MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/picture). ## Setup In order to use `<NuxtPicture>` you should install and enable the Nuxt Image module: ```bash [Terminal] npx nuxt module add image ``` <read-more target="_blank" to="https://image.nuxt.com/usage/nuxt-picture"> Read more about the `<NuxtPicture>` component. </read-more> --- - [Source](https://github.com/nuxt/image/blob/main/src/runtime/components/NuxtPicture.vue) # <NuxtRouteAnnouncer> > The <NuxtRouteAnnouncer> component adds a hidden element with the page title to announce route changes to assistive technologies. <important> This component is available in Nuxt v3.12+. </important> ## Usage Add `<NuxtRouteAnnouncer/>` in your [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app) or [`layouts/`](https://nuxt.com/docs/3.x/directory-structure/layouts) to enhance accessibility by informing assistive technologies about page title changes. This ensures that navigational changes are announced to users relying on screen readers. ```vue [app.vue] <template> <NuxtRouteAnnouncer /> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` ## Slots You can pass custom HTML or components through the route announcer's default slot. ```vue <template> <NuxtRouteAnnouncer> <template #default="{ message }"> <p>{{ message }} was loaded.</p> </template> </NuxtRouteAnnouncer> </template> ``` ## Props - `atomic`: Controls if screen readers only announce changes or the entire content. Set to true for full content readouts on updates, false for changes only. (default `false`) - `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`) <callout> This component is optional. <br /> To achieve full customization, you can implement your own one based on [its source code](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts). </callout> <callout> You can hook into the underlying announcer instance using [the `useRouteAnnouncer` composable](https://nuxt.com/docs/3.x/api/composables/use-route-announcer), which allows you to set a custom announcement message. </callout> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-route-announcer.ts) # <NuxtTime> > The <NuxtTime> component displays time in a locale-friendly format with server-client consistency. <important> This component is available in Nuxt v3.17+. </important> The `<NuxtTime>` component lets you display dates and times in a locale-friendly format with proper `<time>` HTML semantics. It ensures consistent rendering between server and client without hydration mismatches. ## Usage You can use the `<NuxtTime>` component anywhere in your app: ```vue <template> <NuxtTime :datetime="Date.now()" /> </template> ``` ## Props ### `datetime` - Type: `Date | number | string` - Required: `true` The date and time value to display. You can provide: - A `Date` object - A timestamp (number) - An ISO-formatted date string ```vue <template> <NuxtTime :datetime="Date.now()" /> <NuxtTime :datetime="new Date()" /> <NuxtTime datetime="2023-06-15T09:30:00.000Z" /> </template> ``` ### `locale` - Type: `string` - Required: `false` - Default: Uses the browser or server's default locale The [BCP 47 language tag](https://datatracker.ietf.org/doc/html/rfc5646) for formatting (e.g., 'en-US', 'fr-FR', 'ja-JP'): ```vue <template> <NuxtTime :datetime="Date.now()" locale="fr-FR" /> </template> ``` ### Formatting Props The component accepts any property from the [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat) options: ```vue <template> <NuxtTime :datetime="Date.now()" year="numeric" month="long" day="numeric" hour="2-digit" minute="2-digit" /> </template> ``` This would output something like: "April 22, 2025, 08:30 AM" ### `relative` - Type: `boolean` - Required: `false` - Default: `false` Enables relative time formatting using the Intl.RelativeTimeFormat API: ```vue <template> <!-- Shows something like "5 minutes ago" --> <NuxtTime :datetime="Date.now() - 5 * 60 * 1000" relative /> </template> ``` ### Relative Time Formatting Props When `relative` is set to `true`, the component also accepts properties from [Intl.RelativeTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat): <warning> Due to `style` being a reserved prop, `relativeStyle` prop is used instead. </warning> ```vue <template> <NuxtTime :datetime="Date.now() - 3 * 24 * 60 * 60 * 1000" relative numeric="auto" relative-style="long" /> </template> ``` This would output something like: "3 days ago" or "last Friday" depending on the `numeric` setting. ## Examples ### Basic Usage ```vue <template> <NuxtTime :datetime="Date.now()" /> </template> ``` ### Custom Formatting ```vue <template> <NuxtTime :datetime="Date.now()" weekday="long" year="numeric" month="short" day="numeric" hour="numeric" minute="numeric" second="numeric" time-zone-name="short" /> </template> ``` ### Relative Time ```vue <template> <div> <p> <NuxtTime :datetime="Date.now() - 30 * 1000" relative /> <!-- 30 seconds ago --> </p> <p> <NuxtTime :datetime="Date.now() - 45 * 60 * 1000" relative /> <!-- 45 minutes ago --> </p> <p> <NuxtTime :datetime="Date.now() + 2 * 24 * 60 * 60 * 1000" relative /> <!-- in 2 days --> </p> </div> </template> ``` ### With Custom Locale ```vue <template> <div> <NuxtTime :datetime="Date.now()" locale="en-US" weekday="long" /> <NuxtTime :datetime="Date.now()" locale="fr-FR" weekday="long" /> <NuxtTime :datetime="Date.now()" locale="ja-JP" weekday="long" /> </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/nuxt-time.vue) # <NuxtWelcome> > The <NuxtWelcome> component greets users in new projects made from the starter template. It includes links to the Nuxt documentation, source code, and social media accounts. ```vue [app.vue] <template> <NuxtWelcome /> </template> ``` <read-more target="_blank" to="https://templates.ui.nuxtjs.org/templates/welcome"> Preview the `<NuxtWelcome />` component. </read-more> <tip> This component is part of [`@nuxt/ui-templates`](https://github.com/nuxt/nuxt/tree/main/packages/ui-templates) package. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/ui-templates/templates/welcome/index.html) # <Teleport> > The <Teleport> component teleports a component to a different location in the DOM. <warning> The `to` target of [`<Teleport>`](https://vuejs.org/guide/built-ins/teleport) expects a CSS selector string or an actual DOM node. Nuxt currently has SSR support for teleports to `#teleports` only, with client-side support for other targets using a `<ClientOnly>` wrapper. </warning> ## Body Teleport ```vue <template> <button @click="open = true"> Open Modal </button> <Teleport to="#teleports"> <div v-if="open" class="modal" > <p>Hello from the modal!</p> <button @click="open = false"> Close </button> </div> </Teleport> </template> ``` ## Client-side Teleport ```vue <template> <ClientOnly> <Teleport to="#some-selector"> <!-- content --> </Teleport> </ClientOnly> </template> ``` <link-example to="https://nuxt.com/docs/3.x/examples/advanced/teleport"> </link-example> # onPrehydrate > Use onPrehydrate to run a callback on the client immediately before Nuxt hydrates the page. <important> This composable is available in Nuxt v3.12+. </important> `onPrehydrate` is a composable lifecycle hook that allows you to run a callback on the client immediately before Nuxt hydrates the page. <note> This is an advanced utility and should be used with care. For example, [`nuxt-time`](https://github.com/danielroe/nuxt-time/pull/251) and [`@nuxtjs/color-mode`](https://github.com/nuxt-modules/color-mode/blob/main/src/script.js) manipulate the DOM to avoid hydration mismatches. </note> ## Usage Call `onPrehydrate` in the setup function of a Vue component (e.g., in `<script setup>`) or in a plugin. It only has an effect when called on the server and will not be included in your client build. ## Type ```ts [Signature] export function onPrehydrate (callback: (el: HTMLElement) => void): void export function onPrehydrate (callback: string | ((el: HTMLElement) => void), key?: string): undefined | string ``` ## Parameters <table> <thead> <tr> <th> Parameter </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> callback </code> </td> <td> <code> ((el: HTMLElement) => void) | string </code> </td> <td> Yes </td> <td> A function (or stringified function) to run before Nuxt hydrates. It will be stringified and inlined in the HTML. Should not have external dependencies or reference variables outside the callback. Runs before Nuxt runtime initializes, so it should not rely on Nuxt or Vue context. </td> </tr> <tr> <td> <code> key </code> </td> <td> <code> string </code> </td> <td> No </td> <td> (Advanced) A unique key to identify the prehydrate script, useful for advanced scenarios like multiple root nodes. </td> </tr> </tbody> </table> ## Return Values - Returns `undefined` when called with only a callback function. - Returns a string (the prehydrate id) when called with a callback and a key, which can be used to set or access the `data-prehydrate-id` attribute for advanced use cases. ## Example ```vue [app.vue]twoslash <script setup lang="ts"> declare const window: Window // ---cut--- // Run code before Nuxt hydrates onPrehydrate(() => { console.log(window) }) // Access the root element onPrehydrate((el) => { console.log(el.outerHTML) // <div data-v-inspector="app.vue:15:3" data-prehydrate-id=":b3qlvSiBeH:"> Hi there </div> }) // Advanced: access/set `data-prehydrate-id` yourself const prehydrateId = onPrehydrate((el) => {}) </script> <template> <div> Hi there </div> </template> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useAppConfig > Access the reactive app config defined in the project. ## Usage ```ts const appConfig = useAppConfig() console.log(appConfig) ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/app-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/config.ts) # useAsyncData > useAsyncData provides access to data that resolves asynchronously in an SSR-friendly composable. Within your pages, components, and plugins you can use useAsyncData to get access to data that resolves asynchronously. <note> [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) is a composable meant to be called directly in the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context). It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client **without re-fetching the data on client side** when the page hydrates. </note> ## Usage ```vue [pages/index.vue] <script setup lang="ts"> const { data, status, pending, error, refresh, clear } = await useAsyncData( 'mountains', (_nuxtApp, { signal }) => $fetch('https://api.nuxtjs.dev/mountains', { signal }), ) </script> ``` <warning to="https://nuxt.com/docs/3.x/guide/recipes/custom-usefetch#custom-usefetchuseasyncdata"> If you're using a custom `useAsyncData` wrapper, do not await it in the composable as that can cause unexpected behavior. See recipe for custom async data fetcher. </warning> <note> `data`, `status`, `pending` and `error` are Vue refs and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions. </note> ### Watch Params The built-in `watch` option allows automatically rerunning the fetcher function when any changes are detected. ```vue [pages/index.vue] <script setup lang="ts"> const page = ref(1) const { data: posts } = await useAsyncData( 'posts', (_nuxtApp, { signal }) => $fetch('https://fakeApi.com/posts', { params: { page: page.value, }, signal, }), { watch: [page], }, ) </script> ``` ### Reactive Keys You can use a computed ref, plain ref or a getter function as the key, allowing for dynamic data fetching that automatically updates when the key changes: ```vue [pages/[id].vue] <script setup lang="ts"> const route = useRoute() const userId = computed(() => `user-${route.params.id}`) // When the route changes and userId updates, the data will be automatically refetched const { data: user } = useAsyncData( userId, () => fetchUserById(route.params.id), ) </script> ``` ### Make your `handler` abortable You can make your `handler` function abortable by using the `signal` provided in the second argument. This is useful for cancelling requests when they are no longer needed, such as when a user navigates away from a page. `$fetch` natively supports abort signals. ```ts const { data, error } = await useAsyncData( 'users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), ) refresh() // will actually cancel the $fetch request (if dedupe: cancel) refresh() // will actually cancel the $fetch request (if dedupe: cancel) refresh() clear() // will cancel the latest pending handler ``` You can also pass an `AbortSignal` to the `refresh`/`execute` function to cancel individual requests manually. ```ts const { refresh } = await useAsyncData( 'users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), ) let abortController: AbortController | undefined function handleUserAction () { abortController = new AbortController() refresh({ signal: abortController.signal }) } function handleCancel () { abortController?.abort() // aborts the ongoing refresh request } ``` If your `handler` function does not support abort signals, you can implement your own abort logic using the `signal` provided. ```ts const { data, error } = await useAsyncData( 'users', (_nuxtApp, { signal }) => { return new Promise((resolve, reject) => { signal?.addEventListener('abort', () => { reject(new Error('Request aborted')) }) return Promise.resolve(callback.call(this, yourHandler)).then(resolve, reject) }) }, ) ``` The handler signal will be aborted when: - A new request is made with `dedupe: 'cancel'` - The `clear` function is called - The `options.timeout` duration is exceeded <warning> [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) is a reserved function name transformed by the compiler, so you should not name your own function [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data). </warning> <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching#useasyncdata"> </read-more> ## Params - `key`: a unique key to ensure that data fetching can be properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you. - `handler`: an asynchronous function that must return a truthy value (for example, it should not be `undefined` or `null`) or the request may be duplicated on the client side. <warning> The `handler` function should be **side-effect free** to ensure predictable behavior during SSR and CSR hydration. If you need to trigger side effects, use the [`callOnce`](https://nuxt.com/docs/3.x/api/utils/call-once) utility to do so. </warning> - `options`: - `server`: whether to fetch the data on the server (defaults to `true`) - `lazy`: whether to resolve the async function after loading the route, instead of blocking client-side navigation (defaults to `false`) - `immediate`: when set to `false`, will prevent the request from firing immediately. (defaults to `true`) - `default`: a factory function to set the default value of the `data`, before the async function resolves - useful with the `lazy: true` or `immediate: false` option - `transform`: a function that can be used to alter `handler` function result after resolving - `getCachedData`: Provide a function which returns cached data. An `undefined` return value will trigger a fetch. By default, this is: ```ts const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key] ``` Which only caches data when `experimental.payloadExtraction` of `nuxt.config` is enabled. - `pick`: only pick specified keys in this array from the `handler` function result - `watch`: watch reactive sources to auto-refresh - `deep`: return data in a deep ref object (it is `true` by default). It can be set to `false` to return data in a shallow ref object, which can improve performance if your data does not need to be deeply reactive. - `dedupe`: avoid fetching same key more than once at a time (defaults to `cancel`). Possible options: - `cancel` - cancels existing requests when a new one is made - `defer` - does not make new requests at all if there is a pending request - `timeout` - a number in milliseconds to wait before timing out the request (defaults to `undefined`, which means no timeout) <note> Under the hood, `lazy: false` uses `<Suspense>` to block the loading of the route before the data has been fetched. Consider using `lazy: true` and implementing a loading state instead for a snappier user experience. </note> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-lazy-async-data"> You can use `useLazyAsyncData` to have the same behavior as `lazy: true` with `useAsyncData`. </read-more> <video-accordion title="Watch a video from Alexander Lichter about client-side caching with getCachedData" video-id="aQPR0xn-MMk"> </video-accordion> ### Shared State and Option Consistency When using the same key for multiple `useAsyncData` calls, they will share the same `data`, `error`, `status` and `pending` refs. This ensures consistency across components but requires option consistency. The following options **must be consistent** across all calls with the same key: - `handler` function - `deep` option - `transform` function - `pick` array - `getCachedData` function - `default` value The following options **can differ** without triggering warnings: - `server` - `lazy` - `immediate` - `dedupe` - `watch` ```ts // โŒ This will trigger a development warning const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true }) // โœ… This is allowed const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false }) ``` <tip> Keyed state created using `useAsyncData` can be retrieved across your Nuxt application using [`useNuxtData`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-data). </tip> ## Return Values - `data`: the result of the asynchronous function that is passed in. - `refresh`/`execute`: a function that can be used to refresh the data returned by the `handler` function. - `error`: an error object if the data fetching failed. - `status`: a string indicating the status of the data request: - `idle`: when the request has not started, such as: - when `execute` has not yet been called and `{ immediate: false }` is set - when rendering HTML on the server and `{ server: false }` is set - `pending`: the request is in progress - `success`: the request has completed successfully - `error`: the request has failed - `pending`: a `Ref<boolean>` that is `true` while the request is in progress. - `clear`: a function that can be used to set `data` to `undefined` (or the value of `options.default()` if provided), set `error` to `null`, set `status` to `idle`, and mark any currently pending requests as cancelled. By default, Nuxt waits until a `refresh` is finished before it can be executed again. <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) on the client side, `data` will remain `undefined` within `<script setup>`. </note> ## Type ```ts [Signature] export type AsyncDataHandler<ResT> = (nuxtApp: NuxtApp, options: { signal: AbortSignal }) => Promise<ResT> export function useAsyncData<DataT, DataE> ( handler: AsyncDataHandler<DataT>, options?: AsyncDataOptions<DataT>, ): AsyncData<DataT, DataE> export function useAsyncData<DataT, DataE> ( key: MaybeRefOrGetter<string>, handler: AsyncDataHandler<DataT>, options?: AsyncDataOptions<DataT>, ): Promise<AsyncData<DataT, DataE>> type AsyncDataOptions<DataT> = { server?: boolean lazy?: boolean immediate?: boolean deep?: boolean dedupe?: 'cancel' | 'defer' default?: () => DataT | Ref<DataT> | null transform?: (input: DataT) => DataT | Promise<DataT> pick?: string[] watch?: MultiWatchSources | false getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined timeout?: number } type AsyncDataRequestContext = { /** The reason for this data request */ cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch' } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | null> refresh: (opts?: AsyncDataExecuteOptions) => Promise<void> execute: (opts?: AsyncDataExecuteOptions) => Promise<void> clear: () => void error: Ref<ErrorT | null> status: Ref<AsyncDataRequestStatus> pending: Ref<boolean> } interface AsyncDataExecuteOptions { dedupe?: 'cancel' | 'defer' timeout?: number signal?: AbortSignal } type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # useCookie > useCookie is an SSR-friendly composable to read and write cookies. ## Usage Within your pages, components, and plugins, you can use `useCookie` to read and write cookies in an SSR-friendly way. ```ts const cookie = useCookie(name, options) ``` <note> `useCookie` only works in the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context). </note> <tip> The returned ref will automatically serialize and deserialize cookie values to JSON. </tip> ## Type ```ts [Signature] import type { Ref } from 'vue' import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es' export interface CookieOptions<T = any> extends Omit<CookieSerializeOptions & CookieParseOptions, 'decode' | 'encode'> { decode?(value: string): T encode?(value: T): string default?: () => T | Ref<T> watch?: boolean | 'shallow' readonly?: boolean } export interface CookieRef<T> extends Ref<T> {} export function useCookie<T = string | null | undefined> ( name: string, options?: CookieOptions<T>, ): CookieRef<T> ``` ## Parameters `name`: The name of the cookie. `options`: Options to control cookie behavior. The object can have the following properties: Most of the options will be directly passed to the [cookie](https://github.com/jshttp/cookie) package. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> decode </code> </td> <td> <code> (value: string) => T </code> </td> <td> <code> decodeURIComponent </code> + <a href="https://github.com/unjs/destr" rel="nofollow"> destr </a> . </td> <td> Custom function to decode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to decode a previously encoded cookie value into a JavaScript string or other object. <br /> <strong> Note: </strong> If an error is thrown from this function, the original, non-decoded cookie value will be returned as the cookie's value. </td> </tr> <tr> <td> <code> encode </code> </td> <td> <code> (value: T) => string </code> </td> <td> <code> JSON.stringify </code> + <code> encodeURIComponent </code> </td> <td> Custom function to encode the cookie value. Since the value of a cookie has a limited character set (and must be a simple string), this function can be used to encode a value into a string suited for a cookie's value. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => T | Ref<T> </code> </td> <td> <code> undefined </code> </td> <td> Function returning the default value if the cookie does not exist. The function can also return a <code> Ref </code> . </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> boolean | 'shallow' </code> </td> <td> <code> true </code> </td> <td> Whether to watch for changes and update the cookie. <code> true </code> for deep watch, <code> 'shallow' </code> for shallow watch, i.e. data changes for only top level properties, <code> false </code> to disable. <br /> <strong> Note: </strong> Refresh <code> useCookie </code> values manually when a cookie has changed with <a href="https://nuxt.com/docs/3.x/api/utils/refresh-cookie"> <code> refreshCookie </code> </a> . </td> </tr> <tr> <td> <code> readonly </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , disables writing to the cookie. </td> </tr> <tr> <td> <code> maxAge </code> </td> <td> <code> number </code> </td> <td> <code> undefined </code> </td> <td> Max age in seconds for the cookie, i.e. the value for the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.2" rel="nofollow"> <code> Max-Age </code> <code> Set-Cookie </code> attribute </a> . The given number will be converted to an integer by rounding down. By default, no maximum age is set. </td> </tr> <tr> <td> <code> expires </code> </td> <td> <code> Date </code> </td> <td> <code> undefined </code> </td> <td> Expiration date for the cookie. By default, no expiration is set. Most clients will consider this a "non-persistent cookie" and will delete it on a condition like exiting a web browser application. <br /> <strong> Note: </strong> The <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.3" rel="nofollow"> cookie storage model specification </a> states that if both <code> expires </code> and <code> maxAge </code> is set, then <code> maxAge </code> takes precedence, but not all clients may obey this, so if both are set, they should point to the same date and time! <br /> If neither of <code> expires </code> and <code> maxAge </code> is set, the cookie will be session-only and removed when the user closes their browser. </td> </tr> <tr> <td> <code> httpOnly </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the HttpOnly attribute. <br /> <strong> Note: </strong> Be careful when setting this to <code> true </code> , as compliant clients will not allow client-side JavaScript to see the cookie in <code> document.cookie </code> . </td> </tr> <tr> <td> <code> secure </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.5" rel="nofollow"> <code> Secure </code> <code> Set-Cookie </code> attribute </a> . <br /> <strong> Note: </strong> Be careful when setting this to <code> true </code> , as compliant clients will not send the cookie back to the server in the future if the browser does not have an HTTPS connection. This can lead to hydration errors. </td> </tr> <tr> <td> <code> partitioned </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/draft-cutler-httpbis-partitioned-cookies#section-2.1" rel="nofollow"> <code> Partitioned </code> <code> Set-Cookie </code> attribute </a> . <br /> <strong> Note: </strong> This is an attribute that has not yet been fully standardized, and may change in the future. <br /> This also means many clients may ignore this attribute until they understand it.<br /> More information can be found in the <a href="https://github.com/privacycg/CHIPS" rel="nofollow"> proposal </a> . </td> </tr> <tr> <td> <code> domain </code> </td> <td> <code> string </code> </td> <td> <code> undefined </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.3" rel="nofollow"> <code> Domain </code> <code> Set-Cookie </code> attribute </a> . By default, no domain is set, and most clients will consider applying the cookie only to the current domain. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> '/' </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.2.4" rel="nofollow"> <code> Path </code> <code> Set-Cookie </code> attribute </a> . By default, the path is considered the <a href="https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.4" rel="nofollow"> "default path" </a> . </td> </tr> <tr> <td> <code> sameSite </code> </td> <td> <code> boolean | string </code> </td> <td> <code> undefined </code> </td> <td> Sets the <a href="https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.2.7" rel="nofollow"> <code> SameSite </code> <code> Set-Cookie </code> attribute </a> . <br /> - <code> true </code> will set the <code> SameSite </code> attribute to <code> Strict </code> for strict same-site enforcement.<br /> - <code> false </code> will not set the <code> SameSite </code> attribute.<br /> - <code> 'lax' </code> will set the <code> SameSite </code> attribute to <code> Lax </code> for lax same-site enforcement.<br /> - <code> 'none' </code> will set the <code> SameSite </code> attribute to <code> None </code> for an explicit cross-site cookie.<br /> - <code> 'strict' </code> will set the <code> SameSite </code> attribute to <code> Strict </code> for strict same-site enforcement. </td> </tr> </tbody> </table> ## Return Values Returns a Vue `Ref<T>` representing the cookie value. Updating the ref will update the cookie (unless `readonly` is set). The ref is SSR-friendly and will work on both client and server. ## Examples ### Basic Usage The example below creates a cookie called `counter`. If the cookie doesn't exist, it is initially set to a random value. Whenever we update the `counter` variable, the cookie will be updated accordingly. ```vue [app.vue] <script setup lang="ts"> const counter = useCookie('counter') counter.value ||= Math.round(Math.random() * 1000) </script> <template> <div> <h1>Counter: {{ counter || '-' }}</h1> <button @click="counter = null"> reset </button> <button @click="counter--"> - </button> <button @click="counter++"> + </button> </div> </template> ``` ### Readonly Cookies ```vue <script setup lang="ts"> const user = useCookie( 'userInfo', { default: () => ({ score: -1 }), watch: false, }, ) if (user.value) { // the actual `userInfo` cookie will not be updated user.value.score++ } </script> <template> <div>User score: {{ user?.score }}</div> </template> ``` ### Writable Cookies ```vue <script setup lang="ts"> const list = useCookie( 'list', { default: () => [], watch: 'shallow', }, ) function add () { list.value?.push(Math.round(Math.random() * 1000)) // list cookie won't be updated with this change } function save () { // the actual `list` cookie will be updated list.value &&= [...list.value] } </script> <template> <div> <h1>List</h1> <pre>{{ list }}</pre> <button @click="add"> Add </button> <button @click="save"> Save </button> </div> </template> ``` ### Cookies in API Routes You can use `getCookie` and `setCookie` from [`h3`](https://github.com/h3js/h3) package to set cookies in server API routes. ```ts [server/api/counter.ts] export default defineEventHandler((event) => { // Read counter cookie let counter = getCookie(event, 'counter') || 0 // Increase counter cookie by 1 setCookie(event, 'counter', ++counter) // Send JSON response return { counter } }) ``` <link-example to="https://nuxt.com/docs/3.x/examples/advanced/use-cookie"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts) # useError > useError composable returns the global Nuxt error that is being handled. ## Usage The `useError` composable returns the global Nuxt error that is being handled and is available on both client and server. It provides a reactive, SSR-friendly error state across your app. ```ts const error = useError() ``` You can use this composable in your components, pages, or plugins to access or react to the current Nuxt error. ## Type ```ts interface NuxtError<DataT = unknown> { status: number statusText: string message: string data?: DataT error?: true } export const useError: () => Ref<NuxtError | undefined> ``` ## Parameters This composable does not take any parameters. ## Return Values Returns a `Ref` containing the current Nuxt error (or `undefined` if there is no error). The error object is reactive and will update automatically when the error state changes. ## Example ```vue <script setup lang="ts"> const error = useError() if (error.value) { console.error('Nuxt error:', error.value) } </script> ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # useFetch > Fetch data from an API endpoint with an SSR-friendly composable. This composable provides a convenient wrapper around [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) and [`$fetch`](https://nuxt.com/docs/3.x/api/utils/dollarfetch). It automatically generates a key based on URL and fetch options, provides type hints for request url based on server routes, and infers API response type. <note> `useFetch` is a composable meant to be called directly in a setup function, plugin, or route middleware. It returns reactive composables and handles adding responses to the Nuxt payload so they can be passed from server to client without re-fetching the data on client side when the page hydrates. </note> ## Usage ```vue [pages/modules.vue] <script setup lang="ts"> const { data, status, error, refresh, clear } = await useFetch('/api/modules', { pick: ['title'], }) </script> ``` <warning to="https://nuxt.com/docs/3.x/guide/recipes/custom-usefetch#custom-usefetchuseasyncdata"> If you're using a custom `useFetch` wrapper, do not await it in the composable as that can cause unexpected behavior. See recipe for custom async data fetcher. </warning> <note> `data`, `status`, and `error` are Vue refs, and they should be accessed with `.value` when used within the `<script setup>`, while `refresh`/`execute` and `clear` are plain functions. </note> Using the `query` option, you can add search parameters to your query. This option is extended from [unjs/ofetch](https://github.com/unjs/ofetch) and is using [unjs/ufo](https://github.com/unjs/ufo) to create the URL. Objects are automatically stringified. ```ts const param1 = ref('value1') const { data, status, error, refresh } = await useFetch('/api/modules', { query: { param1, param2: 'value2' }, }) ``` The above example results in `https://api.nuxt.com/modules?param1=value1¶m2=value2`. You can also use [interceptors](https://github.com/unjs/ofetch#%EF%B8%8F-interceptors): ```ts const { data, status, error, refresh, clear } = await useFetch('/api/auth/login', { onRequest ({ request, options }) { // Set the request headers // note that this relies on ofetch >= 1.4.0 - you may need to refresh your lockfile options.headers.set('Authorization', '...') }, onRequestError ({ request, options, error }) { // Handle the request errors }, onResponse ({ request, response, options }) { // Process the response data localStorage.setItem('token', response._data.token) }, onResponseError ({ request, response, options }) { // Handle the response errors }, }) ``` ### Reactive Keys and Shared State You can use a computed ref or a plain ref as the URL, allowing for dynamic data fetching that automatically updates when the URL changes: ```vue [pages/[id].vue] <script setup lang="ts"> const route = useRoute() const id = computed(() => route.params.id) // When the route changes and id updates, the data will be automatically refetched const { data: post } = await useFetch(() => `/api/posts/${id.value}`) </script> ``` When using `useFetch` with the same URL and options in multiple components, they will share the same `data`, `error` and `status` refs. This ensures consistency across components. <tip> Keyed state created using `useFetch` can be retrieved across your Nuxt application using [`useNuxtData`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-data). </tip> <warning> `useFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useFetch`. </warning> <warning> If you encounter the `data` variable destructured from a `useFetch` returns a string and not a JSON parsed object then make sure your component doesn't include an import statement like `import { useFetch } from '@vueuse/core`. </warning> <video-accordion title="Watch the video from Alexander Lichter to avoid using useFetch the wrong way" video-id="njsGVmcWviY"> </video-accordion> <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> ### Reactive Fetch Options Fetch options can be provided as reactive, supporting `computed`, `ref` and [computed getters](https://vuejs.org/guide/essentials/computed). When a reactive fetch option is updated it will trigger a refetch using the updated resolved reactive value. ```ts const searchQuery = ref('initial') const { data } = await useFetch('/api/search', { query: { q: searchQuery }, }) // triggers a refetch: /api/search?q=new%20search searchQuery.value = 'new search' ``` If needed, you can opt out of this behavior using `watch: false`: ```ts const searchQuery = ref('initial') const { data } = await useFetch('/api/search', { query: { q: searchQuery }, watch: false, }) // does not trigger a refetch searchQuery.value = 'new search' ``` ## Type ```ts [Signature] export function useFetch<DataT, ErrorT> ( url: string | Request | Ref<string | Request> | (() => string | Request), options?: UseFetchOptions<DataT>, ): Promise<AsyncData<DataT, ErrorT>> type UseFetchOptions<DataT> = { key?: MaybeRefOrGetter<string> method?: MaybeRefOrGetter<string> query?: MaybeRefOrGetter<SearchParams> params?: MaybeRefOrGetter<SearchParams> body?: MaybeRefOrGetter<RequestInit['body'] | Record<string, any>> headers?: MaybeRefOrGetter<Record<string, string> | [key: string, value: string][] | Headers> baseURL?: MaybeRefOrGetter<string> cache?: false | 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload' server?: boolean lazy?: boolean immediate?: boolean getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined deep?: boolean dedupe?: 'cancel' | 'defer' timeout?: number default?: () => DataT transform?: (input: DataT) => DataT | Promise<DataT> pick?: string[] $fetch?: typeof globalThis.$fetch watch?: MultiWatchSources | false timeout?: MaybeRefOrGetter<number> } type AsyncDataRequestContext = { /** The reason for this data request */ cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch' } type AsyncData<DataT, ErrorT> = { data: Ref<DataT | null> pending: Ref<boolean> refresh: (opts?: AsyncDataExecuteOptions) => Promise<void> execute: (opts?: AsyncDataExecuteOptions) => Promise<void> clear: () => void error: Ref<ErrorT | null> status: Ref<AsyncDataRequestStatus> } interface AsyncDataExecuteOptions { dedupe?: 'cancel' | 'defer' timeout?: number signal?: AbortSignal } type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error' ``` ## Parameters - `URL` (`string | Request | Ref<string | Request> | () => string | Request`): The URL or request to fetch. Can be a string, a Request object, a Vue ref, or a function returning a string/Request. Supports reactivity for dynamic endpoints. - `options` (object): Configuration for the fetch request. Extends [unjs/ofetch](https://github.com/unjs/ofetch) options and [`AsyncDataOptions`](https://nuxt.com/docs/3.x/api/composables/use-async-data#params). All options can be a static value, a `ref`, or a computed value. <table> <thead> <tr> <th> Option </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> key </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> auto-gen </td> <td> Unique key for de-duplication. If not provided, generated from URL and options. </td> </tr> <tr> <td> <code> method </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> <code> 'GET' </code> </td> <td> HTTP request method. </td> </tr> <tr> <td> <code> query </code> </td> <td> <code> MaybeRefOrGetter<SearchParams> </code> </td> <td> - </td> <td> Query/search params to append to the URL. Alias: <code> params </code> . </td> </tr> <tr> <td> <code> params </code> </td> <td> <code> MaybeRefOrGetter<SearchParams> </code> </td> <td> - </td> <td> Alias for <code> query </code> . </td> </tr> <tr> <td> <code> body </code> </td> <td> <code> MaybeRefOrGetter<RequestInit['body'] | Record<string, any>> </code> </td> <td> - </td> <td> Request body. Objects are automatically stringified. </td> </tr> <tr> <td> <code> headers </code> </td> <td> <code> MaybeRefOrGetter<Record<string, string> | [key, value][] | Headers> </code> </td> <td> - </td> <td> Request headers. </td> </tr> <tr> <td> <code> baseURL </code> </td> <td> <code> MaybeRefOrGetter<string> </code> </td> <td> - </td> <td> Base URL for the request. </td> </tr> <tr> <td> <code> cache </code> </td> <td> <code> false | string </code> </td> <td> - </td> <td> Cache control. Boolean disables cache, or use Fetch API values: <code> default </code> , <code> no-store </code> , etc. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> Whether to fetch on the server. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If true, resolves after route loads (does not block navigation). </td> </tr> <tr> <td> <code> immediate </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If false, prevents request from firing immediately. </td> </tr> <tr> <td> <code> default </code> </td> <td> <code> () => DataT </code> </td> <td> - </td> <td> Factory for default value of <code> data </code> before async resolves. </td> </tr> <tr> <td> <code> timeout </code> </td> <td> <code> number </code> </td> <td> - </td> <td> A number in milliseconds to wait before timing out the request (defaults to <code> undefined </code> , which means no timeout) </td> </tr> <tr> <td> <code> transform </code> </td> <td> <code> (input: DataT) => DataT | Promise<DataT> </code> </td> <td> - </td> <td> Function to transform the result after resolving. </td> </tr> <tr> <td> <code> getCachedData </code> </td> <td> <code> (key, nuxtApp, ctx) => DataT | undefined </code> </td> <td> - </td> <td> Function to return cached data. See below for default. </td> </tr> <tr> <td> <code> pick </code> </td> <td> <code> string[] </code> </td> <td> - </td> <td> Only pick specified keys from the result. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> MultiWatchSources | false </code> </td> <td> - </td> <td> Array of reactive sources to watch and auto-refresh. <code> false </code> disables watching. </td> </tr> <tr> <td> <code> deep </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Return data in a deep ref object. </td> </tr> <tr> <td> <code> dedupe </code> </td> <td> <code> 'cancel' | 'defer' </code> </td> <td> <code> 'cancel' </code> </td> <td> Avoid fetching same key more than once at a time. </td> </tr> <tr> <td> <code> $fetch </code> </td> <td> <code> typeof globalThis.$fetch </code> </td> <td> - </td> <td> Custom $fetch implementation. See <a href="https://nuxt.com/docs/3.x/guide/recipes/custom-usefetch"> Custom useFetch in Nuxt </a> </td> </tr> </tbody> </table> <note> All fetch options can be given a `computed` or `ref` value. These will be watched and new requests made automatically with any new values if they are updated. </note> **getCachedData default:** ```ts const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating ? nuxtApp.payload.data[key] : nuxtApp.static.data[key] ``` This only caches data when `experimental.payloadExtraction` in `nuxt.config` is enabled. ## Return Values <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous fetch. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. By default, Nuxt waits until a <code> refresh </code> is finished before it can be executed again. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the data fetching failed. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the data request. See below for possible values. </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> Boolean flag indicating whether the current request is in progress. </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> (or the value of <code> options.default() </code> if provided), <code> error </code> to <code> undefined </code> , set <code> status </code> to <code> idle </code> , and cancels any pending requests. </td> </tr> </tbody> </table> ### Status values - `idle`: Request has not started (e.g. `{ immediate: false }` or `{ server: false }` on server render) - `pending`: Request is in progress - `success`: Request completed successfully - `error`: Request failed <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain undefined within `<script setup>`. </note> ### Examples <link-example to="https://nuxt.com/docs/3.x/examples/advanced/use-custom-fetch-composable"> </link-example> <link-example to="https://nuxt.com/docs/3.x/examples/features/data-fetching"> </link-example> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # useHead > useHead customizes the head properties of individual pages of your Nuxt app. ## Usage The `useHead` composable allows you to manage your head tags in a programmatic and reactive way, powered by [Unhead](https://unhead.unjs.io). It lets you customize the meta tags, links, scripts, and other elements in the `<head>` section of your HTML document. ```vue [app.vue] <script setup lang="ts"> useHead({ title: 'My App', meta: [ { name: 'description', content: 'My amazing site.' }, ], bodyAttrs: { class: 'test', }, script: [{ innerHTML: 'console.log(\'Hello world\')' }], }) </script> ``` <warning> If the data comes from a user or other untrusted source, we recommend you check out [`useHeadSafe`](https://nuxt.com/docs/3.x/api/composables/use-head-safe). </warning> <note> The properties of `useHead` can be dynamic, accepting `ref`, `computed` and `reactive` properties. The `meta` parameter can also accept a function returning an object to make the entire object reactive. </note> ## Type ```ts [Signature] export function useHead (meta: MaybeComputedRef<MetaObject>): ActiveHeadEntry<UseHeadInput> interface MetaObject { title?: string titleTemplate?: string | ((title?: string) => string) base?: Base link?: Link[] meta?: Meta[] style?: Style[] script?: Script[] noscript?: Noscript[] htmlAttrs?: HtmlAttributes bodyAttrs?: BodyAttributes } interface ActiveHeadEntry<Input> { /** * Updates the entry with new input. * * Will first clear any side effects for previous input. */ patch: (input: Input) => void /** * Dispose the entry, removing it from the active head. * * Will queue side effects for removal. */ dispose: () => void } ``` See [@unhead/schema](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types. ## Parameters `meta`: An object accepting head metadata properties to customize the page's `<head>` section. All properties support reactive values (`ref`, `computed`, `reactive`) or can be a function returning the metadata object. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> title </code> </td> <td> <code> string </code> </td> <td> Sets the page title. </td> </tr> <tr> <td> <code> titleTemplate </code> </td> <td> <code> string | ((title?: string) => string) </code> </td> <td> Configures a dynamic template to customize the page title. Can be a string with <code> %s </code> placeholder or a function. </td> </tr> <tr> <td> <code> base </code> </td> <td> <code> Base </code> </td> <td> Sets the <code> <base> </code> tag for the document. </td> </tr> <tr> <td> <code> link </code> </td> <td> <code> Link[] </code> </td> <td> Array of link objects. Each element is mapped to a <code> <link> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Meta[] </code> </td> <td> Array of meta objects. Each element is mapped to a <code> <meta> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> style </code> </td> <td> <code> Style[] </code> </td> <td> Array of style objects. Each element is mapped to a <code> <style> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> script </code> </td> <td> <code> Script[] </code> </td> <td> Array of script objects. Each element is mapped to a <code> <script> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> noscript </code> </td> <td> <code> Noscript[] </code> </td> <td> Array of noscript objects. Each element is mapped to a <code> <noscript> </code> tag, where object properties correspond to HTML attributes. </td> </tr> <tr> <td> <code> htmlAttrs </code> </td> <td> <code> HtmlAttributes </code> </td> <td> Sets attributes of the <code> <html> </code> tag. Each object property is mapped to the corresponding attribute. </td> </tr> <tr> <td> <code> bodyAttrs </code> </td> <td> <code> BodyAttributes </code> </td> <td> Sets attributes of the <code> <body> </code> tag. Each object property is mapped to the corresponding attribute. </td> </tr> </tbody> </table> ## Return Values This composable does not return any value. It registers the head metadata with Unhead, which manages the actual DOM updates. ## Examples ### Basic Meta Tags ```vue [pages/about.vue] <script setup lang="ts"> useHead({ title: 'About Us', meta: [ { name: 'description', content: 'Learn more about our company' }, { property: 'og:title', content: 'About Us' }, { property: 'og:description', content: 'Learn more about our company' }, ], }) </script> ``` ### Reactive Meta Tags ```vue [pages/profile.vue] <script setup lang="ts"> const profile = ref({ name: 'John Doe' }) useHead({ title: computed(() => profile.value.name), meta: [ { name: 'description', content: computed(() => `Profile page for ${profile.value.name}`), }, ], }) </script> ``` ### Using a Function for Full Reactivity ```vue [pages/dynamic.vue] <script setup lang="ts"> const count = ref(0) useHead(() => ({ title: `Count: ${count.value}`, meta: [ { name: 'description', content: `Current count is ${count.value}` }, ], })) </script> ``` ### Adding External Scripts and Styles ```vue [pages/external.vue] <script setup lang="ts"> useHead({ link: [ { rel: 'stylesheet', href: 'https://cdn.example.com/styles.css', }, ], script: [ { src: 'https://cdn.example.com/script.js', async: true, }, ], }) </script> ``` ### Body and HTML Attributes ```vue [pages/themed.vue] <script setup lang="ts"> const isDark = ref(true) useHead({ htmlAttrs: { lang: 'en', class: computed(() => isDark.value ? 'dark' : 'light'), }, bodyAttrs: { class: 'themed-page', }, }) </script> ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useHeadSafe > The recommended way to provide head data with user input. ## Usage The `useHeadSafe` composable is a wrapper around the [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable that restricts the input to only allow safe values. This is the recommended way to manage head data when working with user input, as it prevents XSS attacks by sanitizing potentially dangerous attributes. <warning> When using `useHeadSafe`, potentially dangerous attributes like `innerHTML` in scripts or `http-equiv` in meta tags are automatically stripped out to prevent XSS attacks. Use this composable whenever you're working with user-generated content. </warning> ## Type ```ts [Signature] export function useHeadSafe (input: MaybeComputedRef<HeadSafe>): void ``` ### Allowed Attributes The following attributes are whitelisted for each head element type: ```ts const WhitelistAttributes = { htmlAttrs: ['class', 'style', 'lang', 'dir'], bodyAttrs: ['class', 'style'], meta: ['name', 'property', 'charset', 'content', 'media'], noscript: ['textContent'], style: ['media', 'textContent', 'nonce', 'title', 'blocking'], script: ['type', 'textContent', 'nonce', 'blocking'], link: ['color', 'crossorigin', 'fetchpriority', 'href', 'hreflang', 'imagesrcset', 'imagesizes', 'integrity', 'media', 'referrerpolicy', 'rel', 'sizes', 'type'], } ``` See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/safeSchema.ts) for more detailed types. ## Parameters `input`: A `MaybeComputedRef<HeadSafe>` object containing head data. You can pass all the same values as [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head), but only safe attributes will be rendered. ## Return Values This composable does not return any value. ## Example ```vue [pages/user-profile.vue] <script setup lang="ts"> // User-generated content that might contain malicious code const userBio = ref('<script>alert("xss")<' + '/script>') useHeadSafe({ title: `User Profile`, meta: [ { name: 'description', content: userBio.value, // Safely sanitized }, ], }) </script> ``` <read-more target="_blank" to="https://unhead.unjs.io/docs/typescript/head/api/composables/use-head-safe"> Read more on the `Unhead` documentation. </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useHydration > Allows full control of the hydration cycle to set and receive data from the server. `useHydration` is a built-in composable that provides a way to set data on the server side every time a new HTTP request is made and receive that data on the client side. This way `useHydration` allows you to take full control of the hydration cycle. <note> This is an advanced composable, primarily designed for use within plugins, mostly used by Nuxt modules. </note> <note> `useHydration` is designed to **ensure state synchronization and restoration during SSR**. If you need to create a globally reactive state that is SSR-friendly in Nuxt, [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) is the recommended choice. </note> ## Usage The data returned from the `get` function on the server is stored in `nuxtApp.payload` under the unique key provided as the first parameter to `useHydration`. During hydration, this data is then retrieved on the client, preventing redundant computations or API calls. <code-group> ```ts [With useHydration] export default defineNuxtPlugin((nuxtApp) => { const myStore = new MyStore() useHydration( 'myStoreState', () => myStore.getState(), data => myStore.setState(data), ) }) ``` ```ts [Without useHydration] export default defineNuxtPlugin((nuxtApp) => { const myStore = new MyStore() if (import.meta.server) { nuxt.hooks.hook('app:rendered', () => { nuxtApp.payload.myStoreState = myStore.getState() }) } if (import.meta.client) { nuxt.hooks.hook('app:created', () => { myStore.setState(nuxtApp.payload.myStoreState) }) } }) ``` </code-group> ## Type ```ts [Signature] export function useHydration<T> (key: string, get: () => T, set: (value: T) => void): void ``` ## Parameters <table> <thead> <tr> <th> Parameter </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> key </code> </td> <td> <code> string </code> </td> <td> A unique key that identifies the data in your Nuxt application. </td> </tr> <tr> <td> <code> get </code> </td> <td> <code> () => T </code> </td> <td> A function executed <strong> only on the server </strong> (called when SSR rendering is done) to set the initial value. </td> </tr> <tr> <td> <code> set </code> </td> <td> <code> (value: T) => void </code> </td> <td> A function executed <strong> only on the client </strong> (called when initial Vue instance is created) to receive the data. </td> </tr> </tbody> </table> ## Return Values This composable does not return any value. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/hydrate.ts) # useLazyAsyncData > This wrapper around useAsyncData triggers navigation immediately. `useLazyAsyncData` provides a wrapper around [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. <note> By default, [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) blocks navigation until its async handler is resolved. `useLazyAsyncData` allows navigation to occur immediately while data fetching continues in the background. </note> ## Usage ```vue [pages/index.vue] <script setup lang="ts"> const { status, data: posts } = await useLazyAsyncData('posts', () => $fetch('/api/posts')) </script> <template> <div> <div v-if="status === 'pending'"> Loading... </div> <div v-else-if="status === 'error'"> Error loading posts </div> <div v-else> {{ posts }} </div> </div> </template> ``` When using `useLazyAsyncData`, navigation will occur before fetching is complete. This means you must handle `pending` and `error` states directly within your component's template. <warning> `useLazyAsyncData` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyAsyncData`. </warning> ## Type ```ts [Signature] export function useLazyAsyncData<DataT, ErrorT> ( handler: (ctx?: NuxtApp) => Promise<DataT>, options?: AsyncDataOptions<DataT>, ): AsyncData<DataT, ErrorT> export function useLazyAsyncData<DataT, ErrorT> ( key: string, handler: (ctx?: NuxtApp) => Promise<DataT>, options?: AsyncDataOptions<DataT>, ): AsyncData<DataT, ErrorT> ``` `useLazyAsyncData` has the same signature as [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data). ## Parameters `useLazyAsyncData` accepts the same parameters as [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data), with the `lazy` option automatically set to `true`. <read-more to="https://nuxt.com/docs/3.x/api/composables/use-async-data#parameters"> </read-more> ## Return Values `useLazyAsyncData` returns the same values as [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data). <read-more to="https://nuxt.com/docs/3.x/api/composables/use-async-data#return-values"> </read-more> ## Example ```vue [pages/index.vue] <script setup lang="ts"> /* Navigation will occur before fetching is complete. Handle 'pending' and 'error' states directly within your component's template */ const { status, data: count } = await useLazyAsyncData('count', () => $fetch('/api/count')) watch(count, (newCount) => { // Because count might start out null, you won't have access // to its contents immediately, but you can watch it. }) </script> <template> <div> {{ status === 'pending' ? 'Loading' : count }} </div> </template> ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # useLazyFetch > This wrapper around useFetch triggers navigation immediately. `useLazyFetch` provides a wrapper around [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) that triggers navigation before the handler is resolved by setting the `lazy` option to `true`. ## Usage By default, [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) blocks navigation until its async handler is resolved. `useLazyFetch` allows navigation to proceed immediately, with data being fetched in the background. ```vue [pages/index.vue] <script setup lang="ts"> const { status, data: posts } = await useLazyFetch('/api/posts') </script> <template> <div v-if="status === 'pending'"> Loading ... </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` <note> `useLazyFetch` has the same signature as [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch). </note> <warning> Awaiting `useLazyFetch` only ensures the call is initialized. On client-side navigation, data may not be immediately available, and you must handle the `pending` state in your component's template. </warning> <warning> `useLazyFetch` is a reserved function name transformed by the compiler, so you should not name your own function `useLazyFetch`. </warning> ## Type ```ts [Signature] export function useLazyFetch<DataT, ErrorT> ( url: string | Request | Ref<string | Request> | (() => string | Request), options?: UseFetchOptions<DataT>, ): Promise<AsyncData<DataT, ErrorT>> ``` <note> `useLazyFetch` is equivalent to `useFetch` with `lazy: true` option set. See [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) for full type definitions. </note> ## Parameters `useLazyFetch` accepts the same parameters as [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch): - `URL` (`string | Request | Ref<string | Request> | () => string | Request`): The URL or request to fetch. - `options` (object): Same as [`useFetch` options](https://nuxt.com/docs/3.x/api/composables/use-fetch#parameters), with `lazy` automatically set to `true`. <read-more to="https://nuxt.com/docs/3.x/api/composables/use-fetch#parameters"> </read-more> ## Return Values Returns the same `AsyncData` object as [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch): <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> data </code> </td> <td> <code> Ref<DataT | undefined> </code> </td> <td> The result of the asynchronous fetch. </td> </tr> <tr> <td> <code> refresh </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Function to manually refresh the data. </td> </tr> <tr> <td> <code> execute </code> </td> <td> <code> (opts?: AsyncDataExecuteOptions) => Promise<void> </code> </td> <td> Alias for <code> refresh </code> . </td> </tr> <tr> <td> <code> error </code> </td> <td> <code> Ref<ErrorT | undefined> </code> </td> <td> Error object if the data fetching failed. </td> </tr> <tr> <td> <code> status </code> </td> <td> <code> Ref<'idle' | 'pending' | 'success' | 'error'> </code> </td> <td> Status of the data request. </td> </tr> <tr> <td> <code> pending </code> </td> <td> <code> Ref<boolean> </code> </td> <td> Boolean flag indicating whether the current request is in progress. </td> </tr> <tr> <td> <code> clear </code> </td> <td> <code> () => void </code> </td> <td> Resets <code> data </code> to <code> undefined </code> , <code> error </code> to <code> undefined </code> , sets <code> status </code> to <code> idle </code> , and cancels any pending requests. </td> </tr> </tbody> </table> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-fetch#return-values"> </read-more> ## Examples ### Handling Pending State ```vue [pages/index.vue] <script setup lang="ts"> /* Navigation will occur before fetching is complete. * Handle 'pending' and 'error' states directly within your component's template */ const { status, data: posts } = await useLazyFetch('/api/posts') watch(posts, (newPosts) => { // Because posts might start out null, you won't have access // to its contents immediately, but you can watch it. }) </script> <template> <div v-if="status === 'pending'"> Loading ... </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/fetch.ts) # useLoadingIndicator > This composable gives you access to the loading state of the app page. ## Description A composable which returns the loading state of the page. Used by [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/3.x/api/components/nuxt-loading-indicator) and controllable. It hooks into [`page:loading:start`](https://nuxt.com/docs/3.x/api/advanced/hooks#app-hooks-runtime) and [`page:loading:end`](https://nuxt.com/docs/3.x/api/advanced/hooks#app-hooks-runtime) to change its state. ## Parameters - `duration`: Duration of the loading bar, in milliseconds (default `2000`). - `throttle`: Throttle the appearing and hiding, in milliseconds (default `200`). - `estimatedProgress`: By default Nuxt will back off as it approaches 100%. You can provide a custom function to customize the progress estimation, which is a function that receives the duration of the loading bar (above) and the elapsed time. It should return a value between 0 and 100. ## Properties ### `isLoading` - **type**: `Readonly<ShallowRef<boolean>>` - **description**: The loading state ### `error` - **type**: `Readonly<ShallowRef<boolean>>` - **description**: The error state ### `progress` - **type**: `Readonly<ShallowRef<number>>` - **description**: The progress state. From `0` to `100`. ## Methods ### `start()` Set `isLoading` to true and start to increase the `progress` value. `start` accepts a `{ force: true }` option to skip the interval and show the loading state immediately. ### `set()` Set the `progress` value to a specific value. `set` accepts a `{ force: true }` option to skip the interval and show the loading state immediately. ### `finish()` Set the `progress` value to `100`, stop all timers and intervals then reset the loading state `500` ms later. `finish` accepts a `{ force: true }` option to skip the interval before the state is reset, and `{ error: true }` to change the loading bar color and set the error property to true. ### `clear()` Used by `finish()`. Clear all timers and intervals used by the composable. ## Example ```vue <script setup lang="ts"> const { progress, isLoading, start, finish, clear } = useLoadingIndicator({ duration: 2000, throttle: 200, // This is how progress is calculated by default estimatedProgress: (duration, elapsed) => (2 / Math.PI * 100) * Math.atan(elapsed / duration * 100 / 50), }) </script> ``` ```vue <script setup lang="ts"> const { start, set } = useLoadingIndicator() // same as set(0, { force: true }) // set the progress to 0, and show loading immediately start({ force: true }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/loading-indicator.ts) # useNuxtApp > Access the shared runtime context of the Nuxt Application. `useNuxtApp` is a built-in composable that provides a way to access shared runtime context of Nuxt, also known as the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context), which is available on both client and server side (but not within Nitro routes). It helps you access the Vue app instance, runtime hooks, runtime config variables and internal states, such as `ssrContext` and `payload`. ```vue [app.vue] <script setup lang="ts"> const nuxtApp = useNuxtApp() </script> ``` If runtime context is unavailable in your scope, `useNuxtApp` will throw an exception when called. You can use [`tryUseNuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#tryusenuxtapp) instead for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception. ## Methods ### `provide (name, value)` `nuxtApp` is a runtime context that you can extend using [Nuxt plugins](https://nuxt.com/docs/3.x/directory-structure/plugins). Use the `provide` function to create Nuxt plugins to make values and helper methods available in your Nuxt application across all composables and components. `provide` function accepts `name` and `value` parameters. ```ts const nuxtApp = useNuxtApp() nuxtApp.provide('hello', name => `Hello ${name}!`) // Prints "Hello name!" console.log(nuxtApp.$hello('name')) ``` As you can see in the example above, `$hello` has become the new and custom part of `nuxtApp` context and it is available in all places where `nuxtApp` is accessible. ### `hook(name, cb)` Hooks available in `nuxtApp` allows you to customize the runtime aspects of your Nuxt application. You can use runtime hooks in Vue.js composables and [Nuxt plugins](https://nuxt.com/docs/3.x/directory-structure/plugins) to hook into the rendering lifecycle. `hook` function is useful for adding custom logic by hooking into the rendering lifecycle at a specific point. `hook` function is mostly used when creating Nuxt plugins. See [Runtime Hooks](https://nuxt.com/docs/3.x/api/advanced/hooks#app-hooks-runtime) for available runtime hooks called by Nuxt. ```ts [plugins/test.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('page:start', () => { /* your code goes here */ }) nuxtApp.hook('vue:error', (..._args) => { console.log('vue:error') // if (import.meta.client) { // console.log(..._args) // } }) }) ``` ### `callHook(name, ...args)` `callHook` returns a promise when called with any of the existing hooks. ```ts await nuxtApp.callHook('my-plugin:init') ``` ## Properties `useNuxtApp()` exposes the following properties that you can use to extend and customize your app and share state, data and variables. ### `vueApp` `vueApp` is the global Vue.js [application instance](https://vuejs.org/api/application#application-api) that you can access through `nuxtApp`. Some useful methods: - [`component()`](https://vuejs.org/api/application#app-component) - Registers a global component if passing both a name string and a component definition, or retrieves an already registered one if only the name is passed. - [`directive()`](https://vuejs.org/api/application#app-directive) - Registers a global custom directive if passing both a name string and a directive definition, or retrieves an already registered one if only the name is passed[(example)](https://nuxt.com/docs/3.x/directory-structure/plugins#vue-directives). - [`use()`](https://vuejs.org/api/application#app-use) - Installs a **Vue.js Plugin** [(example)](https://nuxt.com/docs/3.x/directory-structure/plugins#vue-plugins). <read-more to="https://vuejs.org/api/application.html#application-api" icon="i-simple-icons-vuedotjs"> </read-more> ### `ssrContext` `ssrContext` is generated during server-side rendering and it is only available on the server side. Nuxt exposes the following properties through `ssrContext`: - `url` (string) - Current request url. - `event` ([h3js/h3](https://github.com/h3js/h3) request event) - Access the request & response of the current route. - `payload` (object) - NuxtApp payload object. ### `payload` `payload` exposes data and state variables from server side to client side. The following keys will be available on the client after they have been passed from the server side: - `serverRendered` (boolean) - Indicates if response is server-side-rendered. - `data` (object) - When you fetch the data from an API endpoint using either [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) , resulting payload can be accessed from the `payload.data`. This data is cached and helps you prevent fetching the same data in case an identical request is made more than once.<code-group> ```vue [app.vue] <script setup lang="ts"> const { data } = await useAsyncData('count', (_nuxtApp, { signal }) => $fetch('/api/count', { signal })) </script> ``` ```ts [server/api/count.ts] export default defineEventHandler((event) => { return { count: 1 } }) ``` </code-group> <br /> After fetching the value of `count` using [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) in the example above, if you access `payload.data`, you will see `{ count: 1 }` recorded there.<br /> When accessing the same `payload.data` from [`ssrcontext`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#ssrcontext), you can access the same value on the server side as well. - `state` (object) - When you use [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) composable in Nuxt to set shared state, this state data is accessed through `payload.state.[name-of-your-state]`.```ts [plugins/my-plugin.ts] export const useColor = () => useState<string>('color', () => 'pink') export default defineNuxtPlugin((nuxtApp) => { if (import.meta.server) { const color = useColor() } }) ``` <br /> It is also possible to use more advanced types, such as `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError`. #### Custom Reducer/Reviver Since [Nuxt v3.4](https://nuxt.com/blog/v3-4#payload-enhancements), it is possible to define your own reducer/reviver for types that are not supported by Nuxt. <video-accordion title="Watch a video from Alexander Lichter about serializing payloads, especially with regards to classes" video-id="8w6ffRBs8a4"> </video-accordion> In the example below, we define a reducer (or a serializer) and a reviver (or deserializer) for the [Luxon](https://moment.github.io/luxon/#/) DateTime class, using a payload plugin. ```ts [plugins/date-time-payload.ts] /** * This kind of plugin runs very early in the Nuxt lifecycle, before we revive the payload. * You will not have access to the router or other Nuxt-injected properties. * * Note that the "DateTime" string is the type identifier and must * be the same on both the reducer and the reviver. */ export default definePayloadPlugin((nuxtApp) => { definePayloadReducer('DateTime', (value) => { return value instanceof DateTime && value.toJSON() }) definePayloadReviver('DateTime', (value) => { return DateTime.fromISO(value) }) }) ``` ### `isHydrating` Use `nuxtApp.isHydrating` (boolean) to check if the Nuxt app is hydrating on the client side. ```ts [components/nuxt-error-boundary.ts] export default defineComponent({ setup (_props, { slots, emit }) { const nuxtApp = useNuxtApp() onErrorCaptured((err) => { if (import.meta.client && !nuxtApp.isHydrating) { // ... } }) }, }) ``` ### `runWithContext` <note> You are likely here because you got a "Nuxt instance unavailable" message. Please use this method sparingly, and report examples that are causing issues, so that it can ultimately be solved at the framework level. </note> The `runWithContext` method is meant to be used to call a function and give it an explicit Nuxt context. Typically, the Nuxt context is passed around implicitly and you do not need to worry about this. However, when working with complex `async`/`await` scenarios in middleware/plugins, you can run into instances where the current instance has been unset after an async call. ```ts [middleware/auth.ts] export default defineNuxtRouteMiddleware(async (to, from) => { const nuxtApp = useNuxtApp() let user try { user = await fetchUser() // the Vue/Nuxt compiler loses context here because of the try/catch block. } catch (e) { user = null } if (!user) { // apply the correct Nuxt context to our `navigateTo` call. return nuxtApp.runWithContext(() => navigateTo('/auth')) } }) ``` #### Usage ```ts const result = nuxtApp.runWithContext(() => functionWithContext()) ``` - `functionWithContext`: Any function that requires the context of the current Nuxt application. This context will be correctly applied automatically. `runWithContext` will return whatever is returned by `functionWithContext`. #### A Deeper Explanation of Context Vue.js Composition API (and Nuxt composables similarly) work by depending on an implicit context. During the lifecycle, Vue sets the temporary instance of the current component (and Nuxt temporary instance of nuxtApp) to a global variable and unsets it in same tick. When rendering on the server side, there are multiple requests from different users and nuxtApp running in a same global context. Because of this, Nuxt and Vue immediately unset this global instance to avoid leaking a shared reference between two users or components. What it does mean? The Composition API and Nuxt Composables are only available during lifecycle and in same tick before any async operation: ```ts // --- Vue internal --- const _vueInstance = null const getCurrentInstance = () => _vueInstance // --- // Vue / Nuxt sets a global variable referencing to current component in _vueInstance when calling setup() async function setup () { getCurrentInstance() // Works await someAsyncOperation() // Vue unsets the context in same tick before async operation! getCurrentInstance() // null } ``` The classic solution to this, is caching the current instance on first call to a local variable like `const instance = getCurrentInstance()` and use it in the next composable call but the issue is that any nested composable calls now needs to explicitly accept the instance as an argument and not depend on the implicit context of composition-api. This is design limitation with composables and not an issue per-se. To overcome this limitation, Vue does some behind the scenes work when compiling our application code and restores context after each call for `<script setup>`: ```ts const __instance = getCurrentInstance() // Generated by Vue compiler getCurrentInstance() // Works! await someAsyncOperation() // Vue unsets the context __restoreInstance(__instance) // Generated by Vue compiler getCurrentInstance() // Still works! ``` For a better description of what Vue actually does, see [unjs/unctx#2 (comment)](https://github.com/unjs/unctx/issues/2#issuecomment-942193723). #### Solution This is where `runWithContext` can be used to restore context, similarly to how `<script setup>` works. Nuxt internally uses [unjs/unctx](https://github.com/unjs/unctx) to support composables similar to Vue for plugins and middleware. This enables composables like `navigateTo()` to work without directly passing `nuxtApp` to them - bringing the DX and performance benefits of Composition API to the whole Nuxt framework. Nuxt composables have the same design as the Vue Composition API and therefore need a similar solution to magically do this transform. Check out [unjs/unctx#2](https://github.com/unjs/unctx/issues/2) (proposal), [unjs/unctx#4](https://github.com/unjs/unctx/pull/4) (transform implementation), and [nuxt/framework#3884](https://github.com/nuxt/framework/pull/3884) (Integration to Nuxt). Vue currently only supports async context restoration for `<script setup>` for async/await usage. In Nuxt, the transform support for `defineNuxtPlugin()` and `defineNuxtRouteMiddleware()` was added, which means when you use them Nuxt automatically transforms them with context restoration. #### Remaining Issues The `unjs/unctx` transformation to automatically restore context seems buggy with `try/catch` statements containing `await` which ultimately needs to be solved in order to remove the requirement of the workaround suggested above. #### Native Async Context Using a new experimental feature, it is possible to enable native async context support using [Node.js `AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) and new unctx support to make async context available **natively** to **any nested async composable** without needing a transform or manual passing/calling with context. <tip> Native async context support works currently in Bun and Node. </tip> <read-more to="https://nuxt.com/docs/3.x/guide/going-further/experimental-features#asynccontext"> </read-more> ## tryUseNuxtApp This function works exactly the same as `useNuxtApp`, but returns `null` if context is unavailable instead of throwing an exception. You can use it for composables that do not require `nuxtApp`, or to simply check if context is available or not without an exception. Example usage: ```ts [composable.ts] export function useStandType () { // Always works on the client if (tryUseNuxtApp()) { return useRuntimeConfig().public.STAND_TYPE } else { return process.env.STAND_TYPE } } ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # useNuxtData > Access the current cached value of data fetching composables. <note> `useNuxtData` gives you access to the current cached value of [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) , [`useLazyAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-lazy-async-data), [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) and [`useLazyFetch`](https://nuxt.com/docs/3.x/api/composables/use-lazy-fetch) with explicitly provided key. </note> ## Usage The `useNuxtData` composable is used to access the current cached value of data-fetching composables such as `useAsyncData`, `useLazyAsyncData`, `useFetch`, and `useLazyFetch`. By providing the key used during the data fetch, you can retrieve the cached data and use it as needed. This is particularly useful for optimizing performance by reusing already-fetched data or implementing features like Optimistic Updates or cascading data updates. To use `useNuxtData`, ensure that the data-fetching composable (`useFetch`, `useAsyncData`, etc.) has been called with an explicitly provided key. <video-accordion title="Watch a video from LearnVue about useNuxtData" video-id="e-_u6swXRWk"> </video-accordion> ## Params - `key`: The unique key that identifies the cached data. This key should match the one used during the original data fetch. ## Return Values - `data`: A reactive reference to the cached data associated with the provided key. If no cached data exists, the value will be `undefined`. This `Ref` automatically updates if the cached data changes, allowing seamless reactivity in your components. ## Example The example below shows how you can use cached data as a placeholder while the most recent data is being fetched from the server. ```vue [pages/posts.vue] <script setup lang="ts"> // We can access same data later using 'posts' key const { data } = await useFetch('/api/posts', { key: 'posts' }) </script> ``` ```vue [pages/posts/[id].vue] <script setup lang="ts"> // Access to the cached value of useFetch in posts.vue (parent route) const { data: posts } = useNuxtData('posts') const route = useRoute() const { data } = useLazyFetch(`/api/posts/${route.params.id}`, { key: `post-${route.params.id}`, default () { // Find the individual post from the cache and set it as the default value. return posts.value.find(post => post.id === route.params.id) }, }) </script> ``` ## Optimistic Updates The example below shows how implementing Optimistic Updates can be achieved using useNuxtData. Optimistic Updates is a technique where the user interface is updated immediately, assuming a server operation will succeed. If the operation eventually fails, the UI is rolled back to its previous state. ```vue [pages/todos.vue] <script setup lang="ts"> // We can access same data later using 'todos' key const { data } = await useAsyncData('todos', (_nuxtApp, { signal }) => $fetch('/api/todos', { signal })) </script> ``` ```vue [components/NewTodo.vue] <script setup lang="ts"> const newTodo = ref('') let previousTodos = [] // Access to the cached value of useAsyncData in todos.vue const { data: todos } = useNuxtData('todos') async function addTodo () { await $fetch('/api/addTodo', { method: 'post', body: { todo: newTodo.value, }, onRequest () { // Store the previously cached value to restore if fetch fails. previousTodos = todos.value // Optimistically update the todos. todos.value = [...todos.value, newTodo.value] }, onResponseError () { // Rollback the data if the request failed. todos.value = previousTodos }, async onResponse () { // Invalidate todos in the background if the request succeeded. await refreshNuxtData('todos') }, }) } </script> ``` ## Type ```ts [Signature] export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | null> } ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # `usePreviewMode` Preview mode allows you to see how your changes would be displayed on a live site without revealing them to users. You can use the built-in `usePreviewMode` composable to access and control preview state in Nuxt. If the composable detects preview mode it will automatically force any updates necessary for [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) to rerender preview content. ```ts const { enabled, state } = usePreviewMode() ``` ## Options ### Custom `enable` check You can specify a custom way to enable preview mode. By default the `usePreviewMode` composable will enable preview mode if there is a `preview` param in url that is equal to `true` (for example, `http://localhost:3000?preview=true`). You can wrap the `usePreviewMode` into custom composable, to keep options consistent across usages and prevent any errors. ```ts export function useMyPreviewMode () { const route = useRoute() return usePreviewMode({ shouldEnable: () => { return !!route.query.customPreview }, }) } ``` ### Modify default state `usePreviewMode` will try to store the value of a `token` param from url in state. You can modify this state and it will be available for all [`usePreviewMode`](https://nuxt.com/docs/3.x/api/composables/use-preview-mode) calls. ```ts const data1 = ref('data1') const { enabled, state } = usePreviewMode({ getState: (currentState) => { return { data1, data2: 'data2' } }, }) ``` <note> The `getState` function will append returned values to current state, so be careful not to accidentally overwrite important state. </note> ### Customize the `onEnable` and `onDisable` callbacks By default, when `usePreviewMode` is enabled, it will call `refreshNuxtData()` to re-fetch all data from the server. When preview mode is disabled, the composable will attach a callback to call `refreshNuxtData()` to run after a subsequent router navigation. You can specify custom callbacks to be triggered by providing your own functions for the `onEnable` and `onDisable` options. ```ts const { enabled, state } = usePreviewMode({ onEnable: () => { console.log('preview mode has been enabled') }, onDisable: () => { console.log('preview mode has been disabled') }, }) ``` ## Example The example below creates a page where part of a content is rendered only in preview mode. ```vue [pages/some-page.vue] <script setup> const { enabled, state } = usePreviewMode() const { data } = await useFetch('/api/preview', { query: { apiKey: state.token, }, }) </script> <template> <div> Some base content <p v-if="enabled"> Only preview content: {{ state.token }} <br> <button @click="enabled = false"> disable preview mode </button> </p> </div> </template> ``` Now you can generate your site and serve it: ```bash [Terminal] npx nuxt generate npx nuxt preview ``` Then you can see your preview page by adding the query param `preview` to the end of the page you want to see once, for example `http://localhost:3000/?preview=true`. <note> `usePreviewMode` should be tested locally with `nuxt generate` and then `nuxt preview` rather than `nuxt dev`. (The [preview command](https://nuxt.com/docs/3.x/api/commands/preview) is not related to preview mode.) </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preview.ts) # useRequestEvent > Access the incoming request event with the useRequestEvent composable. Within the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context) you can use `useRequestEvent` to access the incoming request. ```ts // Get underlying request event const event = useRequestEvent() // Get the URL const url = event?.path ``` <tip> In the browser, `useRequestEvent` will return `undefined`. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestFetch > Forward the request context and headers for server-side fetch requests with the useRequestFetch composable. You can use `useRequestFetch` to forward the request context and headers when making server-side fetch requests. When making a client-side fetch request, the browser automatically sends the necessary headers. However, when making a request during server-side rendering, due to security considerations, we need to forward the headers manually. <note> Headers that are **not meant to be forwarded** will **not be included** in the request. These headers include, for example: `transfer-encoding`, `connection`, `keep-alive`, `upgrade`, `expect`, `host`, `accept` </note> <tip> The [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) composable uses `useRequestFetch` under the hood to automatically forward the request context and headers. </tip> <code-group> ```vue [pages/index.vue] <script setup lang="ts"> // This will forward the user's headers to the `/api/cookies` event handler // Result: { cookies: { foo: 'bar' } } const requestFetch = useRequestFetch() const { data: forwarded } = await useAsyncData(() => requestFetch('/api/cookies')) // This will NOT forward anything // Result: { cookies: {} } const { data: notForwarded } = await useAsyncData((_nuxtApp, { signal }) => $fetch('/api/cookies', { signal })) </script> ``` ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` </code-group> <tip> In the browser during client-side navigation, `useRequestFetch` will behave just like regular [`$fetch`](https://nuxt.com/docs/3.x/api/utils/dollarfetch). </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestHeader > Use useRequestHeader to access a certain incoming request header. You can use the built-in [`useRequestHeader`](https://nuxt.com/docs/3.x/api/composables/use-request-header) composable to access any incoming request header within your pages, components, and plugins. ```ts // Get the authorization request header const authorization = useRequestHeader('authorization') ``` <tip> In the browser, `useRequestHeader` will return `undefined`. </tip> ## Example We can use `useRequestHeader` to easily figure out if a user is authorized or not. The example below reads the `authorization` request header to find out if a person can access a restricted resource. ```ts [middleware/authorized-only.ts] export default defineNuxtRouteMiddleware((to, from) => { if (!useRequestHeader('authorization')) { return navigateTo('/not-authorized') } }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestHeaders > Use useRequestHeaders to access the incoming request headers. You can use built-in [`useRequestHeaders`](https://nuxt.com/docs/3.x/api/composables/use-request-headers) composable to access the incoming request headers within your pages, components, and plugins. ```ts // Get all request headers const headers = useRequestHeaders() // Get only cookie request header const { cookie } = useRequestHeaders(['cookie']) ``` <tip> In the browser, `useRequestHeaders` will return an empty object. </tip> ## Example We can use `useRequestHeaders` to access and proxy the initial request's `authorization` header to any future internal requests during SSR. The example below adds the `authorization` request header to an isomorphic `$fetch` call. ```vue [pages/some-page.vue] <script setup lang="ts"> const { data } = await useFetch('/api/confidential', { headers: useRequestHeaders(['authorization']), }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRequestURL > Access the incoming request URL with the useRequestURL composable. `useRequestURL` is a helper function that returns an [URL object](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) working on both server-side and client-side. <important> When utilizing [Hybrid Rendering](https://nuxt.com/docs/3.x/guide/concepts/rendering#hybrid-rendering) with cache strategies, all incoming request headers are dropped when handling the cached responses via the [Nitro caching layer](https://nitro.build/guide/cache) (meaning `useRequestURL` will return `localhost` for the `host`). You can define the [`cache.varies` option](https://nitro.build/guide/cache#options) to specify headers that will be considered when caching and serving the responses, such as `host` and `x-forwarded-host` for multi-tenant environments. </important> <code-group> ```vue [pages/about.vue] <script setup lang="ts"> const url = useRequestURL() </script> <template> <p>URL is: {{ url }}</p> <p>Path is: {{ url.pathname }}</p> </template> ``` ```html [Result in development] <p>URL is: http://localhost:3000/about</p> <p>Path is: /about</p> ``` </code-group> <tip icon="i-simple-icons-mdnwebdocs" target="_blank" to="https://developer.mozilla.org/en-US/docs/Web/API/URL#instance_properties"> Read about the URL instance properties on the MDN documentation. </tip> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/url.ts) # useResponseHeader > Use useResponseHeader to set a server response header. <important> This composable is available in Nuxt v3.14+. </important> You can use the built-in [`useResponseHeader`](https://nuxt.com/docs/3.x/api/composables/use-response-header) composable to set any server response header within your pages, components, and plugins. ```ts // Set a custom response header const header = useResponseHeader('X-My-Header') header.value = 'my-value' ``` ## Example We can use `useResponseHeader` to easily set a response header on a per-page basis. ```vue [pages/test.vue] <script setup> // pages/test.vue const header = useResponseHeader('X-My-Header') header.value = 'my-value' </script> <template> <h1>Test page with custom header</h1> <p>The response from the server for this "/test" page will have a custom "X-My-Header" header.</p> </template> ``` We can use `useResponseHeader` for example in Nuxt [middleware](https://nuxt.com/docs/3.x/directory-structure/middleware) to set a response header for all pages. ```ts [middleware/my-header-middleware.ts] export default defineNuxtRouteMiddleware((to, from) => { const header = useResponseHeader('X-My-Always-Header') header.value = `I'm Always here!` }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # useRoute > The useRoute composable returns the current route. <note> Within the template of a Vue component, you can access the route using `$route`. </note> The `useRoute` composable is a wrapper around the identically named composable from `vue-router`, providing access to the current route in a Nuxt application. The key difference is that in Nuxt, the composable ensures that the route is updated **only after** the page content has changed after navigation. In contrast, the `vue-router` version updates the route **immediately**, which can lead to synchronization issues between different parts of the template that rely on the route metadata, for example. ## Example In the following example, we call an API via [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) using a dynamic page parameter - `slug` - as part of the URL. ```html [~/pages/[slug].vue] <script setup lang="ts"> const route = useRoute() const { data: mountain } = await useFetch(`/api/mountains/${route.params.slug}`) </script> <template> <div> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </div> </template> ``` If you need to access the route query parameters (for example `example` in the path `/test?example=true`), then you can use `useRoute().query` instead of `useRoute().params`. ## API Apart from dynamic parameters and query parameters, `useRoute()` also provides the following computed references related to the current route: - `fullPath`: encoded URL associated with the current route that contains path, query and hash - `hash`: decoded hash section of the URL that starts with a # - `query`: access route query parameters - `matched`: array of normalized matched routes with current route location - `meta`: custom data attached to the record - `name`: unique name for the route record - `path`: encoded pathname section of the URL - `redirectedFrom`: route location that was attempted to access before ending up on the current route location ## Common Pitfalls ### Route Synchronization Issues Itโ€™s important to use the `useRoute()` composable from Nuxt rather than the one from `vue-router` to avoid synchronization issues during page navigation. Importing `useRoute` directly from `vue-router` bypasses Nuxt's implementation. ```tstwoslash // โŒ do not use `useRoute` from `vue-router` // @errors: 2300 import { useRoute } from 'vue-router' // โœ… use Nuxt's `useRoute` composable import { useRoute } from '#app' ``` ### Calling `useRoute` in Middleware Using `useRoute` in middleware is not recommended because it can lead to unexpected behavior. There is no concept of a "current route" in middleware. The `useRoute()` composable should only be used in the setup function of a Vue component or in a Nuxt plugin. <warning> This applies to any composable that uses `useRoute()` internally too. </warning> <read-more to="https://nuxt.com/docs/3.x/directory-structure/middleware"> Read more about accessing the route in the middleware section. </read-more> ### Hydration Issues with `route.fullPath` Browsers don't send [URL fragments](https://url.spec.whatwg.org/#concept-url-fragment) (for example `#foo`) when making requests. So using `route.fullPath` to affect the template can trigger hydration issues because this will include the fragment on client but not the server. <read-more to="https://router.vuejs.org/api/type-aliases/RouteLocationNormalizedLoaded.html" icon="i-simple-icons-vuedotjs"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # useRouteAnnouncer > This composable observes the page title changes and updates the announcer message accordingly. <important> This composable is available in Nuxt v3.12+. </important> ## Description A composable which observes the page title changes and updates the announcer message accordingly. Used by [`<NuxtRouteAnnouncer>`](https://nuxt.com/docs/3.x/api/components/nuxt-route-announcer) and controllable. It hooks into Unhead's `dom:rendered` hook to read the page's title and set it as the announcer message. ## Parameters - `politeness`: Sets the urgency for screen reader announcements: `off` (disable the announcement), `polite` (waits for silence), or `assertive` (interrupts immediately). (default `polite`). ## Properties ### `message` - **type**: `Ref<string>` - **description**: The message to announce ### `politeness` - **type**: `Ref<string>` - **description**: Screen reader announcement urgency level `off`, `polite`, or `assertive` ## Methods ### `set(message, politeness = "polite")` Sets the message to announce with its urgency level. ### `polite(message)` Sets the message with `politeness = "polite"` ### `assertive(message)` Sets the message with `politeness = "assertive"` ## Example ```vue [pages/index.vue] <script setup lang="ts"> const { message, politeness, set, polite, assertive } = useRouteAnnouncer({ politeness: 'assertive', }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/route-announcer.ts) # useRouter > The useRouter composable returns the router instance. ```vue [pages/index.vue] <script setup lang="ts"> const router = useRouter() </script> ``` If you only need the router instance within your template, use `$router`: ```vue [pages/index.vue] <template> <button @click="$router.back()"> Back </button> </template> ``` If you have a `pages/` directory, `useRouter` is identical in behavior to the one provided by `vue-router`. <read-more to="https://router.vuejs.org/api/interfaces/router#Properties-currentRoute-" icon="i-simple-icons-vuedotjs" target="_blank"> Read `vue-router` documentation about the `Router` interface. </read-more> ## Basic Manipulation - [`addRoute()`](https://router.vuejs.org/api/interfaces/router#addRoute-): Add a new route to the router instance. `parentName` can be provided to add new route as the child of an existing route. - [`removeRoute()`](https://router.vuejs.org/api/interfaces/router#removeRoute-): Remove an existing route by its name. - [`getRoutes()`](https://router.vuejs.org/api/interfaces/router#getRoutes-): Get a full list of all the route records. - [`hasRoute()`](https://router.vuejs.org/api/interfaces/router#hasRoute-): Checks if a route with a given name exists. - [`resolve()`](https://router.vuejs.org/api/interfaces/router#resolve-): Returns the normalized version of a route location. Also includes an `href` property that includes any existing base. ```ts [Example] const router = useRouter() router.addRoute({ name: 'home', path: '/home', component: Home }) router.removeRoute('home') router.getRoutes() router.hasRoute('home') router.resolve({ name: 'home' }) ``` <note> `router.addRoute()` adds route details into an array of routes and it is useful while building [Nuxt plugins](https://nuxt.com/docs/3.x/directory-structure/plugins) while `router.push()` on the other hand, triggers a new navigation immediately and it is useful in pages, Vue components and composable. </note> ## Based on History API - [`back()`](https://router.vuejs.org/api/interfaces/router#back-): Go back in history if possible, same as `router.go(-1)`. - [`forward()`](https://router.vuejs.org/api/interfaces/router#forward-): Go forward in history if possible, same as `router.go(1)`. - [`go()`](https://router.vuejs.org/api/interfaces/router#go-): Move forward or backward through the history without the hierarchical restrictions enforced in `router.back()` and `router.forward()`. - [`push()`](https://router.vuejs.org/api/interfaces/router#push-): Programmatically navigate to a new URL by pushing an entry in the history stack. **It is recommended to use navigateTo instead.** - [`replace()`](https://router.vuejs.org/api/interfaces/router#replace-): Programmatically navigate to a new URL by replacing the current entry in the routes history stack. **It is recommended to use navigateTo instead.** ```ts [Example] const router = useRouter() router.back() router.forward() router.go(3) router.push({ path: '/home' }) router.replace({ hash: '#bio' }) ``` <read-more to="https://developer.mozilla.org/en-US/docs/Web/API/History" icon="i-simple-icons-mdnwebdocs" target="_blank"> Read more about the browser's History API. </read-more> ## Navigation Guards `useRouter` composable provides `afterEach`, `beforeEach` and `beforeResolve` helper methods that acts as navigation guards. However, Nuxt has a concept of **route middleware** that simplifies the implementation of navigation guards and provides a better developer experience. <read-more to="https://nuxt.com/docs/3.x/directory-structure/middleware"> </read-more> ## Promise and Error Handling - [`isReady()`](https://router.vuejs.org/api/interfaces/router#isReady-): Returns a Promise that resolves when the router has completed the initial navigation. - [`onError`](https://router.vuejs.org/api/interfaces/router#onError-): Adds an error handler that is called every time a non caught error happens during navigation. <read-more to="https://router.vuejs.org/api/interfaces/router#Methods-" icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs"> </read-more> ## Universal Router Instance If you do not have a `pages/` folder, then [`useRouter`](https://nuxt.com/docs/3.x/api/composables/use-router) will return a universal router instance with similar helper methods, but be aware that not all features may be supported or behave in exactly the same way as with `vue-router`. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # useRuntimeConfig > Access runtime config variables with the useRuntimeConfig composable. ## Usage ```vue [app.vue] <script setup lang="ts"> const config = useRuntimeConfig() </script> ``` ```ts [server/api/foo.ts] export default defineEventHandler((event) => { const config = useRuntimeConfig(event) }) ``` <read-more to="https://nuxt.com/docs/3.x/guide/going-further/runtime-config"> </read-more> ## Define Runtime Config The example below shows how to set a public API base URL and a secret API token that is only accessible on the server. We should always define `runtimeConfig` variables inside `nuxt.config`. ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { // Private keys are only available on the server apiSecret: '123', // Public keys that are exposed to the client public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api', }, }, }) ``` <note> Variables that need to be accessible on the server are added directly inside `runtimeConfig`. Variables that need to be accessible on both the client and the server are defined in `runtimeConfig.public`. </note> <read-more to="https://nuxt.com/docs/3.x/guide/going-further/runtime-config"> </read-more> ## Access Runtime Config To access runtime config, we can use `useRuntimeConfig()` composable: ```ts [server/api/test.ts] export default defineEventHandler(async (event) => { const config = useRuntimeConfig(event) // Access public variables const result = await $fetch(`/test`, { baseURL: config.public.apiBase, headers: { // Access a private variable (only available on the server) Authorization: `Bearer ${config.apiSecret}`, }, }) return result }) ``` In this example, since `apiBase` is defined within the `public` namespace, it is universally accessible on both server and client-side, while `apiSecret` **is only accessible on the server-side**. ## Environment Variables It is possible to update runtime config values using a matching environment variable name prefixed with `NUXT_`. <read-more to="https://nuxt.com/docs/3.x/guide/going-further/runtime-config"> </read-more> ### Using the `.env` File We can set the environment variables inside the `.env` file to make them accessible during **development** and **build/generate**. ```ini [.env] NUXT_PUBLIC_API_BASE = "https://api.localhost:5555" NUXT_API_SECRET = "123" ``` <note> Any environment variables set within `.env` file are accessed using `process.env` in the Nuxt app during **development** and **build/generate**. </note> <warning> In **production runtime**, you should use platform environment variables and `.env` is not used. </warning> <read-more to="https://nuxt.com/docs/3.x/directory-structure/env"> </read-more> ## `app` namespace Nuxt uses `app` namespace in runtime-config with keys including `baseURL` and `cdnURL`. You can customize their values at runtime by setting environment variables. <note> This is a reserved namespace. You should not introduce additional keys inside `app`. </note> ### `app.baseURL` By default, the `baseURL` is set to `'/'`. However, the `baseURL` can be updated at runtime by setting the `NUXT_APP_BASE_URL` as an environment variable. Then, you can access this new base URL using `config.app.baseURL`: ```ts [/plugins/my-plugin.ts] export default defineNuxtPlugin((NuxtApp) => { const config = useRuntimeConfig() // Access baseURL universally const baseURL = config.app.baseURL }) ``` ### `app.cdnURL` This example shows how to set a custom CDN url and access them using `useRuntimeConfig()`. You can use a custom CDN for serving static assets inside `.output/public` using the `NUXT_APP_CDN_URL` environment variable. And then access the new CDN url using `config.app.cdnURL`. ```ts [server/api/foo.ts] export default defineEventHandler((event) => { const config = useRuntimeConfig(event) // Access cdnURL universally const cdnURL = config.app.cdnURL }) ``` <read-more to="https://nuxt.com/docs/3.x/guide/going-further/runtime-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # useRuntimeHook > Registers a runtime hook in a Nuxt application and ensures it is properly disposed of when the scope is destroyed. <important> This composable is available in Nuxt v3.14+. </important> ```ts [signature] function useRuntimeHook<THookName extends keyof RuntimeNuxtHooks> ( name: THookName, fn: RuntimeNuxtHooks[THookName] extends HookCallback ? RuntimeNuxtHooks[THookName] : never, ): void ``` ## Usage ### Parameters - `name`: The name of the runtime hook to register. You can see the full list of [runtime Nuxt hooks here](https://nuxt.com/docs/3.x/api/advanced/hooks#app-hooks-runtime). - `fn`: The callback function to execute when the hook is triggered. The function signature varies based on the hook name. ### Returns The composable doesn't return a value, but it automatically unregisters the hook when the component's scope is destroyed. ## Example ```vue [pages/index.vue]twoslash <script setup lang="ts"> // Register a hook that runs every time a link is prefetched, but which will be // automatically cleaned up (and not called again) when the component is unmounted useRuntimeHook('link:prefetch', (link) => { console.log('Prefetching', link) }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/runtime-hook.ts) # useSeoMeta > The useSeoMeta composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. This helps you avoid common mistakes, such as using `name` instead of `property`, as well as typos - with over 100+ meta tags fully typed. <important> This is the recommended way to add meta tags to your site as it is XSS safe and has full TypeScript support. </important> <read-more to="https://nuxt.com/docs/3.x/getting-started/seo-meta"> </read-more> ## Usage ```vue [app.vue] <script setup lang="ts"> useSeoMeta({ title: 'My Amazing Site', ogTitle: 'My Amazing Site', description: 'This is my amazing site, let me tell you all about it.', ogDescription: 'This is my amazing site, let me tell you all about it.', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script> ``` When inserting tags that are reactive, you should use the computed getter syntax (`() => value`): ```vue [app.vue] <script setup lang="ts"> const title = ref('My title') useSeoMeta({ title, description: () => `This is a description for the ${title.value} page`, }) </script> ``` ## Parameters There are over 100 parameters. See the [full list of parameters in the source code](https://github.com/harlan-zw/zhead/blob/main/packages/zhead/src/metaFlat.ts#L1035). <read-more to="https://nuxt.com/docs/3.x/getting-started/seo-meta"> </read-more> ## Performance In most instances, SEO meta tags don't need to be reactive as search engine robots primarily scan the initial page load. For better performance, you can wrap your `useSeoMeta` calls in a server-only condition when the meta tags don't need to be reactive: ```vue [app.vue] <script setup lang="ts"> if (import.meta.server) { // These meta tags will only be added during server-side rendering useSeoMeta({ robots: 'index, follow', description: 'Static description that does not need reactivity', ogImage: 'https://example.com/image.png', // other static meta tags... }) } const dynamicTitle = ref('My title') // Only use reactive meta tags outside the condition when necessary useSeoMeta({ title: () => dynamicTitle.value, ogTitle: () => dynamicTitle.value, }) </script> ``` This previously used the [`useServerSeoMeta`](https://nuxt.com/docs/3.x/api/composables/use-server-seo-meta) composable, but it has been deprecated in favor of this approach. --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useServerSeoMeta > The useServerSeoMeta composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. Just like [`useSeoMeta`](https://nuxt.com/docs/3.x/api/composables/use-seo-meta), `useServerSeoMeta` composable lets you define your site's SEO meta tags as a flat object with full TypeScript support. <read-more to="https://nuxt.com/docs/3.x/api/composables/use-seo-meta"> </read-more> In most instances, the meta doesn't need to be reactive as robots will only scan the initial load. So we recommend using [`useServerSeoMeta`](https://nuxt.com/docs/3.x/api/composables/use-server-seo-meta) as a performance-focused utility that will not do anything (or return a `head` object) on the client. ```vue [app.vue] <script setup lang="ts"> useServerSeoMeta({ robots: 'index, follow', }) </script> ``` Parameters are exactly the same as with [`useSeoMeta`](https://nuxt.com/docs/3.x/api/composables/use-seo-meta) <read-more to="https://nuxt.com/docs/3.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/unjs/unhead/blob/main/packages/vue/src/composables.ts) # useState > The useState composable creates a reactive and SSR-friendly shared state. ## Usage ```ts // Create a reactive state and set default value const count = useState('counter', () => Math.round(Math.random() * 100)) ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/state-management"> </read-more> <important> Because the data inside `useState` will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. </important> <warning> `useState` is a reserved function name transformed by the compiler, so you should not name your own function `useState`. </warning> <video-accordion title="Watch a video from Alexander Lichter about why and when to use useState" video-id="mv0WcBABcIk"> </video-accordion> ## Using `shallowRef` If you don't need your state to be deeply reactive, you can combine `useState` with [`shallowRef`](https://vuejs.org/api/reactivity-advanced#shallowref). This can improve performance when your state contains large objects and arrays. ```ts const state = useState('my-shallow-state', () => shallowRef({ deep: 'not reactive' })) // isShallow(state) === true ``` ## Type ```ts [Signature] export function useState<T> (init?: () => T | Ref<T>): Ref<T> export function useState<T> (key: string, init?: () => T | Ref<T>): Ref<T> ``` - `key`: A unique key ensuring that data fetching is properly de-duplicated across requests. If you do not provide a key, then a key that is unique to the file and line number of the instance of [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) will be generated for you. - `init`: A function that provides initial value for the state when not initiated. This function can also return a `Ref`. - `T`: (typescript only) Specify the type of state ## Troubleshooting ### `Cannot stringify arbitrary non-POJOs` This error occurs when you try to store a non-serializable payload with `useState`, such as class instances. If you want to store class instances with `useState` that are not supported by Nuxt, you can use [`definePayloadPlugin`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#custom-reducerreviver) to add a custom serializer and deserializer for your classes. <read-more to="https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#payload"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/state.ts) # Auto-imports > Nuxt Kit provides a set of utilities to help you work with auto-imports. These functions allow you to register your own utils, composables and Vue APIs. Nuxt auto-imports helper functions, composables and Vue APIs to use across your application without explicitly importing them. Based on the directory structure, every Nuxt application can also use auto-imports for its own composables and plugins. With Nuxt Kit you can also add your own auto-imports. `addImports` and `addImportsDir` allow you to add imports to the Nuxt application. `addImportsSources` allows you to add listed imports from 3rd party packages to the Nuxt application. These utilities are powered by [`unimport`](https://github.com/unjs/unimport), which provides the underlying auto-import mechanism used in Nuxt. <note> These functions are designed for registering your own utils, composables and Vue APIs. For pages, components and plugins, please refer to the specific sections: [Pages](https://nuxt.com/docs/3.x/api/kit/pages), [Components](https://nuxt.com/docs/3.x/api/kit/components), [Plugins](https://nuxt.com/docs/3.x/api/kit/plugins). </note> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/expanding-nuxt-s-auto-imports?friend=nuxt"> Watch Vue School video about Auto-imports Nuxt Kit utilities. </tip> ## `addImports` Add imports to the Nuxt application. It makes your imports available in the Nuxt app context without the need to import them manually. <tip> To add imports for the Nitro server context, refer to the [`addServerImports`](https://nuxt.com/docs/3.x/api/kit/nitro#addserverimports) function. </tip> ### Usage ```tstwoslash import { addImports, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const names = [ 'useStoryblok', 'useStoryblokApi', 'useStoryblokBridge', 'renderRichText', 'RichTextSchema', ] names.forEach(name => addImports({ name, as: name, from: '@storyblok/vue' }), ) }, }) ``` ### Type ```ts function addImports (imports: Import | Import[]): void ``` ### Parameters `imports`: An object or an array of objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Import name to be detected. </td> </tr> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the import; if multiple imports have the same name, the one with the highest priority will be used. </td> </tr> <tr> <td> <code> disabled </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is disabled. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Record<string, any> </code> </td> <td> <code> false </code> </td> <td> Metadata of the import. </td> </tr> <tr> <td> <code> type </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is a pure type import. </td> </tr> <tr> <td> <code> typeFrom </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Use this as the <code> from </code> value when generating type declarations. </td> </tr> <tr> <td> <code> as </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Import as this name. </td> </tr> </tbody> </table> ## `addImportsDir` Add imports from a directory to the Nuxt application. It will automatically import all files from the directory and make them available in the Nuxt application without the need to import them manually. ### Usage ```tstwoslash import { addImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: '@vueuse/motion', configKey: 'motion', }, setup (options, nuxt) { const resolver = createResolver(import.meta.url) addImportsDir(resolver.resolve('./runtime/composables')) }, }) ``` ### Type ```ts function addImportsDir (dirs: string | string[], options?: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A string or an array of strings with the path to the directory to import from. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> { </span> <span class="sZSNi"> prepend </span> <span class="sDfIl"> ?: </span> <span class="sZSNi"> boolean </span> <span class="sDfIl"> } </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the import. If <code> prepend </code> is set to <code> true </code> , the imports will be prepended to the list of imports. </td> </tr> </tbody> </table> ## `addImportsSources` Add listed imports to the Nuxt application. ### Usage ```tstwoslash import { addImportsSources, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addImportsSources([ { package: '@vueuse/core' }, { from: 'h3', imports: [ 'defineEventHandler', 'getQuery', 'getRouterParams', 'readBody', 'sendRedirect', ], }, ]) }, }) ``` ### Type ```ts function addImportsSources (importSources: Preset | Preset[]): void ``` ### Parameters **importSources**: An object or an array of objects with the following properties: - InlinePreset <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> imports </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> PresetImport </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ImportSource[] </span> </code> </td> <td> <code> true </code> </td> <td> An object or an array of objects, which can be import names, import objects or import sources. </td> </tr> </tbody> </table> - PackagePreset <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> package </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Name of the package. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/imports.ts) # Builder > Nuxt Kit provides a set of utilities to help you work with the builder. These functions allow you to extend the Vite and webpack configurations. Nuxt have builders based on [Vite](https://github.com/nuxt/nuxt/tree/main/packages/vite) and [webpack](https://github.com/nuxt/nuxt/tree/main/packages/webpack). You can extend the config passed to each one using `extendViteConfig` and `extendWebpackConfig` functions. You can also add additional plugins via `addVitePlugin`, `addWebpackPlugin` and `addBuildPlugin`. ## `extendViteConfig` Extends the Vite configuration. Callback function can be called multiple times, when applying to both client and server builds. <warning> This hook is now deprecated, and we recommend using a Vite plugin instead with a `config` hook, or โ€” for environment-specific configuration โ€” the `applyToEnvironment` hook. </warning> ### Usage ```tstwoslash import { defineNuxtModule, extendViteConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendViteConfig((config) => { config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('cross-fetch') }) }, }) ``` For environment-specific configuration in Nuxt 5+, use `addVitePlugin()` instead: ```tstwoslash import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // For global configuration (affects all environments) addVitePlugin(() => ({ name: 'my-global-plugin', config (config) { // This runs before environment setup config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('cross-fetch') }, })) // For environment-specific configuration addVitePlugin(() => ({ name: 'my-client-plugin', applyToEnvironment (environment) { return environment.name === 'client' }, configEnvironment (name, config) { // This only affects the client environment config.optimizeDeps ||= {} config.optimizeDeps.include ||= [] config.optimizeDeps.include.push('client-only-package') }, })) }, }) ``` <warning> **Important:** The `config` hook runs before `applyToEnvironment` and modifies the global configuration. Use `configEnvironment` for environment-specific configuration changes. </warning> ### Type ```tstwoslash // @errors: 2391 import type { UserConfig as ViteConfig } from 'vite' import type { ExtendViteConfigOptions } from '@nuxt/kit' // ---cut--- function extendViteConfig (callback: ((config: ViteConfig) => void), options?: ExtendViteConfigOptions): void ``` <read-more icon="i-simple-icons-vite" target="_blank" to="https://vite.dev/config/"> Check out the Vite website for more information about its configuration. </read-more> ### Parameters **callback**: A callback function that will be called with the Vite configuration object. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> addVitePlugin() </code> with <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> addVitePlugin() </code> with <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `extendWebpackConfig` Extends the webpack configuration. Callback function can be called multiple times, when applying to both client and server builds. ### Usage ```tstwoslash import { defineNuxtModule, extendWebpackConfig } from '@nuxt/kit' export default defineNuxtModule({ setup () { extendWebpackConfig((config) => { config.module!.rules!.push({ test: /\.txt$/, use: 'raw-loader', }) }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Configuration as WebpackConfig } from 'webpack' import type { ExtendWebpackConfigOptions } from '@nuxt/kit' // ---cut--- function extendWebpackConfig (callback: ((config: WebpackConfig) => void), options?: ExtendWebpackConfigOptions): void ``` <read-more icon="i-simple-icons-webpack" target="_blank" to="https://webpack.js.org/configuration/"> Check out webpack website for more information about its configuration. </read-more> ### Parameters **callback**: A callback function that will be called with the webpack configuration object. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addVitePlugin` Append Vite plugin to the config. <warning> In Nuxt 5+, plugins registered with `server: false` or `client: false` options will not have their `config` or `configResolved` hooks called. Instead, use the `applyToEnvironment()` method instead for environment-specific plugins. </warning> ### Usage ```tstwoslash // @errors: 2307 // ---cut--- import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' import { svg4VuePlugin } from 'vite-plugin-svg4vue' export default defineNuxtModule({ meta: { name: 'nuxt-svg-icons', configKey: 'nuxtSvgIcons', }, defaults: { svg4vue: { assetsDirName: 'assets/icons', }, }, setup (options) { addVitePlugin(svg4VuePlugin(options.svg4vue)) // or, to add a vite plugin to only one environment addVitePlugin(() => ({ name: 'my-client-plugin', applyToEnvironment (environment) { return environment.name === 'client' }, // ... rest of your client-only plugin })) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Plugin as VitePlugin } from 'vite' import type { ExtendViteConfigOptions } from '@nuxt/kit' // ---cut--- function addVitePlugin (pluginOrGetter: VitePlugin | VitePlugin[] | (() => VitePlugin | VitePlugin[]), options?: ExtendViteConfigOptions): void ``` <tip> See [Vite website](https://vite.dev/guide/api-plugin) for more information about Vite plugins. You can also use [this repository](https://github.com/vitejs/awesome-vite#plugins) to find a plugin that suits your needs. </tip> ### Parameters **pluginOrGetter**: A Vite plugin instance or an array of Vite plugin instances. If a function is provided, it must return a Vite plugin instance or an array of Vite plugin instances. The function can also be async or return a Promise, which is useful for lazy-loading plugins: ```tstwoslash // @errors: 2307 import { addVitePlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // Lazy load the plugin - only imported when the build actually runs addVitePlugin(() => import('my-vite-plugin').then(r => r.default())) }, }) ``` **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. <strong> Deprecated in Nuxt 5+. </strong> Use <code> applyToEnvironment() </code> instead. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addWebpackPlugin` Append webpack plugin to the config. ### Usage ```ts import EslintWebpackPlugin from 'eslint-webpack-plugin' import { addWebpackPlugin, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'nuxt-eslint', configKey: 'eslint', }, defaults: nuxt => ({ include: [`${nuxt.options.srcDir}/**/*.{js,jsx,ts,tsx,vue}`], lintOnStart: true, }), setup (options, nuxt) { const webpackOptions = { ...options, context: nuxt.options.srcDir, files: options.include, lintDirtyModulesOnly: !options.lintOnStart, } addWebpackPlugin(new EslintWebpackPlugin(webpackOptions), { server: false }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { WebpackPluginInstance } from 'webpack' import type { ExtendWebpackConfigOptions } from '@nuxt/kit' // ---cut--- function addWebpackPlugin (pluginOrGetter: WebpackPluginInstance | WebpackPluginInstance[] | (() => WebpackPluginInstance | WebpackPluginInstance[]), options?: ExtendWebpackConfigOptions): void ``` <tip> See [webpack website](https://webpack.js.org/concepts/plugins/) for more information about webpack plugins. You can also use [this collection](https://webpack.js.org/awesome-webpack/#webpack-plugins) to find a plugin that suits your needs. </tip> ### Parameters **pluginOrGetter**: A webpack plugin instance or an array of webpack plugin instances. If a function is provided, it must return a webpack plugin instance or an array of webpack plugin instances. The function can also be async or return a Promise, enabling lazy-loading of plugins. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addBuildPlugin` Builder-agnostic version of `addVitePlugin` and `addWebpackPlugin`. It will add the plugin to both Vite and webpack configurations if they are present. ### Type ```tstwoslash // @errors: 2391 import type { ExtendConfigOptions } from '@nuxt/kit' import type { Plugin as VitePlugin } from 'vite' import type { WebpackPluginInstance } from 'webpack' import type { RspackPluginInstance } from '@rspack/core' interface AddBuildPluginFactory { vite?: () => VitePlugin | VitePlugin[] webpack?: () => WebpackPluginInstance | WebpackPluginInstance[] rspack?: () => RspackPluginInstance | RspackPluginInstance[] } // ---cut--- function addBuildPlugin (pluginFactory: AddBuildPluginFactory, options?: ExtendConfigOptions): void ``` ### Parameters **pluginFactory**: A factory function that returns an object with `vite` and/or `webpack` properties. These properties must be functions that return a Vite plugin instance or an array of Vite plugin instances and/or a webpack plugin instance or an array of webpack plugin instances. **options**: Options to pass to the callback function. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in development mode. </td> </tr> <tr> <td> <code> build </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building in production mode. </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the server bundle. </td> </tr> <tr> <td> <code> client </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be called when building the client bundle. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the callback function will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/build.ts) # Compatibility > Nuxt Kit provides a set of utilities to help you check the compatibility of your modules with different Nuxt versions. Nuxt Kit utilities can be used in Nuxt 3, Nuxt 2 with Bridge and even Nuxt 2 without Bridge. To make sure your module is compatible with all versions, you can use the `checkNuxtCompatibility`, `assertNuxtCompatibility` and `hasNuxtCompatibility` functions. They will check if the current Nuxt version meets the constraints you provide. Also you can use `isNuxt2`, `isNuxt3` and `getNuxtVersion` functions for more granular checks. ## `checkNuxtCompatibility` Checks if constraints are met for the current Nuxt version. If not, returns an array of messages. Nuxt 2 version also checks for `bridge` support. ### Usage ```tstwoslash import { checkNuxtCompatibility, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (_options, nuxt) { const issues = await checkNuxtCompatibility({ nuxt: '^2.16.0' }, nuxt) if (issues.length) { console.warn('Nuxt compatibility issues found:\n' + issues.toString()) } else { // do something } }, }) ``` ### Type ```ts function checkNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<NuxtCompatibilityIssues> ``` ### Parameters **constraints**: Version and builder constraints to check against. It accepts the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> nuxt </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Nuxt version in semver format. Versions may be defined in Node.js way, for example: <code> >=2.15.0 <3.0.0 </code> . </td> </tr> <tr> <td> <code> bridge </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sbKd-"> false </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Specifies version constraints or disables compatibility for specific Nuxt builders like <code> vite </code> , <code> webpack </code> , or <code> rspack </code> . Use <code> false </code> to disable. </td> </tr> </tbody> </table> **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `assertNuxtCompatibility` Asserts that constraints are met for the current Nuxt version. If not, throws an error with the list of issues as string. ### Type ```tstwoslash // @errors: 2391 import type { Nuxt, NuxtCompatibility } from '@nuxt/schema' // ---cut--- function assertNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<true> ``` ### Parameters **constraints**: Version and builder constraints to check against. Refer to the [constraints table in `checkNuxtCompatibility`](https://nuxt.com/docs/3.x/api/kit/compatibility#parameters) for details. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `hasNuxtCompatibility` Checks if constraints are met for the current Nuxt version. Return `true` if all constraints are met, otherwise returns `false`. Nuxt 2 version also checks for `bridge` support. ### Usage ```tstwoslash import { defineNuxtModule, hasNuxtCompatibility } from '@nuxt/kit' export default defineNuxtModule({ async setup (_options, nuxt) { const usingNewPostcss = await hasNuxtCompatibility({ nuxt: '^2.16.0' }, nuxt) if (usingNewPostcss) { // do something } else { // do something else } }, }) ``` ### Type ```ts function hasNuxtCompatibility (constraints: NuxtCompatibility, nuxt?: Nuxt): Promise<boolean> ``` ### Parameters **constraints**: Version and builder constraints to check against. Refer to the [constraints table in `checkNuxtCompatibility`](https://nuxt.com/docs/3.x/api/kit/compatibility#parameters) for details. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxtMajorVersion` Check if current Nuxt instance is of specified major version ### Usage ```tstwoslash import { defineNuxtModule, isNuxtMajorVersion } from '@nuxt/kit' export default defineNuxtModule({ setup () { if (isNuxtMajorVersion(3)) { // do something for Nuxt 3 } else { // do something else for other versions } }, }) ``` ### Type ```ts function isNuxtMajorVersion (major: number, nuxt?: Nuxt): boolean ``` ### Parameters **major**: Major version to check against. **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxt3` Checks if the current Nuxt version is 3.x. <note> Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in @nuxt/kit v5 or a future major version. </note> ### Type ```ts function isNuxt3 (nuxt?: Nuxt): boolean ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `isNuxt2` Checks if the current Nuxt version is 2.x. <note> Use `isNuxtMajorVersion(2, nuxt)` instead. This may be removed in @nuxt/kit v5 or a future major version. </note> ### Type ```ts function isNuxt2 (nuxt?: Nuxt): boolean ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. ## `getNuxtVersion` Returns the current Nuxt version. ### Type ```ts function getNuxtVersion (nuxt?: Nuxt): string ``` ### Parameters **nuxt**: Nuxt instance. If not provided, it will be retrieved from the context via `useNuxt()` call. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/compatibility.ts) # Components > Nuxt Kit provides a set of utilities to help you work with components. You can register components globally or locally, and also add directories to be scanned for components. Components are the building blocks of your Nuxt application. They are reusable Vue instances that can be used to create a user interface. In Nuxt, components from the components directory are automatically imported by default. However, if you need to import components from an alternative directory or wish to selectively import them as needed, `@nuxt/kit` provides the `addComponentsDir` and `addComponent` methods. These utils allow you to customize the component configuration to better suit your needs. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-components-and-component-directories?friend=nuxt"> Watch Vue School video about injecting components. </tip> ## `addComponentsDir` Register a directory to be scanned for components and imported only when used. Keep in mind, that this does not register components globally, until you specify `global: true` option. ### Usage ```ts export default defineNuxtModule({ meta: { name: '@nuxt/ui', configKey: 'ui', }, setup () { addComponentsDir({ path: resolve('./runtime/components'), prefix: 'U', pathPrefix: false, }) }, }) ``` ### Type ```ts function addComponentsDir (dir: ComponentsDir, opts: { prepend?: boolean } = {}): void ``` ### Parameters `dir` An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path (absolute or relative) to the directory containing your components. You can use Nuxt aliases (~ or @) to refer to directories inside project or directly use an npm package path similar to require. </td> </tr> <tr> <td> <code> pattern </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> false </code> </td> <td> Accept Pattern that will be run against specified path. </td> </tr> <tr> <td> <code> ignore </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Ignore patterns that will be run against specified path. </td> </tr> <tr> <td> <code> prefix </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Prefix all matched components with this string. </td> </tr> <tr> <td> <code> pathPrefix </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Prefix component name by its path. </td> </tr> <tr> <td> <code> prefetch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> preload </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> isAsync </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> This flag indicates, component should be loaded async (with a separate chunk) regardless of using Lazy prefix or not. </td> </tr> <tr> <td> <code> extendComponent </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> component </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Component </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> Component </span> <span class="sDfIl"> | </span> <span class="sDfIl"> void> </span> <span class="sDfIl"> | </span> <span class="sZSNi"> (Component </span> <span class="sDfIl"> | </span> <span class="sDfIl"> void </span> <span class="sZSNi"> ) </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called for each component found in the directory. It accepts a component object and should return a component object or a promise that resolves to a component object. </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers components to be globally available. </td> </tr> <tr> <td> <code> island </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers components as islands. You can read more about islands in <a href="https://nuxt.com/docs/3.x/api/components/nuxt-island"> <code> <NuxtIsland/> </code> </a> component description. </td> </tr> <tr> <td> <code> watch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Watch specified path for changes, including file additions and file deletions. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Extensions supported by Nuxt builder. </td> </tr> <tr> <td> <code> transpile </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> auto </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sZSNi"> boolean </span> </code> </td> <td> <code> false </code> </td> <td> Transpile specified path using build.transpile. If set to <code> 'auto' </code> , it will set <code> transpile: true </code> if <code> node_modules/ </code> is in path. </td> </tr> </tbody> </table> `opts` <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the directory will be prepended to the array with <code> unshift() </code> instead of <code> push() </code> . </td> </tr> </tbody> </table> ## `addComponent` Register a component to be automatically imported. ### Usage ```ts import { addComponent, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: '@nuxt/image', configKey: 'image', }, setup () { const resolver = createResolver(import.meta.url) addComponent({ name: 'NuxtImg', filePath: resolver.resolve('./runtime/components/NuxtImg.vue'), }) addComponent({ name: 'NuxtPicture', filePath: resolver.resolve('./runtime/components/NuxtPicture.vue'), }) }, }) ``` ### Type ```ts function addComponent (options: AddComponentOptions): void ``` ### Parameters `options`: An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Component name. </td> </tr> <tr> <td> <code> filePath </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the component. </td> </tr> <tr> <td> <code> declarationPath </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to component's declaration file. It is used to generate components' <a href="https://nuxt.com/docs/3.x/api/kit/templates#addtypetemplate"> type templates </a> ; if not provided, <code> filePath </code> is used instead. </td> </tr> <tr> <td> <code> pascalName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Pascal case component name. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> kebabName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Kebab case component name. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> export </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Specify named or default export. If not provided, it will be set to <code> 'default' </code> . </td> </tr> <tr> <td> <code> shortPath </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Short path to the component. If not provided, it will be generated from the component path. </td> </tr> <tr> <td> <code> chunkName </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Chunk name for the component. If not provided, it will be generated from the component name. </td> </tr> <tr> <td> <code> prefetch </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> preload </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> These properties (prefetch/preload) are used in production to configure how components with Lazy prefix are handled by webpack via its magic comments. Learn more on <a href="https://webpack.js.org/api/module-methods/#magic-comments" rel="nofollow"> webpack documentation </a> </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers component to be globally available. </td> </tr> <tr> <td> <code> island </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If enabled, registers component as island. You can read more about islands in <a href="https://nuxt.com/docs/3.x/api/components/nuxt-island"> <code> <NuxtIsland/> </code> </a> component description. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> This options indicates if component should render on client, server or both. By default, it will render on both client and server. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the component, if multiple components have the same name, the one with the highest priority will be used. </td> </tr> </tbody> </table> ### Examples If you want to auto-import a component from an npm package, and the component is a named export (rather than the default), you can use the `export` option to specify it. ```ts import { addComponent, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // import { MyComponent as MyAutoImportedComponent } from 'my-npm-package' addComponent({ name: 'MyAutoImportedComponent', export: 'MyComponent', filePath: 'my-npm-package', }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/components.ts) # Context > Nuxt Kit provides a set of utilities to help you work with context. Nuxt modules allow you to enhance Nuxt's capabilities. They offer a structured way to keep your code organized and modular. If you're looking to break down your module into smaller components, Nuxt offers the `useNuxt` and `tryUseNuxt` functions. These functions enable you to conveniently access the Nuxt instance from the context without having to pass it as an argument. <note> When you're working with the `setup` function in Nuxt modules, Nuxt is already provided as the second argument. This means you can access it directly without needing to call `useNuxt()`. </note> ## `useNuxt` Get the Nuxt instance from the context. It will throw an error if Nuxt is not available. ### Usage ```ts import { useNuxt } from '@nuxt/kit' const setupSomeFeature = () => { const nuxt = useNuxt() // You can now use the nuxt instance console.log(nuxt.options) } ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function useNuxt (): Nuxt ``` ### Return Value The `useNuxt` function returns the Nuxt instance, which contains all the options and methods available in Nuxt. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> options </code> </td> <td> <code> NuxtOptions </code> </td> <td> The resolved Nuxt configuration. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code> Hookable<NuxtHooks> </code> </td> <td> The Nuxt hook system. Allows registering and listening to lifecycle events. </td> </tr> <tr> <td> <code> hook </code> </td> <td> <code> (name: string, (...args: any[]) => Promise<void> | void) => () => void </code> </td> <td> Shortcut for <code> nuxt.hooks.hook </code> . Registers a single callback for a specific lifecycle hook. </td> </tr> <tr> <td> <code> callHook </code> </td> <td> <code> (name: string, ...args: any[]) => Promise<any> </code> </td> <td> Shortcut for <code> nuxt.hooks.callHook </code> . Triggers a lifecycle hook manually and runs all registered callbacks. </td> </tr> <tr> <td> <code> addHooks </code> </td> <td> <code> (configHooks: NestedHooks) => () => void </code> </td> <td> Shortcut for <code> nuxt.hooks.addHooks </code> . Registers multiple hooks at once. </td> </tr> </tbody> </table> ### Examples <code-group> ```ts [setupTranspilation.ts]twoslash import { useNuxt } from '@nuxt/kit' export const setupTranspilation = () => { const nuxt = useNuxt() if (nuxt.options.builder === '@nuxt/webpack-builder') { nuxt.options.build.transpile ||= [] nuxt.options.build.transpile.push('xstate') } } ``` ```ts [module.ts]twoslash // @module: esnext // @filename: setupTranspilation.ts export const setupTranspilation = () => {} // @filename: module.ts import { defineNuxtModule } from '@nuxt/kit' // ---cut--- import { setupTranspilation } from './setupTranspilation' export default defineNuxtModule({ setup () { setupTranspilation() }, }) ``` </code-group> ## `tryUseNuxt` Get the Nuxt instance from the context. It will return `null` if Nuxt is not available. ### Usage ```tstwoslash import { tryUseNuxt } from '@nuxt/kit' function setupSomething () { const nuxt = tryUseNuxt() if (nuxt) { // You can now use the nuxt instance console.log(nuxt.options) } else { console.log('Nuxt is not available') } } ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function tryUseNuxt (): Nuxt | null ``` ### Return Value The `tryUseNuxt` function returns the Nuxt instance if available, or `null` if Nuxt is not available. The Nuxt instance as described in the `useNuxt` section. ### Examples <code-group> ```ts [requireSiteConfig.ts]twoslash declare module 'nuxt/schema' { interface NuxtOptions { siteConfig: SiteConfig } } // ---cut--- import { tryUseNuxt } from '@nuxt/kit' interface SiteConfig { title?: string } export const requireSiteConfig = (): SiteConfig => { const nuxt = tryUseNuxt() if (!nuxt) { return {} } return nuxt.options.siteConfig } ``` ```ts [module.ts]twoslash // @module: esnext // @filename: requireSiteConfig.ts interface SiteConfig { title?: string } export const requireSiteConfig = (): SiteConfig => { return {} } // @filename: module.ts // ---cut--- import { defineNuxtModule, useNuxt } from '@nuxt/kit' import { requireSiteConfig } from './requireSiteConfig' export default defineNuxtModule({ setup (_, nuxt) { const config = requireSiteConfig() nuxt.options.app.head.title = config.title }, }) ``` </code-group> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/context.ts) # Examples > Examples of Nuxt Kit utilities in use. ## Accessing Nuxt Vite Config If you are building an integration that needs access to the runtime Vite or webpack config that Nuxt uses, it is possible to extract this using Kit utilities. Some examples of projects doing this already: - [histoire](https://github.com/histoire-dev/histoire/blob/main/packages/histoire-plugin-nuxt/src/index.ts) - [nuxt-vitest](https://github.com/danielroe/nuxt-vitest/blob/main/packages/nuxt-vitest/src/config.ts) - [@storybook-vue/nuxt](https://github.com/storybook-vue/storybook-nuxt/blob/main/packages/storybook-nuxt/src/preset.ts) Here is a brief example of how you might access the Vite config from a project; you could implement a similar approach to get the webpack configuration. ```js import { buildNuxt, loadNuxt } from '@nuxt/kit' // https://github.com/nuxt/nuxt/issues/14534 async function getViteConfig () { const nuxt = await loadNuxt({ cwd: process.cwd(), dev: false, overrides: { ssr: false } }) return new Promise((resolve, reject) => { nuxt.hook('vite:extend', (config) => { resolve(config) throw new Error('_stop_') }) buildNuxt(nuxt).catch((err) => { if (!err.toString().includes('_stop_')) { reject(err) } }) }).finally(() => nuxt.close()) } const viteConfig = await getViteConfig() console.log(viteConfig) ``` # Head > Nuxt Kit provides utilities to help you manage head configuration in modules. ## `setGlobalHead` Sets global head configuration for your Nuxt application. This utility allows modules to programmatically configure meta tags, links, scripts, and other head elements that will be applied across all pages. The provided head configuration will be merged with any existing head configuration using deep merging, with your provided values taking precedence. <tip> This is particularly useful for modules that need to inject global meta tags, stylesheets, or scripts into the application head. </tip> ### Type ```tstwoslash // @errors: 2391 // ---cut--- import type { SerializableHead } from '@unhead/vue/types' interface AppHeadMetaObject extends SerializableHead { charset?: string viewport?: string } function setGlobalHead (head: AppHeadMetaObject): void ``` ### Parameters #### `head` **Type**: `AppHeadMetaObject` An object containing head configuration. All properties are optional and will be merged with existing configuration: - `charset`: Character encoding for the document - `viewport`: Viewport meta tag configuration - `meta`: Array of meta tag objects - `link`: Array of link tag objects (stylesheets, icons, etc.) - `style`: Array of inline style tag objects - `script`: Array of script tag objects - `noscript`: Array of noscript tag objects - `title`: Default page title - `titleTemplate`: Template for formatting page titles - `bodyAttrs`: Attributes to add to the `<body>` tag - `htmlAttrs`: Attributes to add to the `<html>` tag ### Examples #### Adding Global Meta Tags ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ meta: [ { name: 'theme-color', content: '#ffffff' }, { name: 'author', content: 'Your Name' }, ], }) }, }) ``` #### Injecting Global Stylesheets ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ link: [ { rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap', }, ], }) }, }) ``` #### Adding Global Scripts ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ script: [ { src: 'https://cdn.example.com/analytics.js', async: true, defer: true, }, ], }) }, }) ``` #### Setting HTML Attributes ```ts import { defineNuxtModule, setGlobalHead } from '@nuxt/kit' export default defineNuxtModule({ setup () { setGlobalHead({ htmlAttrs: { lang: 'en', dir: 'ltr', }, bodyAttrs: { class: 'custom-body-class', }, }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/head.ts) # Layers > Nuxt Kit provides utilities to help you work with layers and their directory structures. Nuxt layers provide a powerful way to share and extend functionality across projects. When working with layers in modules, you often need to access directory paths from each layer. Nuxt Kit provides the `getLayerDirectories` utility to access resolved directory paths for all layers in your Nuxt application. ## `getLayerDirectories` Get the resolved directory paths for all layers in a Nuxt application. This function provides a structured way to access layer directories without directly accessing the private `nuxt.options._layers` property. ### Usage ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Access directories from all layers for (const [index, layer] of layerDirs.entries()) { console.log(`Layer ${index}:`) console.log(` Root: ${layer.root}`) console.log(` App: ${layer.app}`) console.log(` Server: ${layer.server}`) console.log(` Pages: ${layer.appPages}`) // ... other directories } }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { Nuxt } from '@nuxt/schema' // ---cut--- function getLayerDirectories (nuxt?: Nuxt): LayerDirectories[] interface LayerDirectories { /** Nuxt rootDir (`/` by default) */ readonly root: string /** Nitro source directory (`/server` by default) */ readonly server: string /** Local modules directory (`/modules` by default) */ readonly modules: string /** Shared directory (`/shared` by default) */ readonly shared: string /** Public directory (`/public` by default) */ readonly public: string /** Nuxt srcDir (`/app/` by default) */ readonly app: string /** Layouts directory (`/layouts` by default) */ readonly appLayouts: string /** Middleware directory (`/middleware` by default) */ readonly appMiddleware: string /** Pages directory (`/pages` by default) */ readonly appPages: string /** Plugins directory (`/plugins` by default) */ readonly appPlugins: string } ``` ### Parameters **nuxt** (optional): The Nuxt instance to get layers from. If not provided, the function will use the current Nuxt context. ### Return Value The `getLayerDirectories` function returns an array of `LayerDirectories` objects, one for each layer in the application. **Layer Priority Ordering**: The layers are ordered by priority, where: - The **first layer** is the user/project layer (highest priority) - **Earlier layers override later layers** in the array - **Base layers appear last** in the array (lowest priority) This ordering matches Nuxt's layer resolution system, where user-defined configurations and files take precedence over those from base layers. **LayerDirectories**: An object containing the resolved directory paths for a layer. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> root </code> </td> <td> <code> string </code> </td> <td> The root directory of the layer (equivalent to <code> rootDir </code> ) </td> </tr> <tr> <td> <code> server </code> </td> <td> <code> string </code> </td> <td> The server directory for Nitro server-side code </td> </tr> <tr> <td> <code> modules </code> </td> <td> <code> string </code> </td> <td> The local modules directory </td> </tr> <tr> <td> <code> shared </code> </td> <td> <code> string </code> </td> <td> The shared directory for code used by both client and server </td> </tr> <tr> <td> <code> app </code> </td> <td> <code> string </code> </td> <td> The source directory of the layer (equivalent to <code> srcDir </code> ) </td> </tr> <tr> <td> <code> public </code> </td> <td> <code> string </code> </td> <td> The public directory for static assets </td> </tr> <tr> <td> <code> appLayouts </code> </td> <td> <code> string </code> </td> <td> The layouts directory for Vue layout components </td> </tr> <tr> <td> <code> appMiddleware </code> </td> <td> <code> string </code> </td> <td> The middleware directory for route middleware </td> </tr> <tr> <td> <code> appPages </code> </td> <td> <code> string </code> </td> <td> The pages directory for file-based routing </td> </tr> <tr> <td> <code> appPlugins </code> </td> <td> <code> string </code> </td> <td> The plugins directory for Nuxt plugins </td> </tr> </tbody> </table> ### Examples **Processing files from all layers:** ```tstwoslash // @errors: 2307 // ---cut--- import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { resolve } from 'pathe' import { globby } from 'globby' export default defineNuxtModule({ async setup () { const layerDirs = getLayerDirectories() // Find all component files across layers // Note: layerDirs[0] is the user layer (highest priority) // Later layers in the array have lower priority const componentFiles = [] for (const [index, layer] of layerDirs.entries()) { const files = await globby('**/*.vue', { cwd: resolve(layer.app, 'components'), absolute: true, }) console.log(`Layer ${index} (${index === 0 ? 'user' : 'base'}):`, files.length, 'components') componentFiles.push(...files) } }, }) ``` **Adding templates from multiple layers:** ```tstwoslash import { addTemplate, defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { basename, resolve } from 'pathe' import { existsSync } from 'node:fs' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Add a config file from each layer that has one for (const dirs of layerDirs) { const configPath = resolve(dirs.app, 'my-module.config.ts') if (existsSync(configPath)) { addTemplate({ filename: `my-module-${basename(dirs.root)}.config.ts`, src: configPath, }) } } }, }) ``` **Respecting layer priority:** ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { resolve } from 'pathe' import { existsSync, readFileSync } from 'node:fs' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Find the first (highest priority) layer that has a specific config file // This respects the layer priority system let configContent = null for (const dirs of layerDirs) { const configPath = resolve(dirs.app, 'my-config.json') if (existsSync(configPath)) { configContent = readFileSync(configPath, 'utf-8') console.log(`Using config from layer: ${dirs.root}`) break // Use the first (highest priority) config found } } // Alternative: Collect configs from all layers, with user layer taking precedence const allConfigs = {} for (const dirs of layerDirs.reverse()) { // Process from lowest to highest priority const configPath = resolve(dirs.app, 'my-config.json') if (existsSync(configPath)) { const config = JSON.parse(readFileSync(configPath, 'utf-8')) Object.assign(allConfigs, config) // Later assignments override earlier ones } } }, }) ``` **Checking for layer-specific directories:** ```tstwoslash import { defineNuxtModule, getLayerDirectories } from '@nuxt/kit' import { existsSync } from 'node:fs' import { resolve } from 'pathe' export default defineNuxtModule({ setup () { const layerDirs = getLayerDirectories() // Find layers that have a specific custom directory const layersWithAssets = layerDirs.filter((layer) => { return existsSync(resolve(layer.app, 'assets')) }) console.log(`Found ${layersWithAssets.length} layers with assets directory`) }, }) ``` <note> The `getLayerDirectories` function includes caching via a WeakMap to avoid recomputing directory paths for the same layers repeatedly, improving performance when called multiple times. </note> <note> Directory paths returned by this function always include a trailing slash for consistency. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/layers.ts) # Layout > Nuxt Kit provides a set of utilities to help you work with layouts. Layouts is used to be a wrapper around your pages. It can be used to wrap your pages with common components, for example, a header and a footer. Layouts can be registered using `addLayout` utility. ## `addLayout` Register template as layout and add it to the layouts. <note> In Nuxt 2 `error` layout can also be registered using this utility. In Nuxt 3+ `error` layout [replaced](https://nuxt.com/docs/3.x/getting-started/error-handling#error-page) with `error.vue` page in project root. </note> ### Usage ```tstwoslash import { addLayout, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addLayout({ src: resolve('templates/custom-layout.ts'), filename: 'custom-layout.ts', }, 'custom') }, }) ``` ### Type ```ts function addLayout (layout: NuxtTemplate | string, name: string): void ``` ### Parameters **layout**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> </tbody> </table> **name**: The name to register the layout under (e.g., `default`, `custom`, etc.). ### Example This will register a layout named `custom` that wraps pages with a header and footer. ```tstwoslash import { addLayout, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addLayout({ write: true, filename: 'my-layout.vue', getContents: () => `<template> <div> <header>My Header</header> <slot /> <footer>My Footer</footer> </div> </template>`, }, 'custom') }, }) ``` You can then use this layout in your pages: ```vue [pages/about.vue] <script setup lang="ts"> definePageMeta({ layout: 'custom', }) </script> <template> <div>About Page</div> </template> ``` <warning> Due to the lack of support for virtual `.vue` files by `@vitejs/plugin-vue`, you can work around this limitation by passing `write: true` to the first argument of `addLayout`. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/layout.ts) # Logging > Nuxt Kit provides a set of utilities to help you work with logging. These functions allow you to log messages with extra features. Nuxt provides a logger instance that you can use to log messages with extra features. `useLogger` allows you to get a logger instance. ## `useLogger` Returns a logger instance. It uses [consola](https://github.com/unjs/consola) under the hood. ### Usage ```tstwoslash import { defineNuxtModule, useLogger } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const logger = useLogger('my-module') logger.info('Hello from my module!') }, }) ``` ### Type ```ts function useLogger (tag?: string, options?: Partial<ConsolaOptions>): ConsolaInstance ``` ### Parameters **tag**: A tag to suffix all log messages with, displayed on the right near the timestamp. **options**: Consola configuration options. ### Examples ```tstwoslash import { defineNuxtModule, useLogger } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const logger = useLogger('my-module', { level: options.quiet ? 0 : 3 }) logger.info('Hello from my module!') }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/logger.ts) # Modules > Nuxt Kit provides a set of utilities to help you create and use modules. You can use these utilities to create your own modules or to reuse existing modules. Modules are the building blocks of Nuxt. Kit provides a set of utilities to help you create and use modules. You can use these utilities to create your own modules or to reuse existing modules. For example, you can use the `defineNuxtModule` function to define a module and specify dependencies using the `moduleDependencies` option. ## `defineNuxtModule` Define a Nuxt module, automatically merging defaults with user provided options, installing any hooks that are provided, and calling an optional setup function for full control. ### Usage ```tstwoslash import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, defaults: { enabled: true, }, setup (options) { if (options.enabled) { console.log('My Nuxt module is enabled!') } }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { ModuleDefinition, ModuleOptions, NuxtModule } from '@nuxt/schema' // ---cut--- export function defineNuxtModule<TOptions extends ModuleOptions> ( definition?: ModuleDefinition<TOptions, Partial<TOptions>, false> | NuxtModule<TOptions, Partial<TOptions>, false>, ): NuxtModule<TOptions, TOptions, false> export function defineNuxtModule<TOptions extends ModuleOptions> (): { with: <TOptionsDefaults extends Partial<TOptions>> ( definition: ModuleDefinition<TOptions, TOptionsDefaults, true> | NuxtModule<TOptions, TOptionsDefaults, true>, ) => NuxtModule<TOptions, TOptionsDefaults, true> } ``` ### Parameters **definition**: A module definition object or a module function. The module definition object should contain the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> meta </code> </td> <td> <code> ModuleMeta </code> </td> <td> <code> false </code> </td> <td> Metadata of the module. It defines the module name, version, config key and compatibility. </td> </tr> <tr> <td> <code> defaults </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> T </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> T) </span> </code> </td> <td> <code> false </code> </td> <td> Default options for the module. If a function is provided, it will be called with the Nuxt instance as the first argument. </td> </tr> <tr> <td> <code> schema </code> </td> <td> <code> T </code> </td> <td> <code> false </code> </td> <td> Schema for the module options. If provided, options will be applied to the schema. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Partial </span> <span class="sDfIl"> < </span> <span class="sZSNi"> NuxtHooks </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Hooks to be installed for the module. If provided, the module will install the hooks. </td> </tr> <tr> <td> <code> moduleDependencies </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> ModuleDependency </span> <span class="sDfIl"> > </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ( </span> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> ModuleDependency </span> <span class="sDfIl"> > </span> <span class="sZSNi"> ) </span> </code> </td> <td> <code> false </code> </td> <td> Dependencies on other modules with version constraints and configuration. Can be an object or a function that receives the Nuxt instance. See <a href="https://nuxt.com/docs/3.x/api/kit/modules#specifying-module-dependencies"> example </a> . </td> </tr> <tr> <td> <code> onInstall </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void> </span> </code> </td> <td> <code> false </code> </td> <td> Lifecycle hook called when the module is first installed. Requires <code> meta.name </code> and <code> meta.version </code> to be defined. </td> </tr> <tr> <td> <code> onUpgrade </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> , </span> <span class="s1nJG"> options </span> <span class="sDfIl"> : </span> <span class="s52Pk"> T </span> <span class="sDfIl"> , </span> <span class="s1nJG"> previousVersion </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void> </span> </code> </td> <td> <code> false </code> </td> <td> Lifecycle hook called when the module is upgraded to a newer version. Requires <code> meta.name </code> and <code> meta.version </code> to be defined. </td> </tr> <tr> <td> <code> setup </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s8R28"> this </span> <span class="sDfIl"> : </span> <span class="s52Pk"> void </span> <span class="sDfIl"> , </span> <span class="s1nJG"> resolvedOptions </span> <span class="sDfIl"> : </span> <span class="s52Pk"> T </span> <span class="sDfIl"> , </span> <span class="s1nJG"> nuxt </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Nuxt </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> Awaitable </span> <span class="sDfIl"> <void </span> <span class="sDfIl"> | </span> <span class="sbKd-"> false </span> <span class="sDfIl"> | </span> <span class="sZSNi"> ModuleSetupInstallResult </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Setup function for the module. If provided, the module will call the setup function. </td> </tr> </tbody> </table> ### Examples #### Using `configKey` to Make Your Module Configurable When defining a Nuxt module, you can set a `configKey` to specify how users should configure the module in their `nuxt.config`. ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, defaults: { // Module options enabled: true, }, setup (options) { if (options.enabled) { console.log('My Nuxt module is enabled!') } }, }) ``` Users can provide options for this module under the corresponding key in `nuxt.config`. ```ts export default defineNuxtConfig({ myModule: { enabled: false, }, }) ``` Users can also completely disable a module by setting the config key to `false`. This prevents the module's setup function from running while still generating types for module options. ```ts export default defineNuxtConfig({ // Disable the module entirely myModule: false, }) ``` <tip> This is particularly useful when you want to disable modules inherited from [Nuxt layers](https://nuxt.com/docs/3.x/guide/going-further/layers#disabling-modules-from-layers). </tip> #### Defining Module Compatibility Requirements If you're developing a Nuxt module and using APIs that are only supported in specific Nuxt versions, it's highly recommended to include `compatibility.nuxt`. ```ts export default defineNuxtModule({ meta: { name: '@nuxt/icon', configKey: 'icon', compatibility: { // Required nuxt version in semver format. nuxt: '>=3.0.0', // or use '^3.0.0' }, }, setup () { const resolver = createResolver(import.meta.url) // Implement }, }) ``` If the user tries to use your module with an incompatible Nuxt version, they will receive a warning in the console. ```terminal WARN Module @nuxt/icon is disabled due to incompatibility issues: - [nuxt] Nuxt version ^3.1.0 is required but currently using 3.0.0 ``` #### Type Safety for Resolved Options with `.with()` When you need type safety for your resolved/merged module options, you can use the `.with()` method. This enables TypeScript to properly infer the relationship between your module's defaults and the final resolved options that your setup function receives. ```ts import { defineNuxtModule } from '@nuxt/kit' // Define your module options interface interface ModuleOptions { apiKey: string baseURL: string timeout?: number retries?: number } export default defineNuxtModule<ModuleOptions>().with({ meta: { name: '@nuxtjs/my-api', configKey: 'myApi', }, defaults: { baseURL: 'https://api.example.com', timeout: 5000, retries: 3, }, setup (resolvedOptions, nuxt) { // resolvedOptions is properly typed as: // { // apiKey: string // Required, no default provided // baseURL: string // Required, has default value // timeout: number // Optional, has default value // retries: number // Optional, has default value // } console.log(resolvedOptions.baseURL) // โœ… TypeScript knows this is always defined console.log(resolvedOptions.timeout) // โœ… TypeScript knows this is always defined console.log(resolvedOptions.retries) // โœ… TypeScript knows this is always defined }, }) ``` Without using `.with()`, the `resolvedOptions` parameter would be typed as the raw `ModuleOptions` interface, where `timeout` and `retries` could be `undefined` even when defaults are provided. The `.with()` method enables TypeScript to understand that default values make those properties non-optional in the resolved options. #### Using Lifecycle Hooks for Module Installation and Upgrade You can define lifecycle hooks that run when your module is first installed or upgraded to a new version. These hooks are useful for performing one-time setup tasks, database migrations, or cleanup operations. <important> For lifecycle hooks to work, you **must** provide both `meta.name` and `meta.version` in your module definition. The hooks use these values to track the module's installation state in the project's `.nuxtrc` file. </important> Lifecycle hooks run before the main `setup` function, and if a hook throws an error, it's logged but doesn't stop the build process. **onInstall** runs only once when the module is first added to a project. **onUpgrade** runs each time the module version increases (using semver comparison) โ€” but only once for each version bump. ##### Example ```ts import { defineNuxtModule } from '@nuxt/kit' import semver from 'semver' export default defineNuxtModule({ meta: { name: 'my-awesome-module', version: '1.2.0', // Required for lifecycle hooks configKey: 'myAwesomeModule', }, defaults: { apiKey: '', enabled: true, }, onInstall (nuxt) { // This runs only when the module is first installed console.log('Setting up my-awesome-module for the first time!') // You might want to: // - Create initial configuration files // - Set up database schemas // - Display welcome messages // - Perform initial data migration }, onUpgrade (nuxt, options, previousVersion) { // This runs when the module is upgraded to a newer version console.log(`Upgrading my-awesome-module from ${previousVersion} to 1.2.0`) // You might want to: // - Migrate configuration files // - Update database schemas // - Clean up deprecated files // - Display upgrade notes if (semver.lt(previousVersion, '1.1.0')) { console.log('โš ๏ธ Breaking changes in 1.1.0 - please check the migration guide') } }, setup (options, nuxt) { // Regular setup logic runs on every build if (options.enabled) { // Configure the module } }, }) ``` #### Specifying Module Dependencies You can use the `moduleDependencies` option to declare dependencies on other modules. This provides a robust way to ensure proper setup order, version compatibility, and configuration management. The `moduleDependencies` option can be either an object or a function that receives the Nuxt instance: ##### Example ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', }, moduleDependencies: { '@nuxtjs/tailwindcss': { // Specify a version constraint (semver format) version: '>=6.0.0', // Configuration that overrides user settings overrides: { exposeConfig: true, }, // Configuration that sets defaults but respects user settings defaults: { config: { darkMode: 'class', }, }, }, '@nuxtjs/fontaine': { // Optional dependencies won't be installed but ensure that options // can be set if they _are_ installed optional: true, defaults: { fonts: [ { family: 'Roboto', fallbacks: ['Impact'], }, ], }, }, }, setup (options, nuxt) { }, }) ``` You can also use a function to dynamically determine dependencies based on the Nuxt configuration: ```ts import { defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', }, moduleDependencies (nuxt) { const dependencies: Record<string, any> = { '@nuxtjs/tailwindcss': { version: '>=6.0.0', }, } // Conditionally add dependencies based on Nuxt config if (nuxt.options.experimental?.someFeature) { dependencies['@nuxtjs/fontaine'] = { optional: true, } } return dependencies }, setup (options, nuxt) { // Your setup logic runs after all dependencies are initialized }, }) ``` ## `installModule` <callout type="warning"> **Deprecated:** Use the [`moduleDependencies`](https://nuxt.com/docs/3.x/api/kit/modules#specifying-module-dependencies) option in `defineNuxtModule` instead. The `installModule` function will be removed (or may become non-blocking) in a future version. </callout> Install specified Nuxt module programmatically. This is helpful when your module depends on other modules. You can pass the module options as an object to `inlineOptions` and they will be passed to the module's `setup` function. ### Usage ```tstwoslash import { defineNuxtModule, installModule } from '@nuxt/kit' export default defineNuxtModule({ async setup () { // will install @nuxtjs/fontaine with Roboto font and Impact fallback await installModule('@nuxtjs/fontaine', { // module configuration fonts: [ { family: 'Roboto', fallbacks: ['Impact'], fallbackName: 'fallback-a', }, ], }) }, }) ``` ### Type ```ts async function installModule (moduleToInstall: string | NuxtModule, inlineOptions?: any, nuxt?: Nuxt) ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> moduleToInstall </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> NuxtModule </span> </code> </td> <td> <code> true </code> </td> <td> The module to install. Can be either a string with the module name or a module object itself. </td> </tr> <tr> <td> <code> inlineOptions </code> </td> <td> <code> any </code> </td> <td> <code> false </code> </td> <td> An object with the module options to be passed to the module's <code> setup </code> function. </td> </tr> <tr> <td> <code> nuxt </code> </td> <td> <code> Nuxt </code> </td> <td> <code> false </code> </td> <td> Nuxt instance. If not provided, it will be retrieved from the context via <code> useNuxt() </code> call. </td> </tr> </tbody> </table> ### Examples ```ts import { defineNuxtModule, installModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (options, nuxt) { // will install @nuxtjs/fontaine with Roboto font and Impact fallback await installModule('@nuxtjs/fontaine', { // module configuration fonts: [ { family: 'Roboto', fallbacks: ['Impact'], fallbackName: 'fallback-a', }, ], }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/tree/main/packages/kit/src/module) # Nitro > Nuxt Kit provides a set of utilities to help you work with Nitro. These functions allow you to add server handlers, plugins, and prerender routes. Nitro is an open source TypeScript framework to build ultra-fast web servers. Nuxt uses Nitro as its server engine. You can use `useNitro` to access the Nitro instance, `addServerHandler` to add a server handler, `addDevServerHandler` to add a server handler to be used only in development mode, `addServerPlugin` to add a plugin to extend Nitro's runtime behavior, and `addPrerenderRoutes` to add routes to be prerendered by Nitro. ## `addServerHandler` Adds a Nitro server handler. Use this if you want to create server middleware or a custom route. ### Usage ```tstwoslash import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) addServerHandler({ route: '/robots.txt', handler: resolve('./runtime/robots.get'), }) }, }) ``` ### Type ```ts function addServerHandler (handler: NitroEventHandler): void ``` ### Parameters **handler**: A handler object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> handler </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to event handler. </td> </tr> <tr> <td> <code> route </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path prefix or route. If an empty string used, will be used as a middleware. </td> </tr> <tr> <td> <code> middleware </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Specifies this is a middleware handler. Middleware are called on every route and should normally return nothing to pass to the next handlers. </td> </tr> <tr> <td> <code> lazy </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Use lazy loading to import the handler. This is useful when you only want to load the handler on demand. </td> </tr> <tr> <td> <code> method </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Router method matcher. If handler name contains method name, it will be used as a default value. </td> </tr> </tbody> </table> ### Examples #### Basic Usage You can use `addServerHandler` to add a server handler from your module. <code-group> ```ts [module.ts]twoslash import { addServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) addServerHandler({ route: '/robots.txt', handler: resolve('./runtime/robots.get'), }) }, }) ``` ```ts [runtime/robots.get.ts]twoslash export default defineEventHandler(() => { return { body: `User-agent: *\nDisallow: /`, } }) ``` </code-group> When you access `/robots.txt`, it will return the following response: ```txt User-agent: * Disallow: / ``` ## `addDevServerHandler` Adds a Nitro server handler to be used only in development mode. This handler will be excluded from production build. ### Usage ```tstwoslash import { defineEventHandler } from 'h3' import { addDevServerHandler, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addDevServerHandler({ handler: defineEventHandler(() => { return { body: `Response generated at ${new Date().toISOString()}`, } }), route: '/_handler', }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NitroDevEventHandler } from 'nitropack/types' // ---cut--- function addDevServerHandler (handler: NitroDevEventHandler): void ``` ### Parameters **handler**: A handler object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> handler </code> </td> <td> <code> EventHandler </code> </td> <td> <code> true </code> </td> <td> Event handler. </td> </tr> <tr> <td> <code> route </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path prefix or route. If an empty string used, will be used as a middleware. </td> </tr> </tbody> </table> ### Examples #### Basic Usage In some cases, you may want to create a server handler specifically for development purposes, such as a Tailwind config viewer. ```ts import { joinURL } from 'ufo' import { addDevServerHandler, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ async setup (options, nuxt) { const route = joinURL(nuxt.options.app?.baseURL, '/_tailwind') // @ts-expect-error - tailwind-config-viewer does not have correct types const createServer = await import('tailwind-config-viewer/server/index.js').then(r => r.default || r) as any const viewerDevMiddleware = createServer({ tailwindConfigProvider: () => options, routerPrefix: route }).asMiddleware() addDevServerHandler({ route, handler: viewerDevMiddleware }) }, }) ``` ## `useNitro` Returns the Nitro instance. <warning> You can call `useNitro()` only after `ready` hook. </warning> <note> Changes to the Nitro instance configuration are not applied. </note> ### Usage ```ts import { defineNuxtModule, useNitro } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const resolver = createResolver(import.meta.url) nuxt.hook('ready', () => { const nitro = useNitro() // Do something with Nitro instance }) }, }) ``` ### Type ```ts function useNitro (): Nitro ``` ## `addServerPlugin` Add plugin to extend Nitro's runtime behavior. <tip> You can read more about Nitro plugins in the [Nitro documentation](https://nitro.build/guide/plugins). </tip> <warning> It is necessary to explicitly import `defineNitroPlugin` from `nitropack/runtime` within your plugin file. The same requirement applies to utilities such as `useRuntimeConfig`. </warning> ### Usage ```tstwoslash import { addServerPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addServerPlugin(resolve('./runtime/plugin.ts')) }, }) ``` ### Type ```ts function addServerPlugin (plugin: string): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> plugin </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the plugin. The plugin must export a default function that accepts the Nitro instance as an argument. </td> </tr> </tbody> </table> ### Examples <code-group> ```ts [module.ts] import { addServerPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addServerPlugin(resolve('./runtime/plugin.ts')) }, }) ``` ```ts [runtime/plugin.ts] export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('request', (event) => { console.log('on request', event.path) }) nitroApp.hooks.hook('beforeResponse', (event, { body }) => { console.log('on response', event.path, { body }) }) nitroApp.hooks.hook('afterResponse', (event, { body }) => { console.log('on after response', event.path, { body }) }) }) ``` </code-group> ## `addPrerenderRoutes` Add routes to be prerendered to Nitro. ### Usage ```ts import { addPrerenderRoutes, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'nuxt-sitemap', configKey: 'sitemap', }, defaults: { sitemapUrl: '/sitemap.xml', prerender: true, }, setup (options) { if (options.prerender) { addPrerenderRoutes(options.sitemapUrl) } }, }) ``` ### Type ```ts function addPrerenderRoutes (routes: string | string[]): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> routes </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A route or an array of routes to prerender. </td> </tr> </tbody> </table> ## `addServerImports` Add imports to the server. It makes your imports available in Nitro without the need to import them manually. <warning> If you want to provide a utility that works in both server and client contexts and is usable in the [`shared/`](https://nuxt.com/docs/3.x/directory-structure/shared) directory, the function must be imported from the same source file for both [`addImports`](https://nuxt.com/docs/3.x/api/kit/autoimports#addimports) and `addServerImports` and should have identical signature. That source file should not import anything context-specific (i.e., Nitro context, Nuxt app context) or else it might cause errors during type-checking. </warning> ### Usage ```tstwoslash import { addServerImports, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const names = [ 'useStoryblok', 'useStoryblokApi', 'useStoryblokBridge', 'renderRichText', 'RichTextSchema', ] names.forEach(name => addServerImports({ name, as: name, from: '@storyblok/vue' }), ) }, }) ``` ### Type ```ts function addServerImports (dirs: Import | Import[]): void ``` ### Parameters `imports`: An object or an array of objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Import name to be detected. </td> </tr> <tr> <td> <code> from </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Module specifier to import from. </td> </tr> <tr> <td> <code> priority </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Priority of the import; if multiple imports have the same name, the one with the highest priority will be used. </td> </tr> <tr> <td> <code> disabled </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is disabled. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code> Record<string, any> </code> </td> <td> <code> false </code> </td> <td> Metadata of the import. </td> </tr> <tr> <td> <code> type </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If this import is a pure type import. </td> </tr> <tr> <td> <code> typeFrom </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Use this as the <code> from </code> value when generating type declarations. </td> </tr> <tr> <td> <code> as </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Import as this name. </td> </tr> </tbody> </table> ## `addServerImportsDir` Add a directory to be scanned for auto-imports by Nitro. ### Usage ```tstwoslash import { addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerImportsDir(resolve('./runtime/server/composables')) }, }) ``` ### Type ```ts function addServerImportsDir (dirs: string | string[], opts: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A directory or an array of directories to register to be scanned by Nitro. </td> </tr> <tr> <td> <code> opts </code> </td> <td> <code> { prepend?: boolean } </code> </td> <td> <code> false </code> </td> <td> Options for the import directory. If <code> prepend </code> is <code> true </code> , the directory is added to the beginning of the scan list. </td> </tr> </tbody> </table> ### Examples You can use `addServerImportsDir` to add a directory to be scanned by Nitro. This is useful when you want Nitro to auto-import functions from a custom server directory. <code-group> ```ts [module.ts]twoslash import { addServerImportsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerImportsDir(resolve('./runtime/server/composables')) }, }) ``` ```ts [runtime/server/composables/index.ts]twoslash export function useApiSecret () { const { apiSecret } = useRuntimeConfig() return apiSecret } ``` </code-group> You can then use the `useApiSecret` function in your server code: ```ts [runtime/server/api/hello.ts]twoslash const useApiSecret = (): string => '' // ---cut--- export default defineEventHandler(() => { const apiSecret = useApiSecret() // Do something with the apiSecret }) ``` ## `addServerScanDir` Add directories to be scanned by Nitro. It will check for subdirectories, which will be registered just like the `~~/server` folder is. <note> Only `~~/server/api`, `~~/server/routes`, `~~/server/middleware`, and `~~/server/utils` are scanned. </note> ### Usage ```tstwoslash import { addServerScanDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerScanDir(resolve('./runtime/server')) }, }) ``` ### Type ```ts function addServerScanDir (dirs: string | string[], opts: { prepend?: boolean }): void ``` ### Parameters <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dirs </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string[] </span> </code> </td> <td> <code> true </code> </td> <td> A directory or an array of directories to register to be scanned for by Nitro as server dirs. </td> </tr> <tr> <td> <code> opts </code> </td> <td> <code> { prepend?: boolean } </code> </td> <td> <code> false </code> </td> <td> Options for the import directory. If <code> prepend </code> is <code> true </code> , the directory is added to the beginning of the scan list. </td> </tr> </tbody> </table> ### Examples You can use `addServerScanDir` to add a directory to be scanned by Nitro. This is useful when you want to add a custom server directory. <code-group> ```ts [module.ts]twoslash import { addServerScanDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ meta: { name: 'my-module', configKey: 'myModule', }, setup (options) { const { resolve } = createResolver(import.meta.url) addServerScanDir(resolve('./runtime/server')) }, }) ``` ```ts [runtime/server/utils/index.ts]twoslash export function hello () { return 'Hello from server utils!' } ``` </code-group> You can then use the `hello` function in your server code. ```ts [runtime/server/api/hello.ts]twoslash function hello () { return 'Hello from server utils!' } // ---cut--- export default defineEventHandler(() => { return hello() // Hello from server utils! }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/nitro.ts) # Pages > Nuxt Kit provides a set of utilities to help you create and use pages. You can use these utilities to manipulate the pages configuration or to define route rules. ## `extendPages` In Nuxt, routes are automatically generated based on the structure of the files in the `pages` directory. However, there may be scenarios where you'd want to customize these routes. For instance, you might need to add a route for a dynamic page not generated by Nuxt, remove an existing route, or modify the configuration of a route. For such customizations, Nuxt offers the `extendPages` feature, which allows you to extend and alter the pages configuration. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/extend-and-alter-nuxt-pages?friend=nuxt"> Watch Vue School video about extendPages. </tip> ### Usage ```tstwoslash import { createResolver, defineNuxtModule, extendPages } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) extendPages((pages) => { pages.unshift({ name: 'prismic-preview', path: '/preview', file: resolve('runtime/preview.vue'), }) }) }, }) ``` ### Type ```ts function extendPages (callback: (pages: NuxtPage[]) => void): void ``` ### Parameters **callback**: A function that will be called with the pages configuration. You can alter this array by adding, deleting, or modifying its elements. Note: You should modify the provided pages array directly, as changes made to a copied array will not be reflected in the configuration. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The name of the route. Useful for programmatic navigation and identifying routes. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> The route URL path. If not set, Nuxt will infer it from the file location. </td> </tr> <tr> <td> <code> file </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the Vue file that should be used as the component for the route. </td> </tr> <tr> <td> <code> meta </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Custom metadata for the route. Can be used in layouts, middlewares, or navigation guards. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> string[] </span> <span class="sDfIl"> | </span> <span class="sZSNi"> string </span> </code> </td> <td> <code> false </code> </td> <td> One or more alias paths for the route. Useful for supporting multiple URLs. </td> </tr> <tr> <td> <code> redirect </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> RouteLocationRaw </span> </code> </td> <td> <code> false </code> </td> <td> Redirect rule for the route. Supports named routes, objects, or string paths. </td> </tr> <tr> <td> <code> children </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> NuxtPage[] </span> </code> </td> <td> <code> false </code> </td> <td> Nested child routes under this route for layout or view nesting. </td> </tr> </tbody> </table> ## `extendRouteRules` Nuxt is powered by the [Nitro](https://nitro.build/) server engine. With Nitro, you can incorporate high-level logic directly into your configuration, which is useful for actions like redirects, proxying, caching, and appending headers to routes. This configuration works by associating route patterns with specific route settings. <tip> You can read more about Nitro route rules in the [Nitro documentation](https://nitro.build/guide/routing#route-rules). </tip> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/adding-route-rules-and-route-middlewares?friend=nuxt"> Watch Vue School video about adding route rules and route middelwares. </tip> ### Usage ```tstwoslash import { createResolver, defineNuxtModule, extendPages, extendRouteRules } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { const { resolve } = createResolver(import.meta.url) extendPages((pages) => { pages.unshift({ name: 'preview-new', path: '/preview-new', file: resolve('runtime/preview.vue'), }) }) extendRouteRules('/preview', { redirect: { to: '/preview-new', statusCode: 302, }, }) extendRouteRules('/preview-new', { cache: { maxAge: 60 * 60 * 24 * 7, }, }) }, }) ``` ### Type ```ts function extendRouteRules (route: string, rule: NitroRouteConfig, options?: ExtendRouteRulesOptions): void ``` ### Parameters **route**: A route pattern to match against.<br /> **rule**: A route rule configuration to apply to the matched route. <tip> About route rules configurations, you can get more detail in [Hybrid Rendering > Route Rules](https://nuxt.com/docs/3.x/guide/concepts/rendering#route-rules). </tip> **options**: A object to pass to the route configuration. If `override` is set to `true`, it will override the existing route configuration. <table> <thead> <tr> <th> Name </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> override </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Override route rule config, default is false </td> </tr> </tbody> </table> ## `addRouteMiddleware` Registers route middlewares to be available for all routes or for specific routes. Route middlewares can be also defined in plugins via [`addRouteMiddleware`](https://nuxt.com/docs/3.x/api/utils/add-route-middleware) composable. <tip> Read more about route middlewares in the [Route middleware documentation](https://nuxt.com/docs/3.x/getting-started/routing#route-middleware). </tip> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/adding-route-rules-and-route-middlewares?friend=nuxt"> Watch Vue School video about adding route rules and route middelwares. </tip> ### Usage <code-group> ```ts [module.ts]twoslash import { addRouteMiddleware, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addRouteMiddleware({ name: 'auth', path: resolve('runtime/auth'), global: true, }, { prepend: true }) }, }) ``` ```ts [runtime/auth.ts]twoslash function isAuthenticated (): boolean { return false } // ---cut--- export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (to.path !== '/login' && isAuthenticated() === false) { return navigateTo('/login') } }) ``` </code-group> ### Type ```ts function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], options?: AddRouteMiddlewareOptions): void ``` ### Parameters **input**: A middleware object or an array of middleware objects with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> The name of the middleware. </td> </tr> <tr> <td> <code> path </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> The file path to the middleware. </td> </tr> <tr> <td> <code> global </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , applies middleware to all routes. </td> </tr> </tbody> </table> **options**: An object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Default </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> override </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , replaces middleware with the same name. </td> </tr> <tr> <td> <code> prepend </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , prepends middleware before existing middlewares. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/pages.ts) # Plugins > Nuxt Kit provides a set of utilities to help you create and use plugins. You can add plugins or plugin templates to your module using these functions. Plugins are self-contained code that usually add app-level functionality to Vue. In Nuxt, plugins are automatically imported from the `plugins/` directory. However, if you need to ship a plugin with your module, Nuxt Kit provides the `addPlugin` and `addPluginTemplate` methods. These utils allow you to customize the plugin configuration to better suit your needs. ## `addPlugin` Registers a Nuxt plugin and adds it to the plugins array. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-plugins?friend=nuxt"> Watch Vue School video about `addPlugin`. </tip> ### Usage ```tstwoslash import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addPlugin({ src: resolve('runtime/plugin.js'), mode: 'client', }) }, }) ``` ### Type ```ts function addPlugin (plugin: NuxtPlugin | string, options?: AddPluginOptions): NuxtPlugin ``` ### Parameters **plugin**: A plugin object or a string with the path to the plugin. If a string is provided, it will be converted to a plugin object with `src` set to the string value. If a plugin object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Path to the plugin file. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> If set to <code> 'all' </code> , the plugin will be included in both client and server bundles. If set to <code> 'server' </code> , the plugin will only be included in the server bundle. If set to <code> 'client' </code> , the plugin will only be included in the client bundle. You can also use <code> .client </code> and <code> .server </code> modifiers when specifying <code> src </code> option to use plugin only in client or server side. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Order of the plugin. This allows more granular control over plugin order and should only be used by advanced users. Lower numbers run first, and user plugins default to <code> 0 </code> . It's recommended to set <code> order </code> to a number between <code> -20 </code> for <code> pre </code> -plugins (plugins that run before Nuxt plugins) and <code> 20 </code> for <code> post </code> -plugins (plugins that run after Nuxt plugins). </td> </tr> </tbody> </table> <warning> Avoid using `order` unless necessary. Use `append` if you simply need to register plugins after Nuxt defaults. </warning> **options**: Optional object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> append </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the plugin will be appended to the plugins array. If <code> false </code> , it will be prepended. Defaults to <code> false </code> . </td> </tr> </tbody> </table> ### Examples <code-group> ```ts [module.ts] import { addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const { resolve } = createResolver(import.meta.url) addPlugin({ src: resolve('runtime/plugin.js'), mode: 'client', }) }, }) ``` ```ts [runtime/plugin.ts] export default defineNuxtPlugin((nuxtApp) => { const colorMode = useColorMode() nuxtApp.hook('app:mounted', () => { if (colorMode.preference !== 'dark') { colorMode.preference = 'dark' } }) }) ``` </code-group> ## `addPluginTemplate` Adds a template and registers as a nuxt plugin. This is useful for plugins that need to generate code at build time. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/injecting-plugin-templates?friend=nuxt"> Watch Vue School video about `addPluginTemplate`. </tip> ### Usage ```tstwoslash import { addPluginTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options) { addPluginTemplate({ filename: 'module-plugin.mjs', getContents: () => `import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'module-plugin', setup (nuxtApp) { ${options.log ? 'console.log("Plugin install")' : ''} } })`, }) }, }) ``` ### Type ```ts function addPluginTemplate (pluginOptions: NuxtPluginTemplate, options?: AddPluginOptions): NuxtPlugin ``` ### Parameters **pluginOptions**: A plugin template object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> mode </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ' </span> <span class="sGFVr"> all </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> server </span> <span class="sDfIl"> ' </span> <span class="sDfIl"> | </span> <span class="sDfIl"> ' </span> <span class="sGFVr"> client </span> <span class="sDfIl"> ' </span> </code> </td> <td> <code> false </code> </td> <td> If set to <code> 'all' </code> , the plugin will be included in both client and server bundles. If set to <code> 'server' </code> , the plugin will only be included in the server bundle. If set to <code> 'client' </code> , the plugin will only be included in the client bundle. You can also use <code> .client </code> and <code> .server </code> modifiers when specifying <code> src </code> option to use plugin only in client or server side. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> any </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Record </span> <span class="sDfIl"> < </span> <span class="s52Pk"> string </span> <span class="sDfIl"> , </span> <span class="s52Pk"> any </span> <span class="sDfIl"> >) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> Order of the plugin. This allows more granular control over plugin order and should only be used by advanced users. Lower numbers run first, and user plugins default to <code> 0 </code> . It's recommended to set <code> order </code> to a number between <code> -20 </code> for <code> pre </code> -plugins (plugins that run before Nuxt plugins) and <code> 20 </code> for <code> post </code> -plugins (plugins that run after Nuxt plugins). </td> </tr> </tbody> </table> <warning> Prefer using `getContents` for dynamic plugin generation. Avoid setting `order` unless necessary. </warning> **options**: Optional object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> append </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If <code> true </code> , the plugin will be appended to the plugins array. If <code> false </code> , it will be prepended. Defaults to <code> false </code> . </td> </tr> </tbody> </table> ### Examples #### Generate a plugin template with different options Use `addPluginTemplate` when you need to generate plugin code dynamically at build time. This allows you to generate different plugin contents based on the options passed to it. For example, Nuxt internally uses this function to generate Vue app configurations. ```ts [module.ts]twoslash import { addPluginTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (_, nuxt) { if (nuxt.options.vue.config && Object.values(nuxt.options.vue.config).some(v => v !== null && v !== undefined)) { addPluginTemplate({ filename: 'vue-app-config.mjs', write: true, getContents: () => `import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { ${Object.keys(nuxt.options.vue.config!) .map(k => `nuxtApp.vueApp.config[${JSON.stringify(k)}] = ${JSON.stringify(nuxt.options.vue.config![k as 'idPrefix'])}`) .join('\n') } } })`, }) } }, }) ``` This generates different plugin code depending on the provided configuration. <code-group> ```ts [nuxt.config.ts] export default defineNuxtConfig({ vue: { config: { idPrefix: 'nuxt', }, }, }) ``` ```ts [#build/vue-app-config.mjs] import { defineNuxtPlugin } from '#app/nuxt' export default defineNuxtPlugin({ name: 'nuxt:vue-app-config', enforce: 'pre', setup (nuxtApp) { nuxtApp.vueApp.config.idPrefix = 'nuxt' }, }) ``` </code-group> #### Using an EJS template to generate a plugin You can also use an EJS template to generate your plugin. Options can be passed through the `options` property and then used within the EJS template to generate the plugin content. <code-group> ```ts [module.ts] import { addPluginTemplate, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const { resolve } = createResolver(import.meta.url) addPluginTemplate({ src: resolve('templates/plugin.ejs'), filename: 'plugin.mjs', options: { ssr: nuxt.options.ssr, }, }) }, }) ``` ```ejs [templates/plugin.ejs] import { VueFire, useSSRInitialState } from 'vuefire' import { defineNuxtPlugin } from '#imports' export default defineNuxtPlugin((nuxtApp) => { const firebaseApp = nuxtApp.$firebaseApp nuxtApp.vueApp.use(VueFire, { firebaseApp }) <% if(options.ssr) { %> if (import.meta.server) { nuxtApp.payload.vuefire = useSSRInitialState(undefined, firebaseApp) } else if (nuxtApp.payload?.vuefire) { useSSRInitialState(nuxtApp.payload.vuefire, firebaseApp) } <% } %> }) ``` </code-group> <warning> If you set `compatibilityVersion` to `4`, Nuxt no longer uses `lodash.template` to compile templates by default. You can still enable it via the `experimental.compileTemplate` option, but support for EJS templates will be removed entirely in the next major version. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/plugin.ts) # Programmatic Usage > Nuxt Kit provides a set of utilities to help you work with Nuxt programmatically. These functions allow you to load Nuxt, build Nuxt, and load Nuxt configuration. Programmatic usage can be helpful when you want to use Nuxt programmatically, for example, when building a [CLI tool](https://github.com/nuxt/cli) or [test utils](https://github.com/nuxt/test-utils). ## `loadNuxt` Load Nuxt programmatically. It will load the Nuxt configuration, instantiate and return the promise with Nuxt instance. ### Type ```ts function loadNuxt (loadOptions?: LoadNuxtOptions): Promise<Nuxt> ``` ### Parameters **loadOptions**: Loading conditions for Nuxt. `loadNuxt` uses [`c12`](https://github.com/unjs/c12) under the hood, so it accepts the same options as `c12.loadConfig` with some additional options: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> dev </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , Nuxt will be loaded in development mode. </td> </tr> <tr> <td> <code> ready </code> </td> <td> <code> boolean </code> </td> <td> <code> true </code> </td> <td> If set to <code> true </code> , Nuxt will be ready to use after the <code> loadNuxt </code> call. If set to <code> false </code> , you will need to call <code> nuxt.ready() </code> to make sure Nuxt is ready to use. </td> </tr> </tbody> </table> ## `buildNuxt` Build Nuxt programmatically. It will invoke the builder (currently [@nuxt/vite-builder](https://github.com/nuxt/nuxt/tree/main/packages/vite) or [@nuxt/webpack-builder](https://github.com/nuxt/nuxt/tree/main/packages/webpack)) to bundle the application. ### Type ```ts function buildNuxt (nuxt: Nuxt): Promise<any> ``` ### Parameters **nuxt**: Nuxt instance to build. It can be retrieved from the context via `useNuxt()` call. ## `loadNuxtConfig` Load Nuxt configuration. It will return the promise with the configuration object. ### Type ```ts function loadNuxtConfig (options: LoadNuxtConfigOptions): Promise<NuxtOptions> ``` ### Parameters **options**: Options to pass in [`c12`](https://github.com/unjs/c12#options) `loadConfig` call. ## `writeTypes` Generates `tsconfig.json` and writes it to the project buildDir. ### Type ```ts function writeTypes (nuxt?: Nuxt): void ``` ### Parameters **nuxt**: Nuxt instance to build. It can be retrieved from the context via `useNuxt()` call. --- - [Source](https://github.com/nuxt/nuxt/tree/main/packages/kit/src/loader) # Resolving > Nuxt Kit provides a set of utilities to help you resolve paths. These functions allow you to resolve paths relative to the current module, with unknown name or extension. Sometimes you need to resolve a path relative to the current module without knowing the name or extension. For example, you may want to add a plugin that is located in the same directory as the module. To handle these cases, Nuxt provides a set of utilities to resolve paths. `resolvePath` and `resolveAlias` are used to resolve paths relative to the current module. `findPath` is used to find the first existing file in a given set of paths. `createResolver` is used to create a resolver relative to the base path. ## `resolvePath` Resolves the full path to a file or directory, respecting Nuxt alias and extensions options. If a path could not be resolved, a normalized input path will be returned. ### Usage ```ts import { defineNuxtModule, resolvePath } from '@nuxt/kit' export default defineNuxtModule({ async setup () { const entrypoint = await resolvePath('@unhead/vue') console.log(`Unhead entrypoint is ${entrypoint}`) }, }) ``` ### Type ```ts function resolvePath (path: string, options?: ResolvePathOptions): Promise<string> ``` ### Parameters **path**: A path to resolve. **options**: Options to pass to the resolver. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> cwd </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Base for resolving paths from. Default is Nuxt rootDir. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> An object of aliases. Default is Nuxt configured aliases. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> The file extensions to try. Default is Nuxt configured extensions. </td> </tr> <tr> <td> <code> virtual </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template). </td> </tr> <tr> <td> <code> fallbackToOriginal </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to fallback to the original path if the resolved path does not exist instead of returning the normalized input path. </td> </tr> </tbody> </table> ### Examples ```ts import { defineNuxtModule, resolvePath } from '@nuxt/kit' import { join } from 'pathe' const headlessComponents: ComponentGroup[] = [ { relativePath: 'combobox/combobox.js', chunkName: 'headlessui/combobox', exports: [ 'Combobox', 'ComboboxLabel', 'ComboboxButton', 'ComboboxInput', 'ComboboxOptions', 'ComboboxOption', ], }, ] export default defineNuxtModule({ meta: { name: 'nuxt-headlessui', configKey: 'headlessui', }, defaults: { prefix: 'Headless', }, async setup (options) { const entrypoint = await resolvePath('@headlessui/vue') const root = join(entrypoint, '../components') for (const group of headlessComponents) { for (const e of group.exports) { addComponent( { name: e, export: e, filePath: join(root, group.relativePath), chunkName: group.chunkName, mode: 'all', }, ) } } }, }) ``` ## `resolveAlias` Resolves path aliases respecting Nuxt alias options. ### Type ```ts function resolveAlias (path: string, alias?: Record<string, string>): string ``` ### Parameters **path**: A path to resolve. **alias**: An object of aliases. If not provided, it will be read from `nuxt.options.alias`. ## `findPath` Try to resolve first existing file in a given set of paths. ### Usage ```ts import { defineNuxtModule, findPath } from '@nuxt/kit' import { join } from 'pathe' export default defineNuxtModule({ async setup (_, nuxt) { // Resolve main (app.vue) const mainComponent = await findPath([ join(nuxt.options.srcDir, 'App'), join(nuxt.options.srcDir, 'app'), ]) }, }) ``` ### Type ```ts function findPath (paths: string | string[], options?: ResolvePathOptions, pathType: 'file' | 'dir'): Promise<string | null> ``` ### Parameters **paths**: A path or an array of paths to resolve. **options**: Options to pass to the resolver. This object can have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> cwd </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Base for resolving paths from. Default is Nuxt rootDir. </td> </tr> <tr> <td> <code> alias </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Record </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> , </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> An object of aliases. Default is Nuxt configured aliases. </td> </tr> <tr> <td> <code> extensions </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> The file extensions to try. Default is Nuxt configured extensions. </td> </tr> <tr> <td> <code> virtual </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to resolve files that exist in the Nuxt VFS (for example, as a Nuxt template). </td> </tr> <tr> <td> <code> fallbackToOriginal </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to fallback to the original path if the resolved path does not exist instead of returning the normalized input path. </td> </tr> </tbody> </table> ## `createResolver` Creates resolver relative to base path. <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/resolving-paths-and-injecting-assets-to-the-app?friend=nuxt"> Watch Vue School video about createResolver. </tip> ### Usage ```ts import { createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup (_, nuxt) { const { resolve, resolvePath } = createResolver(import.meta.url) }, }) ``` ### Type ```ts function createResolver (basePath: string | URL): Resolver ``` ### Parameters **basePath**: A base path to resolve from. It can be a string or a URL. ### Return Value The `createResolver` function returns an object with the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> resolve </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> path </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> </code> </td> <td> A function that resolves a path relative to the base path. </td> </tr> <tr> <td> <code> resolvePath </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> path </span> <span class="sDfIl"> : </span> <span class="s52Pk"> string </span> <span class="sDfIl"> , </span> <span class="s1nJG"> options </span> <span class="sDfIl"> ?: </span> <span class="s52Pk"> ResolvePathOptions </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> A function that resolves a path relative to the base path and respects Nuxt alias and extensions options. </td> </tr> </tbody> </table> ### Examples ```ts import { createResolver, defineNuxtModule, isNuxt2 } from '@nuxt/kit' export default defineNuxtModule({ setup (options, nuxt) { const resolver = createResolver(import.meta.url) nuxt.hook('modules:done', () => { if (isNuxt2()) { addPlugin(resolver.resolve('./runtime/plugin.vue2')) } else { addPlugin(resolver.resolve('./runtime/plugin.vue3')) } }) }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/resolve.ts) # Runtime Config > Nuxt Kit provides a set of utilities to help you access and modify Nuxt runtime configuration. ## `useRuntimeConfig` At build-time, it is possible to access the resolved Nuxt [runtime config](https://nuxt.com/docs/3.x/guide/going-further/runtime-config). ### Type ```ts function useRuntimeConfig (): Record<string, unknown> ``` ## `updateRuntimeConfig` It is also possible to update runtime configuration. This will be merged with the existing runtime configuration, and if Nitro has already been initialized it will trigger an HMR event to reload the Nitro runtime config. ### Type ```ts function updateRuntimeConfig (config: Record<string, unknown>): void | Promise<void> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/runtime-config.ts) # Templates > Nuxt Kit provides a set of utilities to help you work with templates. These functions allow you to generate extra files during development and build time. Templates allow you to generate extra files during development and build time. These files will be available in virtual filesystem and can be used in plugins, layouts, components, etc. `addTemplate` and `addTypeTemplate` allow you to add templates to the Nuxt application. `updateTemplates` allows you to regenerate templates that match the filter. ## `addTemplate` Renders given template during build into the virtual file system, and optionally to disk in the project `buildDir` ### Usage ```tstwoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' import { defu } from 'defu' export default defineNuxtModule({ setup (options, nuxt) { const globalMeta = defu(nuxt.options.app.head, { charset: options.charset, viewport: options.viewport, }) addTemplate({ filename: 'meta.config.mjs', getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' }), }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NuxtTemplate, ResolvedNuxtTemplate } from '@nuxt/schema' // ---cut--- function addTemplate (template: NuxtTemplate | string): ResolvedNuxtTemplate ``` ### Parameters **template**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code> Options </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Options </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> <tr> <td> <code> write </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the template will be written to the destination file. Otherwise, the template will be used only in virtual filesystem. </td> </tr> </tbody> </table> ### Examples #### Creating a Virtual File for Runtime Plugin In this example, we merge an object inside a module and consume the result in a runtime plugin. ```ts [module.ts]twoslash import { addTemplate, defineNuxtModule } from '@nuxt/kit' import { defu } from 'defu' export default defineNuxtModule({ setup (options, nuxt) { const globalMeta = defu(nuxt.options.app.head, { charset: options.charset, viewport: options.viewport, }) addTemplate({ filename: 'meta.config.mjs', getContents: () => 'export default ' + JSON.stringify({ globalMeta, mixinKey: 'setup' }), }) }, }) ``` In the module above, we generate a virtual file named `meta.config.mjs`. In the runtime plugin, we can import it using the `#build` alias: ```ts [runtime/plugin.ts] import { createHead as createServerHead } from '@unhead/vue/server' import { createHead as createClientHead } from '@unhead/vue/client' import { defineNuxtPlugin } from '#imports' // @ts-expect-error - virtual file import metaConfig from '#build/meta.config.mjs' export default defineNuxtPlugin((nuxtApp) => { const createHead = import.meta.server ? createServerHead : createClientHead const head = createHead() head.push(metaConfig.globalMeta) nuxtApp.vueApp.use(head) }) ``` ## `addTypeTemplate` Renders given template during build into the project buildDir, then registers it as types. ### Usage ```tstwoslash import { addTypeTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addTypeTemplate({ filename: 'types/markdown.d.ts', getContents: () => `declare module '*.md' { import type { ComponentOptions } from 'vue' const Component: ComponentOptions export default Component }`, }) }, }) ``` ### Type ```ts function addTypeTemplate (template: NuxtTypeTemplate | string, context?: { nitro?: boolean, nuxt?: boolean }): ResolvedNuxtTemplate ``` ### Parameters **template**: A template object or a string with the path to the template. If a string is provided, it will be converted to a template object with `src` set to the string value. If a template object is provided, it must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> src </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the template. If <code> src </code> is not provided, <code> getContents </code> must be provided instead. </td> </tr> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Filename of the template. If <code> filename </code> is not provided, it will be generated from the <code> src </code> path. In this case, the <code> src </code> option is required. </td> </tr> <tr> <td> <code> dst </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Path to the destination file. If <code> dst </code> is not provided, it will be generated from the <code> filename </code> path and nuxt <code> buildDir </code> option. </td> </tr> <tr> <td> <code> options </code> </td> <td> <code> Options </code> </td> <td> <code> false </code> </td> <td> Options to pass to the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> data </span> <span class="sDfIl"> : </span> <span class="s52Pk"> Options </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. If <code> src </code> is provided, this function will be ignored. </td> </tr> </tbody> </table> **context**: An optional context object can be passed to control where the type is added. If omitted, the type will only be added to the Nuxt context. This object supports the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> nuxt </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the type will be added to the Nuxt context. </td> </tr> <tr> <td> <code> nitro </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> If set to <code> true </code> , the type will be added to the Nitro context. </td> </tr> </tbody> </table> ### Examples #### Adding Type Templates to the Nitro Context By default, ๏ผ๏ผ only adds the type declarations to the Nuxt context. To also add them to the Nitro context, set nitro to true. ```tstwoslash import { addTypeTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addTypeTemplate({ filename: 'types/auth.d.ts', getContents: () => `declare module '#auth-utils' { interface User { id: string; name: string; } }`, }, { nitro: true, }) }, }) ``` This allows the `#auth-utils` module to be used within the Nitro context. ```ts [server/api/auth.ts] import type { User } from '#auth-utils' export default eventHandler(() => { const user: User = { id: '123', name: 'John Doe', } // do something with the user return user }) ``` ## `addServerTemplate` Adds a virtual file that can be used within the Nuxt Nitro server build. ### Usage ```tstwoslash import { addServerTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addServerTemplate({ filename: '#my-module/test.mjs', getContents () { return 'export const test = 123' }, }) }, }) ``` ### Type ```tstwoslash // @errors: 2391 import type { NuxtServerTemplate } from '@nuxt/schema' // ---cut--- function addServerTemplate (template: NuxtServerTemplate): NuxtServerTemplate ``` ### Parameters **template**: A template object. It must have the following properties: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> filename </code> </td> <td> <code> string </code> </td> <td> <code> true </code> </td> <td> Filename of the template. </td> </tr> <tr> <td> <code> getContents </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> () </span> <span class="smZ93"> => </span> <span class="sZSNi"> string </span> <span class="sDfIl"> | </span> <span class="s52Pk"> Promise </span> <span class="sDfIl"> < </span> <span class="sZSNi"> string </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> true </code> </td> <td> A function that will be called with the <code> options </code> object. It should return a string or a promise that resolves to a string. </td> </tr> </tbody> </table> ### Examples ### Creating a Virtual File for Nitro In this example, we create a virtual file that can be used within the Nuxt Nitro server build. ```tstwoslash import { addServerTemplate, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { addServerTemplate({ filename: '#my-module/test.mjs', getContents () { return 'export const test = 123' }, }) }, }) ``` And then in a runtime file ```ts [server/api/test.ts] import { test } from '#my-module/test.js' export default eventHandler(() => { return test }) ``` ## `updateTemplates` Regenerate templates that match the filter. If no filter is provided, all templates will be regenerated. ### Usage ```ts import { defineNuxtModule, updateTemplates } from '@nuxt/kit' import { resolve } from 'pathe' export default defineNuxtModule({ setup (options, nuxt) { const updateTemplatePaths = [ resolve(nuxt.options.srcDir, 'pages'), ] // watch and rebuild routes template list when one of the pages changes nuxt.hook('builder:watch', async (event, relativePath) => { if (event === 'change') { return } const path = resolve(nuxt.options.srcDir, relativePath) if (updateTemplatePaths.some(dir => path.startsWith(dir))) { await updateTemplates({ filter: template => template.filename === 'routes.mjs', }) } }) }, }) ``` ### Type ```ts async function updateTemplates (options: UpdateTemplatesOptions): void ``` ### Parameters **options**: Options to pass to the template. This object can have the following property: <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> filter </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> ( </span> <span class="s1nJG"> template </span> <span class="sDfIl"> : </span> <span class="s52Pk"> ResolvedNuxtTemplate </span> <span class="sDfIl"> ) </span> <span class="smZ93"> => </span> <span class="sZSNi"> boolean </span> </code> </td> <td> <code> false </code> </td> <td> A function that will be called with the <code> template </code> object. It should return a boolean indicating whether the template should be regenerated. If <code> filter </code> is not provided, all templates will be regenerated. </td> </tr> </tbody> </table> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/kit/src/template.ts) # Nuxt Configuration > Discover all the options you can use in your nuxt.config.ts file. <note icon="i-simple-icons-github" target="_blank" to="https://github.com/nuxt/nuxt/tree/main/packages/schema/src/config"> This file is auto-generated from Nuxt source code. </note> ## alias You can improve your DX by defining additional aliases to access custom directories within your JavaScript and CSS. - **Type**: `object` - **Default** ```json { "~": "/<srcDir>/", "@": "/<srcDir>/", "~~": "/<rootDir>/", "@@": "/<rootDir>/", "#shared": "/<rootDir>/shared/", "assets": "/<srcDir>/assets/", "public": "/<srcDir>/public/", "#server": "/<srcDir>/server/", "#build": "/<rootDir>/.nuxt/", "#internal/nuxt/paths": "/<rootDir>/.nuxt/paths.mjs" } ``` <callout> **Note**: Within a webpack context (image sources, CSS - but not JavaScript) you *must* access your alias by prefixing it with `~`. </callout> <callout> **Note**: These aliases will be automatically added to the generated `.nuxt/tsconfig.json` so you can get full type support and path auto-complete. In case you need to extend options provided by `./.nuxt/tsconfig.json` further, make sure to add them here or within the `typescript.tsConfig` property in `nuxt.config`. </callout> **Example**: ```js export default { alias: { 'images': fileURLToPath(new URL('./assets/images', import.meta.url)), 'style': fileURLToPath(new URL('./assets/style', import.meta.url)), 'data': fileURLToPath(new URL('./assets/other/data', import.meta.url)) } } ``` ## analyzeDir The directory where Nuxt will store the generated files when running `nuxt analyze`. If a relative path is specified, it will be relative to your `rootDir`. - **Type**: `string` - **Default:** `"/<rootDir>/.nuxt/analyze"` ## app Nuxt App configuration. ### `baseURL` The base path of your Nuxt application. For example: - **Type**: `string` - **Default:** `"/"` **Example**: ```ts export default defineNuxtConfig({ app: { baseURL: '/prefix/' } }) ``` **Example**: ```bash NUXT_APP_BASE_URL=/prefix/ node .output/server/index.mjs ``` ### `buildAssetsDir` The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set). This is set at build time and should not be customized at runtime. - **Type**: `string` - **Default:** `"/_nuxt/"` ### `cdnURL` An absolute URL to serve the public folder from (production-only). For example: - **Type**: `string` - **Default:** `""` **Example**: ```ts export default defineNuxtConfig({ app: { cdnURL: 'https://mycdn.org/' } }) ``` **Example**: ```bash NUXT_APP_CDN_URL=https://mycdn.org/ node .output/server/index.mjs ``` ### `head` Set default configuration for `<head>` on every page. - **Type**: `object` - **Default** ```json { "meta": [ { "name": "viewport", "content": "width=device-width, initial-scale=1" }, { "charset": "utf-8" } ], "link": [], "style": [], "script": [], "noscript": [] } ``` **Example**: ```js app: { head: { meta: [ // <meta name="viewport" content="width=device-width, initial-scale=1"> { name: 'viewport', content: 'width=device-width, initial-scale=1' } ], script: [ // <script src="https://myawesome-lib.js"></script> { src: 'https://awesome-lib.js' } ], link: [ // <link rel="stylesheet" href="https://myawesome-lib.css"> { rel: 'stylesheet', href: 'https://awesome-lib.css' } ], // please note that this is an area that is likely to change style: [ // <style>:root { color: red }</style> { textContent: ':root { color: red }' } ], noscript: [ // <noscript>JavaScript is required</noscript> { textContent: 'JavaScript is required' } ] } } ``` ### `keepalive` Default values for KeepAlive configuration between pages. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean` - **Default:** `false` **See**: [Vue KeepAlive](https://vuejs.org/api/built-in-components.html#keepalive) ### `layoutTransition` Default values for layout transitions. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean` - **Default:** `false` **See**: [Vue Transition docs](https://vuejs.org/api/built-in-components.html#transition) ### `pageTransition` Default values for page transitions. This can be overridden with `definePageMeta` on an individual page. Only JSON-serializable values are allowed. - **Type**: `boolean` - **Default:** `false` **See**: [Vue Transition docs](https://vuejs.org/api/built-in-components.html#transition) ### `rootAttrs` Customize Nuxt root element id. - **Type**: `object` - **Default** ```json { "id": "__nuxt" } ``` ### `rootId` Customize Nuxt root element id. - **Type**: `string` - **Default:** `"__nuxt"` ### `rootTag` Customize Nuxt root element tag. - **Type**: `string` - **Default:** `"div"` ### `spaLoaderAttrs` Customize Nuxt Nuxt SpaLoader element attributes. #### `id` - **Type**: `string` - **Default:** `"__nuxt-loader"` ### `spaLoaderTag` Customize Nuxt SpaLoader element tag. - **Type**: `string` - **Default:** `"div"` ### `teleportAttrs` Customize Nuxt Teleport element attributes. - **Type**: `object` - **Default** ```json { "id": "teleports" } ``` ### `teleportId` Customize Nuxt Teleport element id. - **Type**: `string` - **Default:** `"teleports"` ### `teleportTag` Customize Nuxt Teleport element tag. - **Type**: `string` - **Default:** `"div"` ### `viewTransition` Default values for view transitions. This only has an effect when **experimental** support for View Transitions is [enabled in your nuxt.config file](https://nuxt.com/docs/getting-started/transitions#view-transitions-api-experimental). This can be overridden with `definePageMeta` on an individual page. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt View Transition API docs](https://nuxt.com/docs/getting-started/transitions#view-transitions-api-experimental) ## appConfig Additional app configuration For programmatic usage and type support, you can directly provide app config with this option. It will be merged with `app.config` file as default value. ### `nuxt` ## appId For multi-app projects, the unique id of the Nuxt application. Defaults to `nuxt-app`. - **Type**: `string` - **Default:** `"nuxt-app"` ## build Shared build configuration. ### `analyze` Nuxt allows visualizing your bundles and how to optimize them. Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - **Type**: `object` - **Default** ```json { "template": "treemap", "projectRoot": "/<rootDir>", "filename": "/<rootDir>/.nuxt/analyze/{name}.html" } ``` **Example**: ```js analyze: { analyzerMode: 'static' } ``` ### `templates` It is recommended to use `addTemplate` from `@nuxt/kit` instead of this option. - **Type**: `array` **Example**: ```js templates: [ { src: '~/modules/support/plugin.js', // `src` can be absolute or relative dst: 'support.js', // `dst` is relative to project `.nuxt` dir } ] ``` ### `transpile` If you want to transpile specific dependencies with Babel, you can add them here. Each item in transpile can be a package name, a function, a string or regex object matching the dependency's file name. You can also use a function to conditionally transpile. The function will receive an object ({ isDev, isServer, isClient, isModern, isLegacy }). - **Type**: `array` **Example**: ```js transpile: [({ isLegacy }) => isLegacy && 'ky'] ``` ## buildDir Define the directory where your built Nuxt files will be placed. Many tools assume that `.nuxt` is a hidden directory (because it starts with a `.`). If that is a problem, you can use this option to prevent that. - **Type**: `string` - **Default:** `"/<rootDir>/.nuxt"` **Example**: ```js export default { buildDir: 'nuxt-build' } ``` ## buildId A unique identifier matching the build. This may contain the hash of the current state of the project. - **Type**: `string` - **Default:** `"cf819bfb-dece-40e8-ad97-a4091ee7fe95"` ## builder The builder to use for bundling the Vue part of your application. - **Type**: `string` - **Default:** `"@nuxt/vite-builder"` ## compatibilityDate Specify a compatibility date for your app. This is used to control the behavior of presets in Nitro, Nuxt Image and other modules that may change behavior without a major version bump. We plan to improve the tooling around this feature in the future. ## components Configure Nuxt component auto-registration. Any components in the directories configured here can be used throughout your pages, layouts (and other components) without needing to explicitly import them. - **Type**: `object` - **Default** ```json { "dirs": [ { "path": "~/components/global", "global": true }, "~/components" ] } ``` **See**: [`components/` directory documentation](https://nuxt.com/docs/guide/directory-structure/components) ## css You can define the CSS files/modules/libraries you want to set globally (included in every page). Nuxt will automatically guess the file type by its extension and use the appropriate pre-processor. You will still need to install the required loader if you need to use them. - **Type**: `array` **Example**: ```js css: [ // Load a Node.js module directly (here it's a Sass file). 'bulma', // CSS file in the project '~/assets/css/main.css', // SCSS file in the project '~/assets/css/main.scss' ] ``` ## debug Set to `true` to enable debug mode. At the moment, it prints out hook names and timings on the server, and logs hook arguments as well in the browser. You can also set this to an object to enable specific debug options. - **Type**: `boolean` - **Default:** `false` ## dev Whether Nuxt is running in development mode. Normally, you should not need to set this. - **Type**: `boolean` - **Default:** `false` ## devServer ### `cors` Set CORS options for the dev server #### `origin` - **Type**: `array` - **Default** ```json [ {} ] ``` ### `host` Dev server listening host ### `https` Whether to enable HTTPS. - **Type**: `boolean` - **Default:** `false` **Example**: ```ts export default defineNuxtConfig({ devServer: { https: { key: './server.key', cert: './server.crt' } } }) ``` ### `loadingTemplate` Template to show a loading screen - **Type**: `function` ### `port` Dev server listening port - **Type**: `number` - **Default:** `3000` ### `url` Listening dev server URL. This should not be set directly as it will always be overridden by the dev server with the full URL (for module and internal use). - **Type**: `string` - **Default:** `"http://localhost:3000"` ## devServerHandlers Nitro development-only server handlers. - **Type**: `array` **See**: [Nitro server routes documentation](https://nitro.build/guide/routing) ## devtools Enable Nuxt DevTools for development. Breaking changes for devtools might not reflect on the version of Nuxt. **See**: [Nuxt DevTools](https://devtools.nuxt.com/) for more information. ## dir Customize default directory structure used by Nuxt. It is better to stick with defaults unless needed. ### `app` - **Type**: `string` - **Default:** `"app"` ### `assets` The assets directory (aliased as `~assets` in your build). - **Type**: `string` - **Default:** `"assets"` ### `layouts` The layouts directory, each file of which will be auto-registered as a Nuxt layout. - **Type**: `string` - **Default:** `"layouts"` ### `middleware` The middleware directory, each file of which will be auto-registered as a Nuxt middleware. - **Type**: `string` - **Default:** `"middleware"` ### `modules` The modules directory, each file in which will be auto-registered as a Nuxt module. - **Type**: `string` - **Default:** `"modules"` ### `pages` The directory which will be processed to auto-generate your application page routes. - **Type**: `string` - **Default:** `"pages"` ### `plugins` The plugins directory, each file of which will be auto-registered as a Nuxt plugin. - **Type**: `string` - **Default:** `"plugins"` ### `public` The directory containing your static files, which will be directly accessible via the Nuxt server and copied across into your `dist` folder when your app is generated. - **Type**: `string` - **Default:** `"public"` ### `shared` The shared directory. This directory is shared between the app and the server. - **Type**: `string` - **Default:** `"shared"` ### `static` - **Type**: `string` - **Default:** `"public"` ## esbuild ### `options` Configure shared esbuild options used within Nuxt and passed to other builders, such as Vite or Webpack. #### `jsxFactory` - **Type**: `string` - **Default:** `"h"` #### `jsxFragment` - **Type**: `string` - **Default:** `"Fragment"` #### `target` - **Type**: `string` - **Default:** `"esnext"` #### `tsconfigRaw` - **Type**: `object` ## experimental ### `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. - **Type**: `boolean` - **Default:** `true` ### `appManifest` Use app manifests to respect route rules on client-side. - **Type**: `boolean` - **Default:** `true` ### `asyncContext` Enable native async context to be accessible for nested composables - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt PR #20918](https://github.com/nuxt/nuxt/pull/20918) ### `asyncEntry` Set to true to generate an async entry point for the Vue bundle (for module federation support). - **Type**: `boolean` - **Default:** `false` ### `browserDevtoolsTiming` Enable timings for Nuxt application hooks in the performance panel of Chromium-based browsers. This feature adds performance markers for Nuxt hooks, allowing you to track their execution time in the browser's Performance tab. This is particularly useful for debugging performance issues. - **Type**: `boolean` - **Default:** `false` **Example**: ```ts // nuxt.config.ts export default defineNuxtConfig({ experimental: { // Enable performance markers for Nuxt hooks in browser devtools browserDevtoolsTiming: true } }) ``` **See**: [PR #29922](https://github.com/nuxt/nuxt/pull/29922) **See**: [Chrome DevTools Performance API](https://developer.chrome.com/docs/devtools/performance/extension#tracks) ### `buildCache` Cache Nuxt/Nitro 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. - **Type**: `boolean` - **Default:** `false` ### `checkOutdatedBuildInterval` Set the time interval (in ms) to check for new builds. Disabled when `experimental.appManifest` is `false`. Set to `false` to disable. - **Type**: `number` - **Default:** `3600000` ### `chromeDevtoolsProjectSettings` Enable integration with Chrome DevTools Workspaces for Nuxt projects. - **Type**: `boolean` - **Default:** `true` **See**: [Chrome DevTools Project Settings](https://docs.google.com/document/d/1rfKPnxsNuXhnF7AiQZhu9kIwdiMS5hnAI05HBwFuBSM) ### `clientFallback` Whether to enable the experimental `<NuxtClientFallback>` component for rendering content on the client if there's an error in SSR. - **Type**: `boolean` - **Default:** `false` ### `clientNodeCompat` Automatically polyfill Node.js imports in the client build using `unenv`. - **Type**: `boolean` - **Default:** `false` **See**: [unenv](https://github.com/unjs/unenv) ### `compileTemplate` Whether to use `lodash.template` to compile Nuxt templates. This flag will be removed with the release of v4 and exists only for advance testing within Nuxt v3.12+ or in [the nightly release channel](https://nuxt.com/docs/guide/going-further/nightly-release-channel). - **Type**: `boolean` - **Default:** `true` ### `componentIslands` Experimental component islands support with `<NuxtIsland>` and `.island.vue` files. By default it is set to 'auto', which means it will be enabled only when there are islands, server components or server pages in your app. - **Type**: `string` - **Default:** `"auto"` ### `configSchema` Config schema support - **Type**: `boolean` - **Default:** `true` **See**: [Nuxt Issue #15592](https://github.com/nuxt/nuxt/issues/15592) ### `cookieStore` Enables CookieStore support to listen for cookie updates (if supported by the browser) and refresh `useCookie` ref values. - **Type**: `boolean` - **Default:** `true` **See**: [CookieStore](https://developer.mozilla.org/en-US/docs/Web/API/CookieStore) ### `crossOriginPrefetch` Enable cross-origin prefetch using the Speculation Rules API. - **Type**: `boolean` - **Default:** `false` ### `debugModuleMutation` Record mutations to `nuxt.options` in module context, helping to debug configuration changes made by modules during the Nuxt initialization phase. When enabled, Nuxt will track which modules modify configuration options, making it easier to trace unexpected configuration changes. - **Type**: `boolean` - **Default:** `false` **Example**: ```ts // nuxt.config.ts export default defineNuxtConfig({ experimental: { // Enable tracking of config mutations by modules debugModuleMutation: true } }) ``` **See**: [PR #30555](https://github.com/nuxt/nuxt/pull/30555) ### `decorators` Enable to use experimental decorators in Nuxt and Nitro. - **Type**: `boolean` - **Default:** `false` **See**: [https://github.com/tc39/proposal-decorators](https://github.com/tc39/proposal-decorators) ### `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. #### `nuxtLink` ##### `componentName` - **Type**: `string` - **Default:** `"NuxtLink"` ##### `prefetch` - **Type**: `boolean` - **Default:** `true` ##### `prefetchOn` ###### `visibility` - **Type**: `boolean` - **Default:** `true` #### `useAsyncData` Options that apply to `useAsyncData` (and also therefore `useFetch`) ##### `deep` - **Type**: `boolean` - **Default:** `true` ##### `errorValue` - **Type**: `string` - **Default:** `"null"` ##### `value` - **Type**: `string` - **Default:** `"null"` #### `useFetch` ### `emitRouteChunkError` Emit `app:chunkError` hook when there is an error loading vite/webpack chunks. 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). You can disable automatic handling by setting this to `false`, or handle chunk errors manually by setting it to `manual`. - **Type**: `string` - **Default:** `"automatic"` **See**: [Nuxt PR #19038](https://github.com/nuxt/nuxt/pull/19038) ### `enforceModuleCompatibility` Whether Nuxt should stop if a Nuxt module is incompatible. - **Type**: `boolean` - **Default:** `false` ### `entryImportMap` - **Type**: `boolean` - **Default:** `true` ### `externalVue` Externalize `vue`, `@vue/*` and `vue-router` when building. - **Type**: `boolean` - **Default:** `true` **See**: [Nuxt Issue #13632](https://github.com/nuxt/nuxt/issues/13632) ### `extraPageMetaExtractionKeys` Configure additional keys to extract from the page metadata when using `scanPageMeta`. This allows modules to access additional metadata from the page metadata. It's recommended to augment the NuxtPage types with your keys. - **Type**: `array` ### `extractAsyncDataHandlers` - **Type**: `boolean` - **Default:** `false` ### `granularCachedData` Whether to call and use the result from `getCachedData` on manual refresh for `useAsyncData` and `useFetch`. - **Type**: `boolean` - **Default:** `false` ### `headNext` Use new experimental 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 - **Type**: `boolean` - **Default:** `true` **See**: [Nuxt Discussion #22632](https://github.com/nuxt/nuxt/discussions/22632) ### `inlineRouteRules` Allow defining `routeRules` directly within your `~/pages` directory using `defineRouteRules`. Rules are converted (based on the path) and applied for server requests. For example, a rule defined in `~/pages/foo/bar.vue` will be applied to `/foo/bar` requests. A rule in `~/pages/foo/[id].vue` will be applied to `/foo/**` requests. For more control, such as if you are using a custom `path` or `alias` set in the page's `definePageMeta`, you should set `routeRules` directly within your `nuxt.config`. - **Type**: `boolean` - **Default:** `false` ### `lazyHydration` Enable automatic configuration of hydration strategies for `<Lazy>` components. This feature intelligently determines when to hydrate lazy components based on visibility, idle time, or other triggers, improving performance by deferring hydration of components until they're needed. - **Type**: `boolean` - **Default:** `true` **Example**: ```ts // nuxt.config.ts export default defineNuxtConfig({ experimental: { lazyHydration: true // Enable smart hydration strategies for Lazy components } }) // In your Vue components <template> <Lazy> <ExpensiveComponent /> </Lazy> </template> ``` **See**: [PR #26468](https://github.com/nuxt/nuxt/pull/26468) ### `localLayerAliases` Resolve `~`, `~~`, `@` and `@@` aliases located within layers with respect to their layer source and root directories. - **Type**: `boolean` - **Default:** `true` ### `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. - **Type**: `boolean` - **Default:** `true` ### `nitroAutoImports` - **Type**: `boolean` - **Default:** `true` ### `noVueServer` Disable vue server renderer endpoint within nitro. - **Type**: `boolean` - **Default:** `false` ### `normalizeComponentNames` Ensure that auto-generated Vue component names match the full component name you would use to auto-import the component. - **Type**: `boolean` - **Default:** `false` ### `parseErrorData` Whether to parse `error.data` when rendering a server error page. - **Type**: `boolean` - **Default:** `false` ### `payloadExtraction` When this option is enabled (by default) payload of pages that are prerendered are extracted - **Type**: `boolean` - **Default:** `true` ### `pendingWhenIdle` For `useAsyncData` and `useFetch`, whether `pending` should be `true` when data has not yet started to be fetched. - **Type**: `boolean` - **Default:** `true` ### `polyfillVueUseHead` Whether or not to add a compatibility layer for modules, plugins or user code relying on the old `@vueuse/head` API. This is disabled to reduce the client-side bundle by ~0.5kb. - **Type**: `boolean` - **Default:** `false` ### `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. - **Type**: `boolean` - **Default:** `true` **Example**: ```ts // nuxt.config.ts export default defineNuxtConfig({ experimental: { // Disable automatic cache cleanup (default is true) purgeCachedData: false } }) ``` **See**: [PR #31379](https://github.com/nuxt/nuxt/pull/31379) ### `relativeWatchPaths` Whether to provide relative paths in the `builder:watch` hook. This flag will be removed with the release of v4 and exists only for advance testing within Nuxt v3.12+ or in [the nightly release channel](https://nuxt.com/docs/guide/going-further/nightly-release-channel). - **Type**: `boolean` - **Default:** `true` ### `renderJsonPayloads` Render JSON payloads with support for revivifying complex types. - **Type**: `boolean` - **Default:** `true` ### `resetAsyncDataToUndefined` Whether `clear` and `clearNuxtData` should reset async data to its *default* value or update it to `null`/`undefined`. - **Type**: `boolean` - **Default:** `true` ### `respectNoSSRHeader` Allow disabling Nuxt SSR responses by setting the `x-nuxt-no-ssr` header. - **Type**: `boolean` - **Default:** `false` ### `restoreState` Whether to restore Nuxt app state 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. Consider carefully before enabling this as it can cause unexpected behavior, and consider providing explicit keys to `useState` as auto-generated keys may not match across builds. - **Type**: `boolean` - **Default:** `false` ### `runtimeBaseURL` - **Type**: `boolean` - **Default:** `false` ### `scanPageMeta` Allow exposing some route metadata defined in `definePageMeta` at build-time to modules (alias, name, path, redirect, props, middleware). This only works with static or strings/arrays rather than variables or conditional assignment. - **Type**: `boolean` - **Default:** `true` **See**: [Nuxt Issues #24770](https://github.com/nuxt/nuxt/issues/24770) ### `serverAppConfig` - **Type**: `boolean` - **Default:** `true` ### `sharedPrerenderData` Automatically share 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. 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.) - **Type**: `boolean` - **Default:** `false` **Example**: ```ts // 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}`) }) ``` ### `spaLoadingTemplateLocation` Keep showing the spa-loading-template until suspense:resolve - **Type**: `string` - **Default:** `"within"` **See**: [Nuxt Issues #21721](https://github.com/nuxt/nuxt/issues/21721) ### `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. - **Type**: `boolean` - **Default:** `true` **Example**: ```ts // nuxt.config.ts export default defineNuxtConfig({ experimental: { // Disable template import resolution from module path templateImportResolution: false } }) ``` **See**: [PR #31175](https://github.com/nuxt/nuxt/pull/31175) ### `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()`. - **Type**: `boolean` - **Default:** `true` ### `templateUtils` Whether to provide a legacy `templateUtils` object (with `serialize`, `importName` and `importSources`) when compiling Nuxt templates. This flag will be removed with the release of v4 and exists only for advance testing within Nuxt v3.12+ or in [the nightly release channel](https://nuxt.com/docs/guide/going-further/nightly-release-channel). - **Type**: `boolean` - **Default:** `true` ### `treeshakeClientOnly` Tree shakes contents of client-only components from server bundle. - **Type**: `boolean` - **Default:** `true` **See**: [Nuxt PR #5750](https://github.com/nuxt/framework/pull/5750) ### `typedPages` Enable the new experimental typed router using [unplugin-vue-router](https://github.com/posva/unplugin-vue-router). - **Type**: `boolean` - **Default:** `false` ### `viewTransition` Enable View Transition API integration with client-side router. - **Type**: `boolean` - **Default:** `false` **See**: [View Transitions API](https://developer.chrome.com/docs/web-platform/view-transitions) ### `viteEnvironmentApi` - **Type**: `boolean` - **Default:** `false` ### `watcher` Set an alternative watcher that will be used as the watching service for Nuxt. Nuxt uses 'chokidar-granular' if your source directory is the same as your root directory . This 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. - **Type**: `string` - **Default:** `"chokidar"` **See**: [chokidar](https://github.com/paulmillr/chokidar) **See**: [@parcel/watcher](https://github.com/parcel-bundler/watcher) ### `writeEarlyHints` Write early hints when using node server. - **Type**: `boolean` - **Default:** `false` <callout> **Note**: nginx does not support 103 Early hints in the current version. </callout> ## extends Extend project from multiple local or remote sources. Value should be either a string or array of strings pointing to source directories or config path relative to current config. You can use `github:`, `gh:` `gitlab:` or `bitbucket:` **See**: [`c12` docs on extending config layers](https://github.com/unjs/c12#extending-config-layer-from-remote-sources) **See**: [`giget` documentation](https://github.com/unjs/giget) ## extensions The extensions that should be resolved by the Nuxt resolver. - **Type**: `array` - **Default** ```json [ ".js", ".jsx", ".mjs", ".ts", ".tsx", ".vue" ] ``` ## features Some features of Nuxt are available on an opt-in basis, or can be disabled based on your needs. ### `devLogs` Stream server logs to the client as you are developing. These logs can be handled in the `dev:ssr-logs` hook. If set to `silent`, the logs will not be printed to the browser console. - **Type**: `boolean` - **Default:** `false` ### `inlineStyles` Inline styles when rendering HTML (currently vite only). You can also pass a function that receives the path of a Vue component and returns a boolean indicating whether to inline the styles for that component. - **Type**: `boolean` - **Default:** `true` ### `noScripts` Turn off rendering of Nuxt scripts and JS resource hints. You can also disable scripts more granularly within `routeRules`. If set to 'production' or `true`, JS will be disabled in production mode only. - **Type**: `boolean` - **Default:** `false` ## future `future` is for early opting-in to new features that will become default in a future (possibly major) version of the framework. ### `compatibilityVersion` Enable early access to Nuxt v4 features or flags. Setting `compatibilityVersion` to `4` changes defaults throughout your Nuxt configuration, but you can granularly re-enable Nuxt v3 behaviour when testing (see example). Please file issues if so, so that we can address in Nuxt or in the ecosystem. - **Type**: `number` - **Default:** `3` **Example**: ```ts export default defineNuxtConfig({ future: { compatibilityVersion: 4, }, // To re-enable _all_ Nuxt v3 behaviour, set the following options: srcDir: '.', dir: { app: 'app' }, experimental: { compileTemplate: true, templateUtils: true, relativeWatchPaths: true, resetAsyncDataToUndefined: true, defaults: { useAsyncData: { deep: true } } }, unhead: { renderSSRHeadOptions: { omitLineBreaks: false } } }) ``` ### `multiApp` This enables early access to the experimental multi-app support. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt Issue #21635](https://github.com/nuxt/nuxt/issues/21635) ### `typescriptBundlerResolution` This enables 'Bundler' module resolution mode for TypeScript, which is the recommended setting for frameworks like Nuxt and Vite. It improves type support when using modern libraries with `exports`. You can set it to false to use the legacy 'Node' mode, which is the default for TypeScript. - **Type**: `boolean` - **Default:** `true` **See**: [TypeScript PR implementing `bundler` module resolution](https://github.com/microsoft/TypeScript/pull/51669) ## generate ### `exclude` This option is no longer used. Instead, use `nitro.prerender.ignore`. - **Type**: `array` ### `routes` The routes to generate. If you are using the crawler, this will be only the starting point for route generation. This is often necessary when using dynamic routes. It is preferred to use `nitro.prerender.routes`. - **Type**: `array` **Example**: ```js routes: ['/users/1', '/users/2', '/users/3'] ``` ## hooks Hooks are listeners to Nuxt events that are typically used in modules, but are also available in `nuxt.config`. Internally, hooks follow a naming pattern using colons (e.g., build:done). For ease of configuration, you can also structure them as an hierarchical object in `nuxt.config` (as below). **Example**: ```js import fs from 'node:fs' import path from 'node:path' export default { hooks: { build: { done(builder) { const extraFilePath = path.join( builder.nuxt.options.buildDir, 'extra-file' ) fs.writeFileSync(extraFilePath, 'Something extra') } } } } ``` ## ignore More customizable than `ignorePrefix`: all files matching glob patterns specified inside the `ignore` array will be ignored in building. - **Type**: `array` - **Default** ```json [ "**/*.stories.{js,cts,mts,ts,jsx,tsx}", "**/*.{spec,test}.{js,cts,mts,ts,jsx,tsx}", "**/*.d.{cts,mts,ts}", "**/*.d.vue.{cts,mts,ts}", "**/.{pnpm-store,vercel,netlify,output,git,cache,data,direnv}", "/vendor", "**/node-compile-cache", "**/test-results", "**/*.sock", ".nuxt/analyze", ".nuxt", "**/-*.*" ] ``` ## ignoreOptions Pass options directly to `node-ignore` (which is used by Nuxt to ignore files). **See**: [node-ignore](https://github.com/kaelzhang/node-ignore) **Example**: ```js ignoreOptions: { ignorecase: false } ``` ## ignorePrefix Any file in `pages/`, `layouts/`, `middleware/`, and `public/` directories will be ignored during the build process if its filename starts with the prefix specified by `ignorePrefix`. This is intended to prevent certain files from being processed or served in the built application. By default, the `ignorePrefix` is set to '-', ignoring any files starting with '-'. - **Type**: `string` - **Default:** `"-"` ## imports Configure how Nuxt auto-imports composables into your application. **See**: [Nuxt documentation](https://nuxt.com/docs/guide/directory-structure/composables) ### `dirs` An array of custom directories that will be auto-imported. Note that this option will not override the default directories (~/composables, ~/utils). - **Type**: `array` **Example**: ```js imports: { // Auto-import pinia stores defined in `~/stores` dirs: ['stores'] } ``` ### `global` - **Type**: `boolean` - **Default:** `false` ### `scan` Whether to scan your `composables/` and `utils/` directories for composables to auto-import. Auto-imports registered by Nuxt or other modules, such as imports from `vue` or `nuxt`, will still be enabled. - **Type**: `boolean` - **Default:** `true` ## logLevel Log level when building logs. Defaults to 'silent' when running in CI or when a TTY is not available. This option is then used as 'silent' in Vite and 'none' in Webpack - **Type**: `string` - **Default:** `"info"` ## modules Modules are Nuxt extensions which can extend its core functionality and add endless integrations. Each module is either a string (which can refer to a package, or be a path to a file), a tuple with the module as first string and the options as a second object, or an inline module function. Nuxt tries to resolve each item in the modules array using node require path (in `node_modules`) and then will be resolved from project `srcDir` if `~` alias is used. - **Type**: `array` <callout> **Note**: Modules are executed sequentially so the order is important. First, the modules defined in `nuxt.config.ts` are loaded. Then, modules found in the `modules/` directory are executed, and they load in alphabetical order. </callout> **Example**: ```js modules: [ // Using package name '@nuxtjs/axios', // Relative to your project srcDir '~/modules/awesome.js', // Providing options ['@nuxtjs/google-analytics', { ua: 'X1234567' }], // Inline definition function () {} ] ``` ## modulesDir Used to set the modules directories for path resolving (for example, webpack's `resolveLoading`, `nodeExternals` and `postcss`). The configuration path is relative to `options.rootDir` (default is current working directory). Setting this field may be necessary if your project is organized as a yarn workspace-styled mono-repository. - **Type**: `array` - **Default** ```json [ "/<rootDir>/node_modules" ] ``` **Example**: ```js export default { modulesDir: ['../../node_modules'] } ``` ## nitro Configuration for Nitro. **See**: [Nitro configuration docs](https://nitro.build/config/) ### `routeRules` - **Type**: `object` ### `runtimeConfig` - **Type**: `object` - **Default** ```json { "public": {}, "app": { "buildId": "cf819bfb-dece-40e8-ad97-a4091ee7fe95", "baseURL": "/", "buildAssetsDir": "/_nuxt/", "cdnURL": "" }, "nitro": { "envPrefix": "NUXT_" } } ``` ## optimization Build time optimization configuration. ### `asyncTransforms` Options passed directly to the transformer from `unctx` that preserves async context after `await`. #### `asyncFunctions` - **Type**: `array` - **Default** ```json [ "defineNuxtPlugin", "defineNuxtRouteMiddleware" ] ``` #### `objectDefinitions` ##### `defineNuxtComponent` - **Type**: `array` - **Default** ```json [ "asyncData", "setup" ] ``` ##### `defineNuxtPlugin` - **Type**: `array` - **Default** ```json [ "setup" ] ``` ##### `definePageMeta` - **Type**: `array` - **Default** ```json [ "middleware", "validate" ] ``` ### `keyedComposables` Functions to inject a key for. As long as the number of arguments passed to the function is less than `argumentLength`, an additional magic string will be injected that can be used to deduplicate requests between server and client. You will need to take steps to handle this additional key. The key will be unique based on the location of the function being invoked within the file. - **Type**: `array` - **Default** ```json [ { "name": "callOnce", "argumentLength": 3, "source": "#app/composables/once" }, { "name": "defineNuxtComponent", "argumentLength": 2, "source": "#app/composables/component" }, { "name": "useState", "argumentLength": 2, "source": "#app/composables/state" }, { "name": "useFetch", "argumentLength": 3, "source": "#app/composables/fetch" }, { "name": "useAsyncData", "argumentLength": 3, "source": "#app/composables/asyncData" }, { "name": "useLazyAsyncData", "argumentLength": 3, "source": "#app/composables/asyncData" }, { "name": "useLazyFetch", "argumentLength": 3, "source": "#app/composables/fetch" } ] ``` ### `treeShake` Tree shake code from specific builds. #### `composables` Tree shake composables from the server or client builds. **Example**: ```js treeShake: { client: { myPackage: ['useServerOnlyComposable'] } } ``` ##### `client` - **Type**: `object` - **Default** ```json { "vue": [ "onRenderTracked", "onRenderTriggered", "onServerPrefetch" ], "#app": [ "definePayloadReducer", "definePageMeta", "onPrehydrate" ] } ``` ##### `server` - **Type**: `object` - **Default** ```json { "vue": [ "onMounted", "onUpdated", "onUnmounted", "onBeforeMount", "onBeforeUpdate", "onBeforeUnmount", "onRenderTracked", "onRenderTriggered", "onActivated", "onDeactivated" ], "#app": [ "definePayloadReviver", "definePageMeta" ] } ``` ## oxc Configure shared oxc options used within Nuxt and passed where necessary. ### `transform` Options for `oxc-transform` **See**: [Oxc transform docs](https://oxc.rs/docs/guide/usage/transformer.html) #### `options` ##### `jsxFactory` - **Type**: `string` - **Default:** `"h"` ##### `jsxFragment` - **Type**: `string` - **Default:** `"Fragment"` ##### `target` - **Type**: `string` - **Default:** `"esnext"` ## pages Whether to use the vue-router integration in Nuxt 3. If you do not provide a value it will be enabled if you have a `pages/` directory in your source folder. Additionally, you can provide a glob pattern or an array of patterns to scan only certain files for pages. **Example**: ```js pages: { pattern: ['**\/*\/*.vue', '!**\/*.spec.*'], } ``` ## plugins An array of nuxt app plugins. Each plugin can be a string (which can be an absolute or relative path to a file). If it ends with `.client` or `.server` then it will be automatically loaded only in the appropriate context. It can also be an object with `src` and `mode` keys. - **Type**: `array` <callout> **Note**: Plugins are also auto-registered from the `~/plugins` directory and these plugins do not need to be listed in `nuxt.config` unless you need to customize their order. All plugins are deduplicated by their src path. </callout> **See**: [`plugins/` directory documentation](https://nuxt.com/docs/guide/directory-structure/plugins) **Example**: ```js plugins: [ '~/plugins/foo.client.js', // only in client side '~/plugins/bar.server.js', // only in server side '~/plugins/baz.js', // both client & server { src: '~/plugins/both-sides.js' }, { src: '~/plugins/client-only.js', mode: 'client' }, // only on client side { src: '~/plugins/server-only.js', mode: 'server' } // only on server side ] ``` ## postcss ### `order` A strategy for ordering PostCSS plugins. - **Type**: `function` ### `plugins` Options for configuring PostCSS plugins. **See**: [PostCSS docs](https://postcss.org/) #### `autoprefixer` Plugin to parse CSS and add vendor prefixes to CSS rules. **See**: [`autoprefixer`](https://github.com/postcss/autoprefixer) #### `cssnano` - **Type**: `object` **See**: [`cssnano` configuration options](https://cssnano.github.io/cssnano/docs/config-file/#configuration-options) ## rootDir Define the root directory of your application. This property can be overwritten (for example, running `nuxt ./my-app/` will set the `rootDir` to the absolute path of `./my-app/` from the current/working directory. It is normally not needed to configure this option. - **Type**: `string` - **Default:** `"/<rootDir>"` ## routeRules Global route options applied to matching server routes. **Experimental**: This is an experimental feature and API may change in the future. **See**: [Nitro route rules documentation](https://nitro.build/config/#routerules) ## router ### `options` Additional router options passed to `vue-router`. On top of the options for `vue-router`, Nuxt offers additional options to customize the router (see below). <callout> **Note**: Only JSON serializable options should be passed by Nuxt config. For more control, you can use `app/router.options.ts` file. </callout> **See**: [Vue Router documentation](https://router.vuejs.org/api/interfaces/routeroptions.html). #### `hashMode` You can enable hash history in SPA mode. In this mode, router uses a hash character (#) before the actual URL that is internally passed. When enabled, the **URL is never sent to the server** and **SSR is not supported**. - **Type**: `boolean` - **Default:** `false` **Default**: false #### `scrollBehaviorType` Customize the scroll behavior for hash links. - **Type**: `string` - **Default:** `"auto"` **Default**: 'auto' ## runtimeConfig Runtime config allows passing dynamic config and environment variables to the Nuxt app context. The value of this object is accessible from server only using `useRuntimeConfig`. It mainly should hold *private* configuration which is not exposed on the frontend. This could include a reference to your API secret tokens. Anything under `public` and `app` will be exposed to the frontend as well. Values are automatically replaced by matching env variables at runtime, e.g. setting an environment variable `NUXT_API_KEY=my-api-key NUXT_PUBLIC_BASE_URL=/foo/` would overwrite the two values in the example below. - **Type**: `object` - **Default** ```json { "public": {}, "app": { "buildId": "cf819bfb-dece-40e8-ad97-a4091ee7fe95", "baseURL": "/", "buildAssetsDir": "/_nuxt/", "cdnURL": "" } } ``` **Example**: ```js export default { runtimeConfig: { apiKey: '', // Default to an empty string, automatically set at runtime using process.env.NUXT_API_KEY public: { baseURL: '' // Exposed to the frontend as well. } } } ``` ## server ### `builder` - **Type**: `string` - **Default:** `"@nuxt/nitro-server"` ## serverDir Define the server directory of your Nuxt application, where Nitro routes, middleware and plugins are kept. If a relative path is specified, it will be relative to your `rootDir`. - **Type**: `string` - **Default:** `"/<srcDir>/server"` ## serverHandlers Nitro server handlers. Each handler accepts the following options: - handler: The path to the file defining the handler. - route: The route under which the handler is available. This follows the conventions of [rou3](https://github.com/unjs/rou3). - method: The HTTP method of requests that should be handled. - middleware: Specifies whether it is a middleware handler. - lazy: Specifies whether to use lazy loading to import the handler. - **Type**: `array` **See**: [`server/` directory documentation](https://nuxt.com/docs/guide/directory-structure/server) <callout> **Note**: Files from `server/api`, `server/middleware` and `server/routes` will be automatically registered by Nuxt. </callout> **Example**: ```js serverHandlers: [ { route: '/path/foo/**:name', handler: '~/server/foohandler.ts' } ] ``` ## sourcemap Configures whether and how sourcemaps are generated for server and/or client bundles. If set to a single boolean, that value applies to both server and client. Additionally, the `'hidden'` option is also available for both server and client. Available options for both client and server: - `true`: Generates sourcemaps and includes source references in the final bundle. - `false`: Does not generate any sourcemaps. - `'hidden'`: Generates sourcemaps but does not include references in the final bundle. - **Type**: `object` - **Default** ```json { "server": true, "client": false } ``` ## spaLoadingTemplate Boolean or a path to an HTML file with the contents of which will be inserted into any HTML page rendered with `ssr: false`. - If it is unset, it will use `~/app/spa-loading-template.html` file in one of your layers, if it exists. - If it is false, no SPA loading indicator will be loaded. - If true, Nuxt will look for `~/app/spa-loading-template.html` file in one of your layers, or a default Nuxt image will be used. Some good sources for spinners are [SpinKit](https://github.com/tobiasahlin/SpinKit) or [SVG Spinners](https://icones.js.org/collection/svg-spinners). - **Default:** `null` **Example**: ~/app/spa-loading-template.html ```html <!-- https://github.com/barelyhuman/snips/blob/dev/pages/css-loader.md --> <div class="loader"></div> <style> .loader { display: block; position: fixed; z-index: 1031; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 18px; height: 18px; box-sizing: border-box; border: solid 2px transparent; border-top-color: #000; border-left-color: #000; border-bottom-color: #efefef; border-right-color: #efefef; border-radius: 50%; -webkit-animation: loader 400ms linear infinite; animation: loader 400ms linear infinite; } @-webkit-keyframes loader { 0% { -webkit-transform: translate(-50%, -50%) rotate(0deg); } 100% { -webkit-transform: translate(-50%, -50%) rotate(360deg); } } @keyframes loader { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } </style> ``` ## srcDir Define the source directory of your Nuxt application. If a relative path is specified, it will be relative to the `rootDir`. - **Type**: `string` - **Default:** `"/<srcDir>"` **Example**: ```js export default { srcDir: 'src/' } ``` This would work with the following folder structure: ```bash -| app/ ---| node_modules/ ---| nuxt.config.js ---| package.json ---| src/ ------| assets/ ------| components/ ------| layouts/ ------| middleware/ ------| pages/ ------| plugins/ ------| public/ ------| store/ ------| server/ ------| app.config.ts ------| app.vue ------| error.vue ``` ## ssr Whether to enable rendering of HTML - either dynamically (in server mode) or at generate time. If set to `false` generated pages will have no content. - **Type**: `boolean` - **Default:** `true` ## telemetry Manually disable nuxt telemetry. **See**: [Nuxt Telemetry](https://github.com/nuxt/telemetry) for more information. ## test Whether your app is being unit tested. - **Type**: `boolean` - **Default:** `false` ## theme Extend project from a local or remote source. Value should be a string pointing to source directory or config path relative to current config. You can use `github:`, `gitlab:`, `bitbucket:` or `https://` to extend from a remote git repository. - **Type**: `string` ## typescript Configuration for Nuxt's TypeScript integration. ### `builder` Which builder types to include for your project. By default Nuxt infers this based on your `builder` option (defaulting to 'vite') but you can either turn off builder environment types (with `false`) to handle this fully yourself, or opt for a 'shared' option. The 'shared' option is advised for module authors, who will want to support multiple possible builders. - **Default:** `null` ### `hoist` Modules to generate deep aliases for within `compilerOptions.paths`. This does not yet support subpaths. It may be necessary when using Nuxt within a pnpm monorepo with `shamefully-hoist=false`. - **Type**: `array` - **Default** ```json [ "@unhead/vue", "@nuxt/devtools", "vue", "@vue/runtime-core", "@vue/compiler-sfc", "vue-router", "vue-router/auto-routes", "unplugin-vue-router/client", "@nuxt/schema", "nuxt" ] ``` ### `includeWorkspace` Include parent workspace in the Nuxt project. Mostly useful for themes and module authors. - **Type**: `boolean` - **Default:** `false` ### `shim` Generate a `*.vue` shim. We recommend instead letting the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) generate accurate types for your components. Note that you may wish to set this to `true` if you are using other libraries, such as ESLint, that are unable to understand the type of `.vue` files. - **Type**: `boolean` - **Default:** `false` ### `strict` TypeScript comes with certain checks to give you more safety and analysis of your program. Once youโ€™ve converted your codebase to TypeScript, you can start enabling these checks for greater safety. [Read More](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) - **Type**: `boolean` - **Default:** `true` ### `tsConfig` You can extend generated `.nuxt/tsconfig.json` using this option. ### `typeCheck` Enable build-time type checking. If set to true, this will type check in development. You can restrict this to build-time type checking by setting it to `build`. Requires to install `typescript` and `vue-tsc` as dev dependencies. - **Type**: `boolean` - **Default:** `false` **See**: [Nuxt TypeScript docs](https://nuxt.com/docs/guide/concepts/typescript) ## unhead An object that allows us to configure the `unhead` nuxt module. ### `legacy` Enable the legacy compatibility mode for `unhead` module. This applies the following changes: - Disables Capo.js sorting - Adds the `DeprecationsPlugin`: supports `hid`, `vmid`, `children`, `body` - Adds the `PromisesPlugin`: supports promises as input - **Type**: `boolean` - **Default:** `false` **See**: [`unhead` migration documentation](https://unhead.unjs.io/docs/typescript/head/guides/get-started/migration) **Example**: ```ts export default defineNuxtConfig({ unhead: { legacy: true }) ``` ### `renderSSRHeadOptions` An object that will be passed to `renderSSRHead` to customize the output. - **Type**: `object` - **Default** ```json { "omitLineBreaks": false } ``` **Example**: ```ts export default defineNuxtConfig({ unhead: { renderSSRHeadOptions: { omitLineBreaks: true } }) ``` ## vite Configuration that will be passed directly to Vite. **See**: [Vite configuration docs](https://vite.dev/config) for more information. Please note that not all vite options are supported in Nuxt. ### `build` #### `assetsDir` - **Type**: `string` - **Default:** `"_nuxt/"` #### `emptyOutDir` - **Type**: `boolean` - **Default:** `false` ### `cacheDir` - **Type**: `string` - **Default:** `"/<rootDir>/node_modules/.cache/vite"` ### `clearScreen` - **Type**: `boolean` - **Default:** `true` ### `define` - **Type**: `object` - **Default** ```json { "__VUE_PROD_DEVTOOLS__": false, "__VUE_PROD_HYDRATION_MISMATCH_DETAILS__": false, "process.dev": false, "import.meta.dev": false, "process.test": false, "import.meta.test": false } ``` ### `esbuild` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` ### `mode` - **Type**: `string` - **Default:** `"production"` ### `optimizeDeps` #### `esbuildOptions` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` #### `exclude` - **Type**: `array` - **Default** ```json [ "vue-demi" ] ``` ### `publicDir` - **Type**: `boolean` - **Default:** `false` ### `resolve` #### `extensions` - **Type**: `array` - **Default** ```json [ ".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue" ] ``` ### `root` - **Type**: `string` - **Default:** `"/<srcDir>"` ### `server` #### `fs` ##### `allow` - **Type**: `array` - **Default** ```json [ "/<rootDir>/.nuxt", "/<srcDir>", "/<rootDir>", "/<workspaceDir>" ] ``` ### `vue` #### `features` ##### `propsDestructure` - **Type**: `boolean` - **Default:** `true` #### `isProduction` - **Type**: `boolean` - **Default:** `true` #### `script` ##### `hoistStatic` #### `template` ##### `compilerOptions` - **Type**: `object` ##### `transformAssetUrls` - **Type**: `object` - **Default** ```json { "video": [ "src", "poster" ], "source": [ "src" ], "img": [ "src" ], "image": [ "xlink:href", "href" ], "use": [ "xlink:href", "href" ] } ``` ### `vueJsx` - **Type**: `object` - **Default** ```json { "isCustomElement": { "$schema": { "title": "", "description": "", "tags": [] } }, "defineComponentName": [ "defineComponent", "defineNuxtComponent" ] } ``` ## vue Vue.js config ### `compilerOptions` Options for the Vue compiler that will be passed at build time. **See**: [Vue documentation](https://vuejs.org/api/application.html#app-config-compileroptions) ### `config` It is possible to pass configure the Vue app globally. Only serializable options may be set in your `nuxt.config`. All other options should be set at runtime in a Nuxt plugin.. **See**: [Vue app config documentation](https://vuejs.org/api/application.html#app-config) ### `propsDestructure` Enable reactive destructure for `defineProps` - **Type**: `boolean` - **Default:** `true` ### `runtimeCompiler` Include Vue compiler in runtime bundle. - **Type**: `boolean` - **Default:** `false` ### `transformAssetUrls` #### `image` - **Type**: `array` - **Default** ```json [ "xlink:href", "href" ] ``` #### `img` - **Type**: `array` - **Default** ```json [ "src" ] ``` #### `source` - **Type**: `array` - **Default** ```json [ "src" ] ``` #### `use` - **Type**: `array` - **Default** ```json [ "xlink:href", "href" ] ``` #### `video` - **Type**: `array` - **Default** ```json [ "src", "poster" ] ``` ## watch The watch property lets you define patterns that will restart the Nuxt dev server when changed. It is an array of strings or regular expressions. Strings should be either absolute paths or relative to the `srcDir` (and the `srcDir` of any layers). Regular expressions will be matched against the path relative to the project `srcDir` (and the `srcDir` of any layers). - **Type**: `array` ## watchers The watchers property lets you overwrite watchers configuration in your `nuxt.config`. ### `chokidar` Options to pass directly to `chokidar`. **See**: [chokidar](https://github.com/paulmillr/chokidar#api) #### `ignoreInitial` - **Type**: `boolean` - **Default:** `true` #### `ignorePermissionErrors` - **Type**: `boolean` - **Default:** `true` ### `rewatchOnRawEvents` An array of event types, which, when received, will cause the watcher to restart. ### `webpack` `watchOptions` to pass directly to webpack. **See**: [webpack@4 watch options](https://v4.webpack.js.org/configuration/watch/#watchoptions). #### `aggregateTimeout` - **Type**: `number` - **Default:** `1000` ## webpack ### `aggressiveCodeRemoval` Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle. - **Type**: `boolean` - **Default:** `false` ### `analyze` Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them. Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options). - **Type**: `object` - **Default** ```json { "template": "treemap", "projectRoot": "/<rootDir>", "filename": "/<rootDir>/.nuxt/analyze/{name}.html" } ``` **Example**: ```js analyze: { analyzerMode: 'static' } ``` ### `cssSourceMap` Enables CSS source map support (defaults to `true` in development). - **Type**: `boolean` - **Default:** `false` ### `devMiddleware` See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options. #### `stats` - **Type**: `string` - **Default:** `"none"` ### `experiments` Configure [webpack experiments](https://webpack.js.org/configuration/experiments/) ### `extractCSS` Enables Common CSS Extraction. Using [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) under the hood, your CSS will be extracted into separate files, usually one per component. This allows caching your CSS and JavaScript separately. - **Type**: `boolean` - **Default:** `true` **Example**: ```js export default { webpack: { extractCSS: true, // or extractCSS: { ignoreOrder: true } } } ``` **Example**: ```js export default { webpack: { extractCSS: true, optimization: { splitChunks: { cacheGroups: { styles: { name: 'styles', test: /\.(css|vue)$/, chunks: 'all', enforce: true } } } } } } ``` ### `filenames` Customize bundle filenames. To understand a bit more about the use of manifests, take a look at [webpack documentation](https://webpack.js.org/guides/code-splitting/). <callout> **Note**: Be careful when using non-hashed based filenames in production as most browsers will cache the asset and not detect the changes on first load. </callout> **Example**: ```js filenames: { chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js') } ``` #### `app` - **Type**: `function` #### `chunk` - **Type**: `function` #### `css` - **Type**: `function` #### `font` - **Type**: `function` #### `img` - **Type**: `function` #### `video` - **Type**: `function` ### `friendlyErrors` Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin). - **Type**: `boolean` - **Default:** `true` ### `hotMiddleware` See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options. ### `loaders` Customize the options of Nuxt's integrated webpack loaders. #### `css` See [css-loader](https://github.com/webpack-contrib/css-loader) for available options. ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `importLoaders` - **Type**: `number` - **Default:** `0` ##### `url` ###### `filter` - **Type**: `function` #### `cssModules` See [css-loader](https://github.com/webpack-contrib/css-loader) for available options. ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `importLoaders` - **Type**: `number` - **Default:** `0` ##### `modules` ###### `localIdentName` - **Type**: `string` - **Default:** `"[local]_[hash:base64:5]"` ##### `url` ###### `filter` - **Type**: `function` #### `esbuild` - **Type**: `object` - **Default** ```json { "target": "esnext", "jsxFactory": "h", "jsxFragment": "Fragment", "tsconfigRaw": {} } ``` **See**: [esbuild loader](https://github.com/esbuild-kit/esbuild-loader) #### `file` **See**: [`file-loader` Options](https://github.com/webpack-contrib/file-loader#options) **Default**: ```ts { esModule: false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `fontUrl` **See**: [`file-loader` Options](https://github.com/webpack-contrib/file-loader#options) **Default**: ```ts { esModule: false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `imgUrl` **See**: [`file-loader` Options](https://github.com/webpack-contrib/file-loader#options) **Default**: ```ts { esModule: false } ``` ##### `esModule` - **Type**: `boolean` - **Default:** `false` ##### `limit` - **Type**: `number` - **Default:** `1000` #### `less` - **Default** ```json { "sourceMap": false } ``` **See**: [`less-loader` Options](https://github.com/webpack-contrib/less-loader#options) #### `pugPlain` **See**: [`pug` options](https://pugjs.org/api/reference.html#options) #### `sass` **See**: [`sass-loader` Options](https://github.com/webpack-contrib/sass-loader#options) **Default**: ```ts { sassOptions: { indentedSyntax: true } } ``` ##### `sassOptions` ###### `indentedSyntax` - **Type**: `boolean` - **Default:** `true` #### `scss` - **Default** ```json { "sourceMap": false } ``` **See**: [`sass-loader` Options](https://github.com/webpack-contrib/sass-loader#options) #### `stylus` - **Default** ```json { "sourceMap": false } ``` **See**: [`stylus-loader` Options](https://github.com/webpack-contrib/stylus-loader#options) #### `vue` See [vue-loader](https://github.com/vuejs/vue-loader) for available options. ##### `compilerOptions` - **Type**: `object` ##### `propsDestructure` - **Type**: `boolean` - **Default:** `true` ##### `transformAssetUrls` - **Type**: `object` - **Default** ```json { "video": [ "src", "poster" ], "source": [ "src" ], "img": [ "src" ], "image": [ "xlink:href", "href" ], "use": [ "xlink:href", "href" ] } ``` #### `vueStyle` - **Default** ```json { "sourceMap": false } ``` ### `optimization` Configure [webpack optimization](https://webpack.js.org/configuration/optimization/). #### `minimize` Set minimize to `false` to disable all minimizers. (It is disabled in development by default). - **Type**: `boolean` - **Default:** `true` #### `minimizer` You can set minimizer to a customized array of plugins. #### `runtimeChunk` - **Type**: `string` - **Default:** `"single"` #### `splitChunks` ##### `automaticNameDelimiter` - **Type**: `string` - **Default:** `"/"` ##### `cacheGroups` ##### `chunks` - **Type**: `string` - **Default:** `"all"` ### `optimizeCSS` OptimizeCSSAssets plugin options. Defaults to true when `extractCSS` is enabled. - **Type**: `boolean` - **Default:** `false` **See**: [css-minimizer-webpack-plugin documentation](https://github.com/webpack-contrib/css-minimizer-webpack-plugin). ### `plugins` Add webpack plugins. - **Type**: `array` **Example**: ```js import webpack from 'webpack' import { version } from './package.json' // ... plugins: [ new webpack.DefinePlugin({ 'process.VERSION': version }) ] ``` ### `postcss` Customize PostCSS Loader. same options as [`postcss-loader` options](https://github.com/webpack-contrib/postcss-loader#options) #### `postcssOptions` ##### `plugins` - **Type**: `object` - **Default** ```json { "autoprefixer": {}, "cssnano": {} } ``` ### `profile` Enable the profiler in webpackbar. It is normally enabled by CLI argument `--profile`. - **Type**: `boolean` - **Default:** `false` **See**: [webpackbar](https://github.com/unjs/webpackbar#profile). ### `serverURLPolyfill` The polyfill library to load to provide URL and URLSearchParams. Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)). - **Type**: `string` - **Default:** `"url"` ### `warningIgnoreFilters` Filters to hide build warnings. - **Type**: `array` ## workspaceDir Define the workspace directory of your application. Often this is used when in a monorepo setup. Nuxt will attempt to detect your workspace directory automatically, but you can override it here. It is normally not needed to configure this option. - **Type**: `string` - **Default:** `"/<workspaceDir>"` # abortNavigation > abortNavigation is a helper function that prevents navigation from taking place and throws an error if one is set as a parameter. <warning> `abortNavigation` is only usable inside a [route middleware handler](https://nuxt.com/docs/3.x/directory-structure/middleware). </warning> ## Type ```ts [Signature] export function abortNavigation (err?: Error | string): false ``` ## Parameters ### `err` - **Type**: [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) | `string`<br /> Optional error to be thrown by `abortNavigation`. ## Examples The example below shows how you can use `abortNavigation` in a route middleware to prevent unauthorized route access: ```ts [middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const user = useState('user') if (!user.value.isAuthorized) { return abortNavigation() } if (to.path !== '/edit-post') { return navigateTo('/edit-post') } }) ``` ### `err` as a String You can pass the error as a string: ```ts [middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const user = useState('user') if (!user.value.isAuthorized) { return abortNavigation('Insufficient permissions.') } }) ``` ### `err` as an Error Object You can pass the error as an [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) object, e.g. caught by the `catch`-block: ```ts [middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { try { /* code that might throw an error */ } catch (err) { return abortNavigation(err) } }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # addRouteMiddleware > addRouteMiddleware() is a helper function to dynamically add middleware in your application. <note> Route middleware are navigation guards stored in the [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/middleware) directory of your Nuxt application (unless [set otherwise](https://nuxt.com/docs/3.x/api/nuxt-config#middleware)). </note> ## Type ```ts function addRouteMiddleware (name: string, middleware: RouteMiddleware, options?: AddRouteMiddlewareOptions): void function addRouteMiddleware (middleware: RouteMiddleware): void interface AddRouteMiddlewareOptions { global?: boolean } ``` ## Parameters ### `name` - **Type:** `string` | `RouteMiddleware` Can be either a string or a function of type `RouteMiddleware`. Function takes the next route `to` as the first argument and the current route `from` as the second argument, both of which are Vue route objects. Learn more about available properties of [route objects](https://nuxt.com/docs/3.x/api/composables/use-route). ### `middleware` - **Type:** `RouteMiddleware` The second argument is a function of type `RouteMiddleware`. Same as above, it provides `to` and `from` route objects. It becomes optional if the first argument in `addRouteMiddleware()` is already passed as a function. ### `options` - **Type:** `AddRouteMiddlewareOptions` An optional `options` argument lets you set the value of `global` to `true` to indicate whether the router middleware is global or not (set to `false` by default). ## Examples ### Named Route Middleware Named route middleware is defined by providing a string as the first argument and a function as the second: ```ts [plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware('named-middleware', () => { console.log('named middleware added in Nuxt plugin') }) }) ``` When defined in a plugin, it overrides any existing middleware of the same name located in the `middleware/` directory. ### Global Route Middleware Global route middleware can be defined in two ways: - Pass a function directly as the first argument without a name. It will automatically be treated as global middleware and applied on every route change.```ts [plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware((to, from) => { console.log('anonymous global middleware that runs on every route change') }) }) ``` - Set an optional, third argument `{ global: true }` to indicate whether the route middleware is global.```ts [plugins/my-plugin.ts] export default defineNuxtPlugin(() => { addRouteMiddleware('global-middleware', (to, from) => { console.log('global middleware that runs on every route change') }, { global: true }, ) }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # callOnce > Run a given function or block of code once during SSR or CSR. <important> This utility is available since [Nuxt v3.9](https://nuxt.com/blog/v3-9). </important> ## Purpose The `callOnce` function is designed to execute a given function or block of code only once during: - server-side rendering but not hydration - client-side navigation This is useful for code that should be executed only once, such as logging an event or setting up a global state. ## Usage The default mode of `callOnce` is to run code only once. For example, if the code runs on the server it won't run again on the client. It also won't run again if you `callOnce` more than once on the client, for example by navigating back to this page. ```vue [app.vue] <script setup lang="ts"> const websiteConfig = useState('config') await callOnce(async () => { console.log('This will only be logged once') websiteConfig.value = await $fetch('https://my-cms.com/api/website-config') }) </script> ``` It is also possible to run on every navigation while still avoiding the initial server/client double load. For this, it is possible to use the `navigation` mode: ```vue [app.vue] <script setup lang="ts"> const websiteConfig = useState('config') await callOnce(async () => { console.log('This will only be logged once and then on every client side navigation') websiteConfig.value = await $fetch('https://my-cms.com/api/website-config') }, { mode: 'navigation' }) </script> ``` <important> `navigation` mode is available since [Nuxt v3.15](https://nuxt.com/blog/v3-15). </important> <tip to="https://nuxt.com/docs/3.x/getting-started/state-management#usage-with-pinia"> `callOnce` is useful in combination with the [Pinia module](https://nuxt.com/modules/pinia) to call store actions. </tip> <read-more to="https://nuxt.com/docs/3.x/getting-started/state-management"> </read-more> <warning> Note that `callOnce` doesn't return anything. You should use [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) or [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) if you want to do data fetching during SSR. </warning> <note> `callOnce` is a composable meant to be called directly in a setup function, plugin, or route middleware, because it needs to add data to the Nuxt payload to avoid re-calling the function on the client when the page hydrates. </note> ## Type ```ts [Signature] export function callOnce (key?: string, fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void> export function callOnce (fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void> type CallOnceOptions = { /** * Execution mode for the callOnce function * @default 'render' */ mode?: 'navigation' | 'render' } ``` ## Parameters - `key`: A unique key ensuring that the code is run once. If you do not provide a key, then a key that is unique to the file and line number of the instance of `callOnce` will be generated for you. - `fn`: The function to run once. It can be asynchronous. - `options`: Setup the mode, either to re-execute on navigation (`navigation`) or just once for the lifetime of the app (`render`). Defaults to `render`. - `render`: Executes once during initial render (either SSR or CSR) - Default mode - `navigation`: Executes once during initial render and once per subsequent client-side navigation --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/once.ts) # clearError > The clearError composable clears all handled errors. Within your pages, components, and plugins, you can use `clearError` to clear all errors and redirect the user. **Parameters:** - `options?: { redirect?: string }` You can provide an optional path to redirect to (for example, if you want to navigate to a 'safe' page). ```ts // Without redirect clearError() // With redirect clearError({ redirect: '/homepage' }) ``` Errors are set in state using [`useError()`](https://nuxt.com/docs/3.x/api/composables/use-error). The `clearError` composable will reset this state and calls the `app:error:cleared` hook with the provided options. <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # clearNuxtData > Delete cached data, error status and pending promises of useAsyncData and useFetch. <note> This method is useful if you want to invalidate the data fetching for another page. </note> ## Type ```ts [Signature] export function clearNuxtData (keys?: string | string[] | ((key: string) => boolean)): void ``` ## Parameters - `keys`: One or an array of keys that are used in [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) to delete their cached data. If no keys are provided, **all data** will be invalidated. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # clearNuxtState > Delete the cached state of useState. <note> This method is useful if you want to invalidate the state of `useState`. </note> ## Type ```ts [Signature] export function clearNuxtState (keys?: string | string[] | ((key: string) => boolean)): void ``` ## Parameters - `keys`: One or an array of keys that are used in [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) to delete their cached state. If no keys are provided, **all state** will be invalidated. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/state.ts) # createError > Create an error object with additional metadata. You can use this function to create an error object with additional metadata. It is usable in both the Vue and Nitro portions of your app, and is meant to be thrown. ## Parameters - `err`: `string | { cause, data, message, name, stack, status, statusText, fatal }` You can pass either a string or an object to the `createError` function. If you pass a string, it will be used as the error `message`, and the `status` will default to `500`. If you pass an object, you can set multiple properties of the error, such as `status`, `message`, and other error properties. ## In Vue App If you throw an error created with `createError`: - on server-side, it will trigger a full-screen error page which you can clear with `clearError`. - on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`. ### Example ```vue [pages/movies/[slug].vue] <script setup lang="ts"> const route = useRoute() const { data } = await useFetch(`/api/movies/${route.params.slug}`) if (!data.value) { throw createError({ status: 404, statusText: 'Page Not Found' }) } </script> ``` ## In API Routes Use `createError` to trigger error handling in server API routes. ### Example ```ts [server/api/error.ts] export default eventHandler(() => { throw createError({ status: 404, statusText: 'Page Not Found', }) }) ``` In API routes, using `createError` by passing an object with a short `statusText` is recommended because it can be accessed on the client side. Otherwise, a `message` passed to `createError` on an API route will not propagate to the client. Alternatively, you can use the `data` property to pass data back to the client. When handling the error with `useFetch`, the custom data is available at `error.value.data.data`. In any case, always consider avoiding to put dynamic user input to the message to avoid potential security issues. <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # defineLazyHydrationComponent > Define a lazy hydration component with a specific strategy. `defineLazyHydrationComponent` is a compiler macro that helps you create a component with a specific lazy hydration strategy. Lazy hydration defers hydration until components become visible or until the browser has completed more critical tasks. This can significantly reduce the initial performance cost, especially for non-essential components. ## Usage ### Visibility Strategy Hydrates the component when it becomes visible in the viewport. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'visible', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the element(s) is 100px away from entering the viewport. --> <LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" /> </div> </template> ``` The `hydrateOnVisible` prop is optional. You can pass an object to customize the behavior of the `IntersectionObserver` under the hood. <read-more title="IntersectionObserver options" to="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver"> Read more about the options for `hydrate-on-visible`. </read-more> <note> Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible). </note> ### Idle Strategy Hydrates the component when the browser is idle. This is suitable if you need the component to load as soon as possible, but not block the critical rendering path. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'idle', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the browser is idle or after 2000ms. --> <LazyHydrationMyComponent :hydrate-on-idle="2000" /> </div> </template> ``` The `hydrateOnIdle` prop is optional. You can pass a positive number to specify the maximum timeout. Idle strategy is for components that can be hydrated when the browser is idle. <note> Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle). </note> ### Interaction Strategy Hydrates the component after a specified interaction (e.g., click, mouseover). ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'interaction', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the element(s) is hovered over by the pointer. --> <LazyHydrationMyComponent hydrate-on-interaction="mouseover" /> </div> </template> ``` The `hydrateOnInteraction` prop is optional. If you do not pass an event or a list of events, it defaults to hydrating on `pointerenter`, `click`, and `focus`. <note> Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction). </note> ### Media Query Strategy Hydrates the component when the window matches a media query. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'mediaQuery', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration will be triggered when the window width is greater than or equal to 768px. --> <LazyHydrationMyComponent hydrate-on-media-query="(min-width: 768px)" /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query). </note> ### Time Strategy Hydrates the component after a specified delay (in milliseconds). ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'time', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- Hydration is triggered after 1000ms. --> <LazyHydrationMyComponent :hydrate-after="1000" /> </div> </template> ``` Time strategy is for components that can wait a specific amount of time. ### If Strategy Hydrates the component based on a boolean condition. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'if', () => import('./components/MyComponent.vue'), ) const isReady = ref(false) function myFunction () { // Trigger custom hydration strategy... isReady.value = true } </script> <template> <div> <!-- Hydration is triggered when isReady becomes true. --> <LazyHydrationMyComponent :hydrate-when="isReady" /> </div> </template> ``` If strategy is best for components that might not always need to be hydrated. ### Never Hydrate Never hydrates the component. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'never', () => import('./components/MyComponent.vue'), ) </script> <template> <div> <!-- This component will never be hydrated by Vue. --> <LazyHydrationMyComponent /> </div> </template> ``` ### Listening to Hydration Events All delayed hydration components emit a `@hydrated` event when they are hydrated. ```vue <script setup lang="ts"> const LazyHydrationMyComponent = defineLazyHydrationComponent( 'visible', () => import('./components/MyComponent.vue'), ) function onHydrate () { console.log('Component has been hydrated!') } </script> <template> <div> <LazyHydrationMyComponent :hydrate-on-visible="{ rootMargin: '100px' }" @hydrated="onHydrated" /> </div> </template> ``` ## Parameters <warning> To ensure that the compiler correctly recognizes this macro, avoid using external variables. The following approach will prevent the macro from being properly recognized: ```vue <script setup lang="ts"> const strategy = 'visible' const source = () => import('./components/MyComponent.vue') const LazyHydrationMyComponent = defineLazyHydrationComponent(strategy, source) </script> ``` </warning> ### `strategy` - **Type**: `'visible' | 'idle' | 'interaction' | 'mediaQuery' | 'if' | 'time' | 'never'` - **Required**: `true` <table> <thead> <tr> <th> Strategy </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> visible </code> </td> <td> Hydrates when the component becomes visible in the viewport. </td> </tr> <tr> <td> <code> idle </code> </td> <td> Hydrates when the browser is idle or after a delay. </td> </tr> <tr> <td> <code> interaction </code> </td> <td> Hydrates upon user interaction (e.g., click, hover). </td> </tr> <tr> <td> <code> mediaQuery </code> </td> <td> Hydrates when the specified media query condition is met. </td> </tr> <tr> <td> <code> if </code> </td> <td> Hydrates when a specified boolean condition is met. </td> </tr> <tr> <td> <code> time </code> </td> <td> Hydrates after a specified time delay. </td> </tr> <tr> <td> <code> never </code> </td> <td> Prevents Vue from hydrating the component. </td> </tr> </tbody> </table> ### `source` - **Type**: `() => Promise<Component>` - **Required**: `true` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/components/plugins/lazy-hydration-macro-transform.ts) # defineNuxtComponent > defineNuxtComponent() is a helper function for defining type safe components with Options API. <note> `defineNuxtComponent()` is a helper function for defining type safe Vue components using options API similar to [`defineComponent()`](https://vuejs.org/api/general#definecomponent). `defineNuxtComponent()` wrapper also adds support for `asyncData` and `head` component options. </note> <note> Using `<script setup lang="ts">` is the recommended way of declaring Vue components in Nuxt. </note> <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> ## `asyncData()` If you choose not to use `setup()` in your app, you can use the `asyncData()` method within your component definition: ```vue [pages/index.vue] <script lang="ts"> export default defineNuxtComponent({ asyncData () { return { data: { greetings: 'hello world!', }, } }, }) </script> ``` ## `head()` If you choose not to use `setup()` in your app, you can use the `head()` method within your component definition: ```vue [pages/index.vue] <script lang="ts"> export default defineNuxtComponent({ head (nuxtApp) { return { title: 'My site', } }, }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/component.ts) # defineNuxtPlugin > defineNuxtPlugin() is a helper function for creating Nuxt plugins. `defineNuxtPlugin` is a helper function for creating Nuxt plugins with enhanced functionality and type safety. This utility normalizes different plugin formats into a consistent structure that works seamlessly within Nuxt's plugin system. ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp }) ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/plugins#creating-plugins"> </read-more> ## Type ```ts [Signature] export function defineNuxtPlugin<T extends Record<string, unknown>> (plugin: Plugin<T> | ObjectPlugin<T>): Plugin<T> & ObjectPlugin<T> type Plugin<T> = (nuxt: NuxtApp) => Promise<void> | Promise<{ provide?: T }> | void | { provide?: T } interface ObjectPlugin<T> { name?: string enforce?: 'pre' | 'default' | 'post' dependsOn?: string[] order?: number parallel?: boolean setup?: Plugin<T> hooks?: Partial<RuntimeNuxtHooks> env?: { islands?: boolean } } ``` ## Parameters **plugin**: A plugin can be defined in two ways: 1. **Function Plugin**: A function that receives the [`NuxtApp`](https://nuxt.com/docs/3.x/guide/going-further/internals#the-nuxtapp-interface) instance and can return a promise with a potential object with a [`provide`](https://nuxt.com/docs/3.x/directory-structure/plugins#providing-helpers) property if you want to provide a helper on [`NuxtApp`](https://nuxt.com/docs/3.x/guide/going-further/internals#the-nuxtapp-interface) instance. 2. **Object Plugin**: An object that can include various properties to configure the plugin's behavior, such as `name`, `enforce`, `dependsOn`, `order`, `parallel`, `setup`, `hooks`, and `env`. <table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Required </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> name </code> </td> <td> <code> string </code> </td> <td> <code> false </code> </td> <td> Optional name for the plugin, useful for debugging and dependency management. </td> </tr> <tr> <td> <code> enforce </code> </td> <td> <code> 'pre' </code> | <code> 'default' </code> | <code> 'post' </code> </td> <td> <code> false </code> </td> <td> Controls when the plugin runs relative to other plugins. </td> </tr> <tr> <td> <code> dependsOn </code> </td> <td> <code> string[] </code> </td> <td> <code> false </code> </td> <td> Array of plugin names this plugin depends on. Ensures proper execution order. </td> </tr> <tr> <td> <code> order </code> </td> <td> <code> number </code> </td> <td> <code> false </code> </td> <td> This allows more granular control over plugin order and should only be used by advanced users. <strong> It overrides the value of <code> enforce </code> and is used to sort plugins. </strong> </td> </tr> <tr> <td> <code> parallel </code> </td> <td> <code> boolean </code> </td> <td> <code> false </code> </td> <td> Whether to execute the plugin in parallel with other parallel plugins. </td> </tr> <tr> <td> <code> setup </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Plugin </span> <span class="sDfIl"> < </span> <span class="sZSNi"> T </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> The main plugin function, equivalent to a function plugin. </td> </tr> <tr> <td> <code> hooks </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sZSNi"> Partial </span> <span class="sDfIl"> < </span> <span class="sZSNi"> RuntimeNuxtHooks </span> <span class="sDfIl"> > </span> </code> </td> <td> <code> false </code> </td> <td> Nuxt app runtime hooks to register directly. </td> </tr> <tr> <td> <code> env </code> </td> <td> <code className="language-ts shiki shiki-themes material-theme-lighter material-theme-lighter material-theme-palenight" language="ts" style=""> <span class="sDfIl"> { </span> <span class="sZSNi"> islands </span> <span class="sDfIl"> ?: </span> <span class="sZSNi"> boolean </span> <span class="sDfIl"> } </span> </code> </td> <td> <code> false </code> </td> <td> Set this value to <code> false </code> if you don't want the plugin to run when rendering server-only or island components. </td> </tr> </tbody> </table> <video-accordion title="Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins" video-id="2aXZyXB1QGQ"> </video-accordion> ## Examples ### Basic Usage The example below demonstrates a simple plugin that adds global functionality: ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Add a global method return { provide: { hello: (name: string) => `Hello ${name}!`, }, } }) ``` ### Object Syntax Plugin The example below shows the object syntax with advanced configuration: ```ts [plugins/advanced.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', enforce: 'pre', async setup (nuxtApp) { // Plugin setup logic const data = await $fetch('/api/config') return { provide: { config: data, }, } }, hooks: { 'app:created' () { console.log('App created!') }, }, }) ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/nuxt.ts) # defineNuxtRouteMiddleware > Create named route middleware using defineNuxtRouteMiddleware helper function. Route middleware are stored in the [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/middleware) of your Nuxt application (unless [set otherwise](https://nuxt.com/docs/3.x/api/nuxt-config#middleware)). ## Type ```ts [Signature] export function defineNuxtRouteMiddleware (middleware: RouteMiddleware): RouteMiddleware interface RouteMiddleware { (to: RouteLocationNormalized, from: RouteLocationNormalized): ReturnType<NavigationGuard> } ``` ## Parameters ### `middleware` - **Type**: `RouteMiddleware` A function that takes two Vue Router's route location objects as parameters: the next route `to` as the first, and the current route `from` as the second. Learn more about available properties of `RouteLocationNormalized` in the **Vue Router docs**. ## Examples ### Showing Error Page You can use route middleware to throw errors and show helpful error messages: ```ts [middleware/error.ts] export default defineNuxtRouteMiddleware((to) => { if (to.params.id === '1') { throw createError({ status: 404, statusText: 'Page Not Found' }) } }) ``` The above route middleware will redirect a user to the custom error page defined in the `~/error.vue` file, and expose the error message and code passed from the middleware. ### Redirection Use [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) in combination with `navigateTo` helper function inside the route middleware to redirect users to different routes based on their authentication status: ```ts [middleware/auth.ts] export default defineNuxtRouteMiddleware((to, from) => { const auth = useState('auth') if (!auth.value.isAuthenticated) { return navigateTo('/login') } if (to.path !== '/dashboard') { return navigateTo('/dashboard') } }) ``` Both [navigateTo](https://nuxt.com/docs/3.x/api/utils/navigate-to) and [abortNavigation](https://nuxt.com/docs/3.x/api/utils/abort-navigation) are globally available helper functions that you can use inside `defineNuxtRouteMiddleware`. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # definePageMeta > Define metadata for your page components. `definePageMeta` is a compiler macro that you can use to set metadata for your **page** components located in the [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory (unless [set otherwise](https://nuxt.com/docs/3.x/api/nuxt-config#pages)). This way you can set custom metadata for each static or dynamic route of your Nuxt application. ```vue [pages/some-page.vue] <script setup lang="ts"> definePageMeta({ layout: 'default', }) </script> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/pages#page-metadata"> </read-more> ## Type ```ts [Signature] export function definePageMeta (meta: PageMeta): void interface PageMeta { validate?: ((route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>) redirect?: RouteRecordRedirectOption name?: string path?: string props?: RouteRecordRaw['props'] alias?: string | string[] groups?: string[] pageTransition?: boolean | TransitionProps layoutTransition?: boolean | TransitionProps viewTransition?: boolean | 'always' key?: false | string | ((route: RouteLocationNormalizedLoaded) => string) keepalive?: boolean | KeepAliveProps layout?: false | LayoutKey | Ref<LayoutKey> | ComputedRef<LayoutKey> middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard> scrollToTop?: boolean | ((to: RouteLocationNormalizedLoaded, from: RouteLocationNormalizedLoaded) => boolean) [key: string]: unknown } ``` ## Parameters ### `meta` - **Type**: `PageMeta`<br /> An object accepting the following page metadata:<br /> **name** - **Type**: `string`<br /> You may define a name for this page's route. By default, name is generated based on path inside the [`pages/` directory](https://nuxt.com/docs/3.x/directory-structure/pages).<br /> **path** - **Type**: `string`<br /> You may define a [custom regular expression](https://nuxt.com/docs/3.x/api/utils/define-page-meta#using-a-custom-regular-expression) if you have a more complex pattern than can be expressed with the file name.<br /> **props** - **Type**: [`RouteRecordRaw['props']`](https://router.vuejs.org/guide/essentials/passing-props)<br /> Allows accessing the route `params` as props passed to the page component.<br /> **alias** - **Type**: `string | string[]`<br /> Aliases for the record. Allows defining extra paths that will behave like a copy of the record. Allows having paths shorthands like `/users/:id` and `/u/:id`. All `alias` and `path` values must share the same params.<br /> **groups** - **Type**: `string[]`<br /> Route groups the page belongs to, based on the folder structure. Automatically populated for pages within [route groups](https://nuxt.com/docs/3.x/guide/directory-structure/app/pages#route-groups).<br /> **keepalive** - **Type**: `boolean` | [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive)<br /> Set to `true` when you want to preserve page state across route changes or use the [`KeepAliveProps`](https://vuejs.org/api/built-in-components#keepalive) for a fine-grained control.<br /> **key** - **Type**: `false` | `string` | `((route: RouteLocationNormalizedLoaded) => string)`<br /> Set `key` value when you need more control over when the `<NuxtPage>` component is re-rendered.<br /> **layout** - **Type**: `false` | `LayoutKey` | `Ref<LayoutKey>` | `ComputedRef<LayoutKey>`<br /> Set a static or dynamic name of the layout for each route. This can be set to `false` in case the default layout needs to be disabled.<br /> **layoutTransition** - **Type**: `boolean` | [`TransitionProps`](https://vuejs.org/api/built-in-components#transition)<br /> Set name of the transition to apply for current layout. You can also set this value to `false` to disable the layout transition.<br /> **middleware** - **Type**: `MiddlewareKey` | [`NavigationGuard`](https://router.vuejs.org/api/interfaces/navigationguard) | `Array<MiddlewareKey | NavigationGuard>`<br /> Define anonymous or named middleware directly within `definePageMeta`. Learn more about [route middleware](https://nuxt.com/docs/3.x/directory-structure/middleware).<br /> **pageTransition** - **Type**: `boolean` | [`TransitionProps`](https://vuejs.org/api/built-in-components#transition)<br /> Set name of the transition to apply for current page. You can also set this value to `false` to disable the page transition.<br /> **viewTransition** - **Type**: `boolean | 'always'`<br /> **Experimental feature, only available when enabled in your nuxt.config file**<br /> Enable/disable View Transitions for the current page. If set to true, Nuxt will not apply the transition if the users browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition.<br /> **redirect** - **Type**: [`RouteRecordRedirectOption`](https://router.vuejs.org/guide/essentials/redirect-and-alias)<br /> Where to redirect if the route is directly matched. The redirection happens before any navigation guard and triggers a new navigation with the new target location.<br /> **validate** - **Type**: `(route: RouteLocationNormalized) => boolean | Promise<boolean> | Partial<NuxtError> | Promise<Partial<NuxtError>>`<br /> Validate whether a given route can validly be rendered with this page. Return true if it is valid, or false if not. If another match can't be found, this will mean a 404. You can also directly return an object with `status`/`statusText` to respond immediately with an error (other matches will not be checked).<br /> **scrollToTop** - **Type**: `boolean | (to: RouteLocationNormalized, from: RouteLocationNormalized) => boolean`<br /> Tell Nuxt to scroll to the top before rendering the page or not. Navigation is independent from rendering, so scroll behavior is always triggered even when the page doesn't re-render (e.g. when using a fixed [`key`](https://nuxt.com/docs/3.x/api/utils/define-page-meta#key)). Set `scrollToTop: false` to disable scrolling in such cases. If you want to overwrite the default scroll behavior of Nuxt, you can do so in `~/app/router.options.ts` (see [custom routing](https://nuxt.com/docs/3.x/guide/recipes/custom-routing#using-routeroptions)) for more info.<br /> **[key: string]** - **Type**: `any`<br /> Apart from the above properties, you can also set **custom** metadata. You may wish to do so in a type-safe way by [augmenting the type of the `meta` object](https://nuxt.com/docs/3.x/directory-structure/pages/#typing-custom-metadata). ## Examples ### Basic Usage The example below demonstrates: - how `key` can be a function that returns a value; - how `keepalive` property makes sure that the `<modal>` component is not cached when switching between multiple components; - adding `pageType` as a custom property: ```vue [pages/some-page.vue] <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, keepalive: { exclude: ['modal'], }, pageType: 'Checkout', }) </script> ``` ### Defining Middleware The example below shows how the middleware can be defined using a `function` directly within the `definePageMeta` or set as a `string` that matches the middleware file name located in the `middleware/` directory: ```vue [pages/some-page.vue] <script setup lang="ts"> definePageMeta({ // define middleware as a function middleware: [ function (to, from) { const auth = useState('auth') if (!auth.value.authenticated) { return navigateTo('/login') } if (to.path !== '/checkout') { return navigateTo('/checkout') } }, ], // ... or a string middleware: 'auth', // ... or multiple strings middleware: ['auth', 'another-named-middleware'], }) </script> ``` ### Using a Custom Regular Expression A custom regular expression is a good way to resolve conflicts between overlapping routes, for instance: The two routes "/test-category" and "/1234-post" match both `[postId]-[postSlug].vue` and `[categorySlug].vue` page routes. To make sure that we are only matching digits (`\d+`) for `postId` in the `[postId]-[postSlug]` route, we can add the following to the `[postId]-[postSlug].vue` page template: ```vue [pages/[postId]-[postSlug].vue] <script setup lang="ts"> definePageMeta({ path: '/:postId(\\d+)-:postSlug', }) </script> ``` For more examples see [Vue Router's Matching Syntax](https://router.vuejs.org/guide/essentials/route-matching-syntax). ### Defining Layout You can define the layout that matches the layout's file name located (by default) in the [`layouts/` directory](https://nuxt.com/docs/3.x/directory-structure/layouts). You can also disable the layout by setting the `layout` to `false`: ```vue [pages/some-page.vue] <script setup lang="ts"> definePageMeta({ // set custom layout layout: 'admin', // ... or disable a default layout layout: false, }) </script> ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/composables.ts) # defineRouteRules > Define route rules for hybrid rendering at the page level. <read-more icon="i-lucide-star" to="https://nuxt.com/docs/3.x/guide/going-further/experimental-features#inlinerouterules"> This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`. </read-more> ## Usage ```vue [pages/index.vue] <script setup lang="ts"> defineRouteRules({ prerender: true, }) </script> <template> <h1>Hello world!</h1> </template> ``` Will be translated to: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, }) ``` <note> When running [`nuxt build`](https://nuxt.com/docs/3.x/api/commands/build), the home page will be pre-rendered in `.output/public/index.html` and statically served. </note> ## Notes - A rule defined in `~/pages/foo/bar.vue` will be applied to `/foo/bar` requests. - A rule in `~/pages/foo/[id].vue` will be applied to `/foo/**` requests. For more control, such as if you are using a custom `path` or `alias` set in the page's [`definePageMeta`](https://nuxt.com/docs/3.x/api/utils/define-page-meta), you should set `routeRules` directly within your `nuxt.config`. <read-more icon="i-lucide-medal" to="https://nuxt.com/docs/3.x/guide/concepts/rendering#hybrid-rendering"> Read more about the `routeRules`. </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/pages/runtime/composables.ts) # $fetch > Nuxt uses ofetch to expose globally the $fetch helper for making HTTP requests. Nuxt uses [ofetch](https://github.com/unjs/ofetch) to expose globally the `$fetch` helper for making HTTP requests within your Vue app or API routes. <tip icon="i-lucide-rocket"> During server-side rendering, calling `$fetch` to fetch your internal [API routes](https://nuxt.com/docs/3.x/directory-structure/server) will directly call the relevant function (emulating the request), **saving an additional API call**. </tip> <note color="blue" icon="i-lucide-info"> Using `$fetch` in components without wrapping it with [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) causes fetching the data twice: initially on the server, then again on the client-side during hydration, because `$fetch` does not transfer state from the server to the client. Thus, the fetch will be executed on both sides because the client has to get the data again. </note> ## Usage We recommend using [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) or [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) + `$fetch` to prevent double data fetching when fetching the component data. ```vue [app.vue] <script setup lang="ts"> // During SSR data is fetched twice, once on the server and once on the client. const dataTwice = await $fetch('/api/item') // During SSR data is fetched only on the server side and transferred to the client. const { data } = await useAsyncData('item', () => $fetch('/api/item')) // You can also useFetch as shortcut of useAsyncData + $fetch const { data } = await useFetch('/api/item') </script> ``` <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> You can use `$fetch` in any methods that are executed only on client-side. ```vue [pages/contact.vue] <script setup lang="ts"> async function contactForm () { await $fetch('/api/contact', { method: 'POST', body: { hello: 'world' }, }) } </script> <template> <button @click="contactForm"> Contact </button> </template> ``` <tip> `$fetch` is the preferred way to make HTTP calls in Nuxt instead of [@nuxt/http](https://github.com/nuxt/http) and [@nuxtjs/axios](https://github.com/nuxt-community/axios-module) that are made for Nuxt 2. </tip> <note> If you use `$fetch` to call an (external) HTTPS URL with a self-signed certificate in development, you will need to set `NODE_TLS_REJECT_UNAUTHORIZED=0` in your environment. </note> ### Passing Headers and Cookies When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. However, during Server-Side Rendering, due to security risks such as **Server-Side Request Forgery (SSRF)** or **Authentication Misuse**, the `$fetch` wouldn't include the user's browser cookies, nor pass on cookies from the fetch response. <code-group> ```vue [pages/index.vue] <script setup lang="ts"> // This will NOT forward headers or cookies during SSR const { data } = await useAsyncData(() => $fetch('/api/cookies')) </script> ``` ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const foo = getCookie(event, 'foo') // ... Do something with the cookie }) ``` </code-group> If you need to forward headers and cookies on the server, you must manually pass them: ```vue [pages/index.vue] <script setup lang="ts"> // This will forward the user's headers and cookies to `/api/cookies` const requestFetch = useRequestFetch() const { data } = await useAsyncData(() => requestFetch('/api/cookies')) </script> ``` However, when calling `useFetch` with a relative URL on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/3.x/api/composables/use-request-fetch) to proxy headers and cookies (with the exception of headers not meant to be forwarded, like `host`). --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/entry.ts) # navigateTo > navigateTo is a helper function that programmatically navigates users. ## Usage `navigateTo` is available on both server side and client side. It can be used within the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context), or directly, to perform page navigation. <warning> Make sure to always use `await` or `return` on result of `navigateTo` when calling it. </warning> <note> `navigateTo` cannot be used within Nitro routes. To perform a server-side redirect in Nitro routes, use [`sendRedirect`](https://h3.dev/utils/response#redirectlocation-status-statustext) instead. </note> ### Within a Vue Component ```vue <script setup lang="ts"> // passing 'to' as a string await navigateTo('/search') // ... or as a route object await navigateTo({ path: '/search' }) // ... or as a route object with query parameters await navigateTo({ path: '/search', query: { page: 1, sort: 'asc', }, }) </script> ``` ### Within Route Middleware ```ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { // setting the redirect code to '301 Moved Permanently' return navigateTo('/search', { redirectCode: 301 }) } }) ``` When using `navigateTo` within route middleware, you must **return its result** to ensure the middleware execution flow works correctly. For example, the following implementation **will not work as expected**: ```ts export default defineNuxtRouteMiddleware((to, from) => { if (to.path !== '/search') { // โŒ This will not work as expected navigateTo('/search', { redirectCode: 301 }) return } }) ``` In this case, `navigateTo` will be executed but not returned, which may lead to unexpected behavior. <read-more to="https://nuxt.com/docs/3.x/directory-structure/middleware"> </read-more> ### Navigating to an External URL The `external` parameter in `navigateTo` influences how navigating to URLs is handled: - **Without external: true**: - Internal URLs navigate as expected. - External URLs throw an error. - **With external: true**: - Internal URLs navigate with a full-page reload. - External URLs navigate as expected. #### Example ```vue <script setup lang="ts"> // will throw an error; // navigating to an external URL is not allowed by default await navigateTo('https://nuxt.com') // will redirect successfully with the 'external' parameter set to 'true' await navigateTo('https://nuxt.com', { external: true, }) </script> ``` ### Opening a Page in a New Tab ```vue <script setup lang="ts"> // will open 'https://nuxt.com' in a new tab await navigateTo('https://nuxt.com', { open: { target: '_blank', windowFeatures: { width: 500, height: 500, }, }, }) </script> ``` ## Type ```ts [Signature] export function navigateTo ( to: RouteLocationRaw | undefined | null, options?: NavigateToOptions, ): Promise<void | NavigationFailure | false> | false | void | RouteLocationRaw interface NavigateToOptions { replace?: boolean redirectCode?: number external?: boolean open?: OpenOptions } type OpenOptions = { target: string windowFeatures?: OpenWindowFeatures } type OpenWindowFeatures = { popup?: boolean noopener?: boolean noreferrer?: boolean } & XOR<{ width?: number }, { innerWidth?: number }> & XOR<{ height?: number }, { innerHeight?: number }> & XOR<{ left?: number }, { screenX?: number }> & XOR<{ top?: number }, { screenY?: number }> ``` ## Parameters ### `to` **Type**: [`RouteLocationRaw`](https://router.vuejs.org/api/interfaces/routelocationoptions) | `undefined` | `null` **Default**: `'/'` `to` can be a plain string or a route object to redirect to. When passed as `undefined` or `null`, it will default to `'/'`. #### Example ```ts // Passing the URL directly will redirect to the '/blog' page await navigateTo('/blog') // Using the route object, will redirect to the route with the name 'blog' await navigateTo({ name: 'blog' }) // Redirects to the 'product' route while passing a parameter (id = 1) using the route object. await navigateTo({ name: 'product', params: { id: 1 } }) ``` ### `options` (optional) **Type**: `NavigateToOptions` An object accepting the following properties: - `replace` - **Type**: `boolean` - **Default**: `false` - By default, `navigateTo` pushes the given route into the Vue Router's instance on the client side.<br /> This behavior can be changed by setting `replace` to `true`, to indicate that given route should be replaced. - `redirectCode` - **Type**: `number` - **Default**: `302` - `navigateTo` redirects to the given path and sets the redirect code to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) by default when the redirection takes place on the server side.<br /> This default behavior can be modified by providing different `redirectCode`. Commonly, [`301 Moved Permanently`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) can be used for permanent redirections. - `external` - **Type**: `boolean` - **Default**: `false` - Allows navigating to an external URL when set to `true`. Otherwise, `navigateTo` will throw an error, as external navigation is not allowed by default. - `open` - **Type**: `OpenOptions` - Allows navigating to the URL using the [open()](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) method of the window. This option is only applicable on the client side and will be ignored on the server side.<br /> An object accepting the following properties: - `target` - **Type**: `string` - **Default**: `'_blank'` - A string, without whitespace, specifying the name of the browsing context the resource is being loaded into. - `windowFeatures` - **Type**: `OpenWindowFeatures` - An object accepting the following properties:<table> <thead> <tr> <th> Property </th> <th> Type </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> <code> popup </code> </td> <td> <code> boolean </code> </td> <td> Requests a minimal popup window instead of a new tab, with UI features decided by the browser. </td> </tr> <tr> <td> <code> width </code> or <code> innerWidth </code> </td> <td> <code> number </code> </td> <td> Specifies the content area's width (minimum 100 pixels), including scrollbars. </td> </tr> <tr> <td> <code> height </code> or <code> innerHeight </code> </td> <td> <code> number </code> </td> <td> Specifies the content area's height (minimum 100 pixels), including scrollbars. </td> </tr> <tr> <td> <code> left </code> or <code> screenX </code> </td> <td> <code> number </code> </td> <td> Sets the horizontal position of the new window relative to the left edge of the screen. </td> </tr> <tr> <td> <code> top </code> or <code> screenY </code> </td> <td> <code> number </code> </td> <td> Sets the vertical position of the new window relative to the top edge of the screen. </td> </tr> <tr> <td> <code> noopener </code> </td> <td> <code> boolean </code> </td> <td> Prevents the new window from accessing the originating window via <code> window.opener </code> . </td> </tr> <tr> <td> <code> noreferrer </code> </td> <td> <code> boolean </code> </td> <td> Prevents the Referer header from being sent and implicitly enables <code> noopener </code> . </td> </tr> </tbody> </table> <br /> Refer to the [documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#windowfeatures) for more detailed information on the **windowFeatures** properties. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onBeforeRouteLeave > The onBeforeRouteLeave composable allows registering a route guard within a component. <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs" to="https://router.vuejs.org/api/functions/onbeforerouteleave"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onBeforeRouteUpdate > The onBeforeRouteUpdate composable allows registering a route guard within a component. <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Vue Router Docs" to="https://router.vuejs.org/api/functions/onbeforerouteupdate"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # onNuxtReady > The onNuxtReady composable allows running a callback after your app has finished initializing. <important> `onNuxtReady` only runs on the client-side. <br /> It is ideal for running code that should not block the initial rendering of your app. </important> ```ts [plugins/ready.client.ts] export default defineNuxtPlugin(() => { onNuxtReady(async () => { const myAnalyticsLibrary = await import('my-big-analytics-library') // do something with myAnalyticsLibrary }) }) ``` It is 'safe' to run even after your app has initialized. In this case, then the code will be registered to run in the next idle callback. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ready.ts) # prefetchComponents > Nuxt provides utilities to give you control over prefetching components. Prefetching component downloads the code in the background, this is based on the assumption that the component will likely be used for rendering, enabling the component to load instantly if and when the user requests it. The component is downloaded and cached for anticipated future use without the user making an explicit request for it. Use `prefetchComponents` to manually prefetch individual components that have been registered globally in your Nuxt app. By default Nuxt registers these as async components. You must use the Pascal-cased version of the component name. ```ts await prefetchComponents('MyGlobalComponent') await prefetchComponents(['MyGlobalComponent1', 'MyGlobalComponent2']) ``` <note> Current implementation behaves exactly the same as [`preloadComponents`](https://nuxt.com/docs/3.x/api/utils/preload-components) by preloading components instead of just prefetching we are working to improve this behavior. </note> <note> On server, `prefetchComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # preloadComponents > Nuxt provides utilities to give you control over preloading components. Preloading components loads components that your page will need very soon, which you want to start loading early in rendering lifecycle. This ensures they are available earlier and are less likely to block the page's render, improving performance. Use `preloadComponents` to manually preload individual components that have been registered globally in your Nuxt app. By default Nuxt registers these as async components. You must use the Pascal-cased version of the component name. ```ts await preloadComponents('MyGlobalComponent') await preloadComponents(['MyGlobalComponent1', 'MyGlobalComponent2']) ``` <note> On server, `preloadComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # preloadRouteComponents > preloadRouteComponents allows you to manually preload individual pages in your Nuxt app. Preloading routes loads the components of a given route that the user might navigate to in future. This ensures that the components are available earlier and less likely to block the navigation, improving performance. <tip icon="i-lucide-rocket"> Nuxt already automatically preloads the necessary routes if you're using the `NuxtLink` component. </tip> <read-more to="https://nuxt.com/docs/3.x/api/components/nuxt-link"> </read-more> ## Example Preload a route when using `navigateTo`. ```ts // we don't await this async function, to avoid blocking rendering // this component's setup function preloadRouteComponents('/dashboard') const submit = async () => { const results = await $fetch('/api/authentication') if (results.token) { await navigateTo('/dashboard') } } ``` <read-more to="https://nuxt.com/docs/3.x/api/utils/navigate-to"> </read-more> <note> On server, `preloadRouteComponents` will have no effect. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/preload.ts) # prerenderRoutes > prerenderRoutes hints to Nitro to prerender an additional route. When prerendering, you can hint to Nitro to prerender additional paths, even if their URLs do not show up in the HTML of the generated page. <important> `prerenderRoutes` can only be called within the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context). </important> <note> `prerenderRoutes` has to be executed during prerendering. If the `prerenderRoutes` is used in dynamic pages/routes which are not prerendered, then it will not be executed. </note> ```ts const route = useRoute() prerenderRoutes('/') prerenderRoutes(['/', '/about']) ``` <note> In the browser, or if called outside prerendering, `prerenderRoutes` will have no effect. </note> You can even prerender API routes which is particularly useful for full statically generated sites (SSG) because you can then `$fetch` data as if you have an available server! ```ts prerenderRoutes('/api/content/article/name-of-article') // Somewhere later in App const articleContent = await $fetch('/api/content/article/name-of-article', { responseType: 'json', }) ``` <warning> Prerendered API routes in production may not return the expected response headers, depending on the provider you deploy to. For example, a JSON response might be served with an `application/octet-stream` content type. Always manually set `responseType` when fetching prerendered API routes. </warning> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # refreshCookie > Refresh useCookie values manually when a cookie has changed <important> This utility is available since [Nuxt v3.10](https://nuxt.com/blog/v3-10). </important> ## Purpose The `refreshCookie` function is designed to refresh cookie value returned by `useCookie`. This is useful for updating the `useCookie` ref when we know the new cookie value has been set in the browser. ## Usage ```vue [app.vue] <script setup lang="ts"> const tokenCookie = useCookie('token') const login = async (username, password) => { const token = await $fetch('/api/token', { /** ... */ }) // Sets `token` cookie on response refreshCookie('token') } const loggedIn = computed(() => !!tokenCookie.value) </script> ``` <note to="https://nuxt.com/docs/3.x/guide/going-further/experimental-features#cookiestore"> Since [Nuxt v3.12.0](https://github.com/nuxt/nuxt/releases/tag/v3.12.0), the experimental `cookieStore` option is enabled by default. It automatically refreshes the `useCookie` value when cookies change in the browser. </note> ## Type ```ts [Signature] export function refreshCookie (name: string): void ``` --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/cookie.ts) # refreshNuxtData > Refresh all or specific asyncData instances in Nuxt `refreshNuxtData` is used to refetch all or specific `asyncData` instances, including those from [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data), [`useLazyAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-lazy-async-data), [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch), and [`useLazyFetch`](https://nuxt.com/docs/3.x/api/composables/use-lazy-fetch). <note> If your component is cached by `<KeepAlive>` and enters a deactivated state, the `asyncData` inside the component will still be refetched until the component is unmounted. </note> ## Type ```ts [Signature] export function refreshNuxtData (keys?: string | string[]) ``` ## Parameters - `keys`: A single string or an array of strings as `keys` that are used to fetch the data. This parameter is **optional**. All [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) keys are re-fetched when no `keys` are explicitly specified. ## Return Values `refreshNuxtData` returns a promise, resolving when all or specific `asyncData` instances have been refreshed. ## Examples ### Refresh All Data This example below refreshes all data being fetched using `useAsyncData` and `useFetch` in Nuxt application. ```vue [pages/some-page.vue] <script setup lang="ts"> const refreshing = ref(false) async function refreshAll () { refreshing.value = true try { await refreshNuxtData() } finally { refreshing.value = false } } </script> <template> <div> <button :disabled="refreshing" @click="refreshAll" > Refetch All Data </button> </div> </template> ``` ### Refresh Specific Data This example below refreshes only data where the key matches to `count` and `user`. ```vue [pages/some-page.vue] <script setup lang="ts"> const refreshing = ref(false) async function refresh () { refreshing.value = true try { // you could also pass an array of keys to refresh multiple data await refreshNuxtData(['count', 'user']) } finally { refreshing.value = false } } </script> <template> <div v-if="refreshing"> Loading </div> <button @click="refresh"> Refresh </button> </template> ``` <note> If you have access to the `asyncData` instance, it is recommended to use its `refresh` or `execute` method as the preferred way to refetch the data. </note> <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts) # reloadNuxtApp > reloadNuxtApp will perform a hard reload of the page. <note> `reloadNuxtApp` will perform a hard reload of your app, re-requesting a page and its dependencies from the server. </note> By default, it will also save the current `state` of your app (that is, any state you could access with `useState`). <read-more icon="i-lucide-star" to="https://nuxt.com/docs/3.x/guide/going-further/experimental-features#restorestate"> You can enable experimental restoration of this state by enabling the `experimental.restoreState` option in your `nuxt.config` file. </read-more> ## Type ```ts [Signature] export function reloadNuxtApp (options?: ReloadNuxtAppOptions) interface ReloadNuxtAppOptions { ttl?: number force?: boolean path?: string persistState?: boolean } ``` ### `options` (optional) **Type**: `ReloadNuxtAppOptions` An object accepting the following properties: - `path` (optional)<br /> **Type**: `string`<br /> **Default**: `window.location.pathname`<br /> The path to reload (defaulting to the current path). If this is different from the current window location it will trigger a navigation and add an entry in the browser history. - `ttl` (optional)<br /> **Type**: `number`<br /> **Default**: `10000`<br /> The number of milliseconds in which to ignore future reload requests. If called again within this time period, `reloadNuxtApp` will not reload your app to avoid reload loops. - `force` (optional)<br /> **Type**: `boolean`<br /> **Default**: `false`<br /> This option allows bypassing reload loop protection entirely, forcing a reload even if one has occurred within the previously specified TTL. - `persistState` (optional)<br /> **Type**: `boolean`<br /> **Default**: `false`<br /> Whether to dump the current Nuxt state to sessionStorage (as `nuxt:reload:state`). By default this will have no effect on reload unless `experimental.restoreState` is also set, or unless you handle restoring the state yourself. --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/chunk.ts) # setPageLayout > setPageLayout allows you to dynamically change the layout of a page. <important> `setPageLayout` allows you to dynamically change the layout of a page. It relies on access to the Nuxt context and therefore can only be called within the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context). </important> ```ts [middleware/custom-layout.ts] export default defineNuxtRouteMiddleware((to) => { // Set the layout on the route you are navigating _to_ setPageLayout('other') }) ``` ## Passing Props to Layouts You can pass props to the layout by providing an object as the second argument: ```ts [middleware/admin-layout.ts] export default defineNuxtRouteMiddleware((to) => { setPageLayout('admin', { sidebar: true, title: 'Dashboard', }) }) ``` The layout can then receive these props: ```vue [layouts/admin.vue] <script setup lang="ts"> const props = defineProps<{ sidebar?: boolean title?: string }>() </script> <template> <div> <aside v-if="sidebar"> Sidebar </aside> <main> <h1>{{ title }}</h1> <slot /> </main> </div> </template> ``` <note> If you choose to set the layout dynamically on the server side, you *must* do so before the layout is rendered by Vue (that is, within a plugin or route middleware) to avoid a hydration mismatch. </note> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/router.ts) # setResponseStatus > setResponseStatus sets the status (and optionally the statusText) of the response. Nuxt provides composables and utilities for first-class server-side-rendering support. `setResponseStatus` sets the status (and optionally the statusText) of the response. <important> `setResponseStatus` can only be called in the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context). </important> ```ts const event = useRequestEvent() // event will be undefined in the browser if (event) { // Set the status code to 404 for a custom 404 page setResponseStatus(event, 404) // Set the status message as well setResponseStatus(event, 404, 'Page Not Found') } ``` <note> In the browser, `setResponseStatus` will have no effect. </note> <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/ssr.ts) # showError > Nuxt provides a quick and simple way to show a full screen error page if needed. Within the [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context) you can use `showError` to show an error. **Parameters:** - `error`: `string | Error | Partial<{ cause, data, message, name, stack, status, statusText }>` ```ts showError('๐Ÿ˜ฑ Oh no, an error has been thrown.') showError({ status: 404, statusText: 'Page Not Found', }) ``` The error is set in the state using [`useError()`](https://nuxt.com/docs/3.x/api/composables/use-error) to create a reactive and SSR-friendly shared error state across components. <tip> `showError` calls the `app:error` hook. </tip> <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/error.ts) # updateAppConfig > Update the App Config at runtime. <note> Updates the [`app.config`](https://nuxt.com/docs/3.x/directory-structure/app-config) using deep assignment. Existing (nested) properties will be preserved. </note> ## Usage ```js import { updateAppConfig, useAppConfig } from '#imports' const appConfig = useAppConfig() // { foo: 'bar' } const newAppConfig = { foo: 'baz' } updateAppConfig(newAppConfig) console.log(appConfig) // { foo: 'baz' } ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/app-config"> </read-more> --- - [Source](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/config.ts) # Legacy Composition API > Learn how to migrate to Composition API with Nuxt Bridge. Nuxt Bridge provides access to Composition API syntax. It is specifically designed to be aligned with Nuxt 3. Because of this, there are a few extra steps to take when enabling Nuxt Bridge, if you have been using the Composition API previously. ## Remove Modules - Remove `@vue/composition-api` from your dependencies. - Remove `@nuxtjs/composition-api` from your dependencies (and from your modules in `nuxt.config`). ## Using `@vue/composition-api` If you have been using just `@vue/composition-api` and not `@nuxtjs/composition-api`, then things are very straightforward. 1. First, remove the plugin where you are manually registering the Composition API. Nuxt Bridge will handle this for you.```diff - import Vue from 'vue' - import VueCompositionApi from '@vue/composition-api' - - Vue.use(VueCompositionApi) ``` 2. Otherwise, there is nothing you need to do. However, if you want, you can remove your explicit imports from `@vue/composition-api` and rely on Nuxt Bridge auto-importing them for you. ## Migrating from `@nuxtjs/composition-api` Nuxt Bridge implements the Composition API slightly differently from `@nuxtjs/composition-api` and provides different composables (designed to be aligned with the composables that Nuxt 3 provides). Because some composables have been removed and don't yet have a replacement, this will be a slightly more complicated process. ### Remove `@nuxtjs/composition-api/module` from your buildModules You don't have to immediately update your imports yet - Nuxt Bridge will automatically provide a 'shim' for most imports you currently have, to give you time to migrate to the new, Nuxt 3-compatible composables, with the following exceptions: - `withContext` has been removed. See [below](https://nuxt.com/docs/3.x/bridge/nuxt3-compatible-api#usecontext-and-withcontext). - `useStatic` has been removed. There is no current replacement. Feel free to raise a discussion if you have a use case for this. - `reqRef` and `reqSsrRef`, which were deprecated, have now been removed entirely. Follow the instructions below regarding [ssrRef](https://nuxt.com/docs/3.x/bridge/nuxt3-compatible-api#ssrref-and-shallowssrref) to replace this. ### Set `bridge.capi` ```ts import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { capi: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` For each other composable you are using from `@nuxtjs/composition-api`, follow the steps below. ### useFetch `$fetchState` and `$fetch` have been removed. ```diff const { - $fetch, - $fetchState, + fetch, + fetchState, } = useFetch(() => { posts.value = await $fetch('/api/posts') }) ``` ### `defineNuxtMiddleware` This was a type-helper stub function that is now removed. Remove the `defineNuxtMiddleware` wrapper: ```diff - import { defineNuxtMiddleware } from '@nuxtjs/composition-api` - export default defineNuxtMiddleware((ctx) => {}) + export default (ctx) => {} ``` For typescript support, you can use `@nuxt/types`: ```ts import type { Middleware } from '@nuxt/types' export default <Middleware> function (ctx) { } ``` ### `defineNuxtPlugin` This was a type-helper stub function that is now removed. You may also keep using Nuxt 2-style plugins, by removing the function (as with [defineNuxtMiddleware](https://nuxt.com/docs/3.x/bridge/bridge-composition-api#definenuxtmiddleware)). Remove the `defineNuxtPlugin` wrapper: ```diff - import { defineNuxtPlugin } from '@nuxtjs/composition-api' - export default defineNuxtPlugin((ctx, inject) => {}) + export default (ctx, inject) => {} ``` For typescript support, you can use `@nuxt/types`: ```ts import type { Plugin } from '@nuxt/types' export default <Plugin> function (ctx, inject) {} ``` <warning> While this example is valid, Nuxt 3 introduces a new defineNuxtPlugin function that has a slightly different signature. </warning> <read-more link="/docs/3.x/directory-structure/plugins#creating-plugins"> </read-more> ### `useRouter` and `useRoute` Nuxt Bridge provides direct replacements for these composables via [`useRouter`](https://nuxt.com/docs/3.x/api/composables/use-router) and `useRoute`. The only key difference is that [`useRoute`](https://nuxt.com/docs/3.x/api/composables/use-route) no longer returns a computed property. ```diff - import { useRouter, useRoute } from '@nuxtjs/composition-api' const router = useRouter() const route = useRoute() - console.log(route.value.path) + console.log(route.path) ``` # Configuration > Learn how to configure Nuxt Bridge to your own needs. ## Feature Flags You can optionally disable some features from bridge or opt-in to less stable ones. In normal circumstances, it is always best to stick with defaults! You can check [bridge/src/module.ts](https://github.com/nuxt/bridge/blob/main/packages/bridge/src/module.ts) for latest defaults. ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { // -- Opt-in features -- // Use Vite as the bundler instead of webpack 4 // vite: true, // Enable Nuxt 3 compatible useHead // meta: true, // Enable definePageMeta macro // macros: { // pageMeta: true // }, // Enable transpiling TypeScript with esbuild // typescript: { // esbuild: true // }, // -- Default features -- // Use legacy server instead of Nitro // nitro: false, // Disable Nuxt 3 compatible `nuxtApp` interface // app: false, // Disable Composition API support // capi: false, // ... or just disable legacy Composition API support // capi: { // legacy: false // }, // Do not transpile modules // transpile: false, // Disable <script setup> support // scriptSetup: false, // Disable composables auto importing // imports: false, // Do not warn about module incompatibilities // constraints: false }, vite: { // Config for Vite }, }) ``` ## Migration of each option ### router.base ```diff export default defineNuxtConfig({ - router: { - base: '/my-app/' - } + app: { + baseURL: '/my-app/' + } }) ``` ### build.publicPath ```diff export default defineNuxtConfig({ - build: { - publicPath: 'https://my-cdn.net' - } + app: { + cdnURL: 'https://my-cdn.net' + } }) ``` # Meta Tags > Learn how to migrate from Nuxt 2 to Nuxt Bridge new meta tags. If you need to access the component state with `head`, you should migrate to using [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) . If you need to use the Options API, there is a `head()` method you can use when you use `defineNuxtComponent`. ## Migration ### Set `bridge.meta` ```js import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { meta: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` ### Update head properties In your `nuxt.config`, rename `head` to `app.head`. (Note that objects no longer have a `hid` key for deduplication.) <code-group> ```ts [Nuxt 2] export default { head: { titleTemplate: '%s - Nuxt', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: 'Meta description' }, ], }, } ``` ```ts [Nuxt 3] export default defineNuxtConfig({ app: { head: { titleTemplate: '%s - Nuxt', meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { name: 'description', content: 'Meta description' }, ], }, }, }) ``` </code-group> ## `useHead` Composables Nuxt Bridge provides a new Nuxt 3 meta API that can be accessed with a new [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable. ```vue <script setup lang="ts"> useHead({ title: 'My Nuxt App', }) </script> ``` <tip> This [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`. </tip> <warning> We recommend not using the native Nuxt 2 `head()` properties in addition to [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) , as they may conflict. </warning> For more information on how to use this composable, see [the docs](https://nuxt.com/docs/3.x/getting-started/seo-meta). ## Options API ```vue <script> // if using options API `head` method you must use `defineNuxtComponent` export default defineNuxtComponent({ head (nuxtApp) { // `head` receives the nuxt app but cannot access the component instance return { meta: [{ name: 'description', content: 'This is my page description.', }], } }, }) </script> ``` <warning> Possible breaking change: `head` receives the nuxt app but cannot access the component instance. If the code in your `head` tries to access the data object through `this` or `this.$data`, you will need to migrate to the `useHead` composable. </warning> ## Title Template If you want to use a function (for full control), then this cannot be set in your nuxt.config, and it is recommended instead to set it within your `/layouts` directory. ```vue [layouts/default.vue] <script setup lang="ts"> useHead({ titleTemplate: (titleChunk) => { return titleChunk ? `${titleChunk} - Site Title` : 'Site Title' }, }) </script> ``` # Nitro > Activate Nitro to your Nuxt 2 application with Nuxt Bridge. ## Remove Modules - Remove `@nuxt/nitro`: Bridge injects same functionality ## Update Config ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { nitro: true, }, }) ``` ## Update Your Scripts You will also need to update your scripts within your `package.json` to reflect the fact that Nuxt will now produce a Nitro server as build output. ### Install Nuxi Install `nuxi` as a development dependency: <code-group sync="pm"> ```bash [npm] npm install -D nuxi ``` ```bash [yarn] yarn add --dev nuxi ``` ```bash [pnpm] pnpm add -D nuxi ``` ```bash [bun] bun add -D nuxi ``` ```bash [deno] deno add -D npm:nuxi ``` </code-group> ### Nuxi Nuxt 3 introduced the new Nuxt CLI command [`nuxi`](https://nuxt.com/docs/3.x/api/commands/add). Update your scripts as follows to leverage the better support from Nuxt Bridge: ```diff { "scripts": { - "dev": "nuxt", + "dev": "nuxi dev", - "build": "nuxt build", + "build": "nuxi build", - "start": "nuxt start", + "start": "nuxi preview" } } ``` <tip> If `nitro: false`, use the `nuxt2` command. </tip> ### Static Target If you have set `target: 'static'` in your `nuxt.config` then you need to ensure that you update your build script to be `nuxi generate`. ```json [package.json] { "scripts": { "build": "nuxi generate" } } ``` ### Server Target For all other situations, you can use the `nuxi build` command. ```json [package.json] { "scripts": { "build": "nuxi build", "start": "nuxi preview" } } ``` ## Exclude Built Nitro Folder From Git Add the folder `.output` to the `.gitignore` file. ## Ensure Everything Goes Well โœ”๏ธ Try with `nuxi dev` and `nuxi build` (or `nuxi generate`) to see if everything goes well. # New Composition API > Nuxt Bridge implements composables compatible with Nuxt 3. By migrating from `@nuxtjs/composition-api` to the Nuxt 3 compatible API, there will be less rewriting when migrating to Nuxt 3. ## `ssrRef` and `shallowSsrRef` These two functions have been replaced with a new composable that works very similarly under the hood: `useState`. The key differences are that you must provide a *key* for this state (which Nuxt generated automatically for `ssrRef` and `shallowSsrRef`), and that it can only be called within a Nuxt 3 plugin (which is defined by `defineNuxtPlugin`) or a component instance. (In other words, you cannot use [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) with a global/ambient context, because of the danger of shared state across requests.) ```diff - import { ssrRef } from '@nuxtjs/composition-api' - const ref1 = ssrRef('initialData') - const ref2 = ssrRef(() => 'factory function') + const ref1 = useState('ref1-key', () => 'initialData') + const ref2 = useState('ref2-key', () => 'factory function') // accessing the state console.log(ref1.value) ``` Because the state is keyed, you can access the same state from multiple locations, as long as you are using the same key. You can read more about how to use this composable in [the Nuxt 3 docs](https://nuxt.com/docs/3.x/api/composables/use-state). ## `ssrPromise` This function has been removed, and you will need to find an alternative implementation if you were using it. If you have a use case for `ssrPromise`, please let us know via a discussion. ## `onGlobalSetup` This function has been removed, but its use cases can be met by using [`useNuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) or [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) within `defineNuxtPlugin`. You can also run any custom code within the `setup()` function of a layout. ```diff - import { onGlobalSetup } from '@nuxtjs/composition-api' - export default () => { - onGlobalSetup(() => { + export default defineNuxtPlugin((nuxtApp) => { + nuxtApp.hook('vue:setup', () => { // ... }) - } + }) ``` ## `useStore` In order to access Vuex store instance, you can use `useNuxtApp().$store`. ```diff - import { useStore } from '@nuxtjs/composition-api` + const { $store } = useNuxtApp() ``` ## `useContext` and `withContext` You can access injected helpers using `useNuxtApp`. ```diff - import { useContext } from '@nuxtjs/composition-api` + const { $axios } = useNuxtApp() ``` <note> `useNuxtApp()` also provides a key called `nuxt2Context` which contains all the same properties you would normally access from Nuxt 2 context, but it's advised *not* to use this directly, as it won't exist in Nuxt 3. Instead, see if there is another way to access what you need. (If not, please raise a feature request or discussion.) </note> ## `wrapProperty` This helper function is not provided any more but you can replace it with the following code: ```ts import { computed, getCurrentInstance } from 'vue' const wrapProperty = (property: string, makeComputed = true) => () => { const vm = getCurrentInstance().proxy return makeComputed ? computed(() => vm[property]) : vm[property] } ``` ## `useAsync` and `useFetch` These two composables can be replaced with `useLazyAsyncData` and `useLazyFetch`, which are documented [in the Nuxt 3 docs](https://nuxt.com/docs/3.x/getting-started/data-fetching). Just like the previous `@nuxtjs/composition-api` composables, these composables do not block route navigation on the client-side (hence the 'lazy' part of the name). <important> Note that the API is entirely different, despite similar sounding names. Importantly, you should not attempt to change the value of other variables outside the composable (as you may have been doing with the previous `useFetch`). </important> <warning> The `useLazyFetch` must have been configured for [Nitro](https://nuxt.com/docs/3.x/bridge/nitro). </warning> Migrating to the new composables from `useAsync`: ```diff <script setup> - import { useAsync } from '@nuxtjs/composition-api' - const posts = useAsync(() => $fetch('/api/posts')) + const { data: posts } = useLazyAsyncData('posts', () => $fetch('/api/posts')) + // or, more simply! + const { data: posts } = useLazyFetch('/api/posts') </script> ``` Migrating to the new composables from `useFetch`: ```diff <script setup> - import { useFetch } from '@nuxtjs/composition-api' - const posts = ref([]) - const { fetch } = useFetch(() => { posts.value = await $fetch('/api/posts') }) + const { data: posts, refresh } = useLazyAsyncData('posts', () => $fetch('/api/posts')) + // or, more simply! + const { data: posts, refresh } = useLazyFetch('/api/posts') function updatePosts() { - return fetch() + return refresh() } </script> ``` ### `useMeta` In order to interact with `vue-meta`, you may use `useNuxt2Meta`, which will work in Nuxt Bridge (but not Nuxt 3) and will allow you to manipulate your meta tags in a `vue-meta`-compatible way. ```diff <script setup> - import { useMeta } from '@nuxtjs/composition-api' useNuxt2Meta({ title: 'My Nuxt App', }) </script> ``` You can also pass in computed values or refs, and the meta values will be updated reactively: ```vue <script setup> const title = ref('my title') useNuxt2Meta({ title, }) title.value = 'new title' </script> ``` <note> Be careful not to use both `useNuxt2Meta()` and the Options API `head()` within the same component, as behavior may be unpredictable. </note> Nuxt Bridge also provides a Nuxt 3-compatible meta implementation that can be accessed with the [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable. ```diff <script setup> - import { useMeta } from '@nuxtjs/composition-api' useHead({ title: 'My Nuxt App', }) </script> ``` You will also need to enable it explicitly in your `nuxt.config`: ```js import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { meta: true, }, }) ``` This [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable uses `@unhead/vue` under the hood (rather than `vue-meta`) to manipulate your `<head>`. Accordingly, it is recommended not to use both the native Nuxt 2 `head()` properties as well as [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) , as they may conflict. For more information on how to use this composable, see [the Nuxt 3 docs](https://nuxt.com/docs/3.x/getting-started/seo-meta). ### Explicit Imports Nuxt exposes every auto-import with the `#imports` alias that can be used to make the import explicit if needed: ```vue <script setup lang="ts"> import { computed, ref } from '#imports' const count = ref(1) const double = computed(() => count.value * 2) </script> ``` ### Disabling Auto-imports If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ imports: { autoImport: false, }, }) ``` This will disable auto-imports completely but it's still possible to use [explicit imports](https://nuxt.com/docs/3.x/bridge/nuxt3-compatible-api#explicit-imports) from `#imports`. # Overview > Reduce the differences with Nuxt 3 and reduce the burden of migration to Nuxt 3. <note> If you're starting a fresh Nuxt 3 project, please skip this section and go to [Nuxt 3 Installation](https://nuxt.com/docs/3.x/getting-started/introduction). </note> <warning> Nuxt Bridge provides identical features to Nuxt 3 ([docs](https://nuxt.com/docs/3.x/guide/concepts/auto-imports)) but there are some limitations, notably that [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) composables are not available. Please read the rest of this page for details. </warning> Bridge is a forward-compatibility layer that allows you to experience many of the new Nuxt 3 features by simply installing and enabling a Nuxt module. Using Nuxt Bridge, you can make sure your project is (almost) ready for Nuxt 3 and you can gradually proceed with the transition to Nuxt 3. ## First Step ### Upgrade Nuxt 2 Make sure your dev server (`nuxt dev`) isn't running, remove any package lock files (`package-lock.json` and `yarn.lock`), and install the latest Nuxt 2 version: ```diff [package.json] - "nuxt": "^2.16.3" + "nuxt": "^2.17.3" ``` Then, reinstall your dependencies: <code-group sync="pm"> ```bash [npm] npm install ``` ```bash [yarn] yarn install ``` ```bash [pnpm] pnpm install ``` ```bash [bun] bun install ``` ```bash [deno] deno install ``` </code-group> <note> Once the installation is complete, make sure both development and production builds are working as expected before proceeding. </note> ### Install Nuxt Bridge Install `@nuxt/bridge` and `nuxi` as development dependencies: <code-group sync="pm"> ```bash [npm] npm install -D @nuxt/bridge nuxi ``` ```bash [yarn] yarn add --dev @nuxt/bridge nuxi ``` ```bash [pnpm] pnpm add -D @nuxt/bridge nuxi ``` ```bash [bun] bun add -D @nuxt/bridge nuxi ``` ```bash [deno] deno add -D npm:@nuxt/bridge npm:nuxi ``` </code-group> ### Update `nuxt.config` Please make sure to avoid any CommonJS syntax such as `module.exports`, `require` or `require.resolve` in your config file. It will soon be deprecated and unsupported. You can use static `import`, dynamic `import()` and `export default` instead. Using TypeScript by renaming to [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) is also possible and recommended. ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: false, }) ``` ### Update Commands The `nuxt` command should now be changed to the `nuxt2` command. ```diff { "scripts": { - "dev": "nuxt", + "dev": "nuxt2", - "build": "nuxt build", + "build": "nuxt2 build", - "start": "nuxt start", + "start": "nuxt2 start" } } ``` Try running `nuxt2` once here. You will see that the application works as before. (If 'bridge' is set to false, your application will operate without any changes as before.) ## Upgrade Steps With Nuxt Bridge, the migration to Nuxt 3 can proceed in steps. The below `Upgrade Steps` does not need to be done all at once. - [TypeScript](https://nuxt.com/docs/3.x/bridge/typescript) - [Migrate Legacy Composition API](https://nuxt.com/docs/3.x/bridge/bridge-composition-api) - [Plugins and Middleware](https://nuxt.com/docs/3.x/bridge/plugins-and-middleware) - [Migrate New Composition API](https://nuxt.com/docs/3.x/bridge/nuxt3-compatible-api) - [Meta Tags](https://nuxt.com/docs/3.x/bridge/meta) - [Runtime Config](https://nuxt.com/docs/3.x/bridge/runtime-config) - [Nitro](https://nuxt.com/docs/3.x/bridge/nitro) - [Vite](https://nuxt.com/docs/3.x/bridge/vite) ## Migrate from CommonJS to ESM Nuxt 3 natively supports TypeScript and ECMAScript Modules. Please check [Native ES Modules](https://nuxt.com/docs/3.x/guide/concepts/esm) for more info and upgrading. # Plugins and Middleware > Learn how to migrate from Nuxt 2 to Nuxt Bridge new plugins and middleware. ## New Plugins Format You can now migrate to the Nuxt 3 plugins API, which is slightly different in format from Nuxt 2. Plugins now take only one argument (`nuxtApp`). You can find out more in [the docs](https://nuxt.com/docs/3.x/directory-structure/plugins). ```ts [plugins/hello.ts] export default defineNuxtPlugin((nuxtApp) => { nuxtApp.provide('injected', () => 'my injected function') // now available on `nuxtApp.$injected` }) ``` <note> If you want to use the new Nuxt composables (such as [`useNuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) or `useRuntimeConfig`) within your plugins, you will need to use the `defineNuxtPlugin` helper for those plugins. </note> <warning> Although a compatibility interface is provided via `nuxtApp.vueApp` you should avoid registering plugins, directives, mixins or components this way without adding your own logic to ensure they are not installed more than once, or this may cause a memory leak. </warning> ## New Middleware Format You can now migrate to the Nuxt 3 middleware API, which is slightly different in format from Nuxt 2. Middleware now take only two argument (`to`, `from`). You can find out more in [the docs](https://nuxt.com/docs/3.x/directory-structure/middleware). ```tstwoslash export default defineNuxtRouteMiddleware((to) => { if (to.path !== '/') { return navigateTo('/') } }) ``` <important> Use of `defineNuxtRouteMiddleware` is not supported outside of the `middleware` directory. </important> ## definePageMeta You can also use [`definePageMeta`](https://nuxt.com/docs/3.x/api/utils/define-page-meta) in Nuxt Bridge. It can be enabled with the `macros.pageMeta` option in your configuration file ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { macros: { pageMeta: true, }, }, }) ``` <note> But only for `middleware` and `layout`. </note> # Runtime Config > Nuxt provides a runtime config API to expose configuration and secrets within your application. <warning> When using `runtimeConfig` option, [nitro](https://nuxt.com/docs/3.x/bridge/nitro) must have been configured. </warning> ## Update Runtime Config Nuxt 3 approaches runtime config differently than Nuxt 2, using a new combined `runtimeConfig` option. First, you'll need to combine your `publicRuntimeConfig` and `privateRuntimeConfig` properties into a new one called `runtimeConfig`, with the public config within a key called `public`. ```diff // nuxt.config.js - privateRuntimeConfig: { - apiKey: process.env.NUXT_API_KEY || 'super-secret-key' - }, - publicRuntimeConfig: { - websiteURL: 'https://public-data.com' - } + runtimeConfig: { + apiKey: process.env.NUXT_API_KEY || 'super-secret-key', + public: { + websiteURL: 'https://public-data.com' + } + } ``` This also means that when you need to access public runtime config, it's behind a property called `public`. If you use public runtime config, you'll need to update your code. ```diff // MyWidget.vue - <div>Website: {{ $config.websiteURL }}</div> + <div>Website: {{ $config.public.websiteURL }}</div> ``` # TypeScript > Learn how to use TypeScript with Nuxt Bridge. ## Remove Modules - Remove `@nuxt/typescript-build`: Bridge enables same functionality - Remove `@nuxt/typescript-runtime` and `nuxt-ts`: Nuxt 2 has built-in runtime support ### Set `bridge.typescript` ```ts import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { typescript: true, nitro: false, // If migration to Nitro is complete, set to true }, }) ``` ## Update `tsconfig.json` If you are using TypeScript, you can edit your `tsconfig.json` to benefit from auto-generated Nuxt types: ```diff [tsconfig.json] { + "extends": "./.nuxt/tsconfig.json", "compilerOptions": { ... } } ``` <note> As `.nuxt/tsconfig.json` is generated and not checked into version control, you'll need to generate that file before running your tests. Add `nuxi prepare` as a step before your tests, otherwise you'll see `TS5083: Cannot read file '~/.nuxt/tsconfig.json'` </note> <note> Keep in mind that all options extended from `./.nuxt/tsconfig.json` will be overwritten by the options defined in your `tsconfig.json`. Overwriting options such as `"compilerOptions.paths"` with your own configuration will lead TypeScript to not factor in the module resolutions from `./.nuxt/tsconfig.json`. This can lead to module resolutions such as `#imports` not being recognized. In case you need to extend options provided by `./.nuxt/tsconfig.json` further, you can use the `alias` property within your `nuxt.config`. `nuxi` will pick them up and extend `./.nuxt/tsconfig.json` accordingly. </note> # Vite > Activate Vite to your Nuxt 2 application with Nuxt Bridge. <warning> When using `vite`, [nitro](https://nuxt.com/docs/3.x/bridge/nitro) must have been configured. </warning> ## Remove Modules - Remove `nuxt-vite`: Bridge enables same functionality ## Update Config ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ bridge: { vite: true, nitro: true, }, }) ``` ## Configuration ```ts [nuxt.config.ts] import { defineNuxtConfig } from '@nuxt/bridge' export default defineNuxtConfig({ vite: { // Config for Vite }, }) ``` # Releases > Discover the latest releases of Nuxt & Nuxt official modules. <card-group> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/nuxt" to="https://github.com/nuxt/nuxt/releases"> Nuxt framework releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/cli" to="https://github.com/nuxt/cli/releases"> Nuxt CLI (`@nuxt/cli`) releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/a11y" to="https://github.com/nuxt/a11y/releases"> Nuxt A11y releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/content" to="https://github.com/nuxt/content/releases"> Nuxt Content releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/devtools" to="https://github.com/nuxt/devtools/releases"> Nuxt DevTools releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/fonts" to="https://github.com/nuxt/fonts/releases"> Nuxt Fonts releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/hints" to="https://github.com/nuxt/hints/releases"> Nuxt Hints releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/image" to="https://github.com/nuxt/image/releases"> Nuxt Image releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/scripts" to="https://github.com/nuxt/scripts/releases"> Nuxt Scripts releases. </card> <card :ui="{"icon":{"base":"text-black dark:text-white"}}" icon="i-simple-icons-github" target="_blank" title="nuxt/ui" to="https://github.com/nuxt/ui/releases"> Nuxt UI releases. </card> </card-group> <read-more icon="i-simple-icons-github" target="_blank" to="https://github.com/nuxt"> Discover the `nuxt` organization on GitHub </read-more> # Contribution > Nuxt is a community project - and so we love contributions of all kinds! โค๏ธ There is a range of different ways you might be able to contribute to the Nuxt ecosystem. ## Ecosystem The Nuxt ecosystem includes many different projects and organizations: - [nuxt/](https://github.com/nuxt) - core repositories for the Nuxt framework itself. [**nuxt/nuxt**](https://github.com/nuxt/nuxt) contains the Nuxt framework (both versions 2 and 3). - [nuxt-modules/](https://github.com/nuxt-modules) - community-contributed and maintained modules and libraries. There is a [process to migrate a module](https://nuxt.com/docs/3.x/guide/modules/ecosystem) to `nuxt-modules`. While these modules have individual maintainers, they are not dependent on a single person. - [unjs/](https://github.com/unjs) - many of these libraries are used throughout the Nuxt ecosystem. They are designed to be universal libraries that are framework- and environment-agnostic. We welcome contributions and usage by other frameworks and projects. ## How To Contribute ### Triage Issues and Help Out in Discussions Check out the issues and discussions for the project you want to help. For example, here are [the issues board](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) for Nuxt. Helping other users, sharing workarounds, creating reproductions, or even poking into a bug a little bit and sharing your findings makes a huge difference. ### Creating an Issue Thank you for taking the time to create an issue! โค๏ธ - **Reporting bugs**: Check out [our guide](https://nuxt.com/docs/3.x/community/reporting-bugs) for some things to do before opening an issue. - **Feature requests**: Check that there is not an existing issue or discussion covering the scope of the feature you have in mind. If the feature is to another part of the Nuxt ecosystem (such as a module), please consider raising a feature request there first. If the feature you have in mind is general or the API is not entirely clear, consider opening a discussion in the **Ideas** section to discuss with the community first. We'll do our best to follow our [internal issue decision making flowchart](https://mermaid.live/view#pako:eNqFlE1v2zAMhv8K4UuToslhx2Bo0TZt12Edhm7YMCAXWqJtorLk6qOpkfS_j7KdfpyWQ-BQr8mHL6nsCuU0FauiMm6rGvQRfq03FuRzvvvTYIQHthpcBT_ugQNwPHuZjheLxf4i1VDx8x4udrf5EBCOQvSsYg4ffS79KS9pmX9QALTgyid2KYB7Ih-4bmKWbDk2YB0E1gRUVaRi-FDmmjAmT3u4nB3DmoNKIUA1BsGSohA49jnVMQhHbDh_EZQUImyxh-gAtfaiG-KWSJ-N8nt6YtpCdgEeE5rXPOdav5YwWJIJU7zrvNADV9C7JBIyIC07Wxupkx3LFQ5vCkguRno5f9fP2qnUko0Y2dk9rGdvHAa9IIhVGlCp5FFNPN-ce4DKeXBd53xMliOLp9IZtyORQVsnrGm-WJzejtUu5fFqdr5FGQ3bLslYvGthjZbJTLpReZG5_lLYw7XQ_CbPVT92ws9gnEJj-v84dk-PiaXnmF1XGAaPsOsMKywNvYmG80ZohV8k4wDR9_N3KN_dHm5mh1lnkM5FsYzRfNiTvJoT5gnQsl6uxjqXLhkNQ9syHJ0UZZ8ERUIlNShr6N8gZDEliR-ow7QZa0fhY4LoHLRo-8N7ZxPwjRj5ZZYXpvOSNs9v3Jjs8NXB4ets92xan3zydXZHvj64lKMayh4-gZC1bjASW2ipLeWuzIuToiXfImu5rbucclMIc0ubYiWPGv3DptjYF9Fhiu5nb1Wxij7RSZE6jZHWjLXHtlhVaIJESXN0_m68_sO_wMs_oO9gyg) when responding to issues. ### Send a Pull Request We always welcome pull requests! โค๏ธ #### Before You Start Before you fix a bug, we recommend that you check whether **there's an issue that describes it**, as it's possible it's a documentation issue or that there is some context that would be helpful to know. If you're working on a feature, then we ask that you **open a feature request issue first** to discuss with the maintainers whether the feature is desired - and the design of those features. This helps save time for both the maintainers and the contributors and means that features can be shipped faster. The issue **should be confirmed** by a framework team member before building out a feature in a pull request. For typo fixes, it's recommended to batch multiple typo fixes into one pull request to maintain a cleaner commit history. For bigger changes to Nuxt itself, we recommend that you first [create a Nuxt module](https://nuxt.com/docs/3.x/community/contribution#create-a-module) and implement the feature there. This allows for quick proof-of-concept. You can then [create an RFC](https://nuxt.com/docs/3.x/community/contribution#make-an-rfc) in the form of a discussion. As users adopt it and you gather feedback, it can then be refined and either added to Nuxt core or continue as a standalone module. #### Commit Conventions We use [Conventional Commits](https://www.conventionalcommits.org) for commit messages, which [allows a changelog to be auto-generated](https://github.com/unjs/changelogen) based on the commits. Please read the guide through if you aren't familiar with it already. Note that `fix:` and `feat:` are for **actual code changes** (that might affect logic). For typo or document changes, use `docs:` or `chore:` instead: - ~~fix: typo~~ -> `docs: fix typo` If you are working in a project with a monorepo, like `nuxt/nuxt`, ensure that you specify the main scope of your commit in brackets. For example: `feat(kit): add 'addMagicStuff' utility`. #### Making the Pull Request If you don't know how to send a pull request, we recommend reading [the guide](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). When sending a pull request, make sure your PR's title also follows the [Commit Convention](https://nuxt.com/docs/3.x/community/contribution#commit-conventions). If your PR fixes or resolves existing issues, please make sure you mention them in the PR description. It's ok to have multiple commits in a single PR; you don't need to rebase or force push for your changes as we will use `Squash and Merge` to squash the commits into one commit when merging. We do not add any commit hooks to allow for quick commits. But before you make a pull request, you should ensure that any lint/test scripts are passing. In general, please also make sure that there are no *unrelated* changes in a PR. For example, if your editor has made any changes to whitespace or formatting elsewhere in a file that you edited, please revert these so it is more obvious what your PR changes. And please avoid including multiple unrelated features or fixes in a single PR. If it is possible to separate them, it is better to have multiple PRs to review and merge separately. In general, a PR should do *one thing only*. #### Once You've Made a Pull Request Once you've made a pull request, we'll do our best to review it promptly. If we assign it to a maintainer, then that means that person will take special care to review it and implement any changes that may be required. If we request changes on a PR, please ignore the red text! It doesn't mean we think it's a bad PR - it's just a way of easily telling the status of a list of pull requests at a glance. If we mark a PR as 'pending', that means we likely have another task to do in reviewing the PR - it's an internal note-to-self, and not necessarily a reflection on whether the PR is a good idea or not. We will do our best to explain via a comment the reason for the pending status. We'll do our best to follow [our PR decision making flowchart](https://mermaid.live/view#pako:eNp9VE1v2kAQ_SsjXzBSEqlALlaUisSh0ACK2l4qcVm8Y9hi7672Iwly-O-ZtYPt5FAOCHbee_PmzdpVlCmOURLlhXrJ9sw4-JNuJNBnWs1UQafIQVjrERyWumAOv58-AJeXt29_0b7BXbWwwL0uRPa1vlZvcB_fF8oiMMmB2QM4BXkt3UoON7Lh3LWaDz2SVkK6QGt7DHvw0CKt5sxCKaQoWQEGtVHcZ04oGdw04LTVngW_LHOeFcURGGz97mw6PSv-iJdsi0UCA4nI7SfNwc3W3JZit3eQ1SZFDlKB15yswQ2MgbOjbYeatY3n8bcr-IWlekYYaJRcyB04I9gOB1CEfkF5dAVTzmFAtnqn4-bUYAiMMmHZgWhNPRhgus5mW2BATxq0NkIZ4Y4NbNjzE2ZchBzcHmGLe_ZMSKCcyRXyLrVFa_5n_PBK2xKy3kk9eOjULUdltk6C8kI-7NFDr8f4EVGDoqlp-wa4sJm3ltIMIuZ_mTQXJyTSkQZtunPqsKxShV9GKdkBYe1fHXjpbcjlvONlO9Kqx_M7YHmOmav_luxfE5zKwVs09hM5DLSupgYDlr5flDkwo7ykixKG-xDsUly1LZ-uY32dgDc7lG7YqwbNp0msJwmIUivjWFtfd-xRrEcJ7Omydz37qFplHOtxEp4GskI2qB5dRCWakglOz3oV8JuITJa4iRL6yZk5bKKNPBGOead-H2UWJc54vIiaW53SPgwrz4fIhVNm1bw76lfI6R2_MW21) when responding and reviewing to pull requests. ### AI-Assisted Contributions We welcome the thoughtful use of AI tools when contributing to Nuxt, yet ask all contributors to follow [two core principles](https://roe.dev/blog/using-ai-in-open-source). #### Never let an LLM speak for you - All comments, issues, and pull request descriptions should be written in your own voice - We value clear, human communication over perfect grammar or spelling - Avoid copy-pasting AI-generated summaries that don't reflect your own understanding #### Never let an LLM think for you - Feel free to use AI tools to generate code or explore ideas - Only submit contributions you fully understand and can explain - Contributions should reflect your own reasoning and problem-solving Our aim is ensuring quality and maintaining the joy of collaborating and communicating with real people. If you have ideas for improving our policy on AI in the Nuxt community, we'd love to hear them! โค๏ธ ### Create a Module If you've built something with Nuxt that's cool, why not [extract it into a module](https://nuxt.com/docs/3.x/guide/modules), so it can be shared with others? We have [many excellent modules already](https://nuxt.com/modules), but there's always room for more. If you need help while building it, feel free to [check in with us](https://nuxt.com/docs/3.x/community/getting-help). ### Make an RFC We highly recommend [creating a module](https://nuxt.com/docs/3.x/community/contribution#create-a-module) first to test out big new features and gain community adoption. If you have done this already, or it's not appropriate to create a new module, then please start by creating a new discussion. Make sure it explains your thinking as clearly as possible. Include code examples or function signatures for new APIs. Reference existing issues or pain points with examples. If we think this should be an RFC, we'll change the category to RFC and broadcast it more widely for feedback. An RFC will then move through the following stages: - `rfc: active` - currently open for comment - `rfc: approved` - approved by the Nuxt team - `rfc: ready to implement` - an issue has been created and assigned to implement - `rfc: shipped` - implemented - `rfc: archived` - not approved, but archived for future reference ### Conventions Across Ecosystem The following conventions are *required* within the `nuxt/` organization and recommended for other maintainers in the ecosystem. #### Module Conventions Modules should follow the [Nuxt module template](https://github.com/nuxt/starter/tree/module). See [module guide](https://nuxt.com/docs/3.x/guide/modules) for more information. #### Use Core `unjs/` Libraries We recommend the following libraries which are used throughout the ecosystem: - [pathe](https://github.com/unjs/pathe) - universal path utilities (replacement for node `path`) - [ufo](https://github.com/unjs/ufo) - URL parsing and joining utilities - [obuild](https://github.com/unjs/obuild) - rolldown-powered build system - ... check out the rest of the [unjs/](https://github.com/unjs) organization for many more! #### Use ESM Syntax and Default to `type: module` Most of the Nuxt ecosystem can consume ESM directly. In general we advocate that you avoid using CJS-specific code, such as `__dirname` and `require` statements. You can [read more about ESM](https://nuxt.com/docs/3.x/guide/concepts/esm). #### What's Corepack [Corepack](https://github.com/nodejs/corepack) makes sure you are using the correct version for package manager when you run corresponding commands. Projects might have `packageManager` field in their `package.json`. Under projects with configuration as shown below, Corepack will install `v7.5.0` of `pnpm` (if you don't have it already) and use it to run your commands. ```jsonc [package.json] { "packageManager": "pnpm@7.5.0" } ``` #### Use ESLint We use [ESLint](https://eslint.org) for both linting and formatting with [`@nuxt/eslint`](https://github.com/nuxt/eslint). ##### IDE Setup We recommend using [VS Code](https://code.visualstudio.com) along with the [ESLint extension](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint). If you would like, you can enable auto-fix and formatting when you save the code you are editing: ```json [settings.json] { "editor.codeActionsOnSave": { "source.fixAll": "never", "source.fixAll.eslint": "explicit" } } ``` #### No Prettier Since ESLint is already configured to format the code, there is no need to duplicate the functionality with Prettier. To format the code, you can run `yarn lint --fix`, `pnpm lint --fix`, `bun run lint --fix`, or `deno run lint --fix` or referring the [ESLint section](https://nuxt.com/docs/3.x/community/contribution#use-eslint) for IDE Setup. If you have Prettier installed in your editor, we recommend you disable it when working on the project to avoid conflict. #### Package Manager We recommend `pnpm` as a package manager for modules, libraries and apps. It is important to enable Corepack to ensure you are on the same version of the package manager as the project. Corepack is built-in to new node versions for seamless package manager integration. To enable it, run ```bash [Terminal] corepack enable ``` You only need to do this one time, after Node.js is installed on your computer. ## Documentation Style Guide Documentation is an essential part of Nuxt. We aim to be an intuitive framework - and a big part of that is making sure that both the developer experience and the docs are perfect across the ecosystem. ๐Ÿ‘Œ Here are some tips that may help improve your documentation: - Avoid subjective words like *simply*, *just*, *obviously...* when possible.<br /> Keep in mind your readers can have different backgrounds and experiences. Therefore, these words don't convey meaning and can be harmful.<caution icon="i-lucide-circle-x"> Simply make sure the function returns a promise. </caution> <tip icon="i-lucide-circle-check"> Make sure the function returns a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). </tip> - Prefer [active voice](https://developers.google.com/tech-writing/one/active-voice).<caution icon="i-lucide-circle-x"> An error will be thrown by Nuxt. </caution> <tip icon="i-lucide-circle-check"> Nuxt will throw an error. </tip> <read-more to="https://nuxt.com/docs/3.x/community/framework-contribution#documentation-guide"> Learn how to contribute to the documentation. </read-more> # Framework > Some specific points about contributions to the framework repository. Once you've read the [general contribution guide](https://nuxt.com/docs/3.x/community/contribution), here are some specific points to make about contributions to the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository. ## Monorepo Guide - `packages/kit`: Toolkit for authoring Nuxt modules, published as [`@nuxt/kit`](https://www.npmjs.com/package/@nuxt/kit). - `packages/nuxt`: The core of Nuxt, published as [`nuxt`](https://www.npmjs.com/package/nuxt). - `packages/schema`: Cross-version Nuxt typedefs and defaults, published as [`@nuxt/schema`](https://www.npmjs.com/package/@nuxt/schema). - `packages/rspack`: The [Rspack](https://rspack.rs) bundler for Nuxt, published as [`@nuxt/rspack-builder`](https://www.npmjs.com/package/@nuxt/rspack-builder). - `packages/vite`: The [Vite](https://vite.dev) bundler for Nuxt, published as [`@nuxt/vite-builder`](https://www.npmjs.com/package/@nuxt/vite-builder). - `packages/webpack`: The [webpack](https://webpack.js.org) bundler for Nuxt, published as [`@nuxt/webpack-builder`](https://www.npmjs.com/package/@nuxt/webpack-builder). ## Setup To contribute to Nuxt, you need to set up a local environment. 1. [Fork](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository to your own GitHub account and then [clone](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) it to your local device. 2. Ensure using the latest [Node.js](https://nodejs.org/en) 3. Enable [Corepack](https://github.com/nodejs/corepack) to have `pnpm` and `yarn````bash [Terminal] corepack enable ``` 4. Run `pnpm install --frozen-lockfile` to Install the dependencies with pnpm: ```bash [Terminal] pnpm install --frozen-lockfile ``` <note> If you are adding a dependency, please use `pnpm add`. <br /> The `pnpm-lock.yaml` file is the source of truth for all Nuxt dependencies. </note> 5. Activate the passive development system ```bash [Terminal] pnpm dev:prepare ``` 6. Check out a branch where you can work and commit your changes: ```bash [Terminal] git checkout -b my-new-branch ``` Then, test your changes against the [playground](https://nuxt.com/docs/3.x/community/framework-contribution#playground) and [test](https://nuxt.com/docs/3.x/community/framework-contribution#testing) your changes before submitting a pull request. ### Playground While working on a pull request, you will likely want to check if your changes are working correctly. You can modify the example app in `playground/`, and run: ```bash [Terminal] pnpm dev ``` <important> Please make sure not to commit it to your branch, but it could be helpful to add some example code to your PR description. This can help reviewers and other Nuxt users understand the feature you've built in-depth. </important> ### Testing Every new feature should have a corresponding unit test (if possible). The `test/` directory in this repository is currently a work in progress, but do your best to create a new test following the example of what's already there. Before creating a PR or marking it as ready-to-review, ensure that all tests pass by running: ```bash [Terminal] pnpm test ``` ### Linting You might have noticed already that we use ESLint to enforce a coding standard. Before committing your changes, to verify that the code style is correct, run: ```bash [Terminal] pnpm lint ``` <note> You can use `pnpm lint --fix` to fix most of the style changes. <br /> If there are still errors left, you must correct them manually. </note> ### Documentation If you are adding a new feature or refactoring or changing the behavior of Nuxt in any other manner, you'll likely want to document the changes. Please include any changes to the docs in the same PR. You don't have to write documentation up on the first commit (but please do so as soon as your pull request is mature enough). <important> Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/3.x/community/contribution#documentation-style-guide). </important> ### Final Checklist When submitting your PR, there is a simple template that you have to fill out. Please tick all appropriate "answers" in the checklists. ## Documentation Guide If you spot an area where we can improve documentation or error messages, please do open a PR - even if it's just to fix a typo! <important> Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/3.x/community/contribution#documentation-style-guide). </important> ### Quick Edits If you spot a typo or want to rephrase a sentence, you can click on the **Edit this page** link located on the right aside in the **Community** section. Make the change directly in the GitHub interface and open a Pull Request. ### Longer Edits The documentation content is inside the `docs/` directory of the [nuxt/nuxt](https://github.com/nuxt/nuxt) repository and written in markdown. <note> To preview the docs locally, follow the steps on [nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) repository. </note> <note> We recommend that you install the [MDC extension](https://marketplace.visualstudio.com/items?itemName=Nuxt.mdc) for VS Code. </note> When linking to other documentation pages, use relative paths without the domain or a version segment: `/docs/getting-started/installation` rather than `/docs/3.x/getting-started/installation`. nuxt.com inserts the version segment of the branch the page was built from, so the same link resolves correctly on every version and docs changes can be cherry-picked between branches unchanged. Only write a version segment when you deliberately mean *another* version's docs, and in that case use the full URL, `https://nuxt.com/docs/4.x/getting-started/introduction`, so the intent is obvious in review. ### Linting Docs Documentation is linted using [MarkdownLint](https://github.com/DavidAnson/markdownlint) and [case police](https://github.com/antfu/case-police) to keep the documentation cohesive. ```bash [Terminal] pnpm lint:docs ``` <note> You can also run `pnpm lint:docs:fix` to highlight and resolve any lint issues. </note> ### Open a PR Please make sure your PR title adheres to the [conventional commits](https://www.conventionalcommits.org) guidelines. ```bash [Example of PR title] docs: update the section about the nuxt.config.ts file ``` # Getting Help > We're a friendly community of developers and we'd love to help. At some point, you may find that there's an issue you need some help with. But don't worry! We're a friendly community of developers and we'd love to help. <card-group> <card icon="i-simple-icons-discord" target="_blank" title="Discord" to="https://go.nuxt.com/discord"> Get real-time help, exchange with the core team and the community, and stay updated on the latest Nuxt news. </card> <card icon="i-simple-icons-nuxt" target="_blank" title="Nuxters" to="https://nuxters.nuxt.com"> Connect with other Nuxt enthusiasts. </card> </card-group> ## "I can't figure out how to (...)." You've read through these docs and you think it should be possible, but it's not clear how. The best thing is to [open a GitHub Discussion](https://github.com/nuxt/nuxt/discussions). Please don't feel embarrassed about asking a question that you think is easy - we've all been there! โค๏ธ Everyone you'll encounter is helping out because they care, not because they are paid to do so. The kindest thing to do is make it easy for them to help you. Here are some ideas: - *Explain what your objective is, not just the problem you're facing.* "I need to ensure my form inputs are accessible, so I'm trying to get the ids to match between server and client." - *Make sure you've first read the docs and used your favorite search engine*. Let people know by saying something like "I've Googled for 'nuxt script setup' but I couldn't find code examples anywhere." - *Explain what you've tried.* Tell people the kind of solutions you've experimented with, and why. Often this can make people's advice more relevant to your situation. - *Share your code.* People probably won't be able to help if they just see an error message or a screenshot - but that all changes if you share your code in a copy/pasteable format - preferably in the form of a minimal reproduction like a CodeSandbox. And finally, just ask the question! There's no need to [ask permission to ask a question](https://dontasktoask.com) or [wait for someone to reply to your 'hello'](https://www.nohello.com). If you do, you might not get a response because people are waiting for the whole question before engaging. ## "Could there be a bug?" Something isn't working the way that the docs say that it should. You're not sure if it's a bug. You've searched through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) but you can't find anything. (if there is a closed issue, please create a new one) We recommend taking a look at [how to report bugs](https://nuxt.com/docs/3.x/community/reporting-bugs). Nuxt is still in active development, and every issue helps make it better. ## "I need professional help" If the community couldn't provide the help you need in the time-frame you have, NuxtLabs offers professional support with the [Nuxt Experts](https://nuxt.com/enterprise/agencies). The objective of the Nuxt Expert is to provide support to the Vue ecosystem, while also creating freelance opportunities for those contributing to open-source solutions, thus helping to maintain the sustainability of the ecosystem. The Nuxt experts are Vue, Nuxt and Vite chosen contributors providing professional support and consulting services. # Reporting Bugs > One of the most valuable roles in open source is taking the time to report bugs helpfully. Try as we might, we will never completely eliminate bugs. Even if you can't fix the underlying code, reporting a bug well can enable someone else with a bit more familiarity with the codebase to spot a pattern or make a quick fix. Here are a few key steps. ## Is It Really a Bug? Consider if you're looking to get help with something, or whether you think there's a bug with Nuxt itself. If it's the former, we'd love to help you - but the best way to do that is through [asking for help](https://nuxt.com/docs/3.x/community/getting-help) rather than reporting a bug. ## Search the Issues Search through the [open issues](https://github.com/nuxt/nuxt/issues) and [discussions](https://github.com/nuxt/nuxt/discussions) first. If you find anything that seems like the same bug, it's much better to comment on an existing thread than create a duplicate. ## Create a Minimal Reproduction It's important to be able to reproduce the bug reliably - in a minimal way and apart from the rest of your project. This narrows down what could be causing the issue and makes it possible for someone not only to find the cause, but also to test a potential solution. Start with the Nuxt sandbox and add the **minimum** amount of code necessary to reproduce the bug you're experiencing. <note> If your issue concerns Vue or Vite, please try to reproduce it first with the Vue SSR starter. </note> **Nuxt**: <card-group> <card icon="i-simple-icons-stackblitz" target="_blank" title="Nuxt on StackBlitz" to="https://nuxt.new/s/v3"> </card> <card icon="i-simple-icons-codesandbox" target="_blank" title="Nuxt on CodeSandbox" to="https://nuxt.new/c/v3"> </card> </card-group> **Vue**: <card-group> <card icon="i-simple-icons-stackblitz" target="_blank" title="Vue SSR on StackBlitz" to="https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter/tree/main?terminal=dev"> </card> <card icon="i-simple-icons-codesandbox" target="_blank" title="Vue SSR on CodeSandbox" to="https://codesandbox.io/p/sandbox/github/nuxt-contrib/vue3-ssr-starter/main"> </card> <card icon="i-simple-icons-github" target="_blank" title="Vue SSR Template on GitHub" to="https://github.com/nuxt-contrib/vue3-ssr-starter/generate"> </card> </card-group> Once you've reproduced the issue, remove as much code from your reproduction as you can (while still recreating the bug). The time spent making the reproduction as minimal as possible will make a huge difference to whoever sets out to fix the issue. ## Figure Out What the Cause Might Be With a Nuxt project, there are lots of moving pieces - from [Nuxt modules](https://nuxt.com/modules) to [other JavaScript libraries](https://www.npmjs.com). Try to report the bug at the most relevant and specific place. That will likely be the Nuxt module causing an issue, or the upstream library that Nuxt is depending on. # Roadmap > Nuxt is constantly evolving, with new features and modules being added all the time. <read-more to="https://nuxt.com/blog"> See our blog for the latest framework and ecosystem announcements. </read-more> ## Status Reports <read-more to="https://github.com/nuxt/nuxt/issues/13653" icon="i-simple-icons-github" target="_blank"> Documentation Progress </read-more> <read-more to="https://github.com/nuxt/nuxt/discussions/16119" icon="i-simple-icons-github" target="_blank"> Rendering Optimizations: Today and Tomorrow </read-more> <read-more to="https://github.com/nuxt/image/discussions/563" icon="i-simple-icons-github" target="_blank"> Nuxt Image: Performance and Status </read-more> ## Roadmap In roadmap below are some features we are planning or working on at the moment. <tip> Check [Discussions](https://github.com/nuxt/nuxt/discussions) and [RFCs](https://github.com/nuxt/nuxt/discussions/categories/rfcs) for more upcoming features and ideas. </tip> <table> <thead> <tr> <th> Milestone </th> <th> Expected date </th> <th> Notes </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> SEO & PWA </td> <td> 2025 </td> <td> <a href="https://github.com/nuxt/nuxt/discussions/18395" rel="nofollow"> nuxt/nuxt#18395 </a> </td> <td> Migrating from <a href="https://github.com/nuxt-community/pwa-module" rel="nofollow"> nuxt-community/pwa-module </a> for built-in SEO utils and service worker support </td> </tr> <tr> <td> Assets </td> <td> 2025 </td> <td> <a href="https://github.com/nuxt/nuxt/discussions/22012" rel="nofollow"> nuxt/nuxt#22012 </a> </td> <td> Allow developers and modules to handle loading third-party assets. </td> </tr> <tr> <td> Translations </td> <td> - </td> <td> <a href="https://github.com/nuxt/nuxt.com/issues/1711" rel="nofollow"> nuxt/nuxt.com#1711 </a> </td> <td> A collaborative project for a stable translation process for Nuxt docs. Currently pending for ideas and documentation tooling support. </td> </tr> </tbody> </table> ## Core Modules Roadmap In addition to the Nuxt framework, there are modules that are vital for the ecosystem. Their status will be updated below. <table> <thead> <tr> <th> Module </th> <th> Status </th> <th> Nuxt Support </th> <th> Repository </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> Auth Utils </td> <td> Planned </td> <td> 4.x, 5.x </td> <td> <code> nuxt/auth-utils </code> to be announced </td> <td> The temporary repository <a href="https://github.com/atinux/nuxt-auth-utils" rel="nofollow"> atinux/nuxt-auth-utils </a> is available while awaiting its official integration into Nuxt via RFC. </td> </tr> <tr> <td> <a href="https://github.com/nuxt/a11y" rel="nofollow"> a11y </a> </td> <td> Public Alpha </td> <td> 3.x, 4.x </td> <td> <a href="https://github.com/nuxt/a11y" rel="nofollow"> nuxt/a11y </a> . </td> <td> Real-time accessibility feedback and automated testing in your browser during development (see <a href="https://github.com/nuxt/nuxt/issues/23255" rel="nofollow"> nuxt/nuxt#23255 </a> ). </td> </tr> </tbody> </table> ## Release Cycle Since January 2023, we've adopted a consistent release cycle for Nuxt, following [semver](https://semver.org). We aim for major framework releases every year, with an expectation of patch releases every week or so and minor releases every month or so. They should never contain breaking changes except within options clearly marked as `experimental`. We are planning a slight variation from this plan for Nuxt 4 and Nuxt 5. Nuxt 4 will be a stability-focused release containing all `compatibilityVersion: 4` features, and will be followed shortly by Nuxt 5 which will include an upgrade to Nitro v3 and additional changes. This approach separates breaking changes into manageable phases, allowing for better ecosystem testing and smoother migrations. ### Ongoing Support for Nuxt We commit to support each major version of Nuxt for a minimum of six months after the release of the next major version, and to providing an upgrade path for current users at that point. ### Current Packages The current active version of [Nuxt](https://nuxt.com) is **v4** which is available as `nuxt` on npm with the `latest` tag. Nuxt 3 will continue to receive maintenance updates (bug fixes and security patches) until the end of July 2026. Each active version has its own nightly releases which are generated automatically. For more about enabling the Nuxt nightly release channel, see [the nightly release channel docs](https://nuxt.com/docs/3.x/guide/going-further/nightly-release-channel). <table> <thead> <tr> <th> Release </th> <th> </th> <th> Initial release </th> <th> End Of Life </th> <th> Docs </th> </tr> </thead> <tbody> <tr> <td> <strong> 5.x </strong> (scheduled) </td> <td> </td> <td> Q1 2026 (estimated) </td> <td> TBA </td> <td> </td> </tr> <tr> <td> <strong> 4.x </strong> (stable) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt latest version" src="https://img.shields.io/npm/v/nuxt.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2025-07-16 </td> <td> 6 months after 5.x release </td> <td> <a href="https://nuxt.com/docs/4.x/getting-started/introduction" rel="nofollow"> nuxt.com </a> </td> </tr> <tr> <td> <strong> 3.x </strong> (maintenance) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 3.x version" src="https://img.shields.io/npm/v/nuxt/3x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2022-11-16 </td> <td> 2026-07-31 </td> <td> <a href="https://nuxt.com/docs/3.x/getting-started/introduction" rel="nofollow"> nuxt.com </a> </td> </tr> <tr> <td> <strong> 2.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 2.x version" src="https://img.shields.io/npm/v/nuxt/2x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2018-09-21 </td> <td> 2024-06-30 </td> <td> <a href="https://v2.nuxt.com/docs/get-started/installation/" rel="nofollow"> v2.nuxt.com </a> </td> </tr> <tr> <td> <strong> 1.x </strong> (unsupported) </td> <td> <a href="https://www.npmjs.com/package/nuxt?activeTab=versions"> <img alt="Nuxt 1.x version" src="https://img.shields.io/npm/v/nuxt/1x.svg?logo=nuxt&label=&style=flat&colorA=18181B&colorB=28CF8D" className="not-prose,h-5,w-auto" :zoom="false" /> </a> </td> <td> 2018-01-08 </td> <td> 2019-09-21 </td> <td> </td> </tr> </tbody> </table> ### Support Status <table> <thead> <tr> <th> Status </th> <th> Description </th> </tr> </thead> <tbody> <tr> <td> Unsupported </td> <td> This version is not maintained any more and will not receive security patches </td> </tr> <tr> <td> Maintenance </td> <td> This version will only receive security patches </td> </tr> <tr> <td> Stable </td> <td> This version is being developed for and will receive security patches </td> </tr> <tr> <td> Development </td> <td> This version could be unstable </td> </tr> <tr> <td> Scheduled </td> <td> This version does not exist yet but is planned </td> </tr> </tbody> </table> # Nuxt Directory Structure > Learn about the directory structure of a Nuxt application and how to use it. Nuxt applications have a specific directory structure that is used to organize the code. This structure is designed to be easy to understand and to be used in a consistent way. ## Root Directory The root directory of a Nuxt application is the directory that contains the `nuxt.config.ts` file. This file is used to configure the Nuxt application. ## App Directory The following directories are related to the universal Nuxt application: - [`assets/`](https://nuxt.com/docs/3.x/directory-structure/assets): website's assets that the build tool (Vite or webpack) will process - [`components/`](https://nuxt.com/docs/3.x/directory-structure/components): Vue components of the application - [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables): add your Vue composables - [`layouts/`](https://nuxt.com/docs/3.x/directory-structure/layouts): Vue components that wrap around your pages and avoid re-rendering between pages - [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/middleware): run code before navigating to a particular route - [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages): file-based routing to create routes within your web application - [`plugins/`](https://nuxt.com/docs/3.x/directory-structure/plugins): use Vue plugins and more at the creation of your Nuxt application - [`utils/`](https://nuxt.com/docs/3.x/directory-structure/utils): add functions throughout your application that can be used in your components, composables, and pages. This directory also includes specific files: - [`app.config.ts`](https://nuxt.com/docs/3.x/directory-structure/app-config): a reactive configuration within your application - [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app): the root component of your Nuxt application - [`error.vue`](https://nuxt.com/docs/3.x/directory-structure/error): the error page of your Nuxt application ## Public Directory The [`public/`](https://nuxt.com/docs/3.x/directory-structure/public) directory is the directory that contains the public files of the Nuxt application. Files contained within this directory are served at the root and are not modified by the build process. This is suitable for files that have to keep their names (e.g. `robots.txt`) *or* likely won't change (e.g. `favicon.ico`). ## Server Directory The [`server/`](https://nuxt.com/docs/3.x/directory-structure/server) directory is the directory that contains the server-side code of the Nuxt application. It contains the following subdirectories: - [`api/`](https://nuxt.com/docs/3.x/directory-structure/server#server-routes): contains the API routes of the application. - [`routes/`](https://nuxt.com/docs/3.x/directory-structure/server#server-routes): contains the server routes of the application (e.g. dynamic `/sitemap.xml`). - [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/server#server-middleware): run code before a server route is processed - [`plugins/`](https://nuxt.com/docs/3.x/directory-structure/server#server-plugins): use plugins and more at the creation of the Nuxt server - [`utils/`](https://nuxt.com/docs/3.x/directory-structure/server#server-utilities): add functions throughout your application that can be used in your server code. ## Shared Directory The [`shared/`](https://nuxt.com/docs/3.x/directory-structure/shared) directory is the directory that contains the shared code of the Nuxt application and Nuxt server. This code can be used in both the Vue app and the Nitro server. ## Content Directory The [`content/`](https://nuxt.com/docs/3.x/directory-structure/content) directory is enabled by the [Nuxt Content](https://content.nuxt.com) module. It is used to create a file-based CMS for your application using Markdown files. ## Modules Directory The [`modules/`](https://nuxt.com/docs/3.x/directory-structure/modules) directory is the directory that contains the local modules of the Nuxt application. Modules are used to extend the functionality of the Nuxt application. ## Layers Directory The [`layers/`](https://nuxt.com/docs/3.x/directory-structure/layers) directory allows you to organize and share reusable code, components, composables, and configurations. Layers within this directory are automatically registered in your project. ## Nuxt Files - [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file is the main configuration file for the Nuxt application. - [`.nuxtrc`](https://nuxt.com/docs/3.x/directory-structure/nuxtrc) file is another syntax for configuring the Nuxt application (useful for global configurations). - [`.nuxtignore`](https://nuxt.com/docs/3.x/directory-structure/nuxtignore) file is used to ignore files in the root directory during the build phase. # app.vue > The app.vue file is the main component of your Nuxt application. <tip> If you have a `pages/` directory, the `app.vue` file is optional. Nuxt will automatically include a default `app.vue`, but you can still add your own to customize the structure and content as needed. </tip> ## Usage ### Minimal Usage With Nuxt, the [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory is optional. If it is not present, Nuxt will not include the [vue-router](https://router.vuejs.org) dependency. This is useful when building a landing page or an application that does not require routing. ```vue [app.vue] <template> <h1>Hello World!</h1> </template> ``` <link-example to="https://nuxt.com/docs/3.x/examples/hello-world"> </link-example> ### Usage with Pages When you have a [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory, you need to use the [`<NuxtPage>`](https://nuxt.com/docs/3.x/api/components/nuxt-page) component to display the current page: ```vue [app.vue] <template> <NuxtPage /> </template> ``` You can also define the common structure of your application directly in `app.vue`. This is useful when you want to include global elements such as a header or footer: ```vue [app.vue] <template> <header> Header content </header> <NuxtPage /> <footer> Footer content </footer> </template> ``` <note> Remember that `app.vue` acts as the main component of your Nuxt application. Anything you add to it (JS and CSS) will be global and included in every page. </note> <read-more to="https://nuxt.com/docs/3.x/directory-structure/pages"> Learn more about how to structure your pages using the `pages/` directory. </read-more> ### Usage with Layouts When your application requires different layouts for different pages, you can use the `layouts/` directory with the [`<NuxtLayout>`](https://nuxt.com/docs/3.x/api/components/nuxt-layout) component. This allows you to define multiple layouts and apply them per page. ```vue [app.vue] <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/layouts"> Learn more about how to structure your layouts using the `layouts/` directory. </read-more> # app.config.ts > Expose reactive configuration within your application with the App Config file. Nuxt provides an `app.config.ts` config file to expose reactive configuration within your application with the ability to update it at runtime within lifecycle or using a nuxt plugin and editing it with HMR (hot-module-replacement). You can easily provide runtime app configuration using `app.config.ts` file. It can have either of `.ts`, `.js`, or `.mjs` extensions. ```ts [app.config.ts]twoslash export default defineAppConfig({ foo: 'bar', }) ``` <caution> Do not put any secret values inside `app.config` file. It is exposed to the user client bundle. </caution> <note> When configuring a custom [`srcDir`](https://nuxt.com/docs/3.x/api/nuxt-config#srcdir), make sure to place the `app.config` file at the root of the new `srcDir` path. </note> ## Usage To expose config and environment variables to the rest of your app, you will need to define configuration in `app.config` file. ```ts [app.config.ts]twoslash export default defineAppConfig({ theme: { primaryColor: '#ababab', }, }) ``` We can now universally access `theme` both when server-rendering the page and in the browser using [`useAppConfig`](https://nuxt.com/docs/3.x/api/composables/use-app-config) composable. ```vue [pages/index.vue] <script setup lang="ts"> const appConfig = useAppConfig() console.log(appConfig.theme) </script> ``` The [`updateAppConfig`](https://nuxt.com/docs/3.x/api/utils/update-app-config) utility can be used to update the `app.config` at runtime. ```vue [pages/index.vue] <script setup> const appConfig = useAppConfig() // { foo: 'bar' } const newAppConfig = { foo: 'baz' } updateAppConfig(newAppConfig) console.log(appConfig) // { foo: 'baz' } </script> ``` <read-more to="https://nuxt.com/docs/3.x/api/utils/update-app-config"> Read more about the `updateAppConfig` utility. </read-more> ## Typing App Config Nuxt tries to automatically generate a TypeScript interface from provided app config so you won't have to type it yourself. However, there are some cases where you might want to type it yourself. There are two possible things you might want to type. ### App Config Input `AppConfigInput` might be used by module authors who are declaring what valid *input* options are when setting app config. This will not affect the type of `useAppConfig()`. ```ts [index.d.ts] declare module 'nuxt/schema' { interface AppConfigInput { /** Theme configuration */ theme?: { /** Primary app color */ primaryColor?: string } } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ### App Config Output If you want to type the result of calling [`useAppConfig()`](https://nuxt.com/docs/3.x/api/composables/use-app-config), then you will want to extend `AppConfig`. <warning> Be careful when typing `AppConfig` as you will overwrite the types Nuxt infers from your actually defined app config. </warning> ```ts [index.d.ts] declare module 'nuxt/schema' { interface AppConfig { // This will entirely replace the existing inferred `theme` property theme: { // You might want to type this value to add more specific types than Nuxt can infer, // such as string literal types primaryColor?: 'red' | 'blue' } } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ## Merging Strategy Nuxt uses a custom merging strategy for the `AppConfig` within [the layers](https://nuxt.com/docs/3.x/getting-started/layers) of your application. This strategy is implemented using a [Function Merger](https://github.com/unjs/defu#function-merger), which allows defining a custom merging strategy for every key in `app.config` that has an array as value. <note> The function merger can only be used in the extended layers and not the main `app.config` in project. </note> Here's an example of how you can use: <code-group> ```ts [layer/app.config.ts]twoslash export default defineAppConfig({ // Default array value array: ['hello'], }) ``` ```ts [app.config.ts]twoslash export default defineAppConfig({ // Overwrite default array value by using a merger function array: () => ['bonjour'], }) ``` </code-group> ## Known Limitations As of Nuxt v3.3, the `app.config.ts` file is shared with Nitro, which results in the following limitations: 1. You cannot import Vue components directly in `app.config.ts`. 2. Some auto-imports are not available in the Nitro context. These limitations occur because Nitro processes the app config without full Vue component support. While it's possible to use Vite plugins in the Nitro config as a workaround, this approach is not recommended: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { vite: { plugins: [vue()], }, }, }) ``` <warning> Using this workaround may lead to unexpected behavior and bugs. The Vue plugin is one of many that are not available in the Nitro context. </warning> Related issues: - [Issue #19858](https://github.com/nuxt/nuxt/issues/19858) - [Issue #19854](https://github.com/nuxt/nuxt/issues/19854) <note> Nitro v3 will resolve these limitations by removing support for the app config. You can track the progress in [this pull request](https://github.com/nitrojs/nitro/pull/2521). </note> # assets > The assets/ directory is used to add all the website's assets that the build tool will process. The directory usually contains the following types of files: - Stylesheets (CSS, SASS, etc.) - Fonts - Images that won't be served from the [`public/`](https://nuxt.com/docs/3.x/directory-structure/public) directory. If you want to serve assets from the server, we recommend taking a look at the [`public/`](https://nuxt.com/docs/3.x/directory-structure/public) directory. <read-more to="https://nuxt.com/docs/3.x/getting-started/assets"> </read-more> # components > The components/ directory is where you put all your Vue components. Nuxt automatically imports any components in this directory (along with components that are registered by any modules you may be using). ```bash [Directory Structure] -| components/ ---| AppHeader.vue ---| AppFooter.vue ``` ```html [app.vue] <template> <div> <AppHeader /> <NuxtPage /> <AppFooter /> </div> </template> ``` ## Component Names If you have a component in nested directories such as: ```bash [Directory Structure] -| components/ ---| base/ -----| foo/ -------| Button.vue ``` ... then the component's name will be based on its own path directory and filename, with duplicate segments being removed. Therefore, the component's name will be: ```html <BaseFooButton /> ``` <note> For clarity, we recommend that the component's filename matches its name. So, in the example above, you could rename `Button.vue` to be `BaseFooButton.vue`. </note> If you want to auto-import components based only on its name, not path, then you need to set `pathPrefix` option to `false` using extended form of the configuration object: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ { path: '~/components', pathPrefix: false, // [!code ++] }, ], }) ``` This registers the components using the same strategy as used in Nuxt 2. For example, `~/components/Some/MyComponent.vue` will be usable as `<MyComponent>` and not `<SomeMyComponent>`. ## Dynamic Components If you want to use the Vue `<component :is="someComputedComponent">` syntax, you need to use the `resolveComponent` helper provided by Vue or import the component directly from `#components` and pass it into `is` prop. For example: ```vue [pages/index.vue] <script setup lang="ts"> import { SomeComponent } from '#components' const MyButton = resolveComponent('MyButton') </script> <template> <component :is="clickable ? MyButton : 'div'" /> <component :is="SomeComponent" /> </template> ``` <important> If you are using `resolveComponent` to handle dynamic components, make sure not to insert anything but the name of the component, which must be a literal string and not be or contain a variable. The string is statically analyzed at the compilation step. </important> <video-accordion title="Watch Daniel Roe's short video about resolveComponent()" video-id="4kq8E5IUM2U"> </video-accordion> Alternatively, though not recommended, you can register all your components globally, which will create async chunks for all your components and make them available throughout your application. ```diff export default defineNuxtConfig({ components: { + global: true, + dirs: ['~/components'] }, }) ``` You can also selectively register some components globally by placing them in a `~/components/global` directory, or by using a `.global.vue` suffix in the filename. As noted above, each global component is rendered in a separate chunk, so be careful not to overuse this feature. <note> The `global` option can also be set per component directory. </note> ## Dynamic Imports To dynamically import a component (also known as lazy-loading a component) all you need to do is add the `Lazy` prefix to the component's name. This is particularly useful if the component is not always needed. By using the `Lazy` prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size. ```vue [pages/index.vue] <script setup lang="ts"> const show = ref(false) </script> <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true" > Show List </button> </div> </template> ``` ## Delayed (or Lazy) Hydration Lazy components are great for controlling the chunk sizes in your app, but they don't always enhance runtime performance, as they still load eagerly unless conditionally rendered. In real-world applications, some pages may include a lot of content and a lot of components, and most of the time not all of them need to be interactive as soon as the page is loaded. Having them all load eagerly can negatively impact performance. In order to optimize your app, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks. Nuxt supports this using lazy (or delayed) hydration, allowing you to control when components become interactive. ### Hydration Strategies Nuxt provides a range of built-in hydration strategies. Only one strategy can be used per lazy component. <note> Any prop change on a lazily hydrated component will trigger hydration immediately. (e.g., changing a prop on a component with `hydrate-never` will cause it to hydrate) </note> <warning> Currently Nuxt's built-in lazy hydration only works in single-file components (SFCs), and requires you to define the prop in the template (rather than spreading an object of props via `v-bind`). It also does not work with direct imports from `#components`. </warning> #### `hydrate-on-visible` Hydrates the component when it becomes visible in the viewport. ```vue [pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-visible /> </div> </template> ``` <read-more to="https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver" title="IntersectionObserver options"> Read more about the options for `hydrate-on-visible`. </read-more> <note> Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible). </note> #### `hydrate-on-idle` Hydrates the component when the browser is idle. This is suitable if you need the component to load as soon as possible, but not block the critical rendering path. You can also pass a number which serves as a max timeout. ```vue [pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-idle /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle). </note> #### `hydrate-on-interaction` Hydrates the component after a specified interaction (e.g., click, mouseover). ```vue [pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-interaction="mouseover" /> </div> </template> ``` If you do not pass an event or list of events, it defaults to hydrating on `pointerenter`, `click` and `focus`. <note> Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction). </note> #### `hydrate-on-media-query` Hydrates the component when the window matches a media query. ```vue [pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-media-query="(max-width: 768px)" /> </div> </template> ``` <note> Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query). </note> #### `hydrate-after` Hydrates the component after a specified delay (in milliseconds). ```vue [pages/index.vue] <template> <div> <LazyMyComponent :hydrate-after="2000" /> </div> </template> ``` #### `hydrate-when` Hydrates the component based on a boolean condition. ```vue [pages/index.vue] <template> <div> <LazyMyComponent :hydrate-when="isReady" /> </div> </template> <script setup lang="ts"> const isReady = ref(false) function myFunction () { // trigger custom hydration strategy... isReady.value = true } </script> ``` #### `hydrate-never` Never hydrates the component. ```vue [pages/index.vue] <template> <div> <LazyMyComponent hydrate-never /> </div> </template> ``` ### Listening to Hydration Events All delayed hydration components emit a `@hydrated` event when they are hydrated. ```vue [pages/index.vue] <template> <div> <LazyMyComponent hydrate-on-visible @hydrated="onHydrate" /> </div> </template> <script setup lang="ts"> function onHydrate () { console.log('Component has been hydrated!') } </script> ``` ### Caveats and Best Practices Delayed hydration can offer performance benefits, but it's essential to use it correctly: 1. **Prioritize In-Viewport Content:** Avoid delayed hydration for critical, above-the-fold content. It's best suited for content that isn't immediately needed. 2. **Conditional Rendering:** When using `v-if="false"` on a lazy component, you might not need delayed hydration. You can just use a normal lazy component. 3. **Shared State:** Be mindful of shared state (`v-model`) across multiple components. Updating the model in one component can trigger hydration in all components bound to that model. 4. **Use Each Strategy's Intended Use Case:** Each strategy is optimized for a specific purpose. - `hydrate-when` is best for components that might not always need to be hydrated. - `hydrate-after` is for components that can wait a specific amount of time. - `hydrate-on-idle` is for components that can be hydrated when the browser is idle. 5. **Avoid hydrate-never on interactive components:** If a component requires user interaction, it should not be set to never hydrate. ## Direct Imports You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality. ```vue [pages/index.vue] <script setup lang="ts"> import { LazyMountainsList, NuxtLink } from '#components' const show = ref(false) </script> <template> <div> <h1>Mountains</h1> <LazyMountainsList v-if="show" /> <button v-if="!show" @click="show = true" > Show List </button> <NuxtLink to="/">Home</NuxtLink> </div> </template> ``` ## Custom Directories By default, only the `~/components` directory is scanned. If you want to add other directories, or change how the components are scanned within a subfolder of this directory, you can add additional directories to the configuration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ // ~/calendar-module/components/event/Update.vue => <EventUpdate /> { path: '~/calendar-module/components' }, // ~/user-module/components/account/UserDeleteDialog.vue => <UserDeleteDialog /> { path: '~/user-module/components', pathPrefix: false }, // ~/components/special-components/Btn.vue => <SpecialBtn /> { path: '~/components/special-components', prefix: 'Special' }, // It's important that this comes last if you have overrides you wish to apply // to sub-directories of `~/components`. // // ~/components/Btn.vue => <Btn /> // ~/components/base/Btn.vue => <BaseBtn /> '~/components', ], }) ``` <note> Any nested directories need to be added first as they are scanned in order. </note> ## npm Packages If you want to auto-import components from an npm package, you can use [`addComponent`](https://nuxt.com/docs/3.x/api/kit/components#addcomponent) in a [local module](https://nuxt.com/docs/3.x/directory-structure/modules) to register them. <code-group> ```ts [~/modules/register-component.ts]twoslash import { addComponent, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { // import { MyComponent as MyAutoImportedComponent } from 'my-npm-package' addComponent({ name: 'MyAutoImportedComponent', export: 'MyComponent', filePath: 'my-npm-package', }) }, }) ``` ```vue [app.vue] <template> <div> <!-- the component uses the name we specified and is auto-imported --> <MyAutoImportedComponent /> </div> </template> ``` </code-group> ## Component Extensions By default, any file with an extension specified in the [extensions key of `nuxt.config.ts`](https://nuxt.com/docs/3.x/api/nuxt-config#extensions) is treated as a component. If you need to restrict the file extensions that should be registered as components, you can use the extended form of the components directory declaration and its `extensions` key: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: [ { path: '~/components', extensions: ['.vue'], // [!code ++] }, ], }) ``` ## Client Components If a component is meant to be rendered only client-side, you can add the `.client` suffix to your component. ```bash [Directory Structure] | components/ --| Comments.client.vue ``` ```vue [pages/example.vue] <template> <div> <!-- this component will only be rendered on client side --> <Comments /> </div> </template> ``` <note> This feature only works with Nuxt auto-imports and `#components` imports. Explicitly importing these components from their real paths does not convert them into client-only components. </note> <important> `.client` components are rendered only after being mounted. To access the rendered template using `onMounted()`, add `await nextTick()` in the callback of the `onMounted()` hook. </important> <read-more to="https://nuxt.com/docs/3.x/api/components/client-only"> You can also achieve a similar result with the `<ClientOnly>` component. </read-more> ## Server Components Server components allow server-rendering individual components within your client-side apps. It's possible to use server components within Nuxt, even if you are generating a static site. That makes it possible to build complex sites that mix dynamic components, server-rendered HTML and even static chunks of markup. Server components can either be used on their own or paired with a [client component](https://nuxt.com/docs/3.x/directory-structure/components#paired-with-a-client-component). <video-accordion title="Watch Learn Vue video about Nuxt Server Components" video-id="u1yyXe86xJM"> </video-accordion> <tip icon="i-lucide-newspaper" target="_blank" to="https://roe.dev/blog/nuxt-server-components"> Read Daniel Roe's guide to Nuxt Server Components. </tip> ### Standalone server components Standalone server components will always be rendered on the server, also known as Islands components. When their props update, this will result in a network request that will update the rendered HTML in-place. Server components are currently experimental and in order to use them, you need to enable the 'component islands' feature in your nuxt.config: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { componentIslands: true, }, }) ``` Now you can register server-only components with the `.server` suffix and use them anywhere in your application automatically. ```bash [Directory Structure] -| components/ ---| HighlightedMarkdown.server.vue ``` ```vue [pages/example.vue] <template> <div> <!-- this will automatically be rendered on the server, meaning your markdown parsing + highlighting libraries are not included in your client bundle. --> <HighlightedMarkdown markdown="# Headline" /> </div> </template> ``` Server-only components use [`<NuxtIsland>`](https://nuxt.com/docs/3.x/api/components/nuxt-island) under the hood, meaning that `lazy` prop and `#fallback` slot are both passed down to it. <warning> Server components (and islands) must have a single root element. (HTML comments are considered elements as well.) </warning> <warning> Props are passed to server components via URL query parameters, and are therefore limited by the possible length of a URL, so be careful not to pass enormous amounts of data to server components via props. </warning> <note> Server component props come from the request (URL query or body), so treat them as untrusted input. Nuxt rejects the props most likely to leak through unintentionally: a top-level `as` that the island does not declare (an undeclared prop falls through as an attribute onto the island's root), and, with `vue.runtimeCompiler` enabled, a `template` anywhere in the props. Beyond that, avoid feeding props you have not validated into dynamic component resolution (`<component :is>`, `h()`, `resolveDynamicComponent()`, or a polymorphic `as` / `asChild` prop), since a string can resolve to any registered component or HTML element. Props a component does not declare fall through as attributes onto its single root element, so an island whose root is a polymorphic component (e.g. from `reka-ui` / `@nuxt/ui`) can receive attributes you did not bind. Set `defineOptions({ inheritAttrs: false })` on such islands, or declare the props you accept. To switch components based on caller input, map a discriminator through an allowlist of imported components rather than passing the raw prop: ```vue <script setup lang="ts"> import type { Component } from 'vue' import CardA from './CardA.vue' import CardB from './CardB.vue' const props = defineProps<{ variant: string }>() const allowed: Record<string, Component> = { a: CardA, b: CardB } const component = allowed[props.variant] ?? CardA </script> <template> <component :is="component" /> </template> ``` </note> <warning> Be careful when nesting islands within other islands as each island adds some extra overhead. </warning> <warning> Most features for server-only components and island components, such as slots and client components, are only available for single file components. </warning> #### Client components within server components <note> This feature needs `experimental.componentIslands.selectiveClient` within your configuration to be true. </note> You can partially hydrate a component by setting a `nuxt-client` attribute on the component you wish to be loaded client-side. ```vue [components/ServerWithClient.vue] <template> <div> <HighlightedMarkdown markdown="# Headline" /> <!-- Counter will be loaded and hydrated client-side --> <Counter nuxt-client :count="5" /> </div> </template> ``` <note> This only works within a server component.ย Slots for client components are working only with `experimental.componentIsland.selectiveClient` set to `'deep'` and since they are rendered server-side, they are not interactive once client-side. </note> #### Server Component Context When rendering a server-only or island component, `<NuxtIsland>` makes a fetch request which comes back with a `NuxtIslandResponse`. (This is an internal request if rendered on the server, or a request that you can see in the network tab if it's rendering on client-side navigation.) This means: - A new Vue app will be created server-side to create the `NuxtIslandResponse`. - A new 'island context' will be created while rendering the component. - You can't access the 'island context' from the rest of your app and you can't access the context of the rest of your app from the island component. In other words, the server component or island is *isolated* from the rest of your app. - Your plugins will run again when rendering the island, unless they have `env: { islands: false }` set (which you can do in an object-syntax plugin). <important> Route middleware does not run when rendering island components. Middleware is a routing concept that applies to pages, not components, and is not designed to control component rendering. </important> <important> `useRoute()` and other `vue-router` composables do not track the current page route inside a server (island) component. The island is rendered in its own isolated Vue app keyed only on its props (and any explicit context), which is what keeps islands cacheable independently of the page they are rendered on. Inside an island, `useRoute()` will reflect the island's own request, not the page the user is on. If an island needs information about the current route, pass it in explicitly โ€” either as props from the parent component, or via the `context` prop on `<NuxtIsland>` (read inside the island from `nuxtApp.ssrContext.islandContext`). </important> Within an island component, you can access its island context through `nuxtApp.ssrContext.islandContext`. Note that while island components are still marked as experimental, the format of this context may change. <note> Slots can be interactive and are wrapped within a `<div>` with `display: contents;` </note> ### Paired with a Client component In this case, the `.server` + `.client` components are two 'halves' of a component and can be used in advanced use cases for separate implementations of a component on server and client side. ```bash [Directory Structure] -| components/ ---| Comments.client.vue ---| Comments.server.vue ``` ```vue [pages/example.vue] <template> <div> <!-- this component will render Comments.server on the server then Comments.client once mounted in the browser --> <Comments /> </div> </template> ``` ## Built-In Nuxt Components There are a number of components that Nuxt provides, including `<ClientOnly>` and `<DevOnly>`. You can read more about them in the API documentation. <read-more to="https://nuxt.com/docs/3.x/api"> </read-more> ## Library Authors Making Vue component libraries with automatic tree-shaking and component registration is super easy. โœจ You can use the [`addComponentsDir`](https://nuxt.com/docs/3.x/api/kit/components#addcomponentsdir) method provided from the `@nuxt/kit` to register your components directory in your Nuxt module. Imagine a directory structure like this: ```bash [Directory Structure] -| node_modules/ ---| awesome-ui/ -----| components/ -------| Alert.vue -------| Button.vue -----| nuxt.ts -| pages/ ---| index.vue -| nuxt.config.ts ``` Then in `awesome-ui/nuxt.ts` you can use the `addComponentsDir` hook: ```tstwoslash import { addComponentsDir, createResolver, defineNuxtModule } from '@nuxt/kit' export default defineNuxtModule({ setup () { const resolver = createResolver(import.meta.url) // Add ./components dir to the list addComponentsDir({ path: resolver.resolve('./components'), prefix: 'awesome', }) }, }) ``` That's it! Now in your project, you can import your UI library as a Nuxt module in your `nuxt.config` file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ modules: ['awesome-ui/nuxt'], }) ``` ... and directly use the module components (prefixed with `awesome-`) in our `pages/index.vue`: ```vue <template> <div> My <AwesomeButton>UI button</AwesomeButton>! <awesome-alert>Here's an alert!</awesome-alert> </div> </template> ``` It will automatically import the components only if used and also support HMR when updating your components in `node_modules/awesome-ui/components/`. <link-example to="https://nuxt.com/docs/3.x/examples/features/auto-imports"> </link-example> # composables > Use the composables/ directory to auto-import your Vue composables into your application. ## Usage **Method 1:** Using named export ```ts [composables/useFoo.ts] export const useFoo = () => { return useState('foo', () => 'bar') } ``` **Method 2:** Using default export ```ts [composables/use-foo.ts or composables/useFoo.ts] // It will be available as useFoo() (camelCase of file name without extension) export default function () { return useState('foo', () => 'bar') } ``` **Usage:** You can now use auto imported composable in `.js`, `.ts` and `.vue` files ```vue [app.vue] <script setup lang="ts"> const foo = useFoo() </script> <template> <div> {{ foo }} </div> </template> ``` <note> The `composables/` directory in Nuxt does not provide any additional reactivity capabilities to your code. Instead, any reactivity within composables is achieved using Vue's Composition API mechanisms, such as ref and reactive. Note that reactive code is also not limited to the boundaries of the `composables/` directory. You are free to employ reactivity features wherever they're needed in your application. </note> <read-more to="https://nuxt.com/docs/3.x/guide/concepts/auto-imports"> </read-more> <link-example to="https://nuxt.com/docs/3.x/examples/features/auto-imports"> </link-example> ## Types Under the hood, Nuxt auto generates the file `.nuxt/imports.d.ts` to declare the types. Be aware that you have to run [`nuxt prepare`](https://nuxt.com/docs/3.x/api/commands/prepare), [`nuxt dev`](https://nuxt.com/docs/3.x/api/commands/dev) or [`nuxt build`](https://nuxt.com/docs/3.x/api/commands/build) in order to let Nuxt generate the types. <note> If you create a composable without having the dev server running, TypeScript will throw an error, such as `Cannot find name 'useBar'.` </note> ## Examples ### Nested Composables You can use a composable within another composable using auto imports: ```ts [composables/test.ts] export const useFoo = () => { const nuxtApp = useNuxtApp() const bar = useBar() } ``` ### Access plugin injections You can access [plugin injections](https://nuxt.com/docs/3.x/directory-structure/plugins#providing-helpers) from composables: ```ts [composables/test.ts] export const useHello = () => { const nuxtApp = useNuxtApp() return nuxtApp.$hello } ``` ## How Files Are Scanned Nuxt only scans files at the top level of the [`composables/` directory](https://nuxt.com/docs/3.x/directory-structure/composables), e.g.: ```bash [Directory Structure] -| composables/ ---| index.ts // scanned ---| useFoo.ts // scanned ---| nested/ -----| utils.ts // not scanned ``` Only `composables/index.ts` and `composables/useFoo.ts` would be searched for imports. To get auto imports working for nested modules, you could either re-export them (recommended) or configure the scanner to include nested directories: **Example:** Re-export the composables you need from the `composables/index.ts` file: ```ts [composables/index.ts] // Enables auto import for this export export { utils } from './nested/utils.ts' ``` **Example:** Scan nested directories inside the `composables/` folder: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { dirs: [ // Scan top-level composables '~/composables', // ... or scan composables nested one level deep with a specific name and file extension '~/composables/*/index.{ts,js,mjs,mts}', // ... or scan all composables within given directory '~/composables/**', ], }, }) ``` # content > Use the content/ directory to create a file-based CMS for your application. [Nuxt Content](https://content.nuxt.com) reads the `content/` directory in your project and parses `.md`, `.yml`, `.csv` and `.json` files to create a file-based CMS for your application. - Render your content with built-in components. - Query your content with a MongoDB-like API. - Use your Vue components in Markdown files with the MDC syntax. - Automatically generate your navigation. <read-more target="_blank" to="https://content.nuxt.com"> Learn more in **Nuxt Content** documentation. </read-more> ## Enable Nuxt Content Install the `@nuxt/content` module in your project as well as adding it to your `nuxt.config.ts` with one command: ```bash [Terminal] npx nuxt module add content ``` ## Create Content Place your markdown files inside the `content/` directory: ```md [content/index.md] # Hello Content ``` The module automatically loads and parses them. ## Render Content To render content pages, add a [catch-all route](https://nuxt.com/docs/3.x/directory-structure/pages/#catch-all-route) using the [`<ContentRenderer>`](https://content.nuxt.com/docs/components/content-renderer) component: ```vue [pages/[...slug].vue] <script lang="ts" setup> const route = useRoute() const { data: page } = await useAsyncData(route.path, () => { return queryCollection('content').path(route.path).first() }) </script> <template> <div> <header><!-- ... --></header> <ContentRenderer v-if="page" :value="page" /> <footer><!-- ... --></footer> </div> </template> ``` ## Documentation <tip icon="i-lucide-book"> Head over to [https://content.nuxt.com](https://content.nuxt.com) to learn more about the Content module features, such as how to build queries and use Vue components in your Markdown files with the MDC syntax. </tip> # .env > A .env file specifies your build/dev-time environment variables. <important> This file should be added to your [`.gitignore`](https://nuxt.com/docs/3.x/directory-structure/gitignore) file to avoid pushing secrets to your repository. </important> ## Dev, Build and Generate Time Nuxt CLI has built-in [dotenv](https://github.com/motdotla/dotenv) support in development mode and when running [`nuxt build`](https://nuxt.com/docs/3.x/api/commands/build) and [`nuxt generate`](https://nuxt.com/docs/3.x/api/commands/generate). In addition to any process environment variables, if you have a `.env` file in your project root directory, it will be automatically loaded **at dev, build and generate time**. Any environment variables set there will be accessible within your `nuxt.config` file and modules. ```ini [.env] MY_ENV_VARIABLE=hello ``` <note> Note that removing a variable from `.env` or removing the `.env` file entirely will not unset values that have already been set. </note> ## Custom File If you want to use a different file - for example, to use `.env.local` or `.env.production` - you can do so by passing the `--dotenv` flag when using the Nuxt CLI. ```bash [Terminal] npx nuxt dev --dotenv .env.local ``` When updating `.env` in development mode, the Nuxt instance is automatically restarted to apply new values to the `process.env`. <important> In your application code, you should use [Runtime Config](https://nuxt.com/docs/3.x/guide/going-further/runtime-config) instead of plain env variables. </important> ## Production **After your server is built**, you are responsible for setting environment variables when you run the server. Your `.env` files will not be read at this point. How you do this is different for every environment. This design decision was made to ensure compatibility across various deployment environments, some of which may not have a traditional file system available, such as serverless platforms or edge networks like Cloudflare Workers. Since `.env` files are not used in production, you must explicitly set environment variables using the tools and methods provided by your hosting environment. Here are some common approaches: - You can pass the environment variables as arguments using the terminal:<br /> `$ NODE_ENV=production DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs` - You can set environment variables in shell configuration files like `.bashrc` or `.profile`. - Many cloud service providers, such as Vercel, Netlify, and AWS, provide interfaces for setting environment variables via their dashboards, CLI tools or configuration files. <important> `runtimeConfig` <span> won't pick up environment variables that don't start with `NUXT_` in production </span> (/docs/3.x/guide/going-further/runtime-config#environment-variables). </important> ## Production Preview For local production preview purpose, we recommend using [`nuxt preview`](https://nuxt.com/docs/3.x/api/commands/preview) since using this command, the `.env` file will be loaded into `process.env` for convenience. Note that this command requires dependencies to be installed in the package directory. Or you could pass the environment variables as arguments using the terminal. For example, on Linux or macOS: ```bash [Terminal] NODE_ENV=production DATABASE_HOST=mydatabaseconnectionstring node .output/server/index.mjs ``` Note that for a purely static site, it is not possible to set runtime configuration config after your project is prerendered. <read-more to="https://nuxt.com/docs/3.x/guide/going-further/runtime-config"> </read-more> <note> If you want to use environment variables set at build time but do not care about updating these down the line (or only need to update them reactively *within* your app) then `appConfig` may be a better choice. You can define `appConfig` both within your `nuxt.config` (using environment variables) and also within an `~/app.config.ts` file in your project. <read-more to="https://nuxt.com/docs/3.x/directory-structure/app-config"> </read-more> </note> # error.vue > The error.vue file is the error page in your Nuxt application. During the lifespan of your application, some errors may appear unexpectedly at runtime. In such case, we can use the `error.vue` file to override the default error files and display the error nicely. ```vue [error.vue] <script setup lang="ts"> import type { NuxtError } from '#app' const props = defineProps<{ error: NuxtError }>() </script> <template> <div> <h1>{{ error.status }}</h1> <NuxtLink to="/">Go back home</NuxtLink> </div> </template> ``` <note> Although it is called an 'error page' it's not a route and shouldn't be placed in your `~/pages` directory. For the same reason, you shouldn't use `definePageMeta` within this page. That being said, you can still use layouts in the error file, by utilizing the [`NuxtLayout`](https://nuxt.com/docs/3.x/api/components/nuxt-layout) component and specifying the name of the layout. </note> The error page has a single prop - `error` which contains an error for you to handle. The `error` object provides the following fields: ```ts interface NuxtError { status: number fatal: boolean unhandled: boolean statusText?: string data?: unknown cause?: unknown // legacy/deprecated equivalent of `status` statusCode: number // legacy/deprecated equivalent of `statusText` statusMessage?: string } ``` If you have an error with custom fields they will be lost; you should assign them to `data` instead: ```ts throw createError({ status: 404, statusText: 'Page Not Found', data: { myCustomField: true, }, }) ``` # .gitignore > A .gitignore file specifies intentionally untracked files that git should ignore. A `.gitignore` file specifies intentionally untracked files that git should ignore. <read-more icon="i-simple-icons-git" target="_blank" title="the git documentation" to="https://git-scm.com/docs/gitignore"> </read-more> We recommend having a `.gitignore` file that has **at least** the following entries present: ```bash [.gitignore] # Nuxt dev/build outputs .output .data .nuxt .nitro .cache dist # Node dependencies node_modules # Logs logs *.log # Misc .DS_Store # Local env files .env .env.* !.env.example ``` # layers > Use the layers/ directory to organize and auto-register local layers within your application. The `layers/` directory allows you to organize and share reusable code, components, composables, and configurations across your Nuxt application. Any layers within your project in the `layers/` directory will be automatically registered. <note> The `layers/` directory auto-registration is available in Nuxt v3.12.0+. </note> <tip icon="i-lucide-lightbulb"> Layers are ideal for organizing large codebases with **Domain-Driven Design (DDD)**, creating reusable **UI libraries** or **themes**, sharing **configuration presets** across projects, and separating concerns like **admin panels** or **feature modules**. </tip> ## Structure Each subdirectory within `layers/` is treated as a separate layer. A layer can contain the same structure as a standard Nuxt application. <important> Every layer **must have** a `nuxt.config.ts` file to be recognized as a valid layer, even if it's empty. </important> ```bash [Directory structure] -| layers/ ---| base/ -----| nuxt.config.ts -----| app/ -------| components/ ---------| BaseButton.vue -------| composables/ ---------| useBase.ts -----| server/ -------| api/ ---------| hello.ts ---| admin/ -----| nuxt.config.ts -----| app/ -------| pages/ ---------| admin.vue -------| layouts/ ---------| admin.vue ``` ## Automatic Aliases Named layer aliases to the `srcDir` of each layer are automatically created. You can access a layer using the `#layers/[name]` alias: ```ts // Access the base layer import something from '#layers/base/path/to/file' // Access the admin layer import { useAdmin } from '#layers/admin/composables/useAdmin' ``` <note> Named layer aliases were introduced in Nuxt v3.16.0. </note> ## Layer Content Each layer can include: - [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) - Layer-specific configuration that will be merged with the main config - [`app.config.ts`](https://nuxt.com/docs/3.x/directory-structure/app-config) - Reactive application configuration - [`components/`](https://nuxt.com/docs/3.x/directory-structure/components) - Vue components (auto-imported) - [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables) - Vue composables (auto-imported) - [`utils/`](https://nuxt.com/docs/3.x/directory-structure/utils) - Utility functions (auto-imported) - [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) - Application pages - [`layouts/`](https://nuxt.com/docs/3.x/directory-structure/layouts) - Application layouts - [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/middleware) - Route middleware - [`plugins/`](https://nuxt.com/docs/3.x/directory-structure/plugins) - Nuxt plugins - [`server/`](https://nuxt.com/docs/3.x/directory-structure/server) - Server routes, middleware, and utilities - [`shared/`](https://nuxt.com/docs/3.x/directory-structure/shared) - Shared code between app and server ## Priority Order When multiple layers define the same resource (component, composable, page, etc.), the layer with **higher priority wins**. Layers are sorted alphabetically, with later letters having higher priority (Z > A). To control the order, prefix directories with numbers: `1.base/`, `2.features/`, `3.admin/`. <read-more to="https://nuxt.com/docs/3.x/getting-started/layers#layer-priority"> </read-more> <video-accordion title="Watch a video from Learn Vue about Nuxt Layers" video-id="lnFCM7c9f7I"> </video-accordion> # layouts > Nuxt provides a layouts framework to extract common UI patterns into reusable layouts. <tip icon="i-lucide-rocket"> For best performance, components placed in this directory will be automatically loaded via asynchronous import when used. </tip> ## Enable Layouts Layouts are enabled by adding [`<NuxtLayout>`](https://nuxt.com/docs/3.x/api/components/nuxt-layout) to your [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app): ```vue [app.vue] <template> <NuxtLayout> <NuxtPage /> </NuxtLayout> </template> ``` To use a layout: - Set a `layout` property in your page with [definePageMeta](https://nuxt.com/docs/3.x/api/utils/define-page-meta). - Set the `name` prop of `<NuxtLayout>`. - Set the `appLayout` property in route rules. <note> The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`. </note> <note> If no layout is specified, `layouts/default.vue` will be used. </note> <important> If you only have a single layout in your application, we recommend using [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app) instead. </important> <important> Unlike other components, your layouts must have a single root element to allow Nuxt to apply transitions between layout changes - and this root element cannot be a `<slot />`. </important> ## Default Layout Add a `~/layouts/default.vue`: ```vue [layouts/default.vue] <template> <div> <p>Some default layout content shared across all pages</p> <slot /> </div> </template> ``` In a layout file, the content of the page will be displayed in the `<slot />` component. ## Named Layout ```bash [Directory Structure] -| layouts/ ---| default.vue ---| custom.vue ``` Then you can use the `custom` layout in your page: ```vue [pages/about.vue]twoslash <script setup lang="ts"> declare module 'nuxt/app' { interface NuxtLayouts { 'custom': unknown } } // ---cut--- definePageMeta({ layout: 'custom', }) </script> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/pages#page-metadata"> Learn more about `definePageMeta`. </read-more> You can directly override the default layout for all pages using the `name` property of [`<NuxtLayout>`](https://nuxt.com/docs/3.x/api/components/nuxt-layout): ```vue [app.vue] <script setup lang="ts"> // You might choose this based on an API call or logged-in status const layout = 'custom' </script> <template> <NuxtLayout :name="layout"> <NuxtPage /> </NuxtLayout> </template> ``` If you have a layout in nested directories, the layout's name will be based on its own path directory and filename, with duplicate segments being removed. <table> <thead> <tr> <th> File </th> <th> Layout Name </th> </tr> </thead> <tbody> <tr> <td> <code> ~/layouts/desktop/default.vue </code> </td> <td> <code> desktop-default </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop-base/base.vue </code> </td> <td> <code> desktop-base </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop/index.vue </code> </td> <td> <code> desktop </code> </td> </tr> </tbody> </table> For clarity, we recommend that the layout's filename matches its name: <table> <thead> <tr> <th> File </th> <th> Layout Name </th> </tr> </thead> <tbody> <tr> <td> <code> ~/layouts/desktop/DesktopDefault.vue </code> </td> <td> <code> desktop-default </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop-base/DesktopBase.vue </code> </td> <td> <code> desktop-base </code> </td> </tr> <tr> <td> <code> ~/layouts/desktop/Desktop.vue </code> </td> <td> <code> desktop </code> </td> </tr> </tbody> </table> <link-example to="https://nuxt.com/docs/3.x/examples/features/layouts"> </link-example> ## Changing the Layout Dynamically You can also use the [`setPageLayout`](https://nuxt.com/docs/3.x/api/utils/set-page-layout) helper to change the layout dynamically: ```vue [app/pages/index.vue]twoslash <script setup lang="ts"> declare module 'nuxt/app' { interface NuxtLayouts { 'custom': unknown } } // ---cut--- function enableCustomLayout () { setPageLayout('custom') } definePageMeta({ layout: false, }) </script> <template> <div> <button @click="enableCustomLayout"> Update layout </button> </div> </template> ``` You can also set layouts for specific routes using the `appLayout` property in route rules: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { // Set layout for specific route '/admin': { appLayout: 'admin' }, // Set layout for multiple routes '/dashboard/**': { appLayout: 'dashboard' }, // Disable layout for a route '/landing': { appLayout: false }, }, }) ``` <tip> This is useful when you want to manage layouts centrally in your configuration rather than in each page file, or when you need to apply layouts to routes that don't have corresponding page components (such as catchall pages which might match many paths). </tip> <link-example to="https://nuxt.com/docs/3.x/examples/features/layouts"> </link-example> ## Overriding a Layout on a Per-page Basis If you are using pages, you can take full control by setting `layout: false` and then using the `<NuxtLayout>` component within the page. <code-group> ```vue [pages/index.vue] <script setup lang="ts"> definePageMeta({ layout: false, }) </script> <template> <div> <NuxtLayout name="custom"> <template #header> Some header template content. </template> The rest of the page </NuxtLayout> </div> </template> ``` ```vue [layouts/custom.vue] <template> <div> <header> <slot name="header"> Default header content </slot> </header> <main> <slot /> </main> </div> </template> ``` </code-group> <important> If you use `<NuxtLayout>` within your pages, make sure it is not the root element (or [disable layout/page transitions](https://nuxt.com/docs/3.x/getting-started/transitions#disable-transitions)). </important> # middleware > Nuxt provides middleware to run code before navigating to a particular route. Nuxt provides a customizable **route middleware** framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route. There are three kinds of route middleware: 1. Anonymous (or inline) route middleware are defined directly within the page. 2. Named route middleware, placed in the `middleware/` and automatically loaded via asynchronous import when used on a page. 3. Global route middleware, placed in the `middleware/` with a `.global` suffix and is run on every route change. The first two kinds of route middleware can be defined in [`definePageMeta`](https://nuxt.com/docs/3.x/api/utils/define-page-meta). <note> Name of middleware are normalized to kebab-case: `myMiddleware` becomes `my-middleware`. </note> <note> Route middleware run within the Vue part of your Nuxt app. Despite the similar name, they are completely different from [server middleware](https://nuxt.com/docs/3.x/directory-structure/server#server-middleware), which are run in the Nitro server part of your app. </note> <video-accordion platform="vimeo" title="Watch a video from Vue School on all 3 kinds of middleware" video-id="761471577"> </video-accordion> ## Usage Route middleware are navigation guards that receive the current route and the next route as arguments. ```ts [middleware/my-middleware.ts]twoslash export default defineNuxtRouteMiddleware((to, from) => { if (to.params.id === '1') { return abortNavigation() } // In a real app you would probably not redirect every route to `/` // however it is important to check `to.path` before redirecting or you // might get an infinite redirect loop if (to.path !== '/') { return navigateTo('/') } }) ``` Nuxt provides two globally available helpers that can be returned directly from the middleware. 1. [`navigateTo`](https://nuxt.com/docs/3.x/api/utils/navigate-to) - Redirects to the given route 2. [`abortNavigation`](https://nuxt.com/docs/3.x/api/utils/abort-navigation) - Aborts the navigation, with an optional error message. Unlike [navigation guards](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) from `vue-router`, a third `next()` argument is not passed, and **redirect or route cancellation is handled by returning a value from the middleware**. Possible return values are: - nothing (a simple `return` or no return at all) - does not block navigation and will move to the next middleware function, if any, or complete the route navigation - `return navigateTo('/')` - redirects to the given path and will set the redirect code to [`302` Found](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/302) if the redirect happens on the server side - `return navigateTo('/', { redirectCode: 301 })` - redirects to the given path and will set the redirect code to [`301` Moved Permanently](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/301) if the redirect happens on the server side - `return abortNavigation()` - stops the current navigation - `return abortNavigation(error)` - rejects the current navigation with an error <read-more to="https://nuxt.com/docs/3.x/api/utils/navigate-to"> </read-more> <read-more to="https://nuxt.com/docs/3.x/api/utils/abort-navigation"> </read-more> <important> We recommend using the helper functions above for performing redirects or stopping navigation. Other possible return values described in [the vue-router docs](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards) may work but there may be breaking changes in future. </important> ## Middleware Order Middleware runs in the following order: 1. Global Middleware 2. Page defined middleware order (if there are multiple middleware declared with the array syntax) For example, assuming you have the following middleware and component: ```bash [middleware/ directory] -| middleware/ ---| analytics.global.ts ---| setup.global.ts ---| auth.ts ``` ```vue [pages/profile.vue]twoslash <script setup lang="ts"> definePageMeta({ middleware: [ function (to, from) { // Custom inline middleware }, 'auth', ], }) </script> ``` You can expect the middleware to be run in the following order: 1. `analytics.global.ts` 2. `setup.global.ts` 3. Custom inline middleware 4. `auth.ts` ### Ordering Global Middleware By default, global middleware is executed alphabetically based on the filename. However, there may be times you want to define a specific order. For example, in the last scenario, `setup.global.ts` may need to run before `analytics.global.ts`. In that case, we recommend prefixing global middleware with 'alphabetical' numbering. ```bash [Directory structure] -| middleware/ ---| 01.setup.global.ts ---| 02.analytics.global.ts ---| auth.ts ``` <note> In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.new.global.ts` would come before `2.new.global.ts`. This is why the example prefixes single digit numbers with `0`. </note> ## When Middleware Runs If your site is server-rendered or generated, middleware for the initial page will be executed both when the page is rendered and then again on the client. This might be needed if your middleware needs a browser environment, such as if you have a generated site, aggressively cache responses, or want to read a value from local storage. However, if you want to avoid this behaviour you can do so: ```ts [middleware/example.ts]twoslash export default defineNuxtRouteMiddleware((to) => { // skip middleware on server if (import.meta.server) { return } // skip middleware on client side entirely if (import.meta.client) { return } // or only skip middleware on initial client load const nuxtApp = useNuxtApp() if (import.meta.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) { return } }) ``` This is true even if you throw an error in your middleware on the server, and an error page is rendered. The middleware will still run again in the browser. <note> Rendering an error page is an entirely separate page load, meaning any registered middleware will run again. You can use [`useError`](https://nuxt.com/docs/3.x/getting-started/error-handling#useerror) in middleware to check if an error is being handled. </note> ## Accessing Route in Middleware Always use the `to` and `from` parameters in your middleware to access the next and previous routes. Avoid using the [`useRoute()`](https://nuxt.com/docs/3.x/api/composables/use-route) composable in this context altogether. There is **no concept of a "current route" in middleware**, as middleware can abort a navigation or redirect to a different route. The `useRoute()` composable will always be inaccurate in this context. <warning> Sometimes, you might call a composable that uses `useRoute()` internally, which can trigger this warning even if there is no direct call in your middleware. This leads to the **same issue as above**, so you should structure your functions to accept the route as an argument instead when they are used in middleware. </warning> <code-group> ```ts [middleware/access-route.ts]twoslash // @errors: 2304 export default defineNuxtRouteMiddleware((to) => { // passing the route to the function to avoid calling `useRoute()` in middleware doSomethingWithRoute(to) // โŒ this will output a warning and is NOT recommended callsRouteInternally() }) ``` ```ts [utils/handle-route.ts]twoslash // providing the route as an argument so that it can be used in middleware correctly export function doSomethingWithRoute (route = useRoute()) { // ... } ``` ```ts [utils/dont-do-this.ts]twoslash // โŒ this function is not suitable for use in middleware export function callsRouteInternally () { const route = useRoute() // ... } ``` </code-group> ## Adding Middleware Dynamically It is possible to add global or named route middleware manually using the [`addRouteMiddleware()`](https://nuxt.com/docs/3.x/api/utils/add-route-middleware) helper function, such as from within a plugin. ```tstwoslash export default defineNuxtPlugin(() => { addRouteMiddleware('global-test', () => { console.log('this global middleware was added in a plugin and will be run on every route change') }, { global: true }) addRouteMiddleware('named-test', () => { console.log('this named middleware was added in a plugin and would override any existing middleware of the same name') }) }) ``` ## Example ```bash [Directory Structure] -| middleware/ ---| auth.ts ``` In your page file, you can reference this route middleware: ```vuetwoslash <script setup lang="ts"> definePageMeta({ middleware: ['auth'], // or middleware: 'auth' }) </script> ``` Now, before navigation to that page can complete, the `auth` route middleware will be run. <link-example to="https://nuxt.com/docs/3.x/examples/routing/middleware"> </link-example> ## Setting Middleware at Build Time Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook. ```ts [nuxt.config.ts]twoslash import type { NuxtPage } from 'nuxt/schema' export default defineNuxtConfig({ hooks: { 'pages:extend' (pages) { function setMiddleware (pages: NuxtPage[]) { for (const page of pages) { if (/* some condition */ Math.random() > 0.5) { page.meta ||= {} // Note that this will override any middleware set in `definePageMeta` in the page page.meta.middleware = ['named'] } if (page.children) { setMiddleware(page.children) } } } setMiddleware(pages) }, }, }) ``` # modules > Use the modules/ directory to automatically register local modules within your application. It is a good place to place any local modules you develop while building your application. The auto-registered files patterns are: - `modules/*/index.ts` - `modules/*.ts` You don't need to add those local modules to your [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) separately. <code-group> ```ts [modules/hello/index.ts]twoslash // `nuxt/kit` is a helper subpath import you can use when defining local modules // that means you do not need to add `@nuxt/kit` to your project's dependencies import { addComponentsDir, addServerHandler, createResolver, defineNuxtModule } from 'nuxt/kit' export default defineNuxtModule({ meta: { name: 'hello', }, setup () { const resolver = createResolver(import.meta.url) // Add an API route addServerHandler({ route: '/api/hello', handler: resolver.resolve('./runtime/api-route'), }) // Add components addComponentsDir({ path: resolver.resolve('./runtime/app/components'), pathPrefix: true, // Prefix your exports to avoid conflicts with user code or other modules }) }, }) ``` ```ts [modules/hello/runtime/api-route.ts]twoslash export default defineEventHandler(() => { return { hello: 'world' } }) ``` </code-group> When starting Nuxt, the `hello` module will be registered and the `/api/hello` route will be available. <note> Note that all components, pages, composables and other files that would be normally placed in your `app/` directory need to be in `modules/your-module/runtime/app/`. This ensures they can be type-checked properly. </note> Modules are executed in the following sequence: - First, the modules defined in [`nuxt.config.ts`](https://nuxt.com/docs/3.x/api/nuxt-config#modules-1) are loaded. - Then, modules found in the `modules/` directory are executed, and they load in alphabetical order. You can change the order of local module by adding a number to the front of each directory name: ```bash [Directory structure] modules/ 1.first-module/ index.ts 2.second-module.ts ``` <read-more to="https://nuxt.com/docs/3.x/guide/modules"> </read-more> <tip icon="i-lucide-video" target="_blank" to="https://vueschool.io/lessons/creating-your-first-module-from-scratch?friend=nuxt"> Watch Vue School video about Nuxt private modules. </tip> # node_modules > The package manager stores the dependencies of your project in the node_modules/ directory. The package manager ([`npm`](https://docs.npmjs.com/cli/commands/npm/) or [`yarn`](https://yarnpkg.com) or [`pnpm`](https://pnpm.io/cli/install) or [`bun`](https://bun.com/package-manager) or [`deno`](https://docs.deno.com/runtime/getting_started/installation/)) creates this directory to store the dependencies of your project. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/3.x/directory-structure/gitignore) file to avoid pushing the dependencies to your repository. </important> # .nuxt > Nuxt uses the .nuxt/ directory in development to generate your Vue application. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/3.x/directory-structure/gitignore) file to avoid pushing the dev build output to your repository. </important> This directory is interesting if you want to learn more about the files Nuxt generates based on your directory structure. Nuxt also provides a Virtual File System (VFS) for modules to add templates to this directory without writing them to disk. You can explore the generated files by opening the [Nuxt DevTools](https://devtools.nuxt.com) in development mode and navigating to the **Virtual Files** tab. <warning> You should not touch any files inside since the whole directory will be re-created when running [`nuxt dev`](https://nuxt.com/docs/3.x/api/commands/dev). </warning> # nuxt.config.ts > Nuxt can be easily configured with a single nuxt.config file. The `nuxt.config` file extension can either be `.js`, `.ts` or `.mjs`. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ // My Nuxt config }) ``` <tip> `defineNuxtConfig` helper is globally available without import. </tip> You can explicitly import `defineNuxtConfig` from `nuxt/config` if you prefer: ```ts [nuxt.config.ts]twoslash import { defineNuxtConfig } from 'nuxt/config' export default defineNuxtConfig({ // My Nuxt config }) ``` <read-more to="https://nuxt.com/docs/3.x/api/configuration/nuxt-config"> Discover all the available options in the **Nuxt configuration** documentation. </read-more> To ensure your configuration is up to date, Nuxt will make a full restart when detecting changes in the main configuration file, the [`.env`](https://nuxt.com/docs/3.x/directory-structure/env), [`.nuxtignore`](https://nuxt.com/docs/3.x/directory-structure/nuxtignore) and [`.nuxtrc`](https://nuxt.com/docs/3.x/directory-structure/nuxtrc) dotfiles. # .nuxtignore > The .nuxtignore file lets Nuxt ignore files in your projectโ€™s root directory during the build phase. The `.nuxtignore` file tells Nuxt to ignore files in your projectโ€™s root directory ([`rootDir`](https://nuxt.com/docs/3.x/api/nuxt-config#rootdir)) during the build phase. It is subject to the same specification as [`.gitignore`](https://nuxt.com/docs/3.x/directory-structure/gitignore) and `.eslintignore` files, in which each line is a glob pattern indicating which files should be ignored. <tip> You can also configure [`ignoreOptions`](https://nuxt.com/docs/3.x/api/nuxt-config#ignoreoptions), [`ignorePrefix`](https://nuxt.com/docs/3.x/api/nuxt-config#ignoreprefix) and [`ignore`](https://nuxt.com/docs/3.x/api/nuxt-config#ignore) in your `nuxt.config` file. </tip> ## Usage ```bash [.nuxtignore] # ignore layout foo.vue layouts/foo.vue # ignore layout files whose name ends with -ignore.vue layouts/*-ignore.vue # ignore page bar.vue pages/bar.vue # ignore page inside ignore folder pages/ignore/*.vue # ignore route middleware files under foo folder except foo/bar.js middleware/foo/*.js !middleware/foo/bar.js ``` <read-more icon="i-simple-icons-git" target="_blank" title="the git documentation" to="https://git-scm.com/docs/gitignore"> More details about the spec are in the **gitignore documentation**. </read-more> # .nuxtrc > The .nuxtrc file allows you to define nuxt configurations in a flat syntax. The `.nuxtrc` file can be used to configure Nuxt with a flat syntax. It is based on [`unjs/rc9`](https://github.com/unjs/rc9). <tip> For more advanced configurations, use [`nuxt.config`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config). </tip> ## Usage ```bash [.nuxtrc] # Disable SSR ssr=false # Configuration for `@nuxt/devtools` devtools.enabled=true # Add Nuxt modules modules[]=@nuxt/image modules[]=nuxt-security # Module setups (automatically added by Nuxt) setups.@nuxt/test-utils="3.23.0" ``` If present, the properties in the `nuxt.config` file will overwrite the properties in `.nuxtrc` file. <note> Nuxt automatically adds a `setups` section to track module installation and upgrade state. This is used internally for [module lifecycle hooks](https://nuxt.com/docs/3.x/api/kit/modules#using-lifecycle-hooks-for-module-installation-and-upgrade) and should not be modified manually. </note> <read-more to="https://nuxt.com/docs/3.x/api/configuration/nuxt-config"> Discover all the available options in the **Nuxt configuration** documentation. </read-more> ## Global `.nuxtrc` File You can also create a global `.nuxtrc` file in your home directory to apply configurations globally. - On macOS/Linux, this file is located at:```md ~/.nuxtrc ``` - On Windows, it is located at:```md C:\Users\{username}\.nuxtrc ``` This global `.nuxtrc` file allows you to define default settings that apply to all Nuxt projects on your system. However, project-level `.nuxtrc` files will override these global settings, and `nuxt.config` will take precedence over both. # .output > Nuxt creates the .output/ directory when building your application for production. <important> This directory should be added to your [`.gitignore`](https://nuxt.com/docs/3.x/directory-structure/gitignore) file to avoid pushing the build output to your repository. </important> Use this directory to deploy your Nuxt application to production. <read-more to="https://nuxt.com/docs/3.x/getting-started/deployment"> </read-more> <warning> You should not touch any files inside since the whole directory will be re-created when running [`nuxt build`](https://nuxt.com/docs/3.x/api/commands/build). </warning> # package.json > The package.json file contains all the dependencies and scripts for your application. The minimal `package.json` of your Nuxt application should looks like: ```json [package.json] { "name": "nuxt-app", "private": true, "type": "module", "scripts": { "build": "nuxt build", "dev": "nuxt dev", "generate": "nuxt generate", "preview": "nuxt preview", "postinstall": "nuxt prepare" }, "dependencies": { "nuxt": "latest", "vue": "latest", "vue-router": "latest" } } ``` <read-more icon="i-simple-icons-npm" target="_blank" to="https://docs.npmjs.com/cli/configuring-npm/package-json/"> Read more about the `package.json` file. </read-more> # pages > Nuxt provides file-based routing to create routes within your web application. <note> To reduce your application's bundle size, this directory is **optional**, meaning that [`vue-router`](https://router.vuejs.org) won't be included if you only use [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app). To force the pages system, set `pages: true` in `nuxt.config` or have a [`router.options.ts`](https://nuxt.com/docs/3.x/guide/recipes/custom-routing#using-routeroptions). </note> ## Usage Pages are Vue components and can have any [valid extension](https://nuxt.com/docs/3.x/api/nuxt-config#extensions) that Nuxt supports (by default `.vue`, `.js`, `.jsx`, `.mjs`, `.ts` or `.tsx`). Nuxt will automatically create a route for every page in your `~/pages/` directory. <tip> Pages are only automatically registered for prerendering if you have not disabled `nitro.prerender.crawlLinks` and you have at least one page in your `nitro.prerender.routes` list. See the [prerendering guide](https://nuxt.com/docs/3.x/getting-started/prerendering). </tip> <code-group> ```vue [pages/index.vue] <template> <h1>Index page</h1> </template> ``` ```ts [pages/index.ts]twoslash // https://vuejs.org/guide/extras/render-function.html export default defineComponent({ render () { return h('h1', 'Index page') }, }) ``` ```tsx [pages/index.tsx]twoslash // /docs/examples/advanced/jsx // https://vuejs.org/guide/extras/render-function.html#jsx-tsx export default defineComponent({ render () { return <h1>Index page</h1> }, }) ``` </code-group> The `pages/index.vue` file will be mapped to the `/` route of your application. If you are using [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app), make sure to use the [`<NuxtPage/>`](https://nuxt.com/docs/3.x/api/components/nuxt-page) component to display the current page: ```vue [app.vue] <template> <div> <!-- Markup shared across all pages, ex: NavBar --> <NuxtPage /> </div> </template> ``` Pages **must have a single root element** to allow [route transitions](https://nuxt.com/docs/3.x/getting-started/transitions) between pages. HTML comments are considered elements as well. This means that when the route is server-rendered, or statically generated, you will be able to see its contents correctly, but when you navigate towards that route during client-side navigation the transition between routes will fail and you'll see that the route will not be rendered. Here are some examples to illustrate what a page with a single root element looks like: <code-group> ```vue [pages/working.vue] <template> <div> <!-- This page correctly has only one single root element --> Page content </div> </template> ``` ```vue [pages/bad-1.vue] <template> <!-- This page will not render when route changes during client side navigation, because of this comment --> <div>Page content</div> </template> ``` ```vue [pages/bad-2.vue] <template> <div>This page</div> <div>Has more than one root element</div> <div>And will not render when route changes during client side navigation</div> </template> ``` </code-group> ## Dynamic Routes If you place anything within square brackets, it will be turned into a [dynamic route](https://router.vuejs.org/guide/essentials/dynamic-matching) parameter. You can mix and match multiple parameters and even non-dynamic text within a file name or directory. If you want a parameter to be *optional*, you must enclose it in double square brackets - for example, `~/pages/[[slug]]/index.vue` or `~/pages/[[slug]].vue` will match both `/` and `/test`. ```bash [Directory Structure] -| pages/ ---| index.vue ---| users-[group]/ -----| [id].vue ``` Given the example above, you can access group/id within your component via the `$route` object: ```vue [pages/users-[group]/[id].vue] <template> <p>{{ $route.params.group }} - {{ $route.params.id }}</p> </template> ``` Navigating to `/users-admins/123` would render: ```html <p>admins - 123</p> ``` If you want to access the route using Composition API, there is a global [`useRoute`](https://nuxt.com/docs/3.x/api/composables/use-route) function that will allow you to access the route just like `this.$route` in the Options API. ```vuetwoslash <script setup lang="ts"> const route = useRoute() if (route.params.group === 'admins' && !route.params.id) { console.log('Warning! Make sure user is authenticated!') } </script> ``` <note> Named parent routes will take priority over nested dynamic routes. For the `/foo/hello` route, `~/pages/foo.vue` will take priority over `~/pages/foo/[slug].vue`. <br /> Use `~/pages/foo/index.vue` and `~/pages/foo/[slug].vue` to match `/foo` and `/foo/hello` with different pages,. </note> <video-accordion platform="vimeo" title="Watch a video from Vue School on dynamic routes" video-id="754465699"> </video-accordion> ## Catch-all Route If you need a catch-all route, you create it by using a file named like `[...slug].vue`. This will match *all* routes under that path. ```vue [pages/[...slug].vue] <template> <p>{{ $route.params.slug }}</p> </template> ``` Navigating to `/hello/world` would render: ```html <p>["hello", "world"]</p> ``` ## Nested Routes It is possible to display [nested routes](https://router.vuejs.org/guide/essentials/nested-routes) with `<NuxtPage>`. Example: ```bash [Directory Structure] -| pages/ ---| parent/ -----| child.vue ---| parent.vue ``` This file tree will generate these routes: ```js [ { path: '/parent', component: '~/pages/parent.vue', name: 'parent', children: [ { path: 'child', component: '~/pages/parent/child.vue', name: 'parent-child', }, ], }, ] ``` To display the `child.vue` component, you have to insert the `<NuxtPage>` component inside `pages/parent.vue`: ```vue [pages/parent.vue] <template> <div> <h1>I am the parent view</h1> <NuxtPage :foobar="123" /> </div> </template> ``` ```vue [pages/parent/child.vue] <script setup lang="ts"> const props = defineProps({ foobar: String, }) console.log(props.foobar) </script> ``` ### Child Route Keys If you want more control over when the `<NuxtPage>` component is re-rendered (for example, for transitions), you can either pass a string or function via the `pageKey` prop, or you can define a `key` value via `definePageMeta`: ```vue [pages/parent.vue] <template> <div> <h1>I am the parent view</h1> <NuxtPage :page-key="route => route.fullPath" /> </div> </template> ``` Or alternatively: ```vue [pages/parent/child.vue]twoslash <script setup lang="ts"> definePageMeta({ key: route => route.fullPath, }) </script> ``` <link-example to="https://nuxt.com/docs/3.x/examples/routing/pages"> </link-example> ## Route Groups In some cases, you may want to group a set of routes together in a way which doesn't affect file-based routing. For this purpose, you can put files in a folder which is wrapped in parentheses - `(` and `)`. For example: ```bash [Directory structure] -| pages/ ---| index.vue ---| (marketing)/ -----| about.vue -----| contact.vue ``` This will produce `/`, `/about` and `/contact` pages in your app. The `marketing` group is ignored for purposes of your URL structure. ### Accessing Route Groups Route groups are automatically available in the route metadata as `route.meta.groups`. This allows you to access the group information in your components for conditional logic, styling, or other purposes. ```vue [pages/(marketing)/about.vue] <script setup lang="ts"> const route = useRoute() console.log(route.meta.groups) // Output: ['marketing'] </script> <template> <div> <p v-if="route.meta.groups?.includes('marketing')"> This is a marketing page </p> </div> </template> ``` ## Page Metadata You might want to define metadata for each route in your app. You can do this using the `definePageMeta` macro, which will work both in `<script>` and in `<script setup>`: ```vuetwoslash <script setup lang="ts"> definePageMeta({ title: 'My home page', }) </script> ``` This data can then be accessed throughout the rest of your app from the `route.meta` object. ```vuetwoslash <script setup lang="ts"> const route = useRoute() console.log(route.meta.title) // My home page </script> ``` If you are using nested routes, the page metadata from all these routes will be merged into a single object. For more on route meta, see the [vue-router docs](https://router.vuejs.org/guide/advanced/meta). Much like `defineEmits` or `defineProps` (see [Vue docs](https://vuejs.org/api/sfc-script-setup#defineprops-defineemits)), `definePageMeta` is a **compiler macro**. It will be compiled away so you cannot reference it within your component. Instead, the metadata passed to it will be hoisted out of the component. Therefore, the page meta object cannot reference the component. However, it can reference imported bindings, as well as locally defined **pure functions**. <warning> Make sure not to reference any reactive data or functions that cause side effects. This can lead to unexpected behavior. </warning> ```vue <script setup lang="ts"> import { someData } from '~/utils/example' function validateIdParam (route) { return route.params.id && !Number.isNaN(Number(route.params.id)) } const title = ref('') definePageMeta({ validate: validateIdParam, someData, title, // do not do this, the ref will be hoisted out of the component }) </script> ``` ### Special Metadata Of course, you are welcome to define metadata for your own use throughout your app. But some metadata defined with `definePageMeta` has a particular purpose: #### `alias` You can define page aliases. They allow you to access the same page from different paths. It can be either a string or an array of strings as defined [in the vue-router documentation](https://router.vuejs.org/guide/essentials/redirect-and-alias#Alias). #### `keepalive` Nuxt will automatically wrap your page in [the Vue `<KeepAlive>` component](https://vuejs.org/guide/built-ins/keep-alive#keepalive) if you set `keepalive: true` in your `definePageMeta`. This might be useful to do, for example, in a parent route that has dynamic child routes, if you want to preserve page state across route changes. When your goal is to preserve state for parent routes use this syntax: `<NuxtPage keepalive />`. You can also set props to be passed to `<KeepAlive>` (see [a full list](https://vuejs.org/api/built-in-components#keepalive)). You can set a default value for this property [in your `nuxt.config`](https://nuxt.com/docs/3.x/api/nuxt-config#keepalive). #### `key` [See above](https://nuxt.com/docs/3.x/directory-structure/pages#child-route-keys). #### `layout` You can define the layout used to render the route. This can be either false (to disable any layout), a string or a ref/computed, if you want to make it reactive in some way. [More about layouts](https://nuxt.com/docs/3.x/directory-structure/layouts). #### `layoutTransition` and `pageTransition` You can define transition properties for the `<transition>` component that wraps your pages and layouts, or pass `false` to disable the `<transition>` wrapper for that route. You can see [a list of options that can be passed](https://vuejs.org/api/built-in-components#transition) or read [more about how transitions work](https://vuejs.org/guide/built-ins/transition#transition). You can set default values for these properties [in your `nuxt.config`](https://nuxt.com/docs/3.x/api/nuxt-config#layouttransition). #### `middleware` You can define middleware to apply before loading this page. It will be merged with all the other middleware used in any matching parent/child routes. It can be a string, a function (an anonymous/inlined middleware function following [the global before guard pattern](https://router.vuejs.org/guide/advanced/navigation-guards#Global-Before-Guards)), or an array of strings/functions. [More about named middleware](https://nuxt.com/docs/3.x/directory-structure/middleware). #### `name` You may define a name for this page's route. #### `path` You may define a path matcher, if you have a more complex pattern than can be expressed with the file name. See [the `vue-router` docs](https://router.vuejs.org/guide/essentials/route-matching-syntax#Custom-regex-in-params) for more information. #### `props` Allows accessing the route `params` as props passed to the page component. See [the `vue-router` docs](https://router.vuejs.org/guide/essentials/passing-props) for more information. ### Typing Custom Metadata If you add custom metadata for your pages, you may wish to do so in a type-safe way. It is possible to augment the type of the object accepted by `definePageMeta`: ```ts [index.d.ts] declare module '#app' { interface PageMeta { pageType?: string } } // It is always important to ensure you import/export something when augmenting a type export {} ``` ## Navigation To navigate between pages of your app, you should use the [`<NuxtLink>`](https://nuxt.com/docs/3.x/api/components/nuxt-link) component. This component is included with Nuxt and therefore you don't have to import it as you do with other components. A simple link to the `index.vue` page in your `pages` folder: ```vue <template> <NuxtLink to="/">Home page</NuxtLink> </template> ``` <read-more to="https://nuxt.com/docs/3.x/api/components/nuxt-link"> Learn more about `<NuxtLink>` usage. </read-more> ## Programmatic Navigation Nuxt allows programmatic navigation through the `navigateTo()` utility method. Using this utility method, you will be able to programmatically navigate the user in your app. This is great for taking input from the user and navigating them dynamically throughout your application. In this example, we have a simple method called `navigate()` that gets called when the user submits a search form. <note> Make sure to always `await` on `navigateTo` or chain its result by returning from functions. </note> ```vuetwoslash <script setup lang="ts"> const name = ref('') const type = ref(1) function navigate () { return navigateTo({ path: '/search', query: { name: name.value, type: type.value, }, }) } </script> ``` ## Client-Only Pages You can define a page as [client only](https://nuxt.com/docs/3.x/directory-structure/components#client-components) by giving it a `.client.vue` suffix. None of the content of this page will be rendered on the server. ## Server-Only Pages You can define a page as [server only](https://nuxt.com/docs/3.x/directory-structure/components#server-components) by giving it a `.server.vue` suffix. While you will be able to navigate to the page using client-side navigation, controlled by `vue-router`, it will be rendered with a server component automatically, meaning the code required to render the page will not be in your client-side bundle. <warning> Server-only pages must have a single root element. (HTML comments are considered elements as well.) </warning> ## Custom Routing As your app gets bigger and more complex, your routing might require more flexibility. For this reason, Nuxt directly exposes the router, routes and router options for customization in different ways. <read-more to="https://nuxt.com/docs/3.x/guide/recipes/custom-routing"> </read-more> ## Multiple Pages Directories By default, all your pages should be in one `pages` directory at the root of your project. However, you can use [Nuxt Layers](https://nuxt.com/docs/3.x/getting-started/layers) to create groupings of your app's pages: ```bash [Directory Structure] -| some-app/ ---| nuxt.config.ts ---| pages/ -----| app-page.vue -| nuxt.config.ts ``` ```ts [some-app/nuxt.config.ts]twoslash // some-app/nuxt.config.ts export default defineNuxtConfig({ }) ``` ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ extends: ['./some-app'], }) ``` <read-more to="https://nuxt.com/docs/3.x/guide/going-further/layers"> </read-more> # plugins > Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application. Nuxt automatically reads the files in the `plugins/` directory and loads them at the creation of the Vue application. <note> All plugins inside are auto-registered, you don't need to add them to your `nuxt.config` separately. </note> <note> You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side. </note> ## Registered Plugins Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins. ```bash [Directory structure] -| plugins/ ---| foo.ts // scanned ---| bar/ -----| baz.ts // not scanned -----| foz.vue // not scanned -----| index.ts // currently scanned but deprecated ``` Only `foo.ts` and `bar/index.ts` would be registered. To add plugins in subdirectories, you can use the [`plugins`](https://nuxt.com/docs/3.x/api/nuxt-config#plugins-1) option in `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ plugins: [ '~/plugins/bar/baz', '~/plugins/bar/foz', ], }) ``` ## Creating Plugins The only argument passed to a plugin is [`nuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app). ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp }) ``` ### Object Syntax Plugins It is also possible to define a plugin using an object syntax, for more advanced use cases. For example: ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', enforce: 'pre', // or 'post' async setup (nuxtApp) { // this is the equivalent of a normal functional plugin }, hooks: { // You can directly register Nuxt app runtime hooks here 'app:created' () { const nuxtApp = useNuxtApp() // do something in the hook }, }, env: { // Set this value to `false` if you don't want the plugin to run when rendering server-only or island components. islands: true, }, }) ``` <video-accordion title="Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins" video-id="2aXZyXB1QGQ"> </video-accordion> <note> If you are using the object-syntax, the properties are statically analyzed to produce a more optimized build. So you should not define them at runtime. <br /> For example, setting `enforce: import.meta.server ? 'pre' : 'post'` would defeat any future optimization Nuxt is able to do for your plugins. Nuxt does statically pre-load any hook listeners when using object-syntax, allowing you to define hooks without needing to worry about order of plugin registration. </note> ## Registration Order You can control the order in which plugins are registered by prefixing with 'alphabetical' numbering to the file names. ```bash [Directory structure] plugins/ | - 01.myPlugin.ts | - 02.myOtherPlugin.ts ``` In this example, `02.myOtherPlugin.ts` will be able to access anything that was injected by `01.myPlugin.ts`. This is useful in situations where you have a plugin that depends on another plugin. <note> In case you're new to 'alphabetical' numbering, remember that filenames are sorted as strings, not as numeric values. For example, `10.myPlugin.ts` would come before `2.myOtherPlugin.ts`. This is why the example prefixes single digit numbers with `0`. </note> ## Loading Strategy ### Parallel Plugins By default, Nuxt loads plugins sequentially. You can define a plugin as `parallel` so Nuxt won't wait until the end of the plugin's execution before loading the next plugin. ```ts [plugins/my-plugin.ts]twoslash export default defineNuxtPlugin({ name: 'my-plugin', parallel: true, async setup (nuxtApp) { // the next plugin will be executed immediately }, }) ``` ### Plugins With Dependencies If a plugin needs to wait for another plugin before it runs, you can add the plugin's name to the `dependsOn` array. ```ts [plugins/depending-on-my-plugin.ts]twoslash export default defineNuxtPlugin({ name: 'depends-on-my-plugin', dependsOn: ['my-plugin'], async setup (nuxtApp) { // this plugin will wait for the end of `my-plugin`'s execution before it runs }, }) ``` ## Using Composables You can use [composables](https://nuxt.com/docs/3.x/directory-structure/composables) as well as [utils](https://nuxt.com/docs/3.x/directory-structure/utils) within Nuxt plugins: ```ts [plugins/hello.ts] export default defineNuxtPlugin((nuxtApp) => { const foo = useFoo() }) ``` However, keep in mind there are some limitations and differences: <important> **If a composable depends on another plugin registered later, it might not work.** <br /> Plugins are called in order sequentially and before everything else. You might use a composable that depends on another plugin which has not been called yet. </important> <important> **If a composable depends on the Vue.js lifecycle, it won't work.** <br /> Normally, Vue.js composables are bound to the current component instance while plugins are only bound to [`nuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) instance. </important> ## Providing Helpers If you would like to provide a helper on the [`NuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) instance, return it from the plugin under a `provide` key. <code-group> ```ts [plugins/hello.ts]twoslash export default defineNuxtPlugin(() => { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }) ``` ```ts [plugins/hello-object-syntax.ts]twoslash export default defineNuxtPlugin({ name: 'hello', setup () { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }, }) ``` </code-group> You can then use the helper in your components: ```vue [components/Hello.vue] <script setup lang="ts"> // alternatively, you can also use it here const { $hello } = useNuxtApp() </script> <template> <div> {{ $hello('world') }} </div> </template> ``` <important> Note that we highly recommend using [`composables`](https://nuxt.com/docs/3.x/directory-structure/composables) instead of providing helpers to avoid polluting the global namespace and keep your main bundle entry small. </important> <warning> **If your plugin provides a ref or computed, it will not be unwrapped in a component <template>.** <br /> This is due to how Vue works with refs that aren't top-level to the template. You can read more about it [in the Vue documentation](https://vuejs.org/guide/essentials/reactivity-fundamentals#caveat-when-unwrapping-in-templates). </warning> ## Typing Plugins If you return your helpers from the plugin, they will be typed automatically; you'll find them typed for the return of `useNuxtApp()` and within your templates. <note> If you need to use a provided helper *within* another plugin, you can call [`useNuxtApp()`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) to get the typed version. But in general, this should be avoided unless you are certain of the plugins' order. </note> For advanced use-cases, you can declare the type of injected properties like this: ```ts [index.d.ts] declare module '#app' { interface NuxtApp { $hello (msg: string): string } } declare module 'vue' { interface ComponentCustomProperties { $hello (msg: string): string } } export {} ``` ## Vue Plugins If you want to use Vue plugins, like [vue-gtag](https://github.com/MatteoGabriele/vue-gtag) to add Google Analytics tags, you can use a Nuxt plugin to do so. First, install the Vue plugin dependency: <code-group sync="pm"> ```bash [npm] npm install --save-dev vue-gtag-next ``` ```bash [yarn] yarn add --dev vue-gtag-next ``` ```bash [pnpm] pnpm add -D vue-gtag-next ``` ```bash [bun] bun add -D vue-gtag-next ``` ```bash [deno] deno add -D npm:vue-gtag-next ``` </code-group> Then create a plugin file: ```ts [plugins/vue-gtag.client.ts] import VueGtag, { trackRouter } from 'vue-gtag-next' export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.use(VueGtag, { property: { id: 'GA_MEASUREMENT_ID', }, }) trackRouter(useRouter()) }) ``` ## Vue Directives Similarly, you can register a custom Vue directive in a plugin. ```ts [plugins/my-directive.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.directive('focus', { mounted (el) { el.focus() }, getSSRProps (binding, vnode) { // you can provide SSR-specific props here return {} }, }) }) ``` <warning> If you register a Vue directive, you *must* register it on both client and server side unless you are only using it when rendering one side. If the directive only makes sense from a client side, you can always move it to `~/plugins/my-directive.client.ts` and provide a 'stub' directive for the server in `~/plugins/my-directive.server.ts`. </warning> <read-more icon="i-simple-icons-vuedotjs" target="_blank" title="Custom Directives on Vue Docs" to="https://vuejs.org/guide/reusability/custom-directives.html"> </read-more> # public > The public/ directory is used to serve your website's static assets. Files contained within the `public/` directory are served at the root and are not modified by the build process. This is suitable for files that have to keep their names (e.g. `robots.txt`) *or* likely won't change (e.g. `favicon.ico`). ```bash [Directory structure] -| public/ ---| favicon.ico ---| og-image.png ---| robots.txt ``` ```vue [app.vue] <script setup lang="ts"> useSeoMeta({ ogImage: '/og-image.png', }) </script> ``` <tip target="_blank" to="https://v2.nuxt.com/docs/directory-structure/static/"> This is known as the <span> `static/` </span> directory in Nuxt 2. </tip> # server > The server/ directory is used to register API and server handlers to your application. Nuxt automatically scans files inside these directories to register API and server handlers with Hot Module Replacement (HMR) support. ```bash [Directory structure] -| server/ ---| api/ -----| hello.ts # /api/hello ---| routes/ -----| bonjour.ts # /bonjour ---| middleware/ -----| log.ts # log all requests ``` Each file should export a default function defined with `defineEventHandler()` or `eventHandler()` (alias). The handler can directly return JSON data, a `Promise`, or use `event.node.res.end()` to send a response. ```ts [server/api/hello.ts]twoslash export default defineEventHandler((event) => { return { hello: 'world', } }) ``` You can now universally call this API in your pages and components: ```vue [pages/index.vue] <script setup lang="ts"> const { data } = await useFetch('/api/hello') </script> <template> <pre>{{ data }}</pre> </template> ``` ## Server Routes Files inside the `~~/server/api` are automatically prefixed with `/api` in their route. <video-accordion platform="vimeo" title="Watch a video from Vue School on API routes" video-id="761468863"> </video-accordion> To add server routes without `/api` prefix, put them into `~~/server/routes` directory. **Example:** ```ts [server/routes/hello.ts] export default defineEventHandler(() => 'Hello World!') ``` Given the example above, the `/hello` route will be accessible at [http://localhost:3000/hello](http://localhost:3000/hello). <note> Note that currently server routes do not support the full functionality of dynamic routes as [pages](https://nuxt.com/docs/3.x/directory-structure/pages#dynamic-routes) do. </note> ## Server Middleware Nuxt will automatically read in any file in the `~~/server/middleware` to create server middleware for your project. Middleware handlers will run on every request before any other server route to add or check headers, log requests, or extend the event's request object. <note> Middleware handlers should not return anything (nor close or respond to the request) and only inspect or extend the request context or throw an error. </note> **Examples:** ```ts [server/middleware/log.ts] export default defineEventHandler((event) => { console.log('New request: ' + getRequestURL(event)) }) ``` ```ts [server/middleware/auth.ts] export default defineEventHandler((event) => { event.context.auth = { user: 123 } }) ``` ## Server Plugins Nuxt will automatically read any files in the `~~/server/plugins` directory and register them as Nitro plugins. This allows extending Nitro's runtime behavior and hooking into lifecycle events. **Example:** ```ts [server/plugins/nitroPlugin.ts] export default defineNitroPlugin((nitroApp) => { console.log('Nitro plugin', nitroApp) }) ``` <read-more to="https://nitro.build/guide/plugins" target="_blank" title="Nitro Plugins"> </read-more> ## Server Utilities Server routes are powered by [h3js/h3](https://github.com/h3js/h3) which comes with a handy set of helpers. <read-more to="https://www.jsdocs.io/package/h3#package-index-functions" target="_blank" title="Available H3 Request Helpers"> </read-more> You can add more helpers yourself inside the `~~/server/utils` directory. For example, you can define a custom handler utility that wraps the original handler and performs additional operations before returning the final response. **Example:** ```ts [server/utils/handler.ts] export const defineWrappedResponseHandler = <T extends EventHandlerRequest, D> ( handler: EventHandler<T, D>, ): EventHandler<T, D> => defineEventHandler<T>(async (event) => { try { // do something before the route handler const response = await handler(event) // do something after the route handler return { response } } catch (err) { // Error handling return { err } } }) ``` ```ts [server/api/hello.get.ts] export default defineWrappedResponseHandler(event => 'hello world') ``` ## Server Alias You can use the `#server` alias to import files from anywhere within the `server/` directory, regardless of the importing file's location. ```ts [server/api/users/[id]/profile.ts] // Instead of relative paths like this: // import { formatUser } from '../../../utils/formatUser' // Use the #server alias: import { formatUser } from '#server/utils/formatUser' ``` This alias ensures consistent imports across your server code, especially useful in deeply nested route handlers. <note> The `#server` alias can only be used within the `server/` directory. Importing from `#server` in client code will result in an error. </note> ## Server Types <tip> This feature is available from Nuxt >= 3.5 </tip> To improve clarity within your IDE between the auto-imports from 'nitro' and 'vue', you can add a `~/server/tsconfig.json` with the following content: ```json [server/tsconfig.json] { "extends": "../.nuxt/tsconfig.server.json" } ``` Currently, these values won't be respected when type checking ([`nuxt typecheck`](https://nuxt.com/docs/3.x/api/commands/typecheck)), but you should get better type hints in your IDE. ## Recipes ### Route Parameters Server routes can use dynamic parameters within brackets in the file name like `/api/hello/[name].ts` and be accessed via `event.context.params`. ```ts [server/api/hello/[name].ts] export default defineEventHandler((event) => { const name = getRouterParam(event, 'name') return `Hello, ${name}!` }) ``` <tip to="https://h3.dev/examples/validate-data#validate-params"> Alternatively, use `getValidatedRouterParams` with a schema validator such as Zod for runtime and type safety. </tip> You can now universally call this API on `/api/hello/nuxt` and get `Hello, nuxt!`. ### Matching HTTP Method Handle file names can be suffixed with `.get`, `.post`, `.put`, `.delete`, ... to match request's [HTTP Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Methods). ```ts [server/api/test.get.ts] export default defineEventHandler(() => 'Test get handler') ``` ```ts [server/api/test.post.ts] export default defineEventHandler(() => 'Test post handler') ``` Given the example above, fetching `/test` with: - **GET** method: Returns `Test get handler` - **POST** method: Returns `Test post handler` - Any other method: Returns 405 error You can also use `index.[method].ts` inside a directory for structuring your code differently, this is useful to create API namespaces. <code-group> ```ts [server/api/foo/index.get.ts] export default defineEventHandler((event) => { // handle GET requests for the `api/foo` endpoint }) ``` ```ts [server/api/foo/index.post.ts] export default defineEventHandler((event) => { // handle POST requests for the `api/foo` endpoint }) ``` ```ts [server/api/foo/bar.get.ts] export default defineEventHandler((event) => { // handle GET requests for the `api/foo/bar` endpoint }) ``` </code-group> ### Catch-all Route Catch-all routes are helpful for fallback route handling. For example, creating a file named `~~/server/api/foo/[...].ts` will register a catch-all route for all requests that do not match any route handler, such as `/api/foo/bar/baz`. ```ts [server/api/foo/[...].ts] export default defineEventHandler((event) => { // event.context.path to get the route path: '/api/foo/bar/baz' // event.context.params._ to get the route segment: 'bar/baz' return `Default foo handler` }) ``` You can set a name for the catch-all route by using `~~/server/api/foo/[...slug].ts` and access it via `event.context.params.slug`. ```ts [server/api/foo/[...slug].ts] export default defineEventHandler((event) => { // event.context.params.slug to get the route segment: 'bar/baz' return `Default foo handler` }) ``` ### Body Handling ```ts [server/api/submit.post.ts] export default defineEventHandler(async (event) => { const body = await readBody(event) return { body } }) ``` <tip to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web/#runtime-type-safe-request-utils"> Alternatively, use `readValidatedBody` with a schema validator such as Zod for runtime and type safety. </tip> You can now universally call this API using: ```vue [app.vue] <script setup lang="ts"> async function submit () { const { body } = await $fetch('/api/submit', { method: 'post', body: { test: 123 }, }) } </script> ``` <note> We are using `submit.post.ts` in the filename only to match requests with `POST` method that can accept the request body. When using `readBody` within a GET request, `readBody` will throw a `405 Method Not Allowed` HTTP error. </note> ### Query Parameters Sample query `/api/query?foo=bar&baz=qux` ```ts [server/api/query.get.ts] export default defineEventHandler((event) => { const query = getQuery(event) return { a: query.foo, b: query.baz } }) ``` <tip to="https://unjs.io/blog/2023-08-15-h3-towards-the-edge-of-the-web#runtime-type-safe-request-utils"> Alternatively, use `getValidatedQuery` with a schema validator such as Zod for runtime and type safety. </tip> ### Error Handling If no errors are thrown, a status code of `200 OK` will be returned. Any uncaught errors will return a `500 Internal Server Error` HTTP Error. To return other error codes, throw an exception with [`createError`](https://nuxt.com/docs/3.x/api/utils/create-error): ```ts [server/api/validation/[id].ts] export default defineEventHandler((event) => { const id = Number.parseInt(event.context.params.id) as number if (!Number.isInteger(id)) { throw createError({ status: 400, statusText: 'ID should be an integer', }) } return 'All good' }) ``` ### Status Codes To return other status codes, use the [`setResponseStatus`](https://nuxt.com/docs/3.x/api/utils/set-response-status) utility. For example, to return `202 Accepted` ```ts [server/api/validation/[id].ts] export default defineEventHandler((event) => { setResponseStatus(event, 202) }) ``` ### Runtime Config <code-group> ```ts [server/api/foo.ts] export default defineEventHandler(async (event) => { const config = useRuntimeConfig(event) const repo = await $fetch('https://api.github.com/repos/nuxt/nuxt', { headers: { Authorization: `token ${config.githubToken}`, }, }) return repo }) ``` ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { githubToken: '', }, }) ``` ```ini [.env] NUXT_GITHUB_TOKEN='<my-super-token>' ``` </code-group> <note> Giving the `event` as argument to `useRuntimeConfig` is optional, but it is recommended to pass it to get the runtime config overwritten by [environment variables](https://nuxt.com/docs/3.x/guide/going-further/runtime-config#environment-variables) at runtime for server routes. </note> ### Request Cookies ```ts [server/api/cookies.ts] export default defineEventHandler((event) => { const cookies = parseCookies(event) return { cookies } }) ``` ### Forwarding Context & Headers By default, neither the headers from the incoming request nor the request context are forwarded when making fetch requests in server routes. You can use `event.$fetch` to forward the request context and headers when making fetch requests in server routes. ```ts [server/api/forward.ts] export default defineEventHandler((event) => { return event.$fetch('/api/forwarded') }) ``` <note> Headers that are **not meant to be forwarded** will **not be included** in the request. These headers include, for example: `transfer-encoding`, `connection`, `keep-alive`, `upgrade`, `expect`, `host`, `accept` </note> ### Awaiting Promises After Response When handling server requests, you might need to perform asynchronous tasks that shouldn't block the response to the client (for example, caching and logging). You can use `event.waitUntil` to await a promise in the background without delaying the response. The `event.waitUntil` method accepts a promise that will be awaited before the handler terminates, ensuring the task is completed even if the server would otherwise terminate the handler right after the response is sent. This integrates with runtime providers to leverage their native capabilities for handling asynchronous operations after the response is sent. ```ts [server/api/background-task.ts] const timeConsumingBackgroundTask = async () => { await new Promise(resolve => setTimeout(resolve, 1000)) } export default eventHandler((event) => { // schedule a background task without blocking the response event.waitUntil(timeConsumingBackgroundTask()) // immediately send the response to the client return 'done' }) ``` ## Advanced Usage ### Nitro Config You can use `nitro` key in `nuxt.config` to directly set [Nitro configuration](https://nitro.build/config). <warning> This is an advanced option. Custom config can affect production deployments, as the configuration interface might change over time when Nitro is upgraded in semver-minor versions of Nuxt. </warning> ```ts [nuxt.config.ts] export default defineNuxtConfig({ // https://nitro.build/config nitro: {}, }) ``` <read-more to="https://nuxt.com/docs/3.x/guide/concepts/server-engine"> </read-more> ### Nested Router ```ts [server/api/hello/[...slug].ts] import { createRouter, defineEventHandler, useBase } from 'h3' const router = createRouter() router.get('/test', defineEventHandler(() => 'Hello World')) export default useBase('/api/hello', router.handler) ``` ### Sending Streams <tip> This is an experimental feature and is available in all environments. </tip> ```ts [server/api/foo.get.ts] import fs from 'node:fs' import { sendStream } from 'h3' export default defineEventHandler((event) => { return sendStream(event, fs.createReadStream('/path/to/file')) }) ``` ### Sending Redirect ```ts [server/api/foo.get.ts] export default defineEventHandler(async (event) => { await sendRedirect(event, '/path/redirect/to', 302) }) ``` ### Legacy Handler or Middleware ```ts [server/api/legacy.ts] export default fromNodeMiddleware((req, res) => { res.end('Legacy handler') }) ``` <important> Legacy support is possible using [h3js/h3](https://github.com/h3js/h3), but it is advised to avoid legacy handlers as much as you can. </important> ```ts [server/middleware/legacy.ts] export default fromNodeMiddleware((req, res, next) => { console.log('Legacy middleware') next() }) ``` <warning> Never combine `next()` callback with a legacy middleware that is `async` or returns a `Promise`. </warning> ### Server Storage Nitro provides a cross-platform [storage layer](https://nitro.build/guide/storage). In order to configure additional storage mount points, you can use `nitro.storage`, or [server plugins](https://nuxt.com/docs/3.x/directory-structure/server#server-plugins). **Example of adding a Redis storage:** Using `nitro.storage`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { storage: { redis: { driver: 'redis', /* redis connector options */ port: 6379, // Redis port host: '127.0.0.1', // Redis host username: '', // needs Redis >= 6 password: '', db: 0, // Defaults to 0 tls: {}, // tls/ssl }, }, }, }) ``` Then in your API handler: ```ts [server/api/storage/test.ts] export default defineEventHandler(async (event) => { // List all keys with const keys = await useStorage('redis').getKeys() // Set a key with await useStorage('redis').setItem('foo', 'bar') // Remove a key with await useStorage('redis').removeItem('foo') return {} }) ``` <read-more to="https://nitro.build/guide/storage" target="_blank"> Read more about Nitro Storage Layer. </read-more> Alternatively, you can create a storage mount point using a server plugin and runtime config: <code-group> ```ts [server/plugins/storage.ts] import redisDriver from 'unstorage/drivers/redis' export default defineNitroPlugin(() => { const storage = useStorage() // Dynamically pass in credentials from runtime configuration, or other sources const driver = redisDriver({ base: 'redis', host: useRuntimeConfig().redis.host, port: useRuntimeConfig().redis.port, /* other redis connector options */ }) // Mount driver storage.mount('redis', driver) }) ``` ```ts [nuxt.config.ts] export default defineNuxtConfig({ runtimeConfig: { redis: { // Default values host: '', port: 0, /* other redis connector options */ }, }, }) ``` </code-group> # shared > Use the shared/ directory to share functionality between the Vue app and the Nitro server. The `shared/` directory allows you to share code that can be used in both the Vue app and the Nitro server. <note> The `shared/` directory is available in Nuxt v3.14+. </note> <important> Code in the `shared/` directory cannot import any Vue or Nitro code. </important> <warning> Auto-imports are not enabled by default in Nuxt v3 to prevent breaking changes in existing projects. To use these auto-imported utils and types, you must first [set `future.compatibilityVersion: 4` in your `nuxt.config.ts`](https://nuxt.com/docs/3.x/getting-started/upgrade#opting-in-to-nuxt-4). </warning> <video-accordion title="Watch a video from Vue School on sharing utils and types between app and server" video-id="nnAR-MO3q5M"> </video-accordion> ## Usage **Method 1:** Named export ```ts [shared/utils/capitalize.ts]twoslash export const capitalize = (input: string) => { return input[0] ? input[0].toUpperCase() + input.slice(1) : '' } ``` **Method 2:** Default export ```ts [shared/utils/capitalize.ts]twoslash export default function (input: string) { return input[0] ? input[0].toUpperCase() + input.slice(1) : '' } ``` You can now use [auto-imported](https://nuxt.com/docs/3.x/directory-structure/shared) utilities in your Nuxt app and `server/` directory. ```vue [app.vue] <script setup lang="ts"> const hello = capitalize('hello') </script> <template> <div> {{ hello }} </div> </template> ``` ```ts [server/api/hello.get.ts] export default defineEventHandler((event) => { return { hello: capitalize('hello'), } }) ``` ## How Files Are Scanned Only files in the `shared/utils/` and `shared/types/` directories will be auto-imported. Files nested within subdirectories of these directories will not be auto-imported unless you add these directories to `imports.dirs` and `nitro.imports.dirs`. <tip> The way `shared/utils` and `shared/types` auto-imports work and are scanned is identical to the [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables) and [`utils/`](https://nuxt.com/docs/3.x/directory-structure/utils) directories. </tip> <read-more to="https://nuxt.com/docs/3.x/directory-structure/composables#how-files-are-scanned"> </read-more> ```bash [Directory Structure] -| shared/ ---| capitalize.ts # Not auto-imported ---| formatters -----| lower.ts # Not auto-imported ---| utils/ -----| lower.ts # Auto-imported -----| formatters -------| upper.ts # Not auto-imported ---| types/ -----| bar.ts # Auto-imported ``` Any other files you create in the `shared/` folder must be manually imported using the `#shared` alias (automatically configured by Nuxt): ```ts // For files directly in the shared directory import capitalize from '#shared/capitalize' // For files in nested directories import lower from '#shared/formatters/lower' // For files nested in a folder within utils import upper from '#shared/utils/formatters/upper' ``` This alias ensures consistent imports across your application, regardless of the importing file's location. <read-more to="https://nuxt.com/docs/3.x/guide/concepts/auto-imports"> </read-more> # tsconfig.json > Learn how Nuxt manages TypeScript configuration across different parts of your project. Nuxt [automatically generates](https://nuxt.com/docs/3.x/guide/concepts/typescript) a `.nuxt/tsconfig.json` file with the resolved aliases you are using in your Nuxt project, as well as with other sensible defaults. Your Nuxt project should include the following `tsconfig.json` file at the root of the project: ```json [tsconfig.json] { "extends": "./.nuxt/tsconfig.json" } ``` <note> As you need to, you can customize the contents of this file. However, it is recommended that you don't overwrite `target`, `module` and `moduleResolution`. </note> <note> If you need to customize your `paths`, this will override the auto-generated path aliases. Instead, we recommend that you add any path aliases you need to the [`alias`](https://nuxt.com/docs/3.x/api/nuxt-config#alias) property within your `nuxt.config`, where they will get picked up and added to the auto-generated `tsconfig`. </note> ## Extending TypeScript Configuration You can customize the TypeScript configuration of your Nuxt project for each context (`app` and `server`) in the `nuxt.config.ts` file. ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ typescript: { // customize tsconfig.app.json tsConfig: { // ... }, }, nitro: { typescript: { // customize tsconfig.server.json tsConfig: { // ... }, }, }, }) ``` # utils > Use the utils/ directory to auto-import your utility functions throughout your application. The main purpose of the [`utils/` directory](https://nuxt.com/docs/3.x/directory-structure/utils) is to allow a semantic distinction between your Vue composables and other auto-imported utility functions. ## Usage **Method 1:** Using named export ```ts [utils/index.ts]twoslash export const { format: formatNumber } = Intl.NumberFormat('en-GB', { notation: 'compact', maximumFractionDigits: 1, }) ``` **Method 2:** Using default export ```ts [utils/random-entry.ts or utils/randomEntry.ts]twoslash // It will be available as randomEntry() (camelCase of file name without extension) export default function (arr: Array<any>) { return arr[Math.floor(Math.random() * arr.length)] } ``` You can now use auto imported utility functions in `.js`, `.ts` and `.vue` files ```vue [app.vue] <template> <p>{{ formatNumber(1234) }}</p> </template> ``` <read-more to="https://nuxt.com/docs/3.x/guide/concepts/auto-imports"> </read-more> <link-example to="https://nuxt.com/docs/3.x/examples/features/auto-imports"> </link-example> <tip> The way `utils/` auto-imports work and are scanned is identical to the [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables) directory. </tip> <important> These utils are only available within the Vue part of your app. <br /> Only `server/utils` are auto-imported in the [`server/`](https://nuxt.com/docs/3.x/directory-structure/server#server-utilities) directory. </important> # Layers > This example shows how to use the extends key in `nuxt.config.ts`. <code-explorer default-value="nuxt.config.ts" path="examples/advanced/config-extends"> </code-explorer> <browser src="https://config-extends.example.nuxt.space"> </browser> This example shows how to use the `extends` key in `nuxt.config.ts` to use the `base/` directory as a base Nuxt application, and use its components, composables or config and override them if necessary. <read-more to="https://nuxt.com/docs/3.x/getting-started/layers"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/config-extends) # Error Handling > This example shows how to handle errors in different contexts: pages, plugins, components and middleware. <code-explorer default-value="error.vue" path="examples/advanced/error-handling"> </code-explorer> <browser src="https://error-handling.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/error-handling"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/error-handling) # JSX / TSX > This example shows how to use JSX syntax with typescript in Nuxt pages and components. <code-explorer default-value="app.vue" path="examples/advanced/jsx"> </code-explorer> <browser src="https://jsx.example.nuxt.space"> </browser> <read-more icon="i-simple-icons-vuedotjs" target="_blank" to="https://vuejs.org/guide/extras/render-function.html#jsx-tsx"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/jsx) # Locale > This example shows how to define a locale composable to handle the application's locale, both server and client side. <code-explorer default-value="composables/locale.ts" path="examples/advanced/locale"> </code-explorer> <browser src="https://locale.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/locale) # Module Extend Pages > This example defines a new `test` page using `extendPages` within a module. <code-explorer default-value="modules/pages/index.ts" path="examples/advanced/module-extend-pages"> </code-explorer> <browser src="https://module-extend-pages.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/guide/modules"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/module-extend-pages) # Teleport > This example shows how to use the <Teleport> with client-side and server-side rendering. <code-explorer default-value="app.vue" path="examples/advanced/teleport"> </code-explorer> <browser src="https://teleport.example.nuxt.space"> </browser> Vue 3 provides the [`<Teleport>` component](https://vuejs.org/guide/built-ins/teleport.html) which allows content to be rendered elsewhere in the DOM, outside of the Vue application. This example shows how to use the `<Teleport>` with client-side and server-side rendering. <read-more to="https://nuxt.com/docs/3.x/api/components/teleports"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/teleport) # Testing > This example shows how to test your Nuxt application. <code-explorer default-value="tests/basic.test.ts" path="examples/advanced/testing"> </code-explorer> <browser src="https://testing.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/testing"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/testing) # useCookie > This example shows how to use the useCookie API to persist small amounts of data that both client and server can use. <code-explorer default-value="app.vue" path="examples/advanced/use-cookie"> </code-explorer> <browser src="https://use-cookie.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-cookie"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/use-cookie) # Use Custom Fetch Composable > This example shows a convenient wrapper for the useFetch composable from nuxt. It allows you to customize the fetch request with default values and user authentication token. <code-explorer default-value="plugins/customFetch.ts" path="examples/advanced/use-custom-fetch-composable"> </code-explorer> <browser src="https://use-custom-fetch-composable.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/guide/recipes/custom-usefetch"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/advanced/use-custom-fetch-composable) # WASM > This example demonstrates the server-side support of WebAssembly in Nuxt. <code-explorer default-value="app.vue" path="examples/experimental/wasm"> </code-explorer> <browser src="https://wasm.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/experimental/wasm) # Auto Imports > This example demonstrates the auto-imports feature in Nuxt. <code-explorer default-value="app.vue" path="examples/features/auto-imports"> </code-explorer> <browser src="https://auto-imports.example.nuxt.space"> </browser> Example of the auto-imports feature in Nuxt with: - Vue components in the `components/` directory are auto-imported and can be used directly in your templates. - Vue composables in the `composables/` directory are auto-imported and can be used directly in your templates and JS/TS files. - JS/TS variables and functions in the `utils/` directory are auto-imported and can be used directly in your templates and JS/TS files. <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/components"> </read-more> <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/composables"> </read-more> <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/utils"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/auto-imports) # Data Fetching > This example demonstrates data fetching with Nuxt using built-in composables and API routes. <code-explorer default-value="pages/index.vue" path="examples/features/data-fetching"> </code-explorer> <browser src="https://data-fetching.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/data-fetching"> </read-more> <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/server"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/data-fetching) # Layouts > This example shows how to define default and custom layouts. <code-explorer default-value="pages/index.vue" path="examples/features/layouts"> </code-explorer> <browser src="https://layouts.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/views#layouts"> </read-more> <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/layouts"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/layouts) # Meta Tags > This example shows how to use the Nuxt helpers and composables for SEO and meta management. <code-explorer default-value="pages/index.vue" path="examples/features/meta-tags"> </code-explorer> <browser src="https://meta-tags.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/seo-meta"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/meta-tags) # State Management > This example shows how to use the `useState` composable to create a reactive and SSR-friendly shared state across components. <code-explorer default-value="app.vue" path="examples/features/state-management"> </code-explorer> <browser src="https://state-management.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/state-management"> </read-more> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-state"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/features/state-management) # Hello World > A minimal Nuxt application only requires the `app.vue` and `nuxt.config.js` files. <code-explorer default-value="app.vue" path="examples/hello-world"> </code-explorer> <browser src="https://hello-world.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/getting-started/introduction"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/hello-world) # Middleware > This example shows how to add route middleware with the middleware/ directory or with a plugin, and how to use them globally or per page. <code-explorer default-value="middleware/redirect-me.ts" path="examples/routing/middleware"> </code-explorer> <browser src="https://middleware.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/middleware"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/middleware) # Pages > This example shows how to use the pages/ directory to create application routes. <code-explorer default-value="pages/index.vue" path="examples/routing/pages"> </code-explorer> <browser src="https://pages.example.nuxt.space"> </browser> <read-more to="https://nuxt.com/docs/3.x/guide/directory-structure/pages"> </read-more> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/pages) # Universal Router > This example demonstrates Nuxt universal routing utilities without depending on `pages/` and `vue-router`. <code-explorer default-value="plugins/add.ts" path="examples/routing/universal-router"> </code-explorer> <browser src="https://universal-router.example.nuxt.space"> </browser> --- - [Source](https://github.com/nuxt/examples/tree/main/examples/routing/universal-router) # Assets > Nuxt offers two options for your assets. Nuxt uses two directories to handle assets like stylesheets, fonts or images. - The [`public/`](https://nuxt.com/docs/3.x/directory-structure/public) directory content is served at the server root as-is. - The [`assets/`](https://nuxt.com/docs/3.x/directory-structure/assets) directory contains by convention every asset that you want the build tool (Vite or webpack) to process. ## Public Directory The [`public/`](https://nuxt.com/docs/3.x/directory-structure/public) directory is used as a public server for static assets publicly available at a defined URL of your application. You can get a file in the [`public/`](https://nuxt.com/docs/3.x/directory-structure/public) directory from your application's code or from a browser by the root URL `/`. ### Example For example, referencing an image file in the `public/img/` directory, available at the static URL `/img/nuxt.png`: ```vue [app.vue] <template> <img src="/img/nuxt.png" alt="Discover Nuxt" > </template> ``` ## Assets Directory Nuxt uses [Vite](https://vite.dev/guide/assets) (default) or [webpack](https://webpack.js.org/guides/asset-management/) to build and bundle your application. The main function of these build tools is to process JavaScript files, but they can be extended through [plugins](https://vite.dev/plugins/) (for Vite) or [loaders](https://webpack.js.org/loaders/) (for webpack) to process other kinds of assets, like stylesheets, fonts or SVGs. This step transforms the original file, mainly for performance or caching purposes (such as stylesheet minification or browser cache invalidation). By convention, Nuxt uses the [`assets/`](https://nuxt.com/docs/3.x/directory-structure/assets) directory to store these files but there is no auto-scan functionality for this directory, and you can use any other name for it. In your application's code, you can reference a file located in the [`assets/`](https://nuxt.com/docs/3.x/directory-structure/assets) directory by using the `~/assets/` path. ### Example For example, referencing an image file that will be processed if a build tool is configured to handle this file extension: ```vue [app.vue] <template> <img src="~/assets/img/nuxt.png" alt="Discover Nuxt" > </template> ``` <note> Nuxt won't serve files in the [`assets/`](https://nuxt.com/docs/3.x/directory-structure/assets) directory at a static URL like `/assets/my-file.png`. If you need a static URL, use the [`public/`](https://nuxt.com/docs/3.x/getting-started/assets#public-directory) directory. </note> # Configuration > Nuxt is configured with sensible defaults to make you productive. By default, Nuxt is configured to cover most use cases. The [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file can override or extend this default configuration. ## Nuxt Configuration The [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file is located at the root of a Nuxt project and can override or extend the application's behavior. A minimal configuration file exports the `defineNuxtConfig` function containing an object with your configuration. The `defineNuxtConfig` helper is globally available without import. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ // My Nuxt config }) ``` This file will often be mentioned in the documentation, for example to add custom scripts, register modules or change rendering modes. <read-more to="https://nuxt.com/docs/3.x/api/configuration/nuxt-config"> Every option is described in the **Configuration Reference**. </read-more> <note> You don't have to use TypeScript to build an application with Nuxt. However, it is strongly recommended to use the `.ts` extension for the `nuxt.config` file. This way you can benefit from hints in your IDE to avoid typos and mistakes while editing your configuration. </note> ### Environment Overrides You can configure fully typed, per-environment overrides in your nuxt.config ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ $production: { routeRules: { '/**': { isr: true }, }, }, $development: { // }, $env: { staging: { // }, }, }) ``` To select an environment when running a Nuxt CLI command, simply pass the name to the `--envName` flag, like so: `nuxt build --envName staging`. To learn more about the mechanism behind these overrides, please refer to the `c12` documentation on [environment-specific configuration](https://github.com/unjs/c12?tab=readme-ov-file#environment-specific-configuration). <video-accordion title="Watch a video from Alexander Lichter about the env-aware nuxt.config.ts" video-id="DFZI2iVCrNc"> </video-accordion> <note> If you're authoring layers, you can also use the `$meta` key to provide metadata that you or the consumers of your layer might use. </note> ### Environment Variables and Private Tokens The `runtimeConfig` API exposes values like environment variables to the rest of your application. By default, these keys are only available server-side. The keys within `runtimeConfig.public` and `runtimeConfig.app` (which is used by Nuxt internally) are also available client-side. Those values should be defined in `nuxt.config` and can be overridden using environment variables. <code-group> ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ runtimeConfig: { // The private keys which are only available server-side apiSecret: '123', // Keys within public are also exposed client-side public: { apiBase: '/api', }, }, }) ``` ```ini [.env] # This will override the value of apiSecret NUXT_API_SECRET=api_secret_token ``` </code-group> These variables are exposed to the rest of your application using the [`useRuntimeConfig()`](https://nuxt.com/docs/3.x/api/composables/use-runtime-config) composable. ```vue [pages/index.vue] <script setup lang="ts"> const runtimeConfig = useRuntimeConfig() </script> ``` <read-more to="https://nuxt.com/docs/3.x/guide/going-further/runtime-config"> </read-more> ## App Configuration The `app.config.ts` file, located in the source directory (by default the root of the project), is used to expose public variables that can be determined at build time. Contrary to the `runtimeConfig` option, these cannot be overridden using environment variables. A minimal configuration file exports the `defineAppConfig` function containing an object with your configuration. The `defineAppConfig` helper is globally available without import. ```ts [app.config.ts] export default defineAppConfig({ title: 'Hello Nuxt', theme: { dark: true, colors: { primary: '#ff0000', }, }, }) ``` These variables are exposed to the rest of your application using the [`useAppConfig`](https://nuxt.com/docs/3.x/api/composables/use-app-config) composable. ```vue [pages/index.vue] <script setup lang="ts"> const appConfig = useAppConfig() </script> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/app-config"> </read-more> ## `runtimeConfig` vs. `app.config` As stated above, `runtimeConfig` and `app.config` are both used to expose variables to the rest of your application. To determine whether you should use one or the other, here are some guidelines: - `runtimeConfig`: Private or public tokens that need to be specified after build using environment variables. - `app.config`: Public tokens that are determined at build time, website configuration such as theme variant, title and any project config that are not sensitive. <table> <thead> <tr> <th> Feature </th> <th> <code> runtimeConfig </code> </th> <th> <code> app.config </code> </th> </tr> </thead> <tbody> <tr> <td> Client-side </td> <td> Hydrated </td> <td> Bundled </td> </tr> <tr> <td> Environment variables </td> <td> โœ… Yes </td> <td> โŒ No </td> </tr> <tr> <td> Reactive </td> <td> โœ… Yes </td> <td> โœ… Yes </td> </tr> <tr> <td> Types support </td> <td> โœ… Partial </td> <td> โœ… Yes </td> </tr> <tr> <td> Configuration per request </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> <tr> <td> Hot module replacement </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> <tr> <td> Non-primitive JS types </td> <td> โŒ No </td> <td> โœ… Yes </td> </tr> </tbody> </table> ## External Configuration Files Nuxt uses [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file as the single source of truth for configurations and skips reading external configuration files. During the course of building your project, you may have a need to configure those. The following table highlights common configurations and, where applicable, how they can be configured with Nuxt. <table> <thead> <tr> <th> Name </th> <th> Config File </th> <th> How To Configure </th> </tr> </thead> <tbody> <tr> <td> <a href="https://nitro.build" rel="nofollow"> Nitro </a> </td> <td> <del> <code> nitro.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/3.x/api/nuxt-config#nitro"> <code> nitro </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://postcss.org" rel="nofollow"> PostCSS </a> </td> <td> <del> <code> postcss.config.js </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/3.x/api/nuxt-config#postcss"> <code> postcss </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://vite.dev" rel="nofollow"> Vite </a> </td> <td> <del> <code> vite.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/3.x/api/nuxt-config#vite"> <code> vite </code> </a> key in <code> nuxt.config </code> </td> </tr> <tr> <td> <a href="https://webpack.js.org" rel="nofollow"> webpack </a> </td> <td> <del> <code> webpack.config.ts </code> </del> </td> <td> Use <a href="https://nuxt.com/docs/3.x/api/nuxt-config#webpack-1"> <code> webpack </code> </a> key in <code> nuxt.config </code> </td> </tr> </tbody> </table> Here is a list of other common config files: <table> <thead> <tr> <th> Name </th> <th> Config File </th> <th> How To Configure </th> </tr> </thead> <tbody> <tr> <td> <a href="https://www.typescriptlang.org" rel="nofollow"> TypeScript </a> </td> <td> <code> tsconfig.json </code> </td> <td> <a href="https://nuxt.com/docs/3.x/directory-structure/tsconfig"> More Info </a> </td> </tr> <tr> <td> <a href="https://eslint.org" rel="nofollow"> ESLint </a> </td> <td> <code> eslint.config.js </code> </td> <td> <a href="https://eslint.org/docs/latest/use/configure/configuration-files" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://prettier.io" rel="nofollow"> Prettier </a> </td> <td> <code> prettier.config.js </code> </td> <td> <a href="https://prettier.io/docs/configuration.html" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://stylelint.io" rel="nofollow"> Stylelint </a> </td> <td> <code> stylelint.config.js </code> </td> <td> <a href="https://stylelint.io/user-guide/configure/" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://tailwindcss.com" rel="nofollow"> TailwindCSS </a> </td> <td> <code> tailwind.config.js </code> </td> <td> <a href="https://tailwindcss.nuxtjs.org/tailwindcss/configuration/" rel="nofollow"> More Info </a> </td> </tr> <tr> <td> <a href="https://vitest.dev" rel="nofollow"> Vitest </a> </td> <td> <code> vitest.config.ts </code> </td> <td> <a href="https://vitest.dev/config/" rel="nofollow"> More Info </a> </td> </tr> </tbody> </table> ## Vue Configuration ### With Vite If you need to pass options to `@vitejs/plugin-vue` or `@vitejs/plugin-vue-jsx`, you can do this in your `nuxt.config` file. - `vite.vue` for `@vitejs/plugin-vue`. Check [available options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue). - `vite.vueJsx` for `@vitejs/plugin-vue-jsx`. Check [available options](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ vite: { vue: { customElement: true, }, vueJsx: { mergeProps: true, }, }, }) ``` <read-more to="https://nuxt.com/docs/3.x/api/configuration/nuxt-config#vue"> </read-more> ### With webpack If you use webpack and need to configure `vue-loader`, you can do this using `webpack.loaders.vue` key inside your `nuxt.config` file. The available options are [defined here](https://github.com/vuejs/vue-loader/blob/main/src/index.ts#L32-L62). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ webpack: { loaders: { vue: { hotReload: true, }, }, }, }) ``` <read-more to="https://nuxt.com/docs/3.x/api/configuration/nuxt-config#loaders"> </read-more> ### Enabling Experimental Vue Features You may need to enable experimental features in Vue, such as `propsDestructure`. Nuxt provides an easy way to do that in `nuxt.config.ts`, no matter which builder you are using: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ vue: { propsDestructure: true, }, }) ``` #### experimental `reactivityTransform` migration from Vue 3.4 and Nuxt 3.9 Since Nuxt 3.9 and Vue 3.4, `reactivityTransform` has been moved from Vue to Vue Macros which has a [Nuxt integration](https://vue-macros.dev/guide/nuxt-integration.html). <read-more to="https://nuxt.com/docs/3.x/api/configuration/nuxt-config#vue-1"> </read-more> # Data Fetching > Nuxt provides composables to handle data fetching within your application. Nuxt comes with two composables and a built-in library to perform data-fetching in browser or server environments: `useFetch`, [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) and `$fetch`. In a nutshell: - [`$fetch`](https://nuxt.com/docs/3.x/api/utils/dollarfetch) is the simplest way to make a network request. - [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) is a wrapper around `$fetch` that fetches data only once in [universal rendering](https://nuxt.com/docs/3.x/guide/concepts/rendering#universal-rendering). - [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) is similar to `useFetch` but offers more fine-grained control. Both `useFetch` and `useAsyncData` share a common set of options and patterns that we will detail in the last sections. ## The need for `useFetch` and `useAsyncData` Nuxt is a framework which can run isomorphic (or universal) code in both server and client environments. If the [`$fetch` function](https://nuxt.com/docs/3.x/api/utils/dollarfetch) is used to perform data fetching in the setup function of a Vue component, this may cause data to be fetched twice, once on the server (to render the HTML) and once again on the client (when the HTML is hydrated). This can cause hydration issues, increase the time to interactivity and cause unpredictable behavior. The [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) composables solve this problem by ensuring that if an API call is made on the server, the data is forwarded to the client in the payload. The payload is a JavaScript object accessible through [`useNuxtApp().payload`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#payload). It is used on the client to avoid refetching the same data when the code is executed in the browser [during hydration](https://nuxt.com/docs/3.x/guide/concepts/rendering#universal-rendering). <tip> Use the [Nuxt DevTools](https://devtools.nuxt.com) to inspect this data in the **Payload tab**. </tip> ```vue [app.vue] <script setup lang="ts"> const { data } = await useFetch('/api/data') async function handleFormSubmit () { const res = await $fetch('/api/submit', { method: 'POST', body: { // My form data }, }) } </script> <template> <div v-if="data == null"> No data </div> <div v-else> <form @submit="handleFormSubmit"> <!-- form input tags --> </form> </div> </template> ``` In the example above, `useFetch` would make sure that the request would occur in the server and is properly forwarded to the browser. `$fetch` has no such mechanism and is a better option to use when the request is solely made from the browser. ### Suspense Nuxt uses Vue's [`<Suspense>`](https://vuejs.org/guide/built-ins/suspense) component under the hood to prevent navigation before every async data is available to the view. The data fetching composables can help you leverage this feature and use what suits best on a per-call basis. <note> You can add the [`<NuxtLoadingIndicator>`](https://nuxt.com/docs/3.x/api/components/nuxt-loading-indicator) to add a progress bar between page navigations. </note> ## `$fetch` Nuxt includes the [ofetch](https://github.com/unjs/ofetch) library, and is auto-imported as the `$fetch` alias globally across your application. ```vue [pages/todos.vue]twoslash <script setup lang="ts"> async function addTodo () { const todo = await $fetch('/api/todos', { method: 'POST', body: { // My todo data }, }) } </script> ``` <warning> Beware that using only `$fetch` will not provide [network calls de-duplication and navigation prevention](https://nuxt.com/docs/3.x/getting-started/data-fetching#the-need-for-usefetch-and-useasyncdata). <br /> It is recommended to use `$fetch` for client-side interactions (event-based) or combined with [`useAsyncData`](https://nuxt.com/docs/3.x/getting-started/data-fetching#useasyncdata) when fetching the initial component data. </warning> <read-more to="https://nuxt.com/docs/3.x/api/utils/dollarfetch"> Read more about `$fetch`. </read-more> ### Pass Client Headers to the API When calling `useFetch` on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/3.x/api/composables/use-request-fetch) to proxy client headers and cookies (with the exception of headers not meant to be forwarded, like `host`). ```vue <script setup lang="ts"> const { data } = await useFetch('/api/echo') </script> ``` ```ts // /api/echo.ts export default defineEventHandler(event => parseCookies(event)) ``` Alternatively, the example below shows how to use [`useRequestHeaders`](https://nuxt.com/docs/3.x/api/composables/use-request-headers) to access and send cookies to the API from a server-side request (originating on the client). Using an isomorphic `$fetch` call, we ensure that the API endpoint has access to the same `cookie` header originally sent by the user's browser. This is only necessary if you aren't using `useFetch`. ```vue <script setup lang="ts"> const headers = useRequestHeaders(['cookie']) async function getCurrentUser () { return await $fetch('/api/me', { headers }) } </script> ``` <tip> You can also use [`useRequestFetch`](https://nuxt.com/docs/3.x/api/composables/use-request-fetch) to proxy headers to the call automatically. </tip> <caution> Be very careful before proxying headers to an external API and just include headers that you need. Not all headers are safe to be bypassed and might introduce unwanted behavior. Here is a list of common headers that are NOT to be proxied: - `host`, `accept` - `content-length`, `content-md5`, `content-type` - `x-forwarded-host`, `x-forwarded-port`, `x-forwarded-proto` - `cf-connecting-ip`, `cf-ray` </caution> ## `useFetch` The [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) composable uses `$fetch` under-the-hood to make SSR-safe network calls in the setup function. ```vue [app.vue]twoslash <script setup lang="ts"> const { data: count } = await useFetch('/api/count') </script> <template> <p>Page visits: {{ count }}</p> </template> ``` This composable is a wrapper around the [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) composable and `$fetch` utility. <video-accordion title="Watch a video from Alexander Lichter to avoid using useFetch the wrong way" video-id="njsGVmcWviY"> </video-accordion> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-fetch"> </read-more> <link-example to="https://nuxt.com/docs/3.x/examples/features/data-fetching"> </link-example> ## `useAsyncData` The `useAsyncData` composable is responsible for wrapping async logic and returning the result once it is resolved. <tip> `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => event.$fetch(url))`. <br /> It's developer experience sugar for the most common use case. (You can find out more about `event.fetch` at [`useRequestFetch`](https://nuxt.com/docs/3.x/api/composables/use-request-fetch).) </tip> <video-accordion title="Watch a video from Alexander Lichter to dig deeper into the difference between useFetch and useAsyncData" video-id="0X-aOpSGabA"> </video-accordion> There are some cases when using the [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) composable is not appropriate, for example when a CMS or a third-party provide their own query layer. In this case, you can use [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) to wrap your calls and still keep the benefits provided by the composable. ```vue [pages/users.vue] <script setup lang="ts"> const { data, error } = await useAsyncData('users', () => myGetFunction('users')) // This is also possible: const { data, error } = await useAsyncData(() => myGetFunction('users')) </script> ``` <note> The first argument of [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) is a unique key used to cache the response of the second argument, the querying function. This key can be ignored by directly passing the querying function, the key will be auto-generated. <br /> <br /> Since the autogenerated key only takes into account the file and line where `useAsyncData` is invoked, it is recommended to always create your own key to avoid unwanted behavior, like when you are creating your own custom composable wrapping `useAsyncData`. <br /> <br /> Setting a key can be useful to share the same data between components using [`useNuxtData`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-data) or to [refresh specific data](https://nuxt.com/docs/3.x/api/utils/refresh-nuxt-data#refresh-specific-data). </note> ```vue [pages/users/[id].vue] <script setup lang="ts"> const { id } = useRoute().params const { data, error } = await useAsyncData(`user:${id}`, () => { return myGetFunction('users', { id }) }) </script> ``` The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results. ```vue <script setup lang="ts"> const { data: discounts, status } = await useAsyncData('cart-discount', async (_nuxtApp, { signal }) => { const [coupons, offers] = await Promise.all([ $fetch('/cart/coupons', { signal }), $fetch('/cart/offers', { signal }), ]) return { coupons, offers } }) // discounts.value.coupons // discounts.value.offers </script> ``` <note> `useAsyncData` is for fetching and caching data, not triggering side effects like calling Pinia actions, as this can cause unintended behavior such as repeated executions with nullish values. If you need to trigger side effects, use the [`callOnce`](https://nuxt.com/docs/3.x/api/utils/call-once) utility to do so. ```vue <script setup lang="ts"> const offersStore = useOffersStore() // you can't do this await useAsyncData(() => offersStore.getOffer(route.params.slug)) </script> ``` </note> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-async-data"> Read more about `useAsyncData`. </read-more> ## Return Values `useFetch` and `useAsyncData` have the same return values listed below. - `data`: the result of the asynchronous function that is passed in. - `refresh`/`execute`: a function that can be used to refresh the data returned by the `handler` function. - `clear`: a function that can be used to set `data` to `undefined` (or the value of `options.default()` if provided), set `error` to `null`, set `status` to `idle`, and mark any currently pending requests as cancelled. - `error`: an error object if the data fetching failed. - `status`: a string indicating the status of the data request (`"idle"`, `"pending"`, `"success"`, `"error"`). <note> `data`, `error` and `status` are Vue refs accessible with `.value` in `<script setup>` </note> By default, Nuxt waits until a `refresh` is finished before it can be executed again. <note> If you have not fetched data on the server (for example, with `server: false`), then the data *will not* be fetched until hydration completes. This means even if you await `useFetch` on client-side, `data` will remain undefined within `<script setup>`. </note> ## Options [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) and [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) return the same object type and accept a common set of options as their last argument. They can help you control the composables behavior, such as navigation blocking, caching or execution. ### Lazy By default, data fetching composables will wait for the resolution of their asynchronous function before navigating to a new page by using Vue's Suspense. This feature can be ignored on client-side navigation with the `lazy` option. In that case, you will have to manually handle loading state using the `status` value. ```vue [app.vue]twoslash <script setup lang="ts"> const { status, data: posts } = useFetch('/api/posts', { lazy: true, }) </script> <template> <!-- you will need to handle a loading state --> <div v-if="status === 'pending'"> Loading ... </div> <div v-else> <div v-for="post in posts"> <!-- do something --> </div> </div> </template> ``` You can alternatively use [`useLazyFetch`](https://nuxt.com/docs/3.x/api/composables/use-lazy-fetch) and `useLazyAsyncData` as convenient methods to perform the same. ```vuetwoslash <script setup lang="ts"> const { status, data: posts } = useLazyFetch('/api/posts') </script> ``` <read-more to="https://nuxt.com/docs/3.x/api/composables/use-lazy-fetch"> Read more about `useLazyFetch`. </read-more> <read-more to="https://nuxt.com/docs/3.x/api/composables/use-lazy-async-data"> Read more about `useLazyAsyncData`. </read-more> <video-accordion title="Watch a video from Vue School on blocking vs. non-blocking (lazy) requests" video-id="1022000555" platform="vimeo"> </video-accordion> ### Client-only fetching By default, data fetching composables will perform their asynchronous function on both client and server environments. Set the `server` option to `false` to only perform the call on the client-side. On initial load, the data will not be fetched before hydration is complete so you have to handle a pending state, though on subsequent client-side navigation the data will be awaited before loading the page. Combined with the `lazy` option, this can be useful for data that is not needed on the first render (for example, non-SEO sensitive data). ```tstwoslash /* This call is performed before hydration */ const articles = await useFetch('/api/article') /* This call will only be performed on the client */ const { status, data: comments } = useFetch('/api/comments', { lazy: true, server: false, }) ``` The `useFetch` composable is meant to be invoked in setup method or called directly at the top level of a function in lifecycle hooks, otherwise you should use [`$fetch` method](https://nuxt.com/docs/3.x/getting-started/data-fetching#fetch). ### Minimize payload size The `pick` option helps you to minimize the payload size stored in your HTML document by only selecting the fields that you want returned from the composables. ```vue <script setup lang="ts"> /* only pick the fields used in your template */ const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'], }) </script> <template> <h1>{{ mountain.title }}</h1> <p>{{ mountain.description }}</p> </template> ``` If you need more control or map over several objects, you can use the `transform` function to alter the result of the query. ```ts const { data: mountains } = await useFetch('/api/mountains', { transform: (mountains) => { return mountains.map(mountain => ({ title: mountain.title, description: mountain.description })) }, }) ``` <note> Both `pick` and `transform` don't prevent the unwanted data from being fetched initially. But they will prevent unwanted data from being added to the payload transferred from server to client. </note> <video-accordion title="Watch a video from Vue School on minimizing payload size" video-id="1026410430" platform="vimeo"> </video-accordion> ### Caching and refetching #### Keys [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) use keys to prevent refetching the same data. - [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) uses the provided URL as a key. Alternatively, a `key` value can be provided in the `options` object passed as a last argument. - [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) uses its first argument as a key if it is a string. If the first argument is the handler function that performs the query, then a key that is unique to the file name and line number of the instance of `useAsyncData` will be generated for you. <tip> To get the cached data by key, you can use [`useNuxtData`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-data) </tip> <video-accordion title="Watch a video from Vue School on caching data with the key option" video-id="1026410044" platform="vimeo"> </video-accordion> #### Shared State and Option Consistency When multiple components use the same key with `useAsyncData` or `useFetch`, they will share the same `data`, `error` and `status` refs. This ensures consistency across components but requires some options to be consistent. The following options **must be consistent** across all calls with the same key: - `handler` function - `deep` option - `transform` function - `pick` array - `getCachedData` function - `default` value ```ts // โŒ This will trigger a development warning const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true }) ``` The following options **can safely differ** without triggering warnings: - `server` - `lazy` - `immediate` - `dedupe` - `watch` ```ts // โœ… This is allowed const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true }) const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false }) ``` If you need independent instances, use different keys: ```ts // These are completely independent instances const { data: users1 } = useAsyncData('users-1', (_nuxtApp, { signal }) => $fetch('/api/users', { signal })) const { data: users2 } = useAsyncData('users-2', (_nuxtApp, { signal }) => $fetch('/api/users', { signal })) ``` #### Reactive Keys You can use computed refs, plain refs or getter functions as keys, allowing for dynamic data fetching that automatically updates when dependencies change: ```ts // Using a computed property as a key const userId = ref('123') const { data: user } = useAsyncData( computed(() => `user-${userId.value}`), () => fetchUser(userId.value), ) // When userId changes, the data will be automatically refetched // and the old data will be cleaned up if no other components use it userId.value = '456' ``` #### Refresh and execute If you want to fetch or refresh data manually, use the `execute` or `refresh` function provided by the composables. ```vuetwoslash <script setup lang="ts"> const { data, error, execute, refresh } = await useFetch('/api/users') </script> <template> <div> <p>{{ data }}</p> <button @click="() => refresh()"> Refresh data </button> </div> </template> ``` The `execute` function is an alias for `refresh` that works in exactly the same way but is more semantic for cases when the fetch is [not immediate](https://nuxt.com/docs/3.x/getting-started/data-fetching#not-immediate). <tip> To globally refetch or invalidate cached data, see [`clearNuxtData`](https://nuxt.com/docs/3.x/api/utils/clear-nuxt-data) and [`refreshNuxtData`](https://nuxt.com/docs/3.x/api/utils/refresh-nuxt-data). </tip> #### Clear If you want to clear the data provided, for whatever reason, without needing to know the specific key to pass to `clearNuxtData`, you can use the `clear` function provided by the composables. ```vuetwoslash <script setup lang="ts"> const { data, clear } = await useFetch('/api/users') const route = useRoute() watch(() => route.path, (path) => { if (path === '/') { clear() } }) </script> ``` #### Watch To re-run your fetching function each time other reactive values in your application change, use the `watch` option. You can use it for one or multiple *watchable* elements. ```vuetwoslash <script setup lang="ts"> const id = ref(1) const { data, error, refresh } = await useFetch('/api/users', { /* Changing the id will trigger a refetch */ watch: [id], }) </script> ``` Note that **watching a reactive value won't change the URL fetched**. For example, this will keep fetching the same initial ID of the user because the URL is constructed at the moment the function is invoked. ```vue <script setup lang="ts"> const id = ref(1) const { data, error, refresh } = await useFetch(`/api/users/${id.value}`, { watch: [id], }) </script> ``` If you need to change the URL based on a reactive value, you may want to use a [computed URL](https://nuxt.com/docs/3.x/getting-started/data-fetching#computed-url) instead. When reactive fetch options are provided, they'll be automatically watched and trigger refetches. In some cases, it can be useful to opt-out of this behavior by specifying `watch: false`. ```ts const id = ref(1) // Won't automatically refetch when id changes const { data, execute } = await useFetch('/api/users', { query: { id }, // id is watched by default watch: false, // disables automatic watching of id }) // doesn't trigger refetch id.value = 2 ``` #### Computed URL Sometimes you may need to compute a URL from reactive values, and refresh the data each time these change. Instead of juggling your way around, you can attach each param as a reactive value. Nuxt will automatically use the reactive value and re-fetch each time it changes. ```vue <script setup lang="ts"> const id = ref(null) const { data, status } = useLazyFetch('/api/user', { query: { user_id: id, }, }) </script> ``` In the case of more complex URL construction, you may use a callback as a [computed getter](https://vuejs.org/guide/essentials/computed) that returns the URL string. Every time a dependency changes, the data will be fetched using the newly constructed URL. Combine this with [not-immediate](https://nuxt.com/docs/3.x/getting-started/data-fetching#not-immediate), and you can wait until the reactive element changes before fetching. ```vue <script setup lang="ts"> const id = ref(null) const { data, status } = useLazyFetch(() => `/api/users/${id.value}`, { immediate: false, }) const pending = computed(() => status.value === 'pending') </script> <template> <div> <!-- disable the input while fetching --> <input v-model="id" type="number" :disabled="pending" > <div v-if="status === 'idle'"> Type an user ID </div> <div v-else-if="pending"> Loading ... </div> <div v-else> {{ data }} </div> </div> </template> ``` If you need to force a refresh when other reactive values change, you can also [watch other values](https://nuxt.com/docs/3.x/getting-started/data-fetching#watch). ### Not immediate The `useFetch` composable will start fetching data the moment is invoked. You may prevent this by setting `immediate: false`, for example, to wait for user interaction. With that, you will need both the `status` to handle the fetch lifecycle, and `execute` to start the data fetch. ```vue <script setup lang="ts"> const { data, error, execute, status } = await useLazyFetch('/api/comments', { immediate: false, }) </script> <template> <div v-if="status === 'idle'"> <button @click="execute"> Get data </button> </div> <div v-else-if="status === 'pending'"> Loading comments... </div> <div v-else> {{ data }} </div> </template> ``` For finer control, the `status` variable can be: - `idle` when the fetch hasn't started - `pending` when a fetch has started but not yet completed - `error` when the fetch fails - `success` when the fetch is completed successfully ## Passing Headers and Cookies When we call `$fetch` in the browser, user headers like `cookie` will be directly sent to the API. Normally, during server-side-rendering, due to security considerations, the `$fetch` wouldn't include the user's browser cookies, nor pass on cookies from the fetch response. However, when calling `useFetch` with a relative URL on the server, Nuxt will use [`useRequestFetch`](https://nuxt.com/docs/3.x/api/composables/use-request-fetch) to proxy headers and cookies (with the exception of headers not meant to be forwarded, like `host`). ### Pass Cookies From Server-side API Calls on SSR Response If you want to pass on/proxy cookies in the other direction, from an internal request back to the client, you will need to handle this yourself. ```ts [composables/fetch.ts] import { appendResponseHeader } from 'h3' import type { H3Event } from 'h3' export const fetchWithCookie = async (event: H3Event, url: string) => { /* Get the response from the server endpoint */ const res = await $fetch.raw(url) /* Get the cookies from the response */ const cookies = res.headers.getSetCookie() /* Attach each cookie to our incoming Request */ for (const cookie of cookies) { appendResponseHeader(event, 'set-cookie', cookie) } /* Return the data of the response */ return res._data } ``` ```vue <script setup lang="ts"> // This composable will automatically pass cookies to the client const event = useRequestEvent() const { data: result } = await useAsyncData(() => fetchWithCookie(event!, '/api/with-cookie')) onMounted(() => console.log(document.cookie)) </script> ``` ## Options API Support Nuxt provides a way to perform `asyncData` fetching within the Options API. You must wrap your component definition within `defineNuxtComponent` for this to work. ```vue <script> export default defineNuxtComponent({ /* Use the fetchKey option to provide a unique key */ fetchKey: 'hello', async asyncData () { return { hello: await $fetch('/api/hello'), } }, }) </script> ``` <note> Using `<script setup>` or `<script setup lang="ts">` are the recommended way of declaring Vue components in Nuxt. </note> <read-more to="https://nuxt.com/docs/3.x/api/utils/define-nuxt-component"> </read-more> ## Serializing Data From Server to Client When using `useAsyncData` and `useLazyAsyncData` to transfer data fetched on server to the client (as well as anything else that utilizes [the Nuxt payload](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#payload)), the payload is serialized with [`devalue`](https://github.com/sveltejs/devalue). This allows us to transfer not just basic JSON but also to serialize and revive/deserialize more advanced kinds of data, such as regular expressions, Dates, Map and Set, `ref`, `reactive`, `shallowRef`, `shallowReactive` and `NuxtError` - and more. It is also possible to define your own serializer/deserializer for types that are not supported by Nuxt. You can read more in the [`useNuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app#payload) docs. <note> Note that this *does not apply* to data passed from your server routes when fetched with `$fetch` or `useFetch` - see the next section for more information. </note> ## Serializing Data From API Routes When fetching data from the `server` directory, the response is serialized using `JSON.stringify`. However, since serialization is limited to only JavaScript primitive types, Nuxt does its best to convert the return type of `$fetch` and [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) to match the actual value. <read-more to="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description" icon="i-simple-icons-mdnwebdocs" target="_blank"> Learn more about `JSON.stringify` limitations. </read-more> ### Example ```ts [server/api/foo.ts] export default defineEventHandler(() => { return new Date() }) ``` ```vue [app.vue] <script setup lang="ts"> // Type of `data` is inferred as string even though we returned a Date object const { data } = await useFetch('/api/foo') </script> ``` ### Custom serializer function To customize the serialization behavior, you can define a `toJSON` function on your returned object. If you define a `toJSON` method, Nuxt will respect the return type of the function and will not try to convert the types. ```ts [server/api/bar.ts] export default defineEventHandler(() => { const data = { createdAt: new Date(), toJSON () { return { createdAt: { year: this.createdAt.getFullYear(), month: this.createdAt.getMonth(), day: this.createdAt.getDate(), }, } }, } return data }) ``` ```vue [app.vue] <script setup lang="ts"> // Type of `data` is inferred as // { // createdAt: { // year: number // month: number // day: number // } // } const { data } = await useFetch('/api/bar') </script> ``` ### Using an alternative serializer Nuxt does not currently support an alternative serializer to `JSON.stringify`. However, you can return your payload as a normal string and utilize the `toJSON` method to maintain type safety. In the example below, we use [superjson](https://github.com/flightcontrolhq/superjson) as our serializer. ```ts [server/api/superjson.ts] import superjson from 'superjson' export default defineEventHandler(() => { const data = { createdAt: new Date(), // Workaround the type conversion toJSON () { return this }, } // Serialize the output to string, using superjson return superjson.stringify(data) as unknown as typeof data }) ``` ```vue [app.vue] <script setup lang="ts"> import superjson from 'superjson' // `date` is inferred as { createdAt: Date } and you can safely use the Date object methods const { data } = await useFetch('/api/superjson', { transform: (value) => { return superjson.parse(value as unknown as string) }, }) </script> ``` ## Recipes ### Consuming SSE (Server-Sent Events) via POST request <tip> If you're consuming SSE via GET request, you can use [`EventSource`](https://developer.mozilla.org/en-US/docs/Web/API/EventSource) or VueUse composable [`useEventSource`](https://vueuse.org/core/useeventsource/). </tip> When consuming SSE via POST request, you need to handle the connection manually. Here's how you can do it: ```ts // Make a POST request to the SSE endpoint const response = await $fetch<ReadableStream>('/chats/ask-ai', { method: 'POST', body: { query: 'Hello AI, how are you?', }, responseType: 'stream', }) // Create a new ReadableStream from the response with TextDecoderStream to get the data as text const reader = response.pipeThrough(new TextDecoderStream()).getReader() // Read the chunk of data as we get it while (true) { const { value, done } = await reader.read() if (done) { break } console.log('Received:', value) } ``` ### Making parallel requests When requests don't rely on each other, you can make them in parallel with `Promise.all()` to boost performance. ```ts const { data } = await useAsyncData((_nuxtApp, { signal }) => { return Promise.all([ $fetch('/api/comments/', { signal }), $fetch('/api/author/12', { signal }), ]) }) const comments = computed(() => data.value?.[0]) const author = computed(() => data.value?.[1]) ``` <video-accordion title="Watch a video from Vue School on parallel data fetching" video-id="1024262536" platform="vimeo"> </video-accordion> # Deployment > Learn how to deploy your Nuxt application to any hosting provider. A Nuxt application can be deployed on a Node.js server, pre-rendered for static hosting, or deployed to serverless or edge (CDN) environments. <tip> If you are looking for a list of cloud providers that support Nuxt, see the [Hosting providers](https://nuxt.com/deploy) section. </tip> ## Node.js Server Discover the Node.js server preset with Nitro to deploy on any Node hosting. - **Default output format** if none is specified or auto-detected <br /> - Loads only the required chunks to render the request for optimal cold start timing <br /> - Useful for deploying Nuxt apps to any Node.js hosting ### Entry Point When running `nuxt build` with the Node server preset, the result will be an entry point that launches a ready-to-run Node server. ```bash [Terminal] NODE_ENV=production node .output/server/index.mjs ``` This will launch your production Nuxt server that listens on port 3000 by default. <important> Set `NODE_ENV=production` when running the server. Some dependencies (notably Vue Router) only strip development-only warnings when this is set, so leaving it unset can flood your logs with messages like `[Vue Router warn]: No match found for location with path โ€ฆ` on unmatched routes. </important> It respects the following runtime environment variables: - `NITRO_PORT` or `PORT` (defaults to `3000`) - `NITRO_HOST` or `HOST` (defaults to `'0.0.0.0'`) - `NITRO_SSL_CERT` and `NITRO_SSL_KEY` - if both are present, this will launch the server in HTTPS mode. In the vast majority of cases, this should not be used other than for testing, and the Nitro server should be run behind a reverse proxy like nginx or Cloudflare which terminates SSL. ### PM2 [PM2](https://pm2.keymetrics.io/) (Process Manager 2) is a fast and easy solution for hosting your Nuxt application on your server or VM. To use `pm2`, use an `ecosystem.config.cjs`: ```ts [ecosystem.config.cjs] module.exports = { apps: [ { name: 'NuxtAppName', port: '3000', exec_mode: 'cluster', instances: 'max', script: './.output/server/index.mjs', env: { NODE_ENV: 'production', }, }, ], } ``` ### Cluster Mode You can use `NITRO_PRESET=node_cluster` in order to leverage multi-process performance using Node.js [cluster](https://nodejs.org/dist/latest/docs/api/cluster.html) module. By default, the workload gets distributed to the workers with the round robin strategy. ### Learn More <read-more to="https://nitro.build/deploy/runtimes/node" title="the Nitro documentation for node-server preset"> </read-more> <video-accordion title="Watch Daniel Roe's short video on the topic" video-id="0x1H6K5yOfs"> </video-accordion> ## Static Hosting There are two ways to deploy a Nuxt application to any static hosting services: - Static site generation (SSG) with `ssr: true` pre-renders routes of your application at build time. (This is the default behavior when running `nuxt generate`.) It will also generate `/200.html` and `/404.html` single-page app fallback pages, which can render dynamic routes or 404 errors on the client (though you may need to configure this on your static host). - Alternatively, you can prerender your site with `ssr: false` (static single-page app). This will produce HTML pages with an empty `<div id="__nuxt"></div>` where your Vue app would normally be rendered. You will lose many SEO benefits of prerendering your site, so it is suggested instead to use [`<ClientOnly>`](https://nuxt.com/docs/3.x/api/components/client-only) to wrap the portions of your site that cannot be server rendered (if any). <read-more to="https://nuxt.com/docs/3.x/getting-started/prerendering" title="Nuxt prerendering"> </read-more> ### Client-side Only Rendering If you don't want to pre-render your routes, another way of using static hosting is to set the `ssr` property to `false` in the `nuxt.config` file. The `nuxt generate` command will then output an `.output/public/index.html` entrypoint and JavaScript bundles like a classic client-side Vue.js application. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ ssr: false, }) ``` ## Hosting Providers Nuxt can be deployed to several cloud providers with a minimal amount of configuration: <read-more to="https://nuxt.com/deploy"> </read-more> ## Presets In addition to Node.js servers and static hosting services, a Nuxt project can be deployed with several well-tested presets and minimal amount of configuration. You can explicitly set the desired preset in the [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { preset: 'node-server', }, }) ``` ... or use the `NITRO_PRESET` environment variable when running `nuxt build`: ```bash [Terminal] NITRO_PRESET=node-server nuxt build ``` ๐Ÿ”Ž Check [the Nitro deployment](https://nitro.build/deploy) for all possible deployment presets and providers. ## CDN Proxy In most cases, Nuxt can work with third-party content that is not generated or created by Nuxt itself. But sometimes such content can cause problems, especially Cloudflare's "Minification and Security Options". Accordingly, you should make sure that the following options are unchecked / disabled in Cloudflare. Otherwise, unnecessary re-rendering or hydration errors could impact your production application. 1. Speed > Settings > Content Optimization > Disable "Rocket Loaderโ„ข" 2. Security > Settings > Disable "Email Address Obfuscation" With these settings, you can be sure that Cloudflare won't inject scripts into your Nuxt application that may cause unwanted side effects. <tip> Their location on the Cloudflare dashboard sometimes changes so don't hesitate to look around. </tip> # Error Handling > Learn how to catch and handle errors in Nuxt. Nuxt is a full-stack framework, which means there are several sources of unpreventable user runtime errors that can happen in different contexts: - Errors during the Vue rendering lifecycle (SSR & CSR) - Server and client startup errors (SSR + CSR) - Errors during Nitro server lifecycle ([`server/`](https://nuxt.com/docs/3.x/directory-structure/server) directory) - Errors downloading JS chunks <tip> **SSR** stands for **Server-Side Rendering** and **CSR** for **Client-Side Rendering**. </tip> ## Vue Errors You can hook into Vue errors using [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured). In addition, Nuxt provides a [`vue:error`](https://nuxt.com/docs/3.x/api/advanced/hooks#app-hooks-runtime) hook that will be called if any errors propagate up to the top level. If you are using an error reporting framework, you can provide a global handler through [`vueApp.config.errorHandler`](https://vuejs.org/api/application#app-config-errorhandler). It will receive all Vue errors, even if they are handled. ```ts [plugins/error-handler.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.vueApp.config.errorHandler = (error, instance, info) => { // handle error, e.g. report to a service } // Also possible nuxtApp.hook('vue:error', (error, instance, info) => { // handle error, e.g. report to a service }) }) ``` <note> Note that the `vue:error` hook is based on [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) lifecycle hook. </note> ## Startup Errors Nuxt will call the `app:error` hook if there are any errors in starting your Nuxt application. This includes: - running [Nuxt plugins](https://nuxt.com/docs/3.x/directory-structure/plugins) - processing `app:created` and `app:beforeMount` hooks - rendering your Vue app to HTML (during SSR) - mounting the app (on client-side), though you should handle this case with `onErrorCaptured` or with `vue:error` - processing the `app:mounted` hook ## Nitro Server Errors You cannot currently define a server-side handler for these errors, but can render an error page, see the [Render an Error Page](https://nuxt.com/docs/3.x/getting-started/error-handling#error-page) section. ## Errors with JS Chunks You might encounter chunk loading errors due to a network connectivity failure or a new deployment (which invalidates your old, hashed JS chunk URLs). Nuxt provides built-in support for handling chunk loading errors by performing a hard reload when a chunk fails to load during route navigation. You can change this behavior by setting `experimental.emitRouteChunkError` to `false` (to disable hooking into these errors at all) or to `manual` if you want to handle them yourself. If you want to handle chunk loading errors manually, you can check out the [the automatic implementation](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/plugins/chunk-reload.client.ts) for ideas. ## Error Page <note> When Nuxt encounters a fatal error (any unhandled error on the server, or an error created with `fatal: true` on the client) it will either render a JSON response (if requested with `Accept: application/json` header) or trigger a full-screen error page. </note> An error may occur during the server lifecycle when: - processing your Nuxt plugins - rendering your Vue app into HTML - a server API route throws an error It can also occur on the client side when: - processing your Nuxt plugins - before mounting the application (`app:beforeMount` hook) - mounting your app if the error was not handled with `onErrorCaptured` or `vue:error` hook - the Vue app is initialized and mounted in browser (`app:mounted`). <read-more to="https://nuxt.com/docs/3.x/api/advanced/hooks"> Discover all the Nuxt lifecycle hooks. </read-more> Customize the default error page by adding `~/error.vue` in the source directory of your application, alongside `app.vue`. ```vue [error.vue] <script setup lang="ts"> import type { NuxtError } from '#app' const props = defineProps({ error: Object as () => NuxtError, }) const handleError = () => clearError({ redirect: '/' }) </script> <template> <div> <h2>{{ error?.status }}</h2> <button @click="handleError"> Clear errors </button> </div> </template> ``` <read-more to="https://nuxt.com/docs/3.x/directory-structure/error"> Read more about `error.vue` and its uses. </read-more> For custom errors we highly recommend using `onErrorCaptured` composable that can be called in a page/component setup function or `vue:error` runtime nuxt hook that can be configured in a nuxt plugin. ```ts [plugins/error-handler.ts]twoslash export default defineNuxtPlugin((nuxtApp) => { nuxtApp.hook('vue:error', (err) => { // }) }) ``` When you are ready to remove the error page, you can call the [`clearError`](https://nuxt.com/docs/3.x/api/utils/clear-error) helper function, which takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page). <important> Make sure to check before using anything dependent on Nuxt plugins, such as `$route` or `useRouter`, as if a plugin threw an error, then it won't be re-run until you clear the error. </important> <note> Rendering an error page is an entirely separate page load, meaning any registered middleware will run again. You can use [`useError`](https://nuxt.com/docs/3.x/getting-started/error-handling#useerror) in middleware to check if an error is being handled. </note> <note> If you are running on Node 16 and you set any cookies when rendering your error page, they will [overwrite cookies previously set](https://github.com/nuxt/nuxt/pull/20585). We recommend using a newer version of Node as Node 16 reached end-of-life in September 2023. </note> ## Error Utils ### `useError` ```ts [TS Signature] function useError (): Ref<Error | { url, status, statusText, message, description, data }> ``` This function will return the global Nuxt error that is being handled. <read-more to="https://nuxt.com/docs/3.x/api/composables/use-error"> Read more about `useError` composable. </read-more> ### `createError` ```ts [TS Signature] function createError (err: string | { cause, data, message, name, stack, status, statusText, fatal }): Error ``` Create an error object with additional metadata. You can pass a string to be set as the error `message` or an object containing error properties. It is usable in both the Vue and Server portions of your app, and is meant to be thrown. If you throw an error created with `createError`: - on server-side, it will trigger a full-screen error page which you can clear with [`clearError`](https://nuxt.com/docs/3.x/getting-started/error-handling#clearerror). - on client-side, it will throw a non-fatal error for you to handle. If you need to trigger a full-screen error page, then you can do this by setting `fatal: true`. ```vue [pages/movies/[slug].vue]twoslash <script setup lang="ts"> const route = useRoute() const { data } = await useFetch(`/api/movies/${route.params.slug}`) if (!data.value) { throw createError({ status: 404, statusText: 'Page Not Found', }) } </script> ``` <tip> The `statusText` property is intended for short, HTTP-compliant status texts (e.g., "Not Found"). It should only contain horizontal tabs, spaces, and visible ASCII characters (`[\t\u0020-\u007E]`). For any detailed descriptions, multi-line messages, or content with non-ASCII characters, you should always use the `message` property instead. </tip> <read-more to="https://nuxt.com/docs/3.x/api/utils/create-error"> Read more about `createError` util. </read-more> ### `showError` ```ts [TS Signature] function showError (err: string | Error | { status, statusText }): Error ``` You can call this function at any point on client-side, or (on server side) directly within middleware, plugins or `setup()` functions. It will trigger a full-screen error page which you can clear with [`clearError`](https://nuxt.com/docs/3.x/getting-started/error-handling#clearerror). It is recommended instead to use `throw createError()`. <read-more to="https://nuxt.com/docs/3.x/api/utils/show-error"> Read more about `showError` util. </read-more> ### `clearError` ```ts [TS Signature] function clearError (options?: { redirect?: string }): Promise<void> ``` This function will clear the currently handled Nuxt error. It also takes an optional path to redirect to (for example, if you want to navigate to a 'safe' page). <read-more to="https://nuxt.com/docs/3.x/api/utils/clear-error"> Read more about `clearError` util. </read-more> ## Render Error in Component Nuxt also provides a [`<NuxtErrorBoundary>`](https://nuxt.com/docs/3.x/api/components/nuxt-error-boundary) component that allows you to handle client-side errors within your app, without replacing your entire site with an error page. This component is responsible for handling errors that occur within its default slot. On client-side, it will prevent the error from bubbling up to the top level, and will render the `#error` slot instead. The `#error` slot will receive `error` as a prop. (If you set `error = null` it will trigger re-rendering the default slot; you'll need to ensure that the error is fully resolved first or the error slot will just be rendered a second time.) <tip> If you navigate to another route, the error will be cleared automatically. </tip> ```vue [pages/index.vue] <template> <!-- some content --> <NuxtErrorBoundary @error="someErrorLogger"> <!-- You use the default slot to render your content --> <template #error="{ error, clearError }"> You can display the error locally here: {{ error }} <button @click="clearError"> This will clear the error. </button> </template> </NuxtErrorBoundary> </template> ``` <link-example to="https://nuxt.com/docs/3.x/examples/advanced/error-handling"> </link-example> # Installation > Get started with Nuxt quickly with our online starters or start locally with your terminal. ## Play Online If you just want to play around with Nuxt in your browser without setting up a project, you can use this online sandbox: <card-group> <card color="info" icon="i-simple-icons-stackblitz" target="_blank" title="Open on StackBlitz" to="https://stackblitz.com/github/nuxt/starter?file=app%2Fapp.vue"> Online playground with code editor and terminal access. </card> </card-group> ## New Project <steps> ### Prerequisites - **Node.js** - [`22.x`](https://nodejs.org/en) or newer (but we recommend the [active LTS release](https://github.com/nodejs/release#release-schedule)) - **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box. If you use another editor, such as Neovim, you can configure [Vue Language Server](https://github.com/vuejs/language-tools) support by following the [Vue Language Tools setup guides](https://github.com/vuejs/language-tools/wiki). - **Terminal** - In order to run Nuxt commands <callout> <collapsible name="additional notes for an optimal setup"> - **Node.js**: Make sure to use an even numbered version (22, 24, etc.) - **Neovim**: When configuring the Vue TypeScript plugin, make sure `location` points to the `@vue/language-server` package directory, not its binary. See the [Neovim setup guide](https://github.com/vuejs/language-tools/wiki/Neovim) for a working configuration. - **WSL**: If you are using Windows and experience slow HMR, you may want to try using [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install) which may solve some performance issues. - **Windows slow DNS resolution**: Instead of using `localhost:3000` for local dev server on Windows, use `127.0.0.1` for much faster loading experience on browsers. </collapsible> </callout> ### Create a New Project Open a terminal (if you're using [Visual Studio Code](https://code.visualstudio.com), you can open an [integrated terminal](https://code.visualstudio.com/docs/terminal/basics)) and use the following command to create a new starter project: <code-group sync="pm"> ```bash [npm] npm create nuxt@latest <project-name> -- -t v3 ``` ```bash [yarn] yarn create nuxt <project-name> -t v3 ``` ```bash [pnpm] pnpm create nuxt@latest <project-name> -t v3 ``` ```bash [bun] # you can use this when https://github.com/oven-sh/bun/issues/29087 is resolved # bun create nuxt@latest <project-name> -t v3 bunx create-nuxt@latest init <project-name> -t v3 ``` ```bash [deno] deno -A npm:create-nuxt@latest <project-name> -t v3 ``` </code-group> Open your project folder in Visual Studio Code: ```bash [Terminal] code <project-name> ``` Or change directory into your new project from your terminal: ```bash cd <project-name> ``` ### Development Server Now you'll be able to start your Nuxt app in development mode: <code-group sync="pm"> ```bash [npm] npm run dev -- -o ``` ```bash [yarn] yarn dev --open ``` ```bash [pnpm] pnpm dev -o ``` ```bash [bun] bun run dev -o # To use the Bun runtime during development # bun --bun run dev -o ``` ```bash [deno] deno run dev -o ``` </code-group> <tip icon="i-lucide-circle-check"> Well done! A browser window should automatically open for [http://localhost:3000](http://localhost:3000). </tip> </steps> ## Next Steps Now that you've created your Nuxt project, you are ready to start building your application. <read-more title="Nuxt Concepts" to="https://nuxt.com/docs/3.x/guide/concepts"> </read-more> # Introduction > Nuxt's goal is to make web development intuitive and performant with a great Developer Experience in mind. Nuxt is a free and [open-source framework](https://github.com/nuxt/nuxt) with an intuitive and extendable way to create type-safe, performant and production-grade full-stack web applications and websites with [Vue.js](https://vuejs.org). We made everything so you can start writing `.vue` files from the beginning while enjoying hot module replacement in development and a performant application in production with server-side rendering by default. Nuxt has no vendor lock-in, allowing you to deploy your application [**everywhere, even on the edge**](https://nuxt.com/blog/nuxt-on-the-edge). <tip> If you want to play around with Nuxt in your browser, you can [try it out in one of our online sandboxes](https://nuxt.com/docs/3.x/getting-started/installation#play-online). </tip> ## Automation and Conventions Nuxt uses conventions and an opinionated directory structure to automate repetitive tasks and allow developers to focus on pushing features. The configuration file can still customize and override its default behaviors. - **File-based routing:** define routes based on the structure of your [`pages/` directory](https://nuxt.com/docs/3.x/directory-structure/pages). This can make it easier to organize your application and avoid the need for manual route configuration. - **Code splitting:** Nuxt automatically splits your code into smaller chunks, which can help reduce the initial load time of your application. - **Server-side rendering out of the box:** Nuxt comes with built-in SSR capabilities, so you don't have to set up a separate server yourself. - **Auto-imports:** write Vue composables and components in their respective directories and use them without having to import them with the benefits of tree-shaking and optimized JS bundles. - **Data-fetching utilities:** Nuxt provides composables to handle SSR-compatible data fetching as well as different strategies. - **Zero-config TypeScript support:** write type-safe code without having to learn TypeScript with our auto-generated types and `tsconfig.json`. - **Configured build tools:** we use [Vite](https://vite.dev) by default to support hot module replacement (HMR) in development and bundling your code for production with best-practices baked-in. Nuxt takes care of these and provides both frontend and backend functionality so you can focus on what matters: **creating your web application**. ## Server-Side Rendering Nuxt comes with built-in server-side rendering (SSR) capabilities by default, without having to configure a server yourself, which has many benefits for web applications: - **Faster initial page load time:** Nuxt sends a fully rendered HTML page to the browser, which can be displayed immediately. This can provide a faster perceived page load time and a better user experience (UX), especially on slower networks or devices. - **Improved SEO:** search engines can better index SSR pages because the HTML content is available immediately, rather than requiring JavaScript to render the content on the client-side. - **Better performance on low-powered devices:** it reduces the amount of JavaScript that needs to be downloaded and executed on the client-side, which can be beneficial for low-powered devices that may struggle with processing heavy JavaScript applications. - **Better accessibility:** the content is immediately available on the initial page load, improving accessibility for users who rely on screen readers or other assistive technologies. - **Easier caching:** pages can be cached on the server-side, which can further improve performance by reducing the amount of time it takes to generate and send the content to the client. Overall, server-side rendering can provide a faster and more efficient user experience, as well as improve search engine optimization and accessibility. As Nuxt is a versatile framework, it gives you the possibility to statically render your whole application to a static hosting with `nuxt generate`, disable SSR globally with the `ssr: false` option or leverage hybrid rendering by setting up the `routeRules` option. <read-more title="Nuxt rendering modes" to="https://nuxt.com/docs/3.x/guide/concepts/rendering"> </read-more> ### Server engine The Nuxt server engine [Nitro](https://nitro.build/) unlocks new full-stack capabilities. In development, it uses Rollup and Node.js workers for your server code and context isolation. It also generates your server API by reading files in `server/api/` and server middleware from `server/middleware/`. In production, Nitro builds your app and server into one universal `.output` directory. This output is light: minified and removed from any Node.js modules (except polyfills). You can deploy this output on any system supporting JavaScript, from Node.js, Serverless, Workers, Edge-side rendering or purely static. <read-more title="Nuxt server engine" to="https://nuxt.com/docs/3.x/guide/concepts/server-engine"> </read-more> ### Production-ready A Nuxt application can be deployed on a Node or Deno server, pre-rendered to be hosted in static environments, or deployed to serverless and edge providers. <read-more title="Deployment section" to="https://nuxt.com/docs/3.x/getting-started/deployment"> </read-more> ### Modular A module system allows you to extend Nuxt with custom features and integrations with third-party services. <read-more title="Nuxt Modules Concept" to="https://nuxt.com/docs/3.x/guide/concepts/modules"> </read-more> ### Architecture Nuxt is composed of different [core packages](https://github.com/nuxt/nuxt/tree/main/packages): - Core engine: [nuxt](https://github.com/nuxt/nuxt/tree/main/packages/nuxt) - Bundlers: [@nuxt/vite-builder](https://github.com/nuxt/nuxt/tree/main/packages/vite), [@nuxt/rspack-builder](https://github.com/nuxt/nuxt/tree/main/packages/rspack) and [@nuxt/webpack-builder](https://github.com/nuxt/nuxt/tree/main/packages/webpack) - Command line interface: [@nuxt/cli](https://github.com/nuxt/cli) - Server engine: [nitro](https://github.com/nitrojs/nitro) - Development kit: [@nuxt/kit](https://github.com/nuxt/nuxt/tree/main/packages/kit) We recommend reading each concept to have a full vision of Nuxt capabilities and the scope of each package. # Layers > Nuxt provides a powerful system that allows you to extend the default files, configs, and much more. One of the core features of Nuxt is the layers and extending support. You can extend a default Nuxt application to reuse components, utils, and configuration. The layers structure is almost identical to a standard Nuxt application which makes them easy to author and maintain. ## Use Cases - Share reusable configuration presets across projects using `nuxt.config` and `app.config` - Create a component library using [`components/`](https://nuxt.com/docs/3.x/directory-structure/components) directory - Create utility and composable library using [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables) and [`utils/`](https://nuxt.com/docs/3.x/directory-structure/utils) directories - Create Nuxt module presets - Share standard setup across projects - Create Nuxt themes - Enhance code organization by implementing a modular architecture and support Domain-Driven Design (DDD) pattern in large scale projects. ## Usage By default, any layers within your project in the `~~/layers` directory will be automatically registered as layers in your project. <note> Layer auto-registration was introduced in Nuxt v3.12.0. </note> In addition, named layer aliases to the `srcDir` of each of these layers will automatically be created. For example, you will be able to access the `~~/layers/test` layer via `#layers/test`. <note> Named layer aliases were introduced in Nuxt v3.16.0. </note> In addition, you can extend from a layer by adding the [extends](https://nuxt.com/docs/3.x/api/nuxt-config#extends) property to your [`nuxt.config`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ // Extend from a local layer '../base', // Extend from an installed npm package '@my-themes/awesome', // Extend from a git repository 'github:my-themes/awesome#v1', ], }) ``` You can also pass an authentication token if you are extending from a private GitHub repository: ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ // per layer configuration ['github:my-themes/private-awesome', { auth: process.env.GITHUB_TOKEN }], ], }) ``` <note> If a branch is not specified, this will clone `main`. </note> <tip> You can override a layer's alias by specifying it in the options next to the layer source. ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ [ 'github:my-themes/awesome', { meta: { name: 'my-awesome-theme', }, }, ], ], }) ``` </tip> Nuxt uses [unjs/c12](https://github.com/unjs/c12) and [unjs/giget](https://github.com/unjs/giget) for extending remote layers. Check the documentation for more information and all available options. ## Layer Priority When using multiple layers, it's important to understand the override order. Layers with **higher priority** override layers with lower priority when they define the same files or components. ### Priority Order From highest to lowest priority: 1. **Your project files** - always have the highest priority 2. **Auto-scanned layers** from `~~/layers` directory - sorted alphabetically (Z has higher priority than A) 3. **Layers in extends** config - first entry has higher priority than second ### Practical Example Consider multiple layers defining the same component: ```bash [Directory structure] layers/ 1.base/ components/Button.vue # Base button style 2.theme/ components/Button.vue # Themed button (overrides base) app/ components/Button.vue # Project button (overrides all layers) ``` In this case: - If only layers exist, `2.theme/Button.vue` is used (higher alphabetically) - If `components/Button.vue` exists in your project, it overrides all layers ### Controlling Priority You can prefix layer directories with numbers to control the order: ```bash [Directory structure] layers/ 1.base/ # Lowest priority 2.features/ # Medium priority 3.admin/ # Highest priority (among layers) ``` <tip> This pattern is useful for creating base layers with defaults that can be progressively overridden by more specific layers. </tip> ### When to Use Each - **~~/layers directory** - Use for local layers that are part of your project - **extends** - Use for external dependencies (npm packages, remote repositories) or layers outside your project directory ### Full Example with extends ```ts [nuxt.config.ts] export default defineNuxtConfig({ extends: [ '../base', // Local layer outside project '@my-themes/awesome', // NPM package 'github:my-themes/awesome#v1', // Remote repository ], }) ``` If you also have `~~/layers/custom`, the priority order is: - Your project files (highest) - `~~/layers/custom` - `../base` - `@my-themes/awesome` - `github:my-themes/awesome#v1` (lowest) <read-more to="https://nuxt.com/docs/3.x/directory-structure/layers"> Learn about the **layers/ directory** to organize and share reusable code, components, composables, and configurations across your Nuxt application. </read-more> <read-more to="https://nuxt.com/docs/3.x/guide/going-further/layers"> Read more about layers in the **Layer Author Guide**. </read-more> <video-accordion title="Watch a video from Learn Vue about Nuxt Layers" video-id="lnFCM7c9f7I"> </video-accordion> <video-accordion title="Watch a video from Alexander Lichter about Nuxt Layers" video-id="fr5yo3aVkfA"> </video-accordion> ## Examples <card-group> <card icon="i-simple-icons-github" target="_blank" title="Content Wind" to="https://github.com/Atinux/content-wind"> A lightweight Nuxt theme to build a Markdown driven website. Powered by Nuxt Content, TailwindCSS and Iconify. </card> </card-group> # Prerendering > Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics Nuxt allows for select pages from your application to be rendered at build time. Nuxt will serve the prebuilt pages when requested instead of generating them on the fly. <read-more to="https://nuxt.com/docs/3.x/guide/concepts/rendering" title="Nuxt rendering modes"> </read-more> ## Crawl-based Pre-rendering Use the [`nuxt generate` command](https://nuxt.com/docs/3.x/api/commands/generate) to build and pre-render your application using the [Nitro](https://nuxt.com/docs/3.x/guide/concepts/server-engine) crawler. This command is similar to `nuxt build` with the `nitro.static` option set to `true`, or running `nuxt build --prerender`. This will build your site, stand up a nuxt instance, and, by default, prerender the root page `/` along with any of your site's pages it links to, any of your site's pages they link to, and so on. <code-group sync="pm"> ```bash [npm] npx nuxt generate ``` ```bash [yarn] yarn nuxt generate ``` ```bash [pnpm] pnpm nuxt generate ``` ```bash [bun] bun x nuxt generate ``` ```bash [deno] deno x nuxt generate ``` </code-group> You can now deploy the `.output/public` directory to any static hosting service or preview it locally with `npx serve .output/public`. Working of the Nitro crawler: 1. Load the HTML of your application's root route (`/`), any non-dynamic pages in your `~/pages` directory, and any other routes in the `nitro.prerender.routes` array. 2. Save the HTML and `payload.json` to the `~/.output/public/` directory to be served statically. 3. Find all anchor tags (`<a href="...">`) in the HTML to navigate to other routes. 4. Repeat steps 1-3 for each anchor tag found until there are no more anchor tags to crawl. This is important to understand since pages that are not linked to a discoverable page can't be pre-rendered automatically. ### Payload Extraction Nuxt generates `_payload.json` alongside HTML for: - Prerendered routes (at build time) - ISR/SWR routes (on first request) Payloads contain serialized data from `useAsyncData` and `useFetch`. Client-side navigation loads these cached payloads instead of re-fetching data. Configure dynamic routes like `pages/[...slug].vue` with route rules: `'/**': { isr: true }`. <read-more to="https://nuxt.com/docs/3.x/api/commands/generate#nuxt-generate"> Read more about the `nuxt generate` command. </read-more> ### Selective Pre-rendering You can manually specify routes that [Nitro](https://nuxt.com/docs/3.x/guide/concepts/server-engine) will fetch and pre-render during the build or ignore routes that you don't want to pre-render like `/dynamic` in the `nuxt.config` file: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { prerender: { routes: ['/user/1', '/user/2'], ignore: ['/dynamic'], }, }, }) ``` You can combine this with the `crawlLinks` option to pre-render a set of routes that the crawler can't discover like your `/sitemap.xml` or `/robots.txt`: ```ts [nuxt.config.ts]twoslash // @errors: 2353 export default defineNuxtConfig({ nitro: { prerender: { crawlLinks: true, routes: ['/sitemap.xml', '/robots.txt'], }, }, }) ``` Setting `nitro.prerender` to `true` is similar to `nitro.prerender.crawlLinks` to `true`. <read-more to="https://nitro.build/config#prerender"> Read more about pre-rendering in the Nitro documentation. </read-more> Lastly, you can manually configure this using routeRules. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Set prerender to true to configure it to be prerendered '/rss.xml': { prerender: true }, // Set it to false to configure it to be skipped for prerendering '/this-DOES-NOT-get-prerendered': { prerender: false }, // Everything under /blog gets prerendered as long as it // is linked to from another page '/blog/**': { prerender: true }, }, }) ``` <read-more to="https://nitro.build/config#routerules"> Read more about Nitro's `routeRules` configuration. </read-more> As a shorthand, you can also configure this in a page file using [`defineRouteRules`](https://nuxt.com/docs/3.x/api/utils/define-route-rules). <read-more to="https://nuxt.com/docs/3.x/guide/going-further/experimental-features#inlinerouterules" icon="i-lucide-star"> This feature is experimental and in order to use it you must enable the `experimental.inlineRouteRules` option in your `nuxt.config`. </read-more> ```vue [pages/index.vue] <script setup> // Or set at the page level defineRouteRules({ prerender: true, }) </script> <template> <div> <h1>Homepage</h1> <p>Pre-rendered at build time</p> </div> </template> ``` This will be translated to: ```ts [nuxt.config.ts] export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, }) ``` ## Runtime Prerender Configuration ### `prerenderRoutes` You can use this at runtime within a [Nuxt context](https://nuxt.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context) to add more routes for Nitro to prerender. ```vue [pages/index.vue] <script setup> prerenderRoutes(['/some/other/url']) prerenderRoutes('/api/content/article/my-article') </script> <template> <div> <h1>This will register other routes for prerendering when prerendered</h1> </div> </template> ``` <read-more to="https://nuxt.com/docs/3.x/api/utils/prerender-routes" title="prerenderRoutes"> </read-more> ### `prerender:routes` Nuxt hook This is called before prerendering for additional routes to be registered. ```ts [nuxt.config.ts] export default defineNuxtConfig({ hooks: { async 'prerender:routes' (ctx) { const { pages } = await fetch('https://api.some-cms.com/pages').then( res => res.json(), ) for (const page of pages) { ctx.routes.add(`/${page.name}`) } }, }, }) ``` ### `prerender:generate` Nitro hook This is called for each route during prerendering. You can use this for fine-grained handling of each route that gets prerendered. ```ts [nuxt.config.ts] export default defineNuxtConfig({ nitro: { hooks: { 'prerender:generate' (route) { if (route.route?.includes('private')) { route.skip = true } }, }, }, }) ``` # Routing > Nuxt file-system routing creates a route for every file in the pages/ directory. One core feature of Nuxt is the file system router. Every Vue file inside the [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory creates a corresponding URL (or route) that displays the contents of the file. By using dynamic imports for each page, Nuxt leverages code-splitting to ship the minimum amount of JavaScript for the requested route. ## Pages Nuxt routing is based on [vue-router](https://router.vuejs.org) and generates the routes from every component created in the [`pages/` directory](https://nuxt.com/docs/3.x/directory-structure/pages), based on their filename. This file system routing uses naming conventions to create dynamic and nested routes: <code-group> ```bash [Directory Structure] -| pages/ ---| about.vue ---| index.vue ---| posts/ -----| [id].vue ``` ```json [Generated Router File] { "routes": [ { "path": "/about", "component": "pages/about.vue" }, { "path": "/", "component": "pages/index.vue" }, { "path": "/posts/:id", "component": "pages/posts/[id].vue" } ] } ``` </code-group> <read-more to="https://nuxt.com/docs/3.x/directory-structure/pages"> </read-more> ## Navigation The [`<NuxtLink>`](https://nuxt.com/docs/3.x/api/components/nuxt-link) component links pages between them. It renders an `<a>` tag with the `href` attribute set to the route of the page. Once the application is hydrated, page transitions are performed in JavaScript by updating the browser URL. This prevents full-page refreshes and allows for animated transitions. When a [`<NuxtLink>`](https://nuxt.com/docs/3.x/api/components/nuxt-link) enters the viewport on the client side, Nuxt will automatically prefetch components and payload (generated pages) of the linked pages ahead of time, resulting in faster navigation. ```vue [pages/index.vue] <template> <header> <nav> <ul> <li><NuxtLink to="/about">About</NuxtLink></li> <li><NuxtLink to="/posts/1">Post 1</NuxtLink></li> <li><NuxtLink to="/posts/2">Post 2</NuxtLink></li> </ul> </nav> </header> </template> ``` <read-more to="https://nuxt.com/docs/3.x/api/components/nuxt-link"> </read-more> ## Route Parameters The [`useRoute()`](https://nuxt.com/docs/3.x/api/composables/use-route) composable can be used in a `<script setup>` block or a `setup()` method of a Vue component to access the current route details. ```vue [pages/posts/[id].vue]twoslash <script setup lang="ts"> const route = useRoute() // When accessing /posts/1, route.params.id will be 1 console.log(route.params.id) </script> ``` <read-more to="https://nuxt.com/docs/3.x/api/composables/use-route"> </read-more> ## Route Middleware Nuxt provides a customizable route middleware framework you can use throughout your application, ideal for extracting code that you want to run before navigating to a particular route. <note> Route middleware runs within the Vue part of your Nuxt app. Despite the similar name, they are completely different from server middleware, which are run in the Nitro server part of your app. </note> <important> Route middleware does **not** run for server routes (e.g. `/api/*`) or other server requests. To apply middleware to these requests, use [server middleware](https://nuxt.com/docs/3.x/directory-structure/server#server-middleware) instead. </important> There are three kinds of route middleware: 1. Anonymous (or inline) route middleware, which are defined directly in the pages where they are used. 2. Named route middleware, which are placed in the [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/middleware) directory and will be automatically loaded via asynchronous import when used on a page. (**Note**: The route middleware name is normalized to kebab-case, so `someMiddleware` becomes `some-middleware`.) 3. Global route middleware, which are placed in the [`middleware/`](https://nuxt.com/docs/3.x/directory-structure/middleware) directory (with a `.global` suffix) and will be automatically run on every route change. Example of an `auth` middleware protecting the `/dashboard` page: <code-group> ```ts [middleware/auth.ts]twoslash function isAuthenticated (): boolean { return false } // ---cut--- export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (isAuthenticated() === false) { return navigateTo('/login') } }) ``` ```vue [pages/dashboard.vue]twoslash <script setup lang="ts"> definePageMeta({ middleware: 'auth', }) </script> <template> <h1>Welcome to your dashboard</h1> </template> ``` </code-group> <read-more to="https://nuxt.com/docs/3.x/directory-structure/middleware"> </read-more> ## Route Validation Nuxt offers route validation via the `validate` property in [`definePageMeta()`](https://nuxt.com/docs/3.x/api/utils/define-page-meta) in each page you wish to validate. The `validate` property accepts the `route` as an argument. You can return a boolean value to determine whether or not this is a valid route to be rendered with this page. If you return `false`, this will cause a 404 error. You can also directly return an object with `status`/`statusText` to customize the error returned. If you have a more complex use case, then you can use anonymous route middleware instead. ```vue [pages/posts/[id].vue]twoslash <script setup lang="ts"> definePageMeta({ validate (route) { // Check if the id is made up of digits return typeof route.params.id === 'string' && /^\d+$/.test(route.params.id) }, }) </script> ``` <read-more to="https://nuxt.com/docs/3.x/api/utils/define-page-meta"> </read-more> # SEO and Meta > Improve your Nuxt app's SEO with powerful head config, composables and components. Nuxt head tag management is powered by [Unhead](https://unhead.unjs.io). It provides sensible defaults, several powerful composables and numerous configuration options to manage your app's head and SEO meta tags. ## Nuxt Config Providing an [`app.head`](https://nuxt.com/docs/3.x/api/nuxt-config#head) property in your [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) allows you to statically customize the head for your entire app. <important> This method does not allow you to provide reactive data. We recommend using `useHead()` in `app.vue`. </important> It's good practice to set tags here that won't change such as your site title default, language and favicon. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { title: 'Nuxt', // default fallback title htmlAttrs: { lang: 'en', }, link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }, ], }, }, }) ``` You can also provide any of the keys listed below in [Types](https://nuxt.com/docs/3.x/getting-started/seo-meta#types). ### Defaults Tags Some tags are provided by Nuxt by default to ensure your website works well out of the box. - `viewport`: `width=device-width, initial-scale=1` - `charset`: `utf-8` While most sites won't need to override these defaults, you can update them using the keyed shortcuts. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { // update Nuxt defaults charset: 'utf-16', viewport: 'width=device-width, initial-scale=1, maximum-scale=1', }, }, }) ``` ## `useHead` The [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable function supports reactive input, allowing you to manage your head tags programmatically. ```vue [app.vue]twoslash <script setup lang="ts"> useHead({ title: 'My App', meta: [ { name: 'description', content: 'My amazing site.' }, ], bodyAttrs: { class: 'test', }, script: [{ innerHTML: 'console.log(\'Hello world\')' }], }) </script> ``` We recommend taking a look at the [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) and [`useHeadSafe`](https://nuxt.com/docs/3.x/api/composables/use-head-safe) composables. ## `useSeoMeta` The [`useSeoMeta`](https://nuxt.com/docs/3.x/api/composables/use-seo-meta) composable lets you define your site's SEO meta tags as an object with full type safety. This helps you avoid typos and common mistakes, such as using `name` instead of `property`. ```vue [app.vue]twoslash <script setup lang="ts"> useSeoMeta({ title: 'My Amazing Site', ogTitle: 'My Amazing Site', description: 'This is my amazing site, let me tell you all about it.', ogDescription: 'This is my amazing site, let me tell you all about it.', ogImage: 'https://example.com/image.png', twitterCard: 'summary_large_image', }) </script> ``` <read-more to="https://nuxt.com/docs/3.x/api/composables/use-seo-meta"> </read-more> ## Components While using [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) is recommended in all cases, you may have a personal preference for defining your head tags in your template using components. Nuxt provides the following components for this purpose: `<Title>`, `<Base>`, `<NoScript>`, `<Style>`, `<Meta>`, `<Link>`, `<Body>`, `<Html>` and `<Head>`. Note the capitalization of these components ensuring we don't use invalid native HTML tags. `<Head>` and `<Body>` can accept nested meta tags (for aesthetic reasons) but this does not affect *where* the nested meta tags are rendered in the final HTML. ```vue [app.vue] <script setup lang="ts"> const title = ref('Hello World') </script> <template> <div> <Head> <Title>{{ title }}

{{ title }}

``` It's suggested to wrap your components in either a `` or `` components as tags will be deduped more intuitively. If you need to duplicate tags across client-server boundaries, apply a `key` attribute on the `` component. ## Types Below are the non-reactive types used for [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head), [`app.head`](https://nuxt.com/docs/3.x/api/nuxt-config#head) and components. ```ts interface MetaObject { title?: string titleTemplate?: string | ((title?: string) => string) templateParams?: Record> base?: Base link?: Link[] meta?: Meta[] style?: Style[] script?: Script[] noscript?: Noscript[] htmlAttrs?: HtmlAttributes bodyAttrs?: BodyAttributes } ``` See [@unhead/vue](https://github.com/unjs/unhead/blob/main/packages/vue/src/types/schema.ts) for more detailed types. ## Features ### Reactivity Reactivity is supported on all properties, by providing a computed value, a getter, or a reactive object. ```vue [useHead]twoslash ``` ```vue [useSeoMeta]twoslash ``` ```vue [Components] ``` ### Title Template You can use the `titleTemplate` option to provide a dynamic template for customizing the title of your site. For example, you could add the name of your site to the title of every page. The `titleTemplate` can either be a string, where `%s` is replaced with the title, or a function. If you want to use a function (for full control), then this cannot be set in your `nuxt.config`. It is recommended instead to set it within your `app.vue` file where it will apply to all pages on your site: ```vue [useHead]twoslash ``` Now, if you set the title to `My Page` with [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) on another page of your site, the title would appear as 'My Page - Site Title' in the browser tab. You could also pass `null` to default to 'Site Title'. ### Template Params You can use `templateParams` to provide additional placeholders in your `titleTemplate` besides the default `%s`. This allows for more dynamic title generation. ```vue [useHead]twoslash ``` ### Body Tags You can use the `tagPosition: 'bodyClose'` option on applicable tags to append them to the end of the `` tag. For example: ```vuetwoslash ``` ## Examples ### With `definePageMeta` Within your [`pages/` directory](https://nuxt.com/docs/3.x/directory-structure/pages), you can use `definePageMeta` along with [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) to set metadata based on the current route. For example, you can first set the current page title (this is extracted at build time via a macro, so it can't be set dynamically): ```vue [pages/some-page.vue]twoslash ``` And then in your layout file, you might use the route's metadata you have previously set: ```vue [layouts/default.vue]twoslash ``` ### Dynamic Title In the example below, `titleTemplate` is set either as a string with the `%s` placeholder or as a `function`, which allows greater flexibility in setting the page title dynamically for each route of your Nuxt app: ```vue [app.vue]twoslash ``` ```vue [app.vue]twoslash ``` `nuxt.config` is also used as an alternative way of setting the page title. However, `nuxt.config` does not allow the page title to be dynamic. Therefore, it is recommended to use `titleTemplate` in the `app.vue` file to add a dynamic title, which is then applied to all routes of your Nuxt app. ### External CSS The example below shows how you might enable Google Fonts using either the `link` property of the [`useHead`](https://nuxt.com/docs/3.x/api/composables/use-head) composable or using the `` component: ```vue [useHead]twoslash ``` ```vue [Components] ``` # Server > Build full-stack applications with Nuxt's server framework. You can fetch data from your database or another server, create APIs, or even generate static server-side content like a sitemap or a RSS feed - all from a single codebase. ## Powered by Nitro ![Server engine](https://nuxt.com/assets/docs/getting-started/server.svg) Nuxt's server is [Nitro](https://github.com/nitrojs/nitro). It was originally created for Nuxt but is now part of [UnJS](https://unjs.io) and open for other frameworks - and can even be used on its own. Using Nitro gives Nuxt superpowers: - Full control of the server-side part of your app - Universal deployment on any provider (many zero-config) - Hybrid rendering Nitro is internally using [h3](https://github.com/h3js/h3), a minimal H(TTP) framework built for high performance and portability. ## Server Endpoints & Middleware You can easily manage the server-only part of your Nuxt app, from API endpoints to middleware. Both endpoints and middleware can be defined like this: ```ts [server/api/test.ts]twoslash export default defineEventHandler(async (event) => { // ... Do whatever you want here }) ``` And you can directly return `text`, `json`, `html` or even a `stream`. Out-of-the-box, it supports **hot module replacement** and **auto-import** like the other parts of your Nuxt application. ## Universal Deployment Nitro offers the ability to deploy your Nuxt app anywhere, from a bare metal server to the edge network, with a start time of just a few milliseconds. That's fast! There are more than 15 presets to build your Nuxt app for different cloud providers and servers, including: - [Cloudflare Workers](https://workers.cloudflare.com) - [Netlify Functions](https://www.netlify.com/platform/core/functions/) - [Vercel Cloud](https://vercel.com/home) Or for other runtimes: ## Hybrid Rendering Nitro has a powerful feature called `routeRules` which allows you to define a set of rules to customize how each route of your Nuxt app is rendered (and more). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Generated at build time for SEO purpose '/': { prerender: true }, // Cached for 1 hour '/api/*': { cache: { maxAge: 60 * 60 } }, // Redirection to avoid 404 '/old-page': { redirect: { to: '/new-page', statusCode: 302 }, }, // ... }, }) ``` Learn about all available route rules are available to customize the rendering mode of your routes. In addition, there are some route rules (for example, `ssr`, `appMiddleware`, and `noScripts`) that are Nuxt specific to change the behavior when rendering your pages to HTML. Some route rules (`appMiddleware`, `redirect` and `prerender`) also affect client-side behavior. Nitro is used to build the app for server side rendering, as well as pre-rendering. # State Management > Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state. Nuxt provides the [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) composable to create a reactive and SSR-friendly shared state across components. [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) is an SSR-friendly [`ref`](https://vuejs.org/api/reactivity-core#ref) replacement. Its value will be preserved after server-side rendering (during client-side hydration) and shared across all components using a unique key. Because the data inside [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) will be serialized to JSON, it is important that it does not contain anything that cannot be serialized, such as classes, functions or symbols. Read more about `useState` composable. ## Best Practices Never define `const state = ref()` outside of ` ``` To globally invalidate cached state, see [`clearNuxtState`](https://nuxt.com/docs/3.x/api/utils/clear-nuxt-state) util. ### Initializing State Most of the time, you will want to initialize your state with data that resolves asynchronously. You can use the [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app) component with the [`callOnce`](https://nuxt.com/docs/3.x/api/utils/call-once) util to do so. ```vue [app.vue]twoslash ``` This is similar to the [`nuxtServerInit` action](https://v2.nuxt.com/docs/directory-structure/store/#the-nuxtserverinit-action) in Nuxt 2, which allows filling the initial state of your store server-side before rendering the page. ### Usage with Pinia In this example, we leverage the [Pinia module](https://nuxt.com/modules/pinia) to create a global store and use it across the app. Make sure to install the Pinia module with `npx nuxt module add pinia` or follow the [module's installation steps](https://pinia.vuejs.org/ssr/nuxt.html#Installation). ```ts [stores/website.ts] export const useWebsiteStore = defineStore('websiteStore', { state: () => ({ name: '', description: '', }), actions: { async fetch () { const infos = await $fetch('https://api.nuxt.com/modules/pinia') this.name = infos.name this.description = infos.description }, }, }) ``` ```vue [app.vue] ``` ## Advanced Usage ```ts [composables/locale.ts] import type { Ref } from 'vue' export const useLocale = () => { return useState('locale', () => useDefaultLocale().value) } export const useDefaultLocale = (fallback = 'en-US') => { const locale = ref(fallback) if (import.meta.server) { const reqLocale = useRequestHeaders()['accept-language']?.split(',')[0] if (reqLocale) { locale.value = reqLocale } } else if (import.meta.client) { const navLang = navigator.language if (navLang) { locale.value = navLang } } return locale } export const useLocales = () => { const locale = useLocale() const locales = ref([ 'en-US', 'en-GB', // ..., 'ja-JP-u-ca-japanese', ]) if (!locales.value.includes(locale.value)) { locales.value.unshift(locale.value) } return locales } export const useLocaleDate = (date: Ref | Date, locale = useLocale()) => { return computed(() => new Intl.DateTimeFormat(locale.value, { dateStyle: 'full' }).format(unref(date))) } ``` ```vue [app.vue] ``` ## Shared State By using [auto-imported composables](https://nuxt.com/docs/3.x/directory-structure/composables) we can define global type-safe states and import them across the app. ```ts [composables/states.ts]twoslash export const useColor = () => useState('color', () => 'pink') ``` ```vue [app.vue] ``` ## Using third-party libraries Nuxt **used to rely** on the Vuex library to provide global state management. If you are migrating from Nuxt 2, please head to [the migration guide](https://nuxt.com/docs/3.x/migration/configuration#vuex). Nuxt is not opinionated about state management, so feel free to choose the right solution for your needs. There are multiple integrations with the most popular state management libraries, including: - [Pinia](https://nuxt.com/modules/pinia) - the official Vue recommendation - [Harlem](https://nuxt.com/modules/harlem) - immutable global state management - [XState](https://nuxt.com/modules/xstate) - state machine approach with tools for visualizing and testing your state logic # Styling > Learn how to style your Nuxt application. Nuxt is highly flexible when it comes to styling. Write your own styles, or reference local and external stylesheets. You can use CSS preprocessors, CSS frameworks, UI libraries and Nuxt modules to style your application. ## Local Stylesheets If you're writing local stylesheets, the natural place to put them is the [`assets/` directory](https://nuxt.com/docs/3.x/directory-structure/assets). ### Importing Within Components You can import stylesheets in your pages, layouts and components directly. You can use a JavaScript import, or a CSS [`@import` statement](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@import). ```vue [pages/index.vue] ``` The stylesheets will be inlined in the HTML rendered by Nuxt. ### The CSS Property You can also use the `css` property in the Nuxt configuration. The natural place for your stylesheets is the [`assets/` directory](https://nuxt.com/docs/3.x/directory-structure/assets). You can then reference its path and Nuxt will include it to all the pages of your application. ```ts [nuxt.config.ts] export default defineNuxtConfig({ css: ['~/assets/css/main.css'], }) ``` The stylesheets will be inlined in the HTML rendered by Nuxt, injected globally and present in all pages. ### Working With Fonts Place your local fonts files in your `public/` directory, for example in `public/fonts`. You can then reference them in your stylesheets using `url()`. ```css [assets/css/main.css] @font-face { font-family: 'FarAwayGalaxy'; src: url('/fonts/FarAwayGalaxy.woff') format('woff'); font-weight: normal; font-style: normal; font-display: swap; } ``` Then reference your fonts by name in your stylesheets, pages or components: ```vue ``` ### Stylesheets Distributed Through NPM You can also reference stylesheets that are distributed through npm. Let's use the popular `animate.css` library as an example. ```bash [npm] npm install animate.css ``` ```bash [yarn] yarn add animate.css ``` ```bash [pnpm] pnpm install animate.css ``` ```bash [bun] bun install animate.css ``` ```bash [deno] deno install npm:animate.css ``` Then you can reference it directly in your pages, layouts and components: ```vue [app.vue] ``` The package can also be referenced as a string in the css property of your Nuxt configuration. ```ts [nuxt.config.ts] export default defineNuxtConfig({ css: ['animate.css'], }) ``` ## External Stylesheets You can include external stylesheets in your application by adding a link element in the head section of your nuxt.config file. You can achieve this result using different methods. Note that local stylesheets can also be included this way. You can manipulate the head with the [`app.head`](https://nuxt.com/docs/3.x/api/nuxt-config#head) property of your Nuxt configuration: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { head: { link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }], }, }, }) ``` ### Dynamically Adding Stylesheets You can use the useHead composable to dynamically set a value in your head in your code. ```tstwoslash useHead({ link: [{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css' }], }) ``` Nuxt uses `unhead` under the hood, and you can refer to [its full documentation](https://unhead.unjs.io). ### Modifying The Rendered Head With A Nitro Plugin If you need more advanced control, you can intercept the rendered html with a hook and modify the head programmatically. Create a plugin in `~~/server/plugins/my-plugin.ts` like this: ```ts [server/plugins/my-plugin.ts] export default defineNitroPlugin((nitro) => { nitro.hooks.hook('render:html', (html) => { html.head.push('') }) }) ``` External stylesheets are render-blocking resources: they must be loaded and processed before the browser renders the page. Web pages that contain unnecessarily large styles take longer to render. You can read more about it on [web.dev](https://web.dev/articles/defer-non-critical-css). ## Using Preprocessors To use a preprocessor like SCSS, Sass, Less or Stylus, install it first. ```bash [Sass & SCSS] npm install -D sass ``` ```bash [Less] npm install -D less ``` ```bash [Stylus] npm install -D stylus ``` The natural place to write your stylesheets is the `assets` directory. You can then import your source files in your `app.vue` (or layouts files) using your preprocessor's syntax. ```vue [pages/app.vue] ``` Alternatively, you can use the `css` property of your Nuxt configuration. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ css: ['~/assets/scss/main.scss'], }) ``` In both cases, the compiled stylesheets will be inlined in the HTML rendered by Nuxt. If you need to inject code in pre-processed files, like a [Sass partial](https://sass-lang.com/documentation/at-rules/use/#partials) with color variables, you can do so with the Vite [preprocessors options](https://vite.dev/config/shared-options#css-preprocessoroptions). Create some partials in your `assets` directory: ```scss [assets/_colors.scss] $primary: #49240F; $secondary: #E4A79D; ``` ```sass [assets/_colors.sass] $primary: #49240F $secondary: #E4A79D ``` Then in your `nuxt.config` : ```ts [SCSS]twoslash export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { scss: { additionalData: '@use "~/assets/_colors.scss" as *;', }, }, }, }, }) ``` ```ts [SASS]twoslash export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { sass: { additionalData: '@use "~/assets/_colors.sass" as *\n', }, }, }, }, }) ``` Nuxt uses Vite by default. If you wish to use webpack instead, refer to each preprocessor loader [documentation](https://webpack.js.org/loaders/sass-loader/). ### Preprocessor Workers (Experimental) Vite has made available an [experimental option](https://vite.dev/config/shared-options#css-preprocessormaxworkers) which can speed up using preprocessors. You can enable this in your `nuxt.config`: ```ts export default defineNuxtConfig({ vite: { css: { preprocessorMaxWorkers: true, // number of CPUs minus 1 }, }, }) ``` This is an experimental option and you should refer to the Vite documentation and [provide feedback](https://github.com/vitejs/vite/discussions/15835). ## Single File Components (SFC) Styling One of the best things about Vue and SFC is how great it is at naturally dealing with styling. You can directly write CSS or preprocessor code in the style block of your components file, therefore you will have fantastic developer experience without having to use something like CSS-in-JS. However if you wish to use CSS-in-JS, you can find 3rd party libraries and modules that support it, such as [pinceau](https://github.com/Tahul/pinceau). You can refer to the [Vue docs](https://vuejs.org/api/sfc-css-features) for a comprehensive reference about styling components in SFC. ### Class And Style Bindings You can leverage Vue SFC features to style your components with class and style attributes. ```vue [Ref and Reactive] ``` ```vue [Computed] ``` ```vue [Array] ``` ```vue [Style] ``` Refer to the [Vue docs](https://vuejs.org/guide/essentials/class-and-style) for more information. ### Dynamic Styles With `v-bind` You can reference JavaScript variable and expression within your style blocks with the v-bind function. The binding will be dynamic, meaning that if the variable value changes, the style will be updated. ```vue ``` ### Scoped Styles The scoped attribute allows you to style components in isolation. The styles declared with this attribute will only apply to this component. ```vue ``` ### CSS Modules You can use [CSS Modules](https://github.com/css-modules/css-modules) with the module attribute. Access it with the injected `$style` variable. ```vue ``` ### Preprocessors Support SFC style blocks support preprocessor syntax. Vite comes with built-in support for .scss, .sass, .less, .styl and .stylus files without configuration. You just need to install them first, and they will be available directly in SFC with the lang attribute. ```vue [SCSS] ``` ```vue [Sass] ``` ```vue [LESS] ``` ```vue [Stylus] ``` You can refer to the [Vite CSS docs](https://vite.dev/guide/features#css) and the [@vitejs/plugin-vue docs](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue). For webpack users, refer to the [vue loader docs](https://vue-loader.vuejs.org). ## Using PostCSS Nuxt comes with postcss built-in. You can configure it in your `nuxt.config` file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ postcss: { plugins: { 'postcss-nested': {}, 'postcss-custom-media': {}, }, }, }) ``` For proper syntax highlighting in SFC, you can use the postcss lang attribute. ```vue ``` By default, Nuxt comes with the following plugins already pre-configured: - [postcss-import](https://github.com/postcss/postcss-import): Improves the `@import` rule - [postcss-url](https://github.com/postcss/postcss-url): Transforms `url()` statements - [autoprefixer](https://github.com/postcss/autoprefixer): Automatically adds vendor prefixes - [cssnano](https://cssnano.github.io/cssnano/): Minification and purge ## Leveraging Layouts For Multiple Styles If you need to style different parts of your application completely differently, you can use layouts. Use different styles for different layouts. ```vue ``` ## Third Party Libraries And Modules Nuxt isn't opinionated when it comes to styling and provides you with a wide variety of options. You can use any styling tool that you want, such as popular libraries like [UnoCSS](https://unocss.dev) or [Tailwind CSS](https://tailwindcss.com). The community and the Nuxt team have developed plenty of Nuxt modules to make the integration easier. You can discover them on the [modules section](https://nuxt.com/modules) of the website. Here are a few modules to help you get started: - [UnoCSS](https://nuxt.com/modules/unocss): Instant on-demand atomic CSS engine - [Tailwind CSS](https://nuxt.com/modules/tailwindcss): Utility-first CSS framework - [Fontaine](https://github.com/nuxt-modules/fontaine): Font metric fallback - [Pinceau](https://github.com/Tahul/pinceau): Adaptable styling framework - [Nuxt UI](https://ui.nuxt.com): A UI Library for Modern Web Apps - [Panda CSS](https://panda-css.com/docs/installation/nuxt): CSS-in-JS engine that generates atomic CSS at build time Nuxt modules provide you with a good developer experience out of the box, but remember that if your favorite tool doesn't have a module, it doesn't mean that you can't use it with Nuxt! You can configure it yourself for your own project. Depending on the tool, you might need to use a [Nuxt plugin](https://nuxt.com/docs/3.x/directory-structure/plugins) and/or [make your own module](https://nuxt.com/docs/3.x/guide/modules). Share them with the [community](https://nuxt.com/modules) if you do! ### Easily Load Webfonts You can use [the Nuxt Google Fonts module](https://github.com/nuxt-modules/google-fonts) to load Google Fonts. If you are using [UnoCSS](https://unocss.dev/integrations/nuxt), note that it comes with a [web fonts presets](https://unocss.dev/presets/web-fonts) to conveniently load fonts from common providers, including Google Fonts and more. ## Advanced ### Transitions Nuxt comes with the same `` element that Vue has, and also has support for the experimental [View Transitions API](https://nuxt.com/docs/3.x/getting-started/transitions#view-transitions-api-experimental). ### Font Advanced Optimization We would recommend using [Fontaine](https://github.com/nuxt-modules/fontaine) to reduce your [CLS](https://web.dev/articles/cls). If you need something more advanced, consider creating a Nuxt module to extend the build process or the Nuxt runtime. Always remember to take advantage of the various tools and techniques available in the Web ecosystem at large to make styling your application easier and more efficient. Whether you're using native CSS, a preprocessor, postcss, a UI library or a module, Nuxt has got you covered. Happy styling! ### LCP Advanced Optimizations You can do the following to speed-up the download of your global CSS files: - Use a CDN so the files are physically closer to your users - Compress your assets, ideally using Brotli - Use HTTP2/HTTP3 for delivery - Host your assets on the same domain (do not use a different subdomain) Most of these things should be done for you automatically if you're using modern platforms like Cloudflare, Netlify or Vercel. You can find an LCP optimization guide on [web.dev](https://web.dev/articles/optimize-lcp). If all of your CSS is inlined by Nuxt, you can (experimentally) completely stop external CSS files from being referenced in your rendered HTML. You can achieve that with a hook, that you can place in a module, or in your Nuxt configuration file. ```ts [nuxt.config.ts] export default defineNuxtConfig({ hooks: { 'build:manifest': (manifest) => { // find the app entry, css list const css = Object.values(manifest).find(options => options.isEntry)?.css if (css) { // start from the end of the array and go to the beginning for (let i = css.length - 1; i >= 0; i--) { // if it starts with 'entry', remove it from the list if (css[i].startsWith('entry')) { css.splice(i, 1) } } } }, }, }) ``` # Testing > How to test your Nuxt application. If you are a module author, you can find more specific information in the [Module Author's guide](https://nuxt.com/docs/3.x/guide/modules/testing). Nuxt offers first-class support for end-to-end and unit testing of your Nuxt application via `@nuxt/test-utils`, a library of test utilities and configuration that currently powers the [tests we use on Nuxt itself](https://github.com/nuxt/nuxt/tree/main/test) and tests throughout the module ecosystem. ## Installation In order to allow you to manage your other testing dependencies, `@nuxt/test-utils` ships with various optional peer dependencies. For example: - you can choose between `happy-dom` and `jsdom` for a runtime Nuxt environment - you can choose between `vitest`, `cucumber`, `jest` and `playwright` for end-to-end test runners - `playwright-core` is only required if you wish to use the built-in browser testing utilities (and are not using `@playwright/test` as your test runner) ```bash [npm] npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [yarn] yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [pnpm] pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ```bash [bun] bun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core ``` ## Unit Testing We currently ship an environment for unit testing code that needs a [Nuxt](https://nuxt.com) runtime environment. It currently *only has support for vitest* (although contribution to add other runtimes would be welcome). ### Setup 1. Add `@nuxt/test-utils/module` to your `nuxt.config` file (optional). It adds a Vitest integration to your Nuxt DevTools which supports running your unit tests in development.```tstwoslash export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], }) ``` 2. Create a `vitest.config.ts` with the following content:```tstwoslash import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/unit/*.{test,spec}.ts'], environment: 'node', }, }, { test: { name: 'e2e', include: ['test/e2e/*.{test,spec}.ts'], environment: 'node', }, }, await defineVitestProject({ test: { name: 'nuxt', include: ['test/nuxt/*.{test,spec}.ts'], environment: 'nuxt', }, }), ], }, }) ``` When importing `@nuxt/test-utils` in your vitest config, It is necessary to have `"type": "module"` specified in your `package.json` or rename your vitest config file appropriately. > i.e., `vitest.config.m{ts,js}`. It is possible to set environment variables for testing by using the `.env.test` file. ### Using a Nuxt Runtime Environment Using [Vitest projects](https://vitest.dev/guide/projects.html#test-projects), you have fine-grained control over which tests run in which environment: - **Unit tests**: Place regular unit tests in `test/unit/` - these run in a Node environment for speed - **Nuxt tests**: Place tests that rely on the Nuxt runtime environment in `test/nuxt/` - these will run within a Nuxt runtime environment #### Alternative: Simple Setup If you prefer a simpler setup and want all tests to run in the Nuxt environment, you can use the basic configuration: ```tstwoslash import { defineVitestConfig } from '@nuxt/test-utils/config' import { fileURLToPath } from 'node:url' export default defineVitestConfig({ test: { environment: 'nuxt', // you can optionally set Nuxt-specific environment options // environmentOptions: { // nuxt: { // rootDir: fileURLToPath(new URL('./playground', import.meta.url)), // domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom' // overrides: { // // other Nuxt config you want to pass // } // } // } }, }) ``` If you're using the simple setup with `environment: 'nuxt'` by default, you can opt *out* of the [Nuxt environment](https://vitest.dev/guide/environment.html#test-environment) per test file as needed. ```tstwoslash // @vitest-environment node import { test } from 'vitest' test('my test', () => { // ... test without Nuxt environment! }) ``` This approach is not recommended as it creates a hybrid environment where Nuxt Vite plugins run but the Nuxt entry and `nuxtApp` are not initialized. This can lead to hard-to-debug errors. ### Organizing Your Tests With the project-based setup, you might organize your tests as follows: ```bash [Directory structure] test/ โ”œโ”€โ”€ e2e/ โ”‚ โ””โ”€โ”€ ssr.test.ts โ”œโ”€โ”€ nuxt/ โ”‚ โ”œโ”€โ”€ components.test.ts โ”‚ โ””โ”€โ”€ composables.test.ts โ”œโ”€โ”€ unit/ โ”‚ โ””โ”€โ”€ utils.test.ts ``` You can of course opt for any test structure, but keeping the Nuxt runtime environment separated from Nuxt end-to-end tests is important for test stability. #### Running Tests With the project setup, you can run different test suites: ```bash # Run all tests npx vitest # Run only unit tests npx vitest --project unit # Run only Nuxt tests npx vitest --project nuxt # Run tests in watch mode npx vitest --watch ``` When you run your tests within the Nuxt environment, they will be running in a [`happy-dom`](https://github.com/capricorn86/happy-dom) or [`jsdom`](https://github.com/jsdom/jsdom) environment. Before your tests run, a global Nuxt app will be initialized (including, for example, running any plugins or code you've defined in your `app.vue`). This means you should take particular care not to mutate the global state in your tests (or, if you need to, to reset it afterwards). ### ๐ŸŽญ Built-In Mocks `@nuxt/test-utils` provides some built-in mocks for the DOM environment. #### `intersectionObserver` Default `true`, creates a dummy class without any functionality for the IntersectionObserver API #### `indexedDB` Default `false`, uses [`fake-indexeddb`](https://github.com/dumbmatter/fakeIndexedDB) to create a functional mock of the IndexedDB API These can be configured in the `environmentOptions` section of your `vitest.config.ts` file: ```tstwoslash import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ test: { environmentOptions: { nuxt: { mock: { intersectionObserver: true, indexedDb: true, }, }, }, }, }) ``` ### ๐Ÿ› ๏ธ Helpers `@nuxt/test-utils` provides a number of helpers to make testing Nuxt apps easier. #### `mountSuspended` `mountSuspended` allows you to mount any Vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins. Under the hood, `mountSuspended` wraps `mount` from `@vue/test-utils`, so you can check out [the Vue Test Utils documentation](https://test-utils.vuejs.org/guide/) for more on the options you can pass, and how to use this utility. For example: ```tstwoslash // @noErrors import { expect, it } from 'vitest' import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- // tests/components/SomeComponents.nuxt.spec.ts import { mountSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' it('can mount some component', async () => { const component = await mountSuspended(SomeComponent) expect(component.text()).toMatchInlineSnapshot( '"This is an auto-imported component"', ) }) ``` ```tstwoslash // @noErrors import { expect, it } from 'vitest' // ---cut--- // tests/components/SomeComponents.nuxt.spec.ts import { mountSuspended } from '@nuxt/test-utils/runtime' import App from '~/app.vue' // tests/App.nuxt.spec.ts it('can also mount an app', async () => { const component = await mountSuspended(App, { route: '/test' }) expect(component.html()).toMatchInlineSnapshot(` "
This is an auto-imported component
I am a global component
/
Test link " `) }) ``` The options object accepts `@vue/test-utils` mount options and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). #### `renderSuspended` `renderSuspended` allows you to render any Vue component within the Nuxt environment using `@testing-library/vue`, allowing async setup and access to injections from your Nuxt plugins. This should be used together with utilities from Testing Library, e.g. `screen` and `fireEvent`. Install [@testing-library/vue](https://testing-library.com/docs/vue-testing-library/intro/) in your project to use these. Additionally, Testing Library also relies on testing globals for cleanup. You should turn these on in your [Vitest config](https://vitest.dev/config/globals). The passed in component will be rendered inside a `
`. Examples: ```tstwoslash // @noErrors import { expect, it } from 'vitest' import type { Component } from 'vue' declare module '#components' { export const SomeComponent: Component } // ---cut--- // tests/components/SomeComponents.nuxt.spec.ts import { renderSuspended } from '@nuxt/test-utils/runtime' import { SomeComponent } from '#components' import { screen } from '@testing-library/vue' it('can render some component', async () => { await renderSuspended(SomeComponent) expect(screen.getByText('This is an auto-imported component')).toBeDefined() }) ``` ```tstwoslash // @noErrors import { expect, it } from 'vitest' // ---cut--- // tests/App.nuxt.spec.ts import { renderSuspended } from '@nuxt/test-utils/runtime' import App from '~/app.vue' it('can also render an app', async () => { const html = await renderSuspended(App, { route: '/test' }) expect(html).toMatchInlineSnapshot(` "
This is an auto-imported component
I am a global component
Index page
Test link
" `) }) ``` The options object accepts `@testing-library/vue` render options and the following properties: - `route`: the initial route, or `false` to skip the initial route change (default `/`). #### `mockNuxtImport` `mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useState`, you can do so like this: ```tstwoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', () => { return () => { return { value: 'mocked storage' } } }) // your tests here ``` You can explicitly type the mock for type safety, and use the original implementation passed to the factory function when mocking complex functionality. ```ts [test/nuxt/import.test.ts]twoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', (original) => { return (...args) => { return { ...original('some-key'), value: 'mocked state' } } }) // or specify the target to mock mockNuxtImport(useState, (original) => { return (...args) => { return { ...original('some-key'), value: 'mocked state' } } }) // your tests here ``` `mockNuxtImport` can only be used once per mocked import per test file. It is actually a macro that gets transformed to `vi.mock` and `vi.mock` is hoisted, as described [in the Vitest docs](https://vitest.dev/api/vi#vi-mock). If you need to mock a Nuxt import and provide different implementations between tests, you can do it by creating and exposing your mocks using [`vi.hoisted`](https://vitest.dev/api/vi#vi-hoisted), and then use those mocks in `mockNuxtImport`. You then have access to the mocked imports, and can change the implementation between tests. Be careful to [restore mocks](https://vitest.dev/api/mock#mockrestore) before or after each test to undo mock state changes between runs. ```tstwoslash import { vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' const { useStateMock } = vi.hoisted(() => { return { useStateMock: vi.fn(() => { return { value: 'mocked storage' } }), } }) mockNuxtImport('useState', () => { return useStateMock }) // Then, inside a test useStateMock.mockImplementation(() => { return { value: 'something else' } }) ``` If you need to mock behavior only inside a test, you can also use the following approach. ```tstwoslash import { beforeEach, vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport(useRoute, original => vi.fn(original)) beforeEach(() => { vi.resetAllMocks() }) // Then, inside a test const useRouteOriginal = vi.mocked(useRoute).getMockImplementation()! vi.mocked(useRoute).mockImplementation( (...args) => ({ ...useRouteOriginal(...args), path: '/mocked' }), ) ``` #### `mockComponent` `mockComponent` allows you to mock Nuxt's component. The first argument can be the component name in PascalCase, or the relative path of the component. The second argument is a factory function that returns the mocked component. For example, to mock `MyComponent`, you can: ```tstwoslash import { mockComponent } from '@nuxt/test-utils/runtime' mockComponent('MyComponent', { props: { value: String, }, setup (props) { // ... }, }) // relative path or alias also works mockComponent('~/components/my-component.vue', () => { // or a factory function return defineComponent({ setup (props) { // ... }, }) }) // or you can use SFC for redirecting to a mock component mockComponent('MyComponent', () => import('./MockComponent.vue')) // your tests here ``` > **Note**: You can't reference local variables in the factory function since they are hoisted. If you need to access Vue APIs or other variables, you need to import them in your factory function. ```tstwoslash import { mockComponent } from '@nuxt/test-utils/runtime' mockComponent('MyComponent', async () => { const { ref, h } = await import('vue') return defineComponent({ setup (props) { const counter = ref(0) return () => h('div', null, counter.value) }, }) }) ``` #### `registerEndpoint` `registerEndpoint` allows you create Nitro endpoint that returns mocked data. It can come in handy if you want to test a component that makes requests to API to display some data. The first argument is the endpoint name (e.g. `/test/`). The second argument is a factory function that returns the mocked data. For example, to mock `/test/` endpoint, you can do: ```tstwoslash import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', () => ({ test: 'test-field', })) ``` By default, your request will be made using the `GET` method. You may use another method by setting an object as the second argument instead of a function. ```tstwoslash import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', { method: 'POST', handler: () => ({ test: 'test-field' }), }) ``` This object accepts the following properties: - `handler`: the event handler function - `method`: (optional) HTTP method to match (e.g., 'GET', 'POST') - `once`: (optional) if true, the handler will only be used for the first matching request and then automatically removed > **Note**: If your requests in a component go to an external API, you can use `baseURL` and then make it empty using [Nuxt Environment Override Config](https://nuxt.com/docs/3.x/getting-started/configuration#environment-overrides) (`$test`) so all your requests will go to Nitro server. #### Conflict with End-To-End Testing `@nuxt/test-utils/runtime` and `@nuxt/test-utils/e2e` need to run in different testing environments and so can't be used in the same file. If you would like to use both the end-to-end and unit testing functionality of `@nuxt/test-utils`, you can split your tests into separate files. You then either specify a test environment per-file with the special `// @vitest-environment nuxt` comment, or name your runtime unit test files with the `.nuxt.spec.ts` extension. `app.nuxt.spec.ts` ```tstwoslash import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useState', () => { return () => { return { value: 'mocked storage' } } }) ``` `app.e2e.spec.ts` ```tstwoslash import { $fetch, setup } from '@nuxt/test-utils/e2e' await setup({ setupTimeout: 10000, }) // ... ``` ### Using `@vue/test-utils` If you prefer to use `@vue/test-utils` on its own for unit testing in Nuxt, and you are only testing components which do not rely on Nuxt composables, auto-imports or context, you can follow these steps to set it up. 1. Install the needed dependencies ```bash [npm] npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [yarn] yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [pnpm] pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` ```bash [bun] bun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue ``` 2. Create a `vitest.config.ts` with the following content:```ts import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom', }, }) ``` 3. Add a new command for test in your `package.json````json "scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" }, ``` 4. Create a simple `` component `components/HelloWorld.vue` with the following content:```vue ``` 5. Create a simple unit test for this newly created component `~/components/HelloWorld.spec.ts````tstwoslash import { describe, expect, it } from 'vitest' import { mount } from '@vue/test-utils' import HelloWorld from './HelloWorld.vue' describe('HelloWorld', () => { it('component renders Hello world properly', () => { const wrapper = mount(HelloWorld) expect(wrapper.text()).toContain('Hello world') }) }) ``` 6. Run vitest command ```bash [npm] npm run test ``` ```bash [yarn] yarn test ``` ```bash [pnpm] pnpm run test ``` ```bash [bun] bun run test ``` Congratulations, you're all set to start unit testing with `@vue/test-utils` in Nuxt! Happy testing! ## End-To-End Testing For end-to-end testing, we support [Vitest](https://github.com/vitest-dev/vitest), [Jest](https://jestjs.io), [Cucumber](https://cucumber.io/) and [Playwright](https://playwright.dev/) as test runners. ### Setup In each `describe` block where you are taking advantage of the `@nuxt/test-utils/e2e` helper methods, you will need to set up the test context before beginning. ```ts [test/my-test.spec.ts]twoslash import { describe, test } from 'vitest' import { $fetch, setup } from '@nuxt/test-utils/e2e' describe('My test', async () => { await setup({ // test context options }) test('my test', () => { // ... }) }) ``` Behind the scenes, `setup` performs a number of tasks in `beforeAll`, `beforeEach`, `afterEach` and `afterAll` to set up the Nuxt test environment correctly. Please use the options below for the `setup` method. #### Nuxt Config - `rootDir`: Path to a directory with a Nuxt app to be put under test. - Type: `string` - Default: `'.'` - `configFile`: Name of the configuration file. - Type: `string` - Default: `'nuxt.config'` #### Timings - `setupTimeout`: The amount of time (in milliseconds) to allow for `setupTest` to complete its work (which could include building or generating files for a Nuxt application, depending on the options that are passed). - Type: `number` - Default: `120000` or `240000` on windows - `teardownTimeout`: The amount of time (in milliseconds) to allow tearing down the test environment, such as closing the browser. - Type: `number` - Default: `30000` #### Features - `build`: Whether to run a separate build step. - Type: `boolean` - Default: `true` (`false` if `browser` or `server` is disabled, or if a `host` is provided) - `server`: Whether to launch a server to respond to requests in the test suite. - Type: `boolean` - Default: `true` (`false` if a `host` is provided) - `port`: If provided, set the launched test server port to the value. - Type: `number | undefined` - Default: `undefined` - `host`: If provided, a URL to use as the test target instead of building and running a new server. Useful for running "real" end-to-end tests against a deployed version of your application, or against an already running local server (which may provide a significant reduction in test execution timings). See the [target host end-to-end example below](https://nuxt.com/docs/3.x/getting-started/testing#target-host-end-to-end-example). - Type: `string` - Default: `undefined` - `browser`: Under the hood, Nuxt test utils uses [`playwright`](https://playwright.dev) to carry out browser testing. If this option is set, a browser will be launched and can be controlled in the subsequent test suite. - Type: `boolean` - Default: `false` - `browserOptions` - Type: `object` with the following properties - `type`: The type of browser to launch - either `chromium`, `firefox` or `webkit` - `launch`: `object` of options that will be passed to playwright when launching the browser. See [full API reference](https://playwright.dev/docs/api/class-browsertype#browser-type-launch). - `runner`: Specify the runner for the test suite. Currently, [Vitest](https://vitest.dev) is recommended. - Type: `'vitest' | 'jest' | 'cucumber'` - Default: `'vitest'` ##### Target `host` end-to-end example A common use-case for end-to-end testing is running the tests against a deployed application running in the same environment typically used for Production. For local development or automated deploy pipelines, testing against a separate local server can be more efficient and is typically faster than allowing the test framework to rebuild between tests. To utilize a separate target host for end-to-end tests, simply provide the `host` property of the `setup` function with the desired URL. ```ts import { createPage, setup } from '@nuxt/test-utils/e2e' import { describe, expect, it } from 'vitest' describe('login page', async () => { await setup({ host: 'http://localhost:8787', }) it('displays the email and password fields', async () => { const page = await createPage('/login') expect(await page.getByTestId('email').isVisible()).toBe(true) expect(await page.getByTestId('password').isVisible()).toBe(true) }) }) ``` ### APIs #### `$fetch(url)` Get the HTML of a server-rendered page. ```tstwoslash import { $fetch } from '@nuxt/test-utils/e2e' const html = await $fetch('/') ``` #### `fetch(url)` Get the response of a server-rendered page. ```tstwoslash import { fetch } from '@nuxt/test-utils/e2e' const res = await fetch('/') const { body, headers } = res ``` #### `url(path)` Get the full URL for a given page (including the port the test server is running on.) ```tstwoslash import { url } from '@nuxt/test-utils/e2e' const pageUrl = url('/page') // 'http://localhost:6840/page' ``` ### Testing in a Browser We provide built-in support using Playwright within `@nuxt/test-utils`, either programmatically or via the Playwright test runner. #### `createPage(url)` Within `vitest`, `jest` or `cucumber`, you can create a configured Playwright browser instance with `createPage`, and (optionally) point it at a path from the running server. You can find out more about the API methods available from [in the Playwright documentation](https://playwright.dev/docs/api/class-page). ```tstwoslash import { createPage } from '@nuxt/test-utils/e2e' const page = await createPage('/page') // you can access all the Playwright APIs from the `page` variable ``` #### Testing with Playwright Test Runner We also provide first-class support for testing Nuxt within [the Playwright test runner](https://playwright.dev/docs/intro). ```bash [npm] npm i --save-dev @playwright/test @nuxt/test-utils ``` ```bash [yarn] yarn add --dev @playwright/test @nuxt/test-utils ``` ```bash [pnpm] pnpm add -D @playwright/test @nuxt/test-utils ``` ```bash [bun] bun add --dev @playwright/test @nuxt/test-utils ``` ```bash [deno] deno add --dev npm:@playwright/test npm:@nuxt/test-utils ``` You can provide global Nuxt configuration, with the same configuration details as the `setup()` function mentioned earlier in this section. ```ts [playwright.config.ts] import { fileURLToPath } from 'node:url' import { defineConfig, devices } from '@playwright/test' import type { ConfigOptions } from '@nuxt/test-utils/playwright' export default defineConfig({ use: { nuxt: { rootDir: fileURLToPath(new URL('.', import.meta.url)), }, }, // ... }) ``` Your test file should then use `expect` and `test` directly from `@nuxt/test-utils/playwright`: ```ts [tests/example.test.ts] import { expect, test } from '@nuxt/test-utils/playwright' test('test', async ({ page, goto }) => { await goto('/', { waitUntil: 'hydration' }) await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!') }) ``` You can alternatively configure your Nuxt server directly within your test file: ```ts [tests/example.test.ts] import { expect, test } from '@nuxt/test-utils/playwright' test.use({ nuxt: { rootDir: fileURLToPath(new URL('..', import.meta.url)), }, }) test('test', async ({ page, goto }) => { await goto('/', { waitUntil: 'hydration' }) await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!') }) ``` # Transitions > Apply transitions between pages and layouts with Vue or native browser View Transitions. Nuxt leverages Vue's [``](https://vuejs.org/guide/built-ins/transition#the-transition-component) component to apply transitions between pages and layouts. ## Page Transitions You can enable page transitions to apply an automatic transition for all your [pages](https://nuxt.com/docs/3.x/directory-structure/pages). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: { name: 'page', mode: 'out-in' }, }, }) ``` If you are changing layouts as well as page, the page transition you set here will not run. Instead, you should set a [layout transition](https://nuxt.com/docs/3.x/getting-started/transitions#layout-transitions). To start adding transition between your pages, add the following CSS to your [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app): ```vue [app.vue] ``` ```vue [pages/index.vue] ``` ```vue [pages/about.vue] ``` This produces the following result when navigating between pages: To set a different transition for a page, set the `pageTransition` key in [`definePageMeta`](https://nuxt.com/docs/3.x/api/utils/define-page-meta) of the page: ```vue [pages/about.vue]twoslash ``` ```vue [app.vue] ``` Moving to the about page will add the 3d rotation effect: ## Layout Transitions You can enable layout transitions to apply an automatic transition for all your [layouts](https://nuxt.com/docs/3.x/directory-structure/layouts). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { layoutTransition: { name: 'layout', mode: 'out-in' }, }, }) ``` To start adding transition between your pages and layouts, add the following CSS to your [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app): ```vue [app.vue] ``` ```vue [layouts/default.vue] ``` ```vue [layouts/orange.vue] ``` ```vue [pages/index.vue] ``` ```vue [pages/about.vue] ``` This produces the following result when navigating between pages: Similar to `pageTransition`, you can apply a custom `layoutTransition` to the page component using `definePageMeta`: ```vue [pages/about.vue]twoslash ``` ## Global Settings You can customize these default transition names globally using `nuxt.config`. Both `pageTransition` and `layoutTransition` keys accept [`TransitionProps`](https://vuejs.org/api/built-in-components#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: { name: 'fade', mode: 'out-in', // default }, layoutTransition: { name: 'slide', mode: 'out-in', // default }, }, }) ``` If you change the `name` property, you also have to rename the CSS classes accordingly. To override the global transition property, use the `definePageMeta` to define page or layout transitions for a single Nuxt page and override any page or layout transitions that are defined globally in `nuxt.config` file. ```vue [pages/some-page.vue]twoslash ``` ## Disable Transitions `pageTransition` and `layoutTransition` can be disabled for a specific route: ```vue [pages/some-page.vue]twoslash ``` Or globally in the `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { pageTransition: false, layoutTransition: false, }, }) ``` ## JavaScript Hooks For advanced use-cases, you can use JavaScript hooks to create highly dynamic and custom transitions for your Nuxt pages. This way presents perfect use-cases for JavaScript animation libraries such as [GSAP](https://gsap.com). ```vue [pages/some-page.vue]twoslash ``` Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition#javascript-hooks) available in the `Transition` component. ## Dynamic Transitions To apply dynamic transitions using conditional logic, you can leverage inline [middleware](https://nuxt.com/docs/3.x/directory-structure/middleware) to assign a different transition name to `to.meta.pageTransition`. ```vue [pages/[id].vue]twoslash ``` ```vue [layouts/default.vue] ``` The page now applies the `slide-left` transition when going to the next id and `slide-right` for the previous: ## Transition with NuxtPage When `` is used in `app.vue`, transitions can be configured with the `transition` prop to activate transitions globally. ```vue [app.vue] ``` Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. ## View Transitions API (experimental) Nuxt ships with an experimental implementation of the [**View Transitions API**](https://developer.chrome.com/docs/web-platform/view-transitions) (see [MDN](https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API)). This is an exciting new way to implement native browser transitions which (among other things) have the ability to transition between unrelated elements on different pages. You can check a demo [on StackBlitz](https://stackblitz.com/edit/nuxt-view-transitions). The Nuxt integration can be enabled with the `experimental.viewTransition` option in your configuration file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { viewTransition: true, }, }) ``` The possible values are: `false`, `true`, or `'always'`. If set to true, Nuxt will not apply transitions if the user's browser matches `prefers-reduced-motion: reduce` (recommended). If set to `always`, Nuxt will always apply the transition and it is up to you to respect the user's preference. By default, view transitions are enabled for all [pages](https://nuxt.com/docs/3.x/directory-structure/pages), but you can set a different global default. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ app: { // Disable view transitions globally, and opt-in on a per page basis viewTransition: false, }, }) ``` It is possible to override the default `viewTransition` value for a page by setting the `viewTransition` key in [`definePageMeta`](https://nuxt.com/docs/3.x/api/utils/define-page-meta) of the page: ```vue [pages/about.vue]twoslash ``` Overriding view transitions on a per-page basis will only have an effect if you have enabled the `experimental.viewTransition` option. If you are also using Vue transitions like `pageTransition` and `layoutTransition` (see above) to achieve the same result as the new View Transitions API, then you may wish to *disable* Vue transitions if the user's browser supports the newer, native web API. You can do this by creating `~/middleware/disable-vue-transitions.global.ts` with the following contents: ```ts export default defineNuxtRouteMiddleware((to) => { if (import.meta.server || !document.startViewTransition) { return } // Disable built-in Vue transitions to.meta.pageTransition = false to.meta.layoutTransition = false }) ``` ### Known Issues - If you perform data fetching within your page setup functions, you may wish to reconsider using this feature for the moment. (By design, View Transitions completely freeze DOM updates whilst they are taking place.) We're looking at restricting the View Transition to the final moments before `` resolves, but in the interim you may want to consider carefully whether to adopt this feature if this describes you. # Upgrade Guide > Learn how to upgrade to the latest Nuxt version. ## Upgrading Nuxt ### Latest Nuxt 3 release To upgrade Nuxt to the [latest v3 release](https://github.com/nuxt/nuxt/releases), use the `nuxt upgrade` command with `--channel=v3` flag. ```bash [npm] npx nuxt upgrade --dedupe --channel=v3 ``` ```bash [yarn] yarn nuxt upgrade --dedupe --channel=v3 ``` ```bash [pnpm] pnpm nuxt upgrade --dedupe --channel=v3 ``` ```bash [bun] bun x nuxt upgrade --dedupe --channel=v3 ``` This will only work if you *already have* a version of `@nuxt/cli` which has the `--channel` flag implemented. If this does not work, you can instead use `nuxi@latest` for the initial upgrade. E.g. `npx nuxi@latest upgrade --dedupe --channel=v3` ### Latest release To upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases), use the `nuxt upgrade` command. ```bash [npm] npx nuxt upgrade ``` ```bash [yarn] yarn nuxt upgrade ``` ```bash [pnpm] pnpm nuxt upgrade ``` ```bash [bun] bun x nuxt upgrade ``` ```bash [deno] deno x nuxt upgrade ``` ### Nightly Release Channel To use the latest Nuxt build and test features before their release, read about the [nightly release channel](https://nuxt.com/docs/3.x/guide/going-further/nightly-release-channel) guide. The nightly release channel `latest` tag is currently tracking the Nuxt v4 branch, meaning that it is particularly likely to have breaking changes right now โ€” be careful! You can opt in to the 3.x branch nightly releases with `"nuxt": "npm:nuxt-nightly@3x"`. ## Testing Nuxt 4 Nuxt 4 is **scheduled for release in Q2 2025**. It will include all the features currently available through `compatibilityVersion: 4`. Until the release, it is possible to test many of Nuxt 4's breaking changes from Nuxt version 3.12+. ### Opting in to Nuxt 4 First, upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases). Then you can set your `compatibilityVersion` to match Nuxt 4 behavior: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ future: { compatibilityVersion: 4, }, // To re-enable _all_ Nuxt v3 behavior, set the following options: // srcDir: '.', // dir: { // app: 'app' // }, // experimental: { // scanPageMeta: 'after-resolve', // sharedPrerenderData: false, // compileTemplate: true, // resetAsyncDataToUndefined: true, // templateUtils: true, // relativeWatchPaths: true, // normalizeComponentNames: false, // spaLoadingTemplateLocation: 'within', // parseErrorData: false, // pendingWhenIdle: true, // alwaysRunFetchOnKeyChange: true, // defaults: { // useAsyncData: { // deep: true // } // } // }, // features: { // inlineStyles: true // }, // unhead: { // renderSSRHeadOptions: { // omitLineBreaks: false // } // } }) ``` For now, you need to define the compatibility version in each layer that opts into Nuxt 4 behavior. This will not be required after Nuxt 4 is released. When you set your `compatibilityVersion` to `4`, defaults throughout your Nuxt configuration will change to opt in to Nuxt v4 behavior, but you can granularly re-enable Nuxt v3 behavior when testing, following the commented out lines above. Please file issues if so, so that we can address them in Nuxt or in the ecosystem. Breaking or significant changes are documented below along with migration steps and available configuration options. ### Migrating Using Codemods To facilitate the upgrade process, we have collaborated with the [Codemod](https://github.com/codemod/codemod) team to automate many migration steps with some open-source codemods. If you encounter any issues, please report them to the Codemod team with `npx codemod feedback` ๐Ÿ™ For a complete list of Nuxt 4 codemods, detailed information on each, their source, and various ways to run them, visit the [Codemod Registry](https://app.codemod.com/registry). You can run all the codemods mentioned in this guide using the following `codemod` recipe: ```bash [npm] # Using pinned version due to https://github.com/codemod/codemod/issues/1710 npx codemod@0.18.7 nuxt/4/migration-recipe ``` ```bash [yarn] # Using pinned version due to https://github.com/codemod/codemod/issues/1710 yarn dlx codemod@0.18.7 nuxt/4/migration-recipe ``` ```bash [pnpm] # Using pinned version due to https://github.com/codemod/codemod/issues/1710 pnpm dlx codemod@0.18.7 nuxt/4/migration-recipe ``` ```bash [bun] # Using pinned version due to https://github.com/codemod/codemod/issues/1710 bun x codemod@0.18.7 nuxt/4/migration-recipe ``` ```bash [deno] # Using pinned version due to https://github.com/codemod/codemod/issues/1710 deno x codemod@0.18.7 nuxt/4/migration-recipe ``` This command will execute all codemods in sequence, with the option to deselect any that you do not wish to run. Each codemod is also listed below alongside its respective change and can be executed independently. ### New Directory Structure ๐Ÿšฆ **Impact Level**: Significant Nuxt now defaults to a new directory structure, with backwards compatibility (so if Nuxt detects you are using the old structure, such as with a top-level `pages/` directory, this new structure will not apply). ๐Ÿ‘‰ [See full RFC](https://github.com/nuxt/nuxt/issues/26444) #### What Changed - the new Nuxt default `srcDir` is `app/` by default, and most things are resolved from there. - `serverDir` now defaults to `/server` rather than `/server` - `layers/`, `modules/` and `public/` are resolved relative to `` by default - if using [Nuxt Content v2.13+](https://github.com/nuxt/content/pull/2649), `content/` is resolved relative to `` - a new `dir.app` is added, which is the directory we look for `router.options.ts` and `spa-loading-template.html` - this defaults to `/` - a new [`shared/`](https://nuxt.com/docs/3.x/directory-structure/shared) directory is available for code shared between the Vue app and the Nitro server, with auto-imports for `shared/utils/` and `shared/types/`
An example v4 folder structure. ```sh .output/ .nuxt/ app/ assets/ components/ composables/ layouts/ middleware/ pages/ plugins/ utils/ app.config.ts app.vue router.options.ts content/ layers/ modules/ node_modules/ public/ shared/ types/ utils/ server/ api/ middleware/ plugins/ routes/ utils/ nuxt.config.ts ``` With this new structure, the `~` alias now points to the `app/` directory by default (your `srcDir`). This means `~/components` resolves to `components/`, `~/pages` to `pages/`, etc.
๐Ÿ‘‰ For more details, see the [PR implementing this change](https://github.com/nuxt/nuxt/pull/27029). #### Reasons for Change 1. **Performance** - placing all your code in the root of your repo causes issues with `.git/` and `node_modules/` folders being scanned/included by FS watchers which can significantly delay startup on non-Mac OSes. 2. **IDE type-safety** - `server/` and the rest of your app are running in two entirely different contexts with different global imports available, and making sure `server/` isn't *inside* the same folder as the rest of your app is a big first step to ensuring you get good auto-completes in your IDE. #### Migration Steps 1. Create a new directory called `app/`. 2. Move your `assets/`, `components/`, `composables/`, `layouts/`, `middleware/`, `pages/`, `plugins/` and `utils/` folders under it, as well as `app.vue`, `error.vue`, `app.config.ts`. If you have an `app/router-options.ts` or `app/spa-loading-template.html`, these paths remain the same. 3. Make sure your `nuxt.config.ts`, `content/`, `layers/`, `modules/`, `public/`, `shared/` and `server/` folders remain outside the `app/` folder, in the root of your project. 4. Remember to update any third-party configuration files to work with the new directory structure, such as your `tailwindcss` or `eslint` configuration (if required - `@nuxtjs/tailwindcss` should automatically configure `tailwindcss` correctly). You can automate this migration by running `npx codemod@latest nuxt/4/file-structure` However, migration is *not required*. If you wish to keep your current folder structure, Nuxt should auto-detect it. (If it does not, please raise an issue.) The one exception is that if you *already* have a custom `srcDir`. In this case, you should be aware that your `modules/`, `public/`, `shared/` and `server/` folders will be resolved from your `rootDir` rather than from your custom `srcDir`. You can override this by configuring `dir.modules`, `dir.public` and `serverDir` if you need to. You can also force a v3 folder structure with the following configuration: ```ts [nuxt.config.ts] export default defineNuxtConfig({ // This reverts the new srcDir default from `app` back to your root directory srcDir: '.', // This specifies the directory prefix for `app/router.options.ts` and `app/spa-loading-template.html` dir: { app: 'app', }, }) ``` ### Singleton Data Fetching Layer ๐Ÿšฆ **Impact Level**: Moderate #### What Changed Nuxt's data fetching system (`useAsyncData` and `useFetch`) has been significantly reorganized for better performance and consistency: 1. **Shared refs for the same key**: All calls to `useAsyncData` or `useFetch` with the same key now share the same `data`, `error` and `status` refs. This means that it is important that all calls with an explicit key must not have conflicting `deep`, `transform`, `pick`, `getCachedData` or `default` options. 2. **More control over getCachedData**: The `getCachedData` function is now called every time data is fetched, even if this is caused by a watcher or calling `refreshNuxtData`. (Previously, new data was always fetched and this function was not called in these cases.) To allow more control over when to use cached data and when to refetch, the function now receives a context object with the cause of the request. 3. **Reactive key support**: You can now use computed refs, plain refs or getter functions as keys, which enables automatic data refetching (and stores data separately). 4. **Data cleanup**: When the last component using data fetched with `useAsyncData` is unmounted, Nuxt will remove that data to avoid ever-growing memory usage. #### Reasons for Change These changes have been made to improve memory usage and increase consistency with loading states across calls of `useAsyncData`. #### Migration Steps 1. **Check for inconsistent options**: Review any components using the same key with different options or fetch functions.```ts // This will now trigger a warning const { data: users1 } = useAsyncData('users', () => $fetch('/api/users'), { deep: false }) const { data: users2 } = useAsyncData('users', () => $fetch('/api/users'), { deep: true }) ```
It may be beneficial to extract any calls to `useAsyncData` that share an explicit key (and have custom options) into their own composable:```ts [composables/useUserData.ts] export function useUserData (userId: string) { return useAsyncData( `user-${userId}`, () => fetchUser(userId), { deep: true, transform: user => ({ ...user, lastAccessed: new Date() }), }, ) } ``` 2. **Update getCachedData implementations**:```diff useAsyncData('key', fetchFunction, { - getCachedData: (key, nuxtApp) => { - return cachedData[key] - } + getCachedData: (key, nuxtApp, ctx) => { + // ctx.cause - can be 'initial' | 'refresh:hook' | 'refresh:manual' | 'watch' + + // Example: Don't use cache on manual refresh + if (ctx.cause === 'refresh:manual') return undefined + + return cachedData[key] + } }) ``` Alternatively, for now, you can disable this behaviour with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { granularCachedData: false, purgeCachedData: false, }, }) ``` ### Corrected Module Loading Order in Layers ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The order in which modules are loaded when using [Nuxt layers](https://nuxt.com/docs/3.x/guide/going-further/layers) has been corrected. Previously, modules from the project root were loaded before modules from extended layers, which was the reverse of the expected behavior. Now modules are loaded in the correct order: 1. **Layer modules first** (in extend order - deeper layers first) 2. **Project modules last** (highest priority) This affects both: - Modules defined in the `modules` array in `nuxt.config.ts` - Auto-discovered modules from the `modules/` directory #### Reasons for Change This change ensures that: - Extended layers have lower priority than the consuming project - Module execution order matches the intuitive layer inheritance pattern - Module configuration and hooks work as expected in multi-layer setups #### Migration Steps **Most projects will not need changes**, as this corrects the loading order to match expected behavior. However, if your project was relying on the previous incorrect order, you may need to: 1. **Review module dependencies**: Check if any modules depend on specific loading order 2. **Adjust module configuration**: If modules were configured to work around the incorrect order 3. **Test thoroughly**: Ensure all functionality works as expected with the corrected order Example of the new correct order: ```ts // Layer: my-layer/nuxt.config.ts export default defineNuxtConfig({ modules: ['layer-module-1', 'layer-module-2'], }) // Project: nuxt.config.ts export default defineNuxtConfig({ extends: ['./my-layer'], modules: ['project-module-1', 'project-module-2'], }) // Loading order (corrected): // 1. layer-module-1 // 2. layer-module-2 // 3. project-module-1 (can override layer modules) // 4. project-module-2 (can override layer modules) ``` If you encounter issues with module order dependencies due to needing to register a hook, consider using the [`modules:done` hook](https://nuxt.com/docs/3.x/guide/modules#custom-hooks) for modules that need to call a hook. This is run after all other modules have been loaded, which means it is safe to use. ๐Ÿ‘‰ See [PR #31507](https://github.com/nuxt/nuxt/pull/31507) and [issue #25719](https://github.com/nuxt/nuxt/issues/25719) for more details. ### Deduplication of Route Metadata ๐Ÿšฆ **Impact Level**: Minimal #### What Changed It's possible to set some route metadata using `definePageMeta`, such as the `name`, `path`, and so on. Previously these were available both on the route and on route metadata (for example, `route.name` and `route.meta.name`). Now, they are only accessible on the route object. #### Reasons for Change This is a result of enabling `experimental.scanPageMeta` by default, and is a performance optimization. #### Migration Steps The migration should be straightforward: ```diff const route = useRoute() - console.log(route.meta.name) + console.log(route.name) ``` ### Normalized Component Names ๐Ÿšฆ **Impact Level**: Moderate Vue will now generate component names that match the Nuxt pattern for component naming. #### What Changed By default, if you haven't set it manually, Vue will assign a component name that matches the filename of the component. ```bash [Directory structure] โ”œโ”€ components/ โ”œโ”€โ”€โ”€ SomeFolder/ โ”œโ”€โ”€โ”€โ”€โ”€ MyComponent.vue ``` In this case, the component name would be `MyComponent`, as far as Vue is concerned. If you wanted to use `` with it, or identify it in the Vue DevTools, you would need to use this name. But in order to auto-import it, you would need to use `SomeFolderMyComponent`. With this change, these two values will match, and Vue will generate a component name that matches the Nuxt pattern for component naming. #### Migration Steps Ensure that you use the updated name in any tests which use `findComponent` from `@vue/test-utils` and in any `` which depends on the name of your component. Alternatively, for now, you can disable this behaviour with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { normalizeComponentNames: false, }, }) ``` ### Unhead v2 ๐Ÿšฆ **Impact Level**: Minimal #### What Changed [Unhead](https://unhead.unjs.io/), used to generate `` tags, has been updated to version 2. While mostly compatible it includes several breaking changes for lower-level APIs. - Removed props: `vmid`, `hid`, `children`, `body`. - Promise input no longer supported. - Tags are now sorted using Capo.js by default. #### Migration Steps The above changes should have minimal impact on your app. If you have issues you should verify: - You're not using any of the removed props. ```diff useHead({ meta: [{ name: 'description', // meta tags don't need a vmid, or a key - vmid: 'description' - hid: 'description' }] }) ``` - If you're using [Template Params](https://unhead.unjs.io/docs/head/guides/plugins/template-params) or [Alias Tag Sorting](https://unhead.unjs.io/docs/head/guides/plugins/alias-sorting), you will need to explicitly opt in to these features now. ```ts import { AliasSortingPlugin, TemplateParamsPlugin } from '@unhead/vue/plugins' export default defineNuxtPlugin({ setup () { const unhead = injectHead() unhead.use(TemplateParamsPlugin) unhead.use(AliasSortingPlugin) }, }) ``` While not required it's recommended to update any imports from `@unhead/vue` to `#imports` or `nuxt/app`. ```diff -import { useHead } from '@unhead/vue' +import { useHead } from '#imports' ``` If you still have issues you may revert to the v1 behavior by enabling the `head.legacy` config. ```ts export default defineNuxtConfig({ unhead: { legacy: true, }, }) ``` ### New DOM Location for SPA Loading Screen ๐Ÿšฆ **Impact Level**: Minimal #### What Changed When rendering a client-only page (with `ssr: false`), we optionally render a loading screen (from `~/app/spa-loading-template.html` - note that this has also changed to `~/spa-loading-template.html` in Nuxt 4), within the Nuxt app root: ```html
``` Now, we default to rendering the template alongside the Nuxt app root: ```html
``` #### Reasons for Change This allows the spa loading template to remain in the DOM until the Vue app suspense resolves, preventing a flash of white. #### Migration Steps If you were targeting the spa loading template with CSS or `document.queryElement` you will need to update your selectors. For this purpose you can use the new `app.spaLoaderTag` and `app.spaLoaderAttrs` configuration options. Alternatively, you can revert to the previous behaviour with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { spaLoadingTemplateLocation: 'within', }, }) ``` ### Parsed `error.data` ๐Ÿšฆ **Impact Level**: Minimal It was possible to throw an error with a `data` property, but this was not parsed. Now, it is parsed and made available in the `error` object. Although a fix, this is technically a breaking change if you were relying on the previous behavior and parsing it manually. #### Migration Steps Update your custom `error.vue` to remove any additional parsing of `error.data`: ```diff ``` Alternatively, you can disable this change: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { parseErrorData: false, }, }) ``` ### More Granular Inline Styles ๐Ÿšฆ **Impact Level**: Moderate Nuxt will now only inline styles for Vue components, not global CSS. #### What Changed Previously, Nuxt would inline all CSS, including global styles, and remove `` elements to separate CSS files. Now, Nuxt will only do this for Vue components (which previously produced separate chunks of CSS). We think this is a better balance of reducing separate network requests (just as before, there will not be separate requests for individual `.css` files per-page or per-component on the initial load), as well as allowing caching of a single global CSS file and reducing the document download size of the initial request. #### Migration Steps This feature is fully configurable and you can revert to the previous behavior by setting `inlineStyles: true` to inline global CSS as well as per-component CSS. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ features: { inlineStyles: true, }, }) ``` ### Scan Page Meta After Resolution ๐Ÿšฆ **Impact Level**: Minimal #### What Changed We now scan page metadata (defined in `definePageMeta`) *after* calling the `pages:extend` hook rather than before. #### Reasons for Change This was to allow scanning metadata for pages that users wanted to add in `pages:extend`. We still offer an opportunity to change or override page metadata in a new `pages:resolved` hook. #### Migration Steps If you want to override page metadata, do that in `pages:resolved` rather than in `pages:extend`. ```diff export default defineNuxtConfig({ hooks: { - 'pages:extend'(pages) { + 'pages:resolved'(pages) { const myPage = pages.find(page => page.path === '/') myPage.meta ||= {} myPage.meta.layout = 'overridden-layout' } } }) ``` Alternatively, you can revert to the previous behaviour with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { scanPageMeta: true, }, }) ``` ### Shared Prerender Data ๐Ÿšฆ **Impact Level**: Medium #### What Changed We enabled a previously experimental feature to share data from `useAsyncData` and `useFetch` calls, across different pages. See [original PR](https://github.com/nuxt/nuxt/pull/24894). #### Reasons for Change This feature 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. For example, if your site requires a `useFetch` call for every page (for example, to get navigation data for a menu, or site settings from a CMS), this data would only be fetched once when prerendering the first page that uses it, and then cached for use when prerendering other pages. #### Migration Steps 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.) ```ts [pages/test/[slug].vue] // 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}`) }) ``` Alternatively, you can disable this feature with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { sharedPrerenderData: false, }, }) ``` ### Default `data` and `error` values in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `data` and `error` objects returned from `useAsyncData` will now default to `undefined`. #### Reasons for Change Previously `data` was initialized to `null` but reset in `clearNuxtData` to `undefined`. `error` was initialized to `null`. This change is to bring greater consistency. #### Migration Steps If you were checking if `data.value` or `error.value` were `null`, you can update these checks to check for `undefined` instead. You can automate this step by running `npx codemod@latest nuxt/4/default-data-error-value` If you encounter any issues you can revert back to the previous behavior with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { defaults: { useAsyncData: { value: 'null', errorValue: 'null', }, }, }, }) ``` Please report an issue if you are doing this, as we do not plan to keep this as configurable. ### Removal of deprecated `boolean` values for `dedupe` option when calling `refresh` in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`). ```ts [app.vue]twoslash // @errors: 2322 const { refresh } = await useAsyncData(() => Promise.resolve({ message: 'Hello, Nuxt!' })) async function refreshData () { await refresh({ dedupe: true }) } ``` #### Reasons for Change These aliases were removed, for greater clarity. The issue came up when adding `dedupe` as an option to `useAsyncData`, and we removed the boolean values as they ended up being *opposites*. `refresh({ dedupe: false })` meant **do not cancel existing requests in favour of this new one**. But passing `dedupe: true` within the options of `useAsyncData` means **do not make any new requests if there is an existing pending request.** (See [PR](https://github.com/nuxt/nuxt/pull/24564#pullrequestreview-1764584361).) #### Migration Steps The migration should be straightforward: ```diff const { refresh } = await useAsyncData(async () => ({ message: 'Hello, Nuxt 3!' })) async function refreshData () { - await refresh({ dedupe: true }) + await refresh({ dedupe: 'cancel' }) - await refresh({ dedupe: false }) + await refresh({ dedupe: 'defer' }) } ``` You can automate this step by running `npx codemod@latest nuxt/4/deprecated-dedupe-value` ### Respect defaults when clearing `data` in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed If you provide a custom `default` value for `useAsyncData`, this will now be used when calling `clear` or `clearNuxtData` and it will be reset to its default value rather than simply unset. #### Reasons for Change Often users set an appropriately empty value, such as an empty array, to avoid the need to check for `null`/`undefined` when iterating over it. This should be respected when resetting/clearing the data. #### Migration Steps If you encounter any issues you can revert back to the previous behavior, for now, with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { resetAsyncDataToUndefined: true, }, }) ``` Please report an issue if you are doing so, as we do not plan to keep this as configurable. ### Alignment of `pending` value in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Medium The `pending` object returned from `useAsyncData`, `useFetch`, `useLazyAsyncData` and `useLazyFetch` is now a computed property that is `true` only when `status` is also pending. #### What Changed Now, when `immediate: false` is passed, `pending` will be `false` until the first request is made. This is a change from the previous behavior, where `pending` was always `true` until the first request was made. #### Reasons for Change This aligns the meaning of `pending` with the `status` property, which is also `pending` when the request is in progress. #### Migration Steps If you rely on the `pending` property, ensure that your logic accounts for the new behavior where `pending` will only be `true` when the status is also pending. ```diff ``` Alternatively, you can temporarily revert to the previous behavior with: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { pendingWhenIdle: true, }, }) ``` ### Key Change Behavior in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Medium #### What Changed When using reactive keys in `useAsyncData` or `useFetch`, Nuxt automatically refetches data when the key changes. When `immediate: false` is set, `useAsyncData` will only fetch data when the key changes if the data has already been fetched once. Previously, `useFetch` had slightly different behavior. It would always fetch data when the key changed. Now, `useFetch` and `useAsyncData` behave consistently - by only fetch data when the key changes if the data has already been fetched once. #### Reasons for Change This ensures consistent behavior between `useAsyncData` and `useFetch`, and prevents unexpected fetches. If you have set `immediate: false`, then you must call `refresh` or `execute` or data will never be fetched in `useFetch` or `useAsyncData`. #### Migration Steps This change should generally improve the expected behavior, but if you were expecting changing the key or options of a non-immediate `useFetch`, you now will need to trigger it manually the first time. ```diff const id = ref('123') const { data, execute } = await useFetch('/api/test', { query: { id }, immediate: false ) + watch(id, () => execute(), { once: true }) ``` To opt out of this behavior: ```ts // Or globally in your Nuxt config export default defineNuxtConfig({ experimental: { alwaysRunFetchOnKeyChange: true, }, }) ``` ### Shallow Data Reactivity in `useAsyncData` and `useFetch` ๐Ÿšฆ **Impact Level**: Minimal The `data` object returned from `useAsyncData`, `useFetch`, `useLazyAsyncData` and `useLazyFetch` is now a `shallowRef` rather than a `ref`. #### What Changed When new data is fetched, anything depending on `data` will still be reactive because the entire object is replaced. But if your code changes a property *within* that data structure, this will not trigger any reactivity in your app. #### Reasons for Change This brings a **significant** performance improvement for deeply nested objects and arrays because Vue does not need to watch every single property/array for modification. In most cases, `data` should also be immutable. #### Migration Steps In most cases, no migration steps are required, but if you rely on the reactivity of the data object then you have two options: 1. You can granularly opt in to deep reactivity on a per-composable basis: ```diff - const { data } = useFetch('/api/test') + const { data } = useFetch('/api/test', { deep: true }) ``` 2. You can change the default behavior on a project-wide basis (not recommended): ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ experimental: { defaults: { useAsyncData: { deep: true, }, }, }, }) ``` If you need to, you can automate this step by running `npx codemod@latest nuxt/4/shallow-function-reactivity` ### Absolute Watch Paths in `builder:watch` ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The Nuxt `builder:watch` hook now emits a path which is absolute rather than relative to your project `srcDir`. #### Reasons for Change This allows us to support watching paths which are outside your `srcDir`, and offers better support for layers and other more complex patterns. #### Migration Steps We have already proactively migrated the public Nuxt modules which we are aware use this hook. See [issue #25339](https://github.com/nuxt/nuxt/issues/25339). However, if you are a module author using the `builder:watch` hook and wishing to remain backwards/forwards compatible, you can use the following code to ensure that your code works the same in both Nuxt v3 and Nuxt v4: ```diff + import { relative, resolve } from 'node:fs' // ... nuxt.hook('builder:watch', async (event, path) => { + path = relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, path)) // ... }) ``` You can automate this step by running `npx codemod@latest nuxt/4/absolute-watch-path` ### Removal of `window.__NUXT__` object #### What Changed We are removing the global `window.__NUXT__` object after the app finishes hydration. #### Reasons for Change This opens the way to multi-app patterns ([#21635](https://github.com/nuxt/nuxt/issues/21635)) and enables us to focus on a single way to access Nuxt app data - `useNuxtApp()`. #### Migration Steps The data is still available, but can be accessed with `useNuxtApp().payload`: ```diff - console.log(window.__NUXT__) + console.log(useNuxtApp().payload) ``` ### Directory index scanning ๐Ÿšฆ **Impact Level**: Medium #### What Changed Child folders in your `middleware/` folder are also scanned for `index` files and these are now also registered as middleware in your project. #### Reasons for Change Nuxt scans a number of folders automatically, including `middleware/` and `plugins/`. Child folders in your `plugins/` folder are scanned for `index` files and we wanted to make this behavior consistent between scanned directories. #### Migration Steps Probably no migration is necessary but if you wish to revert to previous behavior you can add a hook to filter out these middleware: ```ts export default defineNuxtConfig({ hooks: { 'app:resolve' (app) { app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path)) }, }, }) ``` ### Template Compilation Changes ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Previously, Nuxt used `lodash/template` to compile templates located on the file system using the `.ejs` file format/syntax. In addition, we provided some template utilities (`serialize`, `importName`, `importSources`) which could be used for code-generation within these templates, which are now being removed. #### Reasons for Change In Nuxt v3 we moved to a 'virtual' syntax with a `getContents()` function which is much more flexible and performant. In addition, `lodash/template` has had a succession of security issues. These do not really apply to Nuxt projects because it is being used at build-time, not runtime, and by trusted code. However, they still appear in security audits. Moreover, `lodash` is a hefty dependency and is unused by most projects. Finally, providing code serialization functions directly within Nuxt is not ideal. Instead, we maintain projects like [unjs/knitwork](https://github.com/unjs/knitwork) which can be dependencies of your project, and where security issues can be reported/resolved directly without requiring an upgrade of Nuxt itself. #### Migration Steps We have raised PRs to update modules using EJS syntax, but if you need to do this yourself, you have three backwards/forwards-compatible alternatives: - Moving your string interpolation logic directly into `getContents()`. - Using a custom function to handle the replacement, such as in [https://github.com/nuxt-modules/color-mode/pull/240](https://github.com/nuxt-modules/color-mode/pull/240). - Use `es-toolkit/compat` (a drop-in replacement for lodash template), as a dependency of *your* project rather than Nuxt: ```diff + import { readFileSync } from 'node:fs' + import { template } from 'es-toolkit/compat' // ... addTemplate({ fileName: 'appinsights-vue.js' options: { /* some options */ }, - src: resolver.resolve('./runtime/plugin.ejs'), + getContents({ options }) { + const contents = readFileSync(resolver.resolve('./runtime/plugin.ejs'), 'utf-8') + return template(contents)({ options }) + }, }) ``` Finally, if you are using the template utilities (`serialize`, `importName`, `importSources`), you can replace them as follows with utilities from `knitwork`: ```ts import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork' const serialize = (data: any) => JSON.stringify(data, null, 2).replace(/"\{(.+)\}"(?=,?$)/gm, r => JSON.parse(r).replace(/^\{(.*)\}$/, '$1')) const importSources = (sources: string | string[], { lazy = false } = {}) => { return toArray(sources).map((src) => { if (lazy) { return `const ${genSafeVariableName(src)} = ${genDynamicImport(src, { comment: `webpackChunkName: ${JSON.stringify(src)}` })}` } return genImport(src, genSafeVariableName(src)) }).join('\n') } const importName = genSafeVariableName ``` You can automate this step by running `npx codemod@latest nuxt/4/template-compilation-changes` ### Default TypeScript Configuration Changes ๐Ÿšฆ **Impact Level**: Minimal #### What Changed `compilerOptions.noUncheckedIndexedAccess` is now `true` instead of `false`. #### Reasons for Change This change is a follow up to a prior [3.12 config update](https://github.com/nuxt/nuxt/pull/27485) where we improved our defaults, mostly adhering to [TotalTypeScript's recommendations](https://www.totaltypescript.com/tsconfig-cheat-sheet). #### Migration Steps There are two approaches: 1. Run a typecheck on your app and fix any new errors (recommended). 2. Override the new default in your `nuxt.config.ts`:```ts export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedIndexedAccess: false, }, }, }, }) ``` ### TypeScript Configuration Splitting ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Nuxt now generates separate TypeScript configurations for different contexts to provide better type-checking experiences: 1. **New TypeScript configuration files**: Nuxt now generates additional TypeScript configurations: - `.nuxt/tsconfig.app.json` - For your app code (Vue components, composables, etc.) - `.nuxt/tsconfig.server.json` - For your server-side code (Nitro/server directory) - `.nuxt/tsconfig.node.json` - For your build-time code (modules, `nuxt.config.ts`, etc.) - `.nuxt/tsconfig.shared.json` - For code shared between app and server contexts (like types and non-environment specific utilities) - `.nuxt/tsconfig.json` - Legacy configuration for backward compatibility 2. **Backward compatibility**: Existing projects that extend `.nuxt/tsconfig.json` will continue to work as before. 3. **Opt-in project references**: New projects or those wanting better type checking can adopt TypeScript's project references feature. 4. **Context-specific type checking**: Each context now has appropriate compiler options and includes/excludes for its specific environment. 5. **New typescript.nodeTsConfig option**: You can now customize the TypeScript configuration for Node.js build-time code. #### Reasons for Change This change provides several benefits: 1. **Better type safety**: Each context (app, server, build-time) gets appropriate type checking with context-specific globals and APIs. 2. **Improved IDE experience**: Better IntelliSense and error reporting for different parts of your codebase. 3. **Cleaner separation**: Server code won't incorrectly suggest client-side APIs and vice versa. 4. **Performance**: TypeScript can more efficiently check code with properly scoped configurations. For example, auto-imports are not available in your `nuxt.config.ts` (but previously this was not flagged by TypeScript). And while IDEs recognized the separate context hinted by `tsconfig.json` in your `server/` directory, this was not reflected in type-checking (requiring a separate step). #### Migration Steps **No migration is required** - existing projects will continue to work as before. However, to take advantage of improved type checking, you can opt in to the new project references approach: 1. **Update your root tsconfig.json** to use project references: If your `tsconfig.json` currently has an `"extends": "./.nuxt/tsconfig.json"` line, **remove it** before adding the references. Project references and extends are mutually exclusive. ```json { // Remove "extends": "./.nuxt/tsconfig.json" if present "files": [], "references": [ { "path": "./.nuxt/tsconfig.app.json" }, { "path": "./.nuxt/tsconfig.server.json" }, { "path": "./.nuxt/tsconfig.shared.json" }, { "path": "./.nuxt/tsconfig.node.json" } ] } ``` 2. **Remove any manual server tsconfig.json** files (like `server/tsconfig.json`) that extended `.nuxt/tsconfig.server.json`. 3. **Update your type checking scripts** to use the build flag for project references:```diff - "typecheck": "nuxt prepare && vue-tsc --noEmit" + "typecheck": "nuxt prepare && vue-tsc -b --noEmit" ``` 4. **Move all type augmentations into their appropriate context**: - If you are augmenting types for the app context, move the files to the `app/` directory. - If you are augmenting types for the server context, move the files to the `server/` directory. - If you are augmenting types that are **shared between the app and server**, move the files to the `shared/` directory. Augmenting types from outside the `app/`, `server/`, or `shared/` directories will not work with the new project references setup. 5. **Configure TypeScript options** if needed:```ts export default defineNuxtConfig({ typescript: { // customize tsconfig.app.json tsConfig: { // ... }, // customize tsconfig.shared.json sharedTsConfig: { // ... }, // customize tsconfig.node.json nodeTsConfig: { // ... }, }, nitro: { typescript: { // customize tsconfig.server.json tsConfig: { // ... }, }, }, }) ``` 6. **Update any CI/build scripts** that run TypeScript checking to ensure they use the new project references approach. The new configuration provides better type safety and IntelliSense for projects that opt in, while maintaining full backward compatibility for existing setups. ### Removal of Experimental Features ๐Ÿšฆ **Impact Level**: Minimal #### What Changed Four experimental features are no longer configurable in Nuxt 4: - `experimental.treeshakeClientOnly` will be `true` (default since v3.0) - `experimental.configSchema` will be `true` (default since v3.3) - `experimental.polyfillVueUseHead` will be `false` (default since v3.4) - `experimental.respectNoSSRHeader` will be `false` (default since v3.4) - `vite.devBundler` is no longer configurable - it will use `vite-node` by default #### Reasons for Change These options have been set to their current values for some time and we do not have a reason to believe that they need to remain configurable. #### Migration Steps - `polyfillVueUseHead` is implementable in user-land with [this plugin](https://github.com/nuxt/nuxt/blob/f209158352b09d1986aa320e29ff36353b91c358/packages/nuxt/src/head/runtime/plugins/vueuse-head-polyfill.ts#L10-L11) - `respectNoSSRHeader`is implementable in user-land with [server middleware](https://github.com/nuxt/nuxt/blob/c660b39447f0d5b8790c0826092638d321cd6821/packages/nuxt/src/core/runtime/nitro/no-ssr.ts#L8-L9) ### Removal of Top-Level `generate` Configuration ๐Ÿšฆ **Impact Level**: Minimal #### What Changed The top-level `generate` configuration option is no longer available in Nuxt 4. This includes all of its properties: - `generate.exclude` - for excluding routes from prerendering - `generate.routes` - for specifying routes to prerender #### Reasons for Change The top level `generate` configuration was a holdover from Nuxt 2. We've supported `nitro.prerender` for a while now, and it is the preferred way to configure prerendering in Nuxt 3+. #### Migration Steps Replace `generate` configuration with the corresponding `nitro.prerender` options: ```diff export default defineNuxtConfig({ - generate: { - exclude: ['/admin', '/private'], - routes: ['/sitemap.xml', '/robots.txt'] - } + nitro: { + prerender: { + ignore: ['/admin', '/private'], + routes: ['/sitemap.xml', '/robots.txt'] + } + } }) ``` Read more about Nitro's prerender configuration options. ## Nuxt 2 vs. Nuxt 3+ In the table below, there is a quick comparison between 3 versions of Nuxt:
Feature / Version Nuxt 2 Nuxt Bridge Nuxt 3+
Vue 2 2 3
Stability ๐Ÿ˜Š Stable ๐Ÿ˜Š Stable ๐Ÿ˜Š Stable
Performance ๐ŸŽ Fast โœˆ๏ธ Faster ๐Ÿš€ Fastest
Nitro Engine โŒ โœ… โœ…
ESM support ๐ŸŒ™ Partial ๐Ÿ‘ Better โœ…
TypeScript โ˜‘๏ธ Opt-in ๐Ÿšง Partial โœ…
Composition API โŒ ๐Ÿšง Partial โœ…
Options API โœ… โœ… โœ…
Components Auto Import โœ… โœ… โœ…
``` **Solution**: You can use [`useCookie`](https://nuxt.com/docs/3.x/api/composables/use-cookie): ```html ``` ### Inconsistent Data **Problem**: Different data between server and client. ```html ``` **Solution**: Use SSR-friendly state: ```html ``` ### Conditional Rendering Based on Client State **Problem**: Using client-only conditions during SSR. ```html ``` **Solution**: Use media queries or handle it client-side: ```html ``` ### Third-party Libraries with Side Effects **Problem**: Libraries that modify the DOM or have browser dependencies (this happens a LOT with tag managers). ```html ``` **Solution**: Initialise libraries after hydration has completed: ```html ``` ### Dynamic Content Based on Time **Problem**: Content that changes based on current time. ```html ``` **Solution**: Use [`NuxtTime`](https://nuxt.com/docs/3.x/api/components/nuxt-time) component or handle it client-side: ```html ``` ```html ``` ## In summary 1. **Use SSR-friendly composables**: [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch), [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data), [`useState`](https://nuxt.com/docs/3.x/api/composables/use-state) 2. **Wrap client-only code**: Use [`ClientOnly`](https://nuxt.com/docs/3.x/api/components/client-only) component for browser-specific content 3. **Consistent data sources**: Ensure server and client uses the same data 4. **Avoid side effects in setup**: Move browser-dependent code to `onMounted` You can read the [Vue documentation on SSR hydration mismatch](https://vuejs.org/guide/scaling-up/ssr#hydration-mismatch) for a better understanding of hydration. # Nuxt performance > Best practices for improving performance of Nuxt apps. Nuxt comes with built-in features designed to improve your application's performance and contribute to better [Core Web Vitals](https://web.dev/articles/vitals). There are also multiple Nuxt core modules that assist in improving performance in specific areas. This guide outlines best practices to optimize performance of your Nuxt application. ## Built-in Features Nuxt offers several built-in features that help you optimize performance of your website. Understanding how these features work is crucial for achieving blazingly-fast performance. ### Links [``](https://nuxt.com/docs/3.x/api/components/nuxt-link) is a drop-in replacement for both Vue Router's `` component and HTML's `` tag. It intelligently determines whether the link is internal or external and renders it accordingly with available optimizations (prefetching, default attributes, etc.) ```html About page ``` Nuxt automatically includes smart prefetching. That means it detects when a link is visible (by default), either in the viewport or when scrolling and prefetches the JavaScript for those pages so that they are ready when the user clicks the link. You can also opt for prefetching on interaction instead: ```ts export default defineNuxtConfig({ experimental: { defaults: { nuxtLink: { prefetchOn: { interaction: true, visibility: false, }, }, }, }, }) ``` ### Hybrid Rendering In more complex applications, we may need a full control over how our application is rendered to support cases where some pages could be generated at build time, while others should be client-side rendered Hybrid rendering allows different caching rules per route using Route Rules and decides how the server should respond to a new request on a given URL: ```ts export default defineNuxtConfig({ routeRules: { '/': { prerender: true, }, '/products/**': { swr: 3600, }, '/blog': { isr: 3600, }, '/admin/**': { ssr: false, }, }, }) ``` Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using Nitro caching layer. ### Lazy Loading Components To dynamically import a component (also known as lazy-loading a component) all you need to do is add the Lazy prefix to the component's name. This is useful if the component is not always needed. ```html ``` By using the Lazy prefix you can delay loading the component code until the right moment, which can be helpful for optimizing your JavaScript bundle size. ### Lazy Hydration It is not always necessary to hydrate (or make interactive) all the components of your site on the initial load. Using lazy hydration, you can control when components can have their code loaded, which can improve the time-to-interactive metric for your app. Nuxt allows you to control when components become interactive with lazy hydration (added in Nuxt v3.16). ```html ``` To optimize your app, you may want to delay the hydration of some components until they're visible, or until the browser is done with more important tasks. ### Fetching data To avoid fetching same data twice (once on the server and once on client) Nuxt provides [`useFetch`](https://nuxt.com/docs/3.x/api/composables/use-fetch) and [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data). They ensure that if an API call is made on the server, the data is forwarded to the client in the payload instead of being fetched again. ## Core Nuxt Modules Apart from Nuxt's built-in features, there are also core modules maintained by the Nuxt team which help improve performance even further. These modules help handle assets such as images, custom fonts, or third party scripts. ### Images Unoptimized images can have a significant negative impact on your website performance, specifically the [Largest Contentful Paint (LCP)](https://web.dev/articles/lcp) score. In Nuxt we can use [Nuxt Image](https://image.nuxt.com/) module that is a plug-and-play image optimization for Nuxt apps. It allows resizing and transforming your images using built-in optimizer or your favorite images CDN. [``](https://nuxt.com/docs/3.x/api/components/nuxt-img) is a drop-in replacement for the native `` tag that comes with following enhancements: - Uses built-in provider to optimize local and remote images - Converts `src` to provider optimized URLs with modern formats such as WebP or Avif - Automatically resizes images based on `width` and `height` - Generates responsive `sizes` when providing sizes option - Supports native `lazy loading` as well as other `` attributes Images in your website can usually be separated by importance; the ones that are needed to be delivered first at initial load (i.e. `Largest Contentful Paint`), and the ones that can be loaded later or when specifically needed. For that, we could use the following optimizations: ```html ``` ### Fonts [Nuxt Fonts](https://fonts.nuxt.com/) will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance. It includes built-in automatic self-hosting for any font file which means you can optimally load web fonts with reduced layout shift, thanks to the underlying package [fontaine](https://github.com/unjs/fontaine). Nuxt Fonts processes all your CSS and does the following things automatically when it encounters a font-family declaration. 1. **Resolves fonts** โ€“ Looks for font files in public/, then checks web providers like Google, Bunny, and Fontshare. 2. **Generates @font-face rules** โ€“ Injects CSS rules to load fonts from the correct sources. 3. **Proxies & caches fonts** โ€“ Rewrites URLs to `/_fonts`, downloads and caches fonts locally. 4. **Creates fallback metrics** โ€“ Adjusts local system fonts to match web fonts, reducing layout shift ([CLS](https://web.dev/articles/cls)). 5. **Includes fonts in build** โ€“ Bundles fonts with your project, hashing file names and setting long-lived cache headers. It supports multiple providers that are designed to be pluggable and extensible, so no matter your setup you should be able to use an existing provider or write your own. ### Scripts Third-party resources like analytics tools, video embeds, maps, and social media integrations enhance website functionality but can significantly degrade user experience and negatively impact [Interaction to Next Paint (INP)](https://web.dev/articles/inp) and Largest Contentful Paint (LCP) scores. [Nuxt Scripts](https://scripts.nuxt.com/) lets you load third-party scripts with better performance, privacy, security and DX. Nuxt Scripts provides an abstraction layer on top of third-party scripts, providing SSR support and type-safety and while still giving you full low-level control over how a script is loaded. ```ts const { onLoaded, proxy } = useScriptGoogleAnalytics( { id: 'G-1234567', scriptOptions: { trigger: 'manual', }, }, ) // queue events to be sent when ga loads proxy.gtag('config', 'UA-123456789-1') // or wait until ga is loaded onLoaded((gtag) => { // script loaded }) ``` ## Profiling Tools To improve performance, we need to first know how to measure it, starting with measuring performance during development - on local environment, and then moving to auditing application that are deployed on production. ### Nuxi Analyze [This](https://nuxt.com/docs/3.x/api/commands/analyze) command of `nuxi` allows to analyze the production bundle or your Nuxt application. It leverages `vite-bundle-visualizer` (similar to `webpack-bundle-analyzer`) to generate a visual representation of your application's bundle, making it easier to identify which components take up the most space. When you see a large block in the visualization, it often signals an opportunity for optimizationโ€”whether by splitting it into smaller parts, implementing lazy loading, or replacing it with a more efficient alternative, especially for third-party libraries. Large blocks containing multiple elements can often be reduced by importing only the necessary components rather than entire modules while large standalone blocks may be better suited for lazy loading rather than being included in the main bundle. ### Nuxt DevTools The [Nuxt DevTools](https://devtools.nuxt.com/) gives you insights and transparency about your Nuxt App to identify performance gaps and seamlessly manage your app configurations. ![Nuxt DevTools example](https://user-images.githubusercontent.com/11247099/217670806-fb39aeff-3881-44e5-b9c8-6c757f5925fc.png) It comes with several features we can use to measure performance of Nuxt apps: 1. **Timeline** โ€“ Tracks time spent on rendering, updating, and initializing components to identify performance bottlenecks. 2. **Assets** โ€“ Displays file sizes (e.g., images) without transformations. 3. **Render Tree** โ€“ Shows connections between Vue components, scripts, and styles to optimize dynamic loading. 4. **Inspect** โ€“ Lists all files used in the Vue app with their size and evaluation time. ### Chrome DevTools Chrome DevTools come with two useful tabs for measuring performance; `Performance` and `Lighthouse`. When you open the [Performance](https://developer.chrome.com/docs/devtools/performance/overview) panel, it instantly shows your local **Largest Contentful Paint (LCP)** and **Cumulative Layout Shift (CLS)** scores (good, needs improvement, or bad). If you interact with the page, it also captures **Interaction to Next Paint (INP)**, giving you a full view of your Core Web Vitals based on your device and network. ![Chrome DevTools Performance Panel](https://developer.chrome.com/static/docs/devtools/performance/image/cpu-throttling_856.png) [Lighthouse](https://developer.chrome.com/docs/devtools/lighthouse) audits performance, accessibility, SEO, progressive web apps, and best practices. It runs tests on your page and generates a report. Use failing audits as a guide to improve your site. ![Lighthouse](https://developer.chrome.com/static/docs/lighthouse/images/lighthouse-overview_720.png) Each audit has a reference document explaining why the audit is important, as well as how to fix it. ### PageSpeed Insights [PageSpeed Insights (PSI)](https://developers.google.com/speed/docs/insights/v5/about) reports on the user experience of a page on both mobile and desktop devices, and provides suggestions on how that page may be improved. It provides both lab and field data about a page. Lab data is useful for debugging issues, as it is collected in a controlled environment while field data is useful for capturing true, real-world user experience. ### Web Page Test [WebPageTest](https://www.webpagetest.org/) is a web performance tool providing deep diagnostic information about how a page performs under a variety of conditions. Each test can be run from different locations around the world, on real browsers, over any number of customizable network conditions. ## Common problems When building more complex Nuxt applications, you will probably encounter some of the problems listed below. Understanding these problems and fixing them will help you improve performance of your website. ### Overusing plugins **Problem**: A large number of plugins can cause performance issues, especially if they require expensive computations or take too long to initialize. Since plugins run during the hydration phase, inefficient setups can block rendering and degrade the user experience. **Solution**: Inspect your plugins and see if some of them could be implemented rather as a composable or utility function instead. ### Unused code / dependencies **Problem**: With the development of the project, there can be a case where there will be some unused code or a dependency. This additional functionality may not be used or needed while it will be increase the bundle size of our project. **Solution**: Inspect your `package.json` for unused dependencies and analyze your code for unused utils/composables/functions. ### Not using Vue Performance tips **Problem**: [Vue documentation](https://vuejs.org/guide/best-practices/performance) lists several Performance improvements we can use in our Nuxt projects as well but as they are part of Vue documentation, developers tend to forget about it and focus on Nuxt specific improvements only - while Nuxt application is still a Vue project. **Solution**: Use concepts such as `shallowRef`, `v-memo`, `v-once`, etc to improve performance. ### Not following patterns **Problem**: The more people are currently working on the project, the more difficult it will be to maintain the stable codebase. Developers have a tendency to introduce new concepts they've seen in another project which can cause conflicts and problems with performance. **Solution**: Establish rules and patterns in the project such as [Good practices and Design Patterns for Vue Composables](https://dev.to/jacobandrewsky/good-practices-and-design-patterns-for-vue-composables-24lk) ### Trying to load everything at the same time **Problem**: When a page is loaded and it is not correctly instructed about the order of loading elements it will result in fetching everything at the same time - which can be slow and result in bad User Experience. **Solution**: Use concepts such as Progressive Enhancement where core webpage content is set first, then more nuanced and technically rigorous layers of presentation and features are added on top as the browser/internet connection allow. ## Useful Resources To learn more about various techniques for improving performance, take a look at the following resources: 1. [Apply instant loading with the PRPL pattern](https://web.dev/articles/apply-instant-loading-with-prpl) 2. [Perceived performance](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance) 3. [Understanding Critical Rendering Path](https://developer.mozilla.org/en-US/docs/Web/Performance/Guides/Critical_rendering_path) # Nuxt Plugins > Best practices when using Nuxt plugins. Plugins in Nuxt allow you to extend your application with additional functionality. However, improper use can lead to performance bottlenecks. This guide outlines best practices to optimize your Nuxt plugins. ## Avoid costly plugin setup A large number of plugins can cause performance issues, especially if they require expensive computations or take too long to initialize. Since plugins run during the hydration phase, inefficient setups can block rendering and degrade the user experience. ## Use Composition whenever possible Whenever possible, favor composition over plugins. Just like in Vue, many utilities and composables can be used directly without the need for a plugin. This keeps your project lightweight and improves maintainability. ## If `async`, enable `parallel` By default, all plugins loads synchronously. When defining asynchronous plugins, setting `parallel: true` allows multiple plugins to load concurrently, improving performance by preventing blocking operations. # Auto-imports > Nuxt auto-imports components, composables, helper functions and Vue APIs. Nuxt auto-imports components, composables and [Vue.js APIs](https://vuejs.org/api/) to use across your application without explicitly importing them. ```vue [app.vue]twoslash ``` Thanks to its opinionated directory structure, Nuxt can auto-import your [`components/`](https://nuxt.com/docs/3.x/directory-structure/components), [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables) and [`utils/`](https://nuxt.com/docs/3.x/directory-structure/utils). Contrary to a classic global declaration, Nuxt preserves typings, IDEs completions and hints, and **only includes what is used in your production code**. In the docs, every function that is not explicitly imported is auto-imported by Nuxt and can be used as-is in your code. You can find a reference for auto-imported components, composables and utilities in the [API section](https://nuxt.com/docs/3.x/api). In the [`server`](https://nuxt.com/docs/3.x/directory-structure/server) directory, Nuxt auto-imports exported functions and variables from `server/utils/`. You can also auto-import functions exported from custom folders or third-party packages by configuring the [`imports`](https://nuxt.com/docs/3.x/api/nuxt-config#imports) section of your `nuxt.config` file. ## Built-in Auto-imports Nuxt auto-imports functions and composables to perform [data fetching](https://nuxt.com/docs/3.x/getting-started/data-fetching), get access to the [app context](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) and [runtime config](https://nuxt.com/docs/3.x/guide/going-further/runtime-config), manage [state](https://nuxt.com/docs/3.x/getting-started/state-management) or define components and plugins. ```vuetwoslash ``` Vue exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt. ```vuetwoslash ``` ### Vue and Nuxt Composables When you are using the built-in Composition API composables provided by Vue and Nuxt, be aware that many of them rely on being called in the right *context*. During a component lifecycle, Vue tracks the temporary instance of the current component (and similarly, Nuxt tracks a temporary instance of `nuxtApp`) via a global variable, and then unsets it in the same tick. This is essential when server rendering, both to avoid cross-request state pollution (leaking a shared reference between two users) and to avoid leakage between different components. That means that (with very few exceptions) you cannot use them outside a Nuxt plugin, Nuxt route middleware or Vue setup function. On top of that, you must use them synchronously - that is, you cannot use `await` before calling a composable, except within ` ``` ### Disabling Auto-imports If you want to disable auto-importing composables and utilities, you can set `imports.autoImport` to `false` in the `nuxt.config` file. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { autoImport: false, }, }) ``` This will disable auto-imports completely but it's still possible to use [explicit imports](https://nuxt.com/docs/3.x/guide/concepts/auto-imports#explicit-imports) from `#imports`. ### Partially Disabling Auto-imports If you want framework-specific functions like `ref` to remain auto-imported but wish to disable auto-imports for your own code (e.g., custom composables), you can set the `imports.scan` option to `false` in your `nuxt.config.ts` file: ```ts export default defineNuxtConfig({ imports: { scan: false, }, }) ``` With this configuration: - Framework functions like `ref`, `computed`, or `watch` will still work without needing manual imports. - Custom code, such as composables, will need to be manually imported in your files. **Caution:** This setup has certain limitations: - If you structure your project with layers, you will need to explicitly import the composables from each layer, rather than relying on auto-imports. - This breaks the layer systemโ€™s override feature. If you use `imports.scan: false`, ensure you understand this side-effect and adjust your architecture accordingly. ## Auto-imported Components Nuxt also automatically imports components from your `~/components` directory, although this is configured separately from auto-importing composables and utility functions. To disable auto-importing components from your own `~/components` directory, you can set `components.dirs` to an empty array (though note that this will not affect components added by modules). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ components: { dirs: [], }, }) ``` ## Auto-import from Third-Party Packages Nuxt also allows auto-importing from third-party packages. If you are using the Nuxt module for that package, it is likely that the module has already configured auto-imports for that package. For example, you could enable the auto-import of the `useI18n` composable from the `vue-i18n` package like this: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ imports: { presets: [ { from: 'vue-i18n', imports: ['useI18n'], }, ], }, }) ``` # Code Style > Nuxt supports ESLint out of the box ## ESLint The recommended approach for Nuxt is to enable ESLint support using the [`@nuxt/eslint`](https://eslint.nuxt.com/packages/module) module, that will setup project-aware ESLint configuration for you. The module is designed for the [new ESLint flat config format](https://eslint.org/docs/latest/use/configure/configuration-files) which is the [default format since ESLint v9](https://eslint.org/blog/2024/04/eslint-v9.0.0-released/). If you are using the legacy `.eslintrc` config, you will need to [configure manually with `@nuxt/eslint-config`](https://eslint.nuxt.com/packages/config#customizing-the-config). We highly recommend you to migrate over the flat config to be future-proof. ## Quick Setup ```bash npx nuxt module add eslint ``` Start your Nuxt app, a `eslint.config.mjs` file will be generated under your project root. You can customize it as needed. You can learn more about the module and customizations in [Nuxt ESLint's documentation](https://eslint.nuxt.com/packages/module). # ES Modules > Nuxt uses native ES modules. This guide helps explain what ES Modules are and how to make a Nuxt app (or upstream library) compatible with ESM. ## Background ### CommonJS Modules CommonJS (CJS) is a format introduced by Node.js that allows sharing functionality between isolated JavaScript modules ([read more](https://nodejs.org/api/modules.html)). You might be already familiar with this syntax: ```js const a = require('./a') module.exports.a = a ``` Bundlers like webpack and Rollup support this syntax and allow you to use modules written in CommonJS in the browser. ### ESM Syntax Most of the time, when people talk about ESM vs. CJS, they are talking about a different syntax for writing [modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules). ```js import a from './a' export { a } ``` Before ECMAScript Modules (ESM) became a standard (it took more than 10 years!), tooling like [webpack](https://webpack.js.org/guides/ecma-script-modules/) and even languages like TypeScript started supporting so-called **ESM syntax**. However, there are some key differences with actual spec; here's [a helpful explainer](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/). ### What is 'Native' ESM? You may have been writing your app using ESM syntax for a long time. After all, it's natively supported by the browser, and in Nuxt 2 we compiled all the code you wrote to the appropriate format (CJS for server, ESM for browser). When adding modules to your package, things were a little different. A sample library might expose both CJS and ESM versions, and let us pick which one we wanted: ```json { "name": "sample-library", "main": "dist/sample-library.cjs.js", "module": "dist/sample-library.esm.js" } ``` So in Nuxt 2, the bundler (webpack) would pull in the CJS file ('main') for the server build and use the ESM file ('module') for the client build. The `module` field is a convention used by bundlers like webpack and Rollup, but is not recognized by Node.js itself. Node.js only uses the [`exports`](https://nodejs.org/api/packages.html#exports) and [`main`](https://nodejs.org/api/packages.html#main) fields for module resolution. However, in recent Node.js LTS releases, it is now possible to [use native ESM module](https://nodejs.org/api/esm.html) within Node.js. That means that Node.js itself can process JavaScript using ESM syntax, although it doesn't do it by default. The two most common ways to enable ESM syntax are: - set `"type": "module"` within your `package.json` and keep using `.js` extension - use the `.mjs` file extensions (recommended) This is what we do for Nuxt Nitro; we output a `.output/server/index.mjs` file. That tells Node.js to treat this file as a native ES module. ### What Are Valid Imports in a Node.js Context? When you `import` a module rather than `require` it, Node.js resolves it differently. For example, when you import `sample-library`, Node.js will look for the `exports` entry in that library's `package.json`, or fall back to the `main` entry if `exports` is not defined. This is also true of dynamic imports, like `const b = await import('sample-library')`. Node supports the following kinds of imports (see [docs](https://nodejs.org/api/packages.html#determining-module-system)): 1. files ending in `.mjs` - these are expected to use ESM syntax 2. files ending in `.cjs` - these are expected to use CJS syntax 3. files ending in `.js` - these are expected to use CJS syntax unless their `package.json` has `"type": "module"` ### What Kinds of Problems Can There Be? For a long time module authors have been producing ESM-syntax builds but using conventions like `.esm.js` or `.es.js`, which they have added to the `module` field in their `package.json`. This hasn't been a problem until now because they have only been used by bundlers like webpack, which don't especially care about the file extension. However, if you try to import a package with an `.esm.js` file in a Node.js ESM context, it won't work, and you'll get an error like: ```bash [Terminal] (node:22145) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension. /path/to/index.js:1 export default {} ^^^^^^ SyntaxError: Unexpected token 'export' at wrapSafe (internal/modules/cjs/loader.js:1001:16) at Module._compile (internal/modules/cjs/loader.js:1049:27) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10) .... at async Object.loadESM (internal/process/esm_loader.js:68:5) ``` You might also get this error if you have a named import from an ESM-syntax build that Node.js thinks is CJS: ```bash [Terminal] file:///path/to/index.mjs:5 import { named } from 'sample-library' ^^^^^ SyntaxError: Named export 'named' not found. The requested module 'sample-library' is a CommonJS module, which may not support all module.exports as named exports. CommonJS modules can always be imported via the default export, for example using: import pkg from 'sample-library'; const { named } = pkg; at ModuleJob._instantiate (internal/modules/esm/module_job.js:120:21) at async ModuleJob.run (internal/modules/esm/module_job.js:165:5) at async Loader.import (internal/modules/esm/loader.js:177:24) at async Object.loadESM (internal/process/esm_loader.js:68:5) ``` ## Troubleshooting ESM Issues If you encounter these errors, the issue is almost certainly with the upstream library. They need to [fix their library](https://nuxt.com/docs/3.x/guide/concepts/esm#library-author-guide) to support being imported by Node. ### Transpiling Libraries In the meantime, you can tell Nuxt not to try to import these libraries by adding them to `build.transpile`: ```tstwoslash export default defineNuxtConfig({ build: { transpile: ['sample-library'], }, }) ``` You may find that you *also* need to add other packages that are being imported by these libraries. ### Aliasing Libraries In some cases, you may also need to manually alias the library to the CJS version, for example: ```tstwoslash export default defineNuxtConfig({ alias: { 'sample-library': 'sample-library/dist/sample-library.cjs.js', }, }) ``` ### Default Exports A dependency with CommonJS format, can use `module.exports` or `exports` to provide a default export: ```js [node_modules/cjs-pkg/index.js] module.exports = { test: 123 } // or exports.test = 123 ``` This normally works well if we `require` such dependency: ```js [test.cjs] const pkg = require('cjs-pkg') console.log(pkg) // { test: 123 } ``` [Node.js in native ESM mode](https://nodejs.org/api/esm.html#interoperability-with-commonjs), [typescript with `esModuleInterop` enabled](https://www.typescriptlang.org/tsconfig/#esModuleInterop) and bundlers such as webpack, provide a compatibility mechanism so that we can default import such library. This mechanism is often referred to as "interop require default": ```js import pkg from 'cjs-pkg' console.log(pkg) // { test: 123 } ``` However, because of the complexities of syntax detection and different bundle formats, there is always a chance that the interop default fails and we end up with something like this: ```js import pkg from 'cjs-pkg' console.log(pkg) // { default: { test: 123 } } ``` Also when using dynamic import syntax (in both CJS and ESM files), we always have this situation: ```js import('cjs-pkg').then(console.log) // [Module: null prototype] { default: { test: '123' } } ``` In this case, we need to manually interop the default export: ```js // Static import import { default as pkg } from 'cjs-pkg' // Dynamic import import('cjs-pkg').then(m => m.default || m).then(console.log) ``` For handling more complex situations and more safety, we recommend and internally use [mlly](https://github.com/unjs/mlly) in Nuxt that can preserve named exports. ```js import { interopDefault } from 'mlly' // Assuming the shape is { default: { foo: 'bar' }, baz: 'qux' } import myModule from 'my-module' console.log(interopDefault(myModule)) // { foo: 'bar', baz: 'qux' } ``` ## Library Author Guide The good news is that it's relatively simple to fix issues of ESM compatibility. There are two main options: 1. **You can rename your ESM files to end with .mjs.**
*This is the recommended and simplest approach.* You may have to sort out issues with your library's dependencies and possibly with your build system, but in most cases, this should fix the problem for you. It's also recommended to rename your CJS files to end with `.cjs`, for the greatest explicitness. 2. **You can opt to make your entire library ESM-only**.
This would mean setting `"type": "module"` in your `package.json` and ensuring that your built library uses ESM syntax. However, you may face issues with your dependencies - and this approach means your library can *only* be consumed in an ESM context. ### Migration The initial step from CJS to ESM is updating any usage of `require` to use `import` instead: ```ts [Before] module.exports = function () { /* ... */ } exports.hello = 'world' ``` ```ts [After] export default function () { /* ... */ } export const hello = 'world' ``` ```js [Before] const myLib = require('my-lib') ``` ```js [After] import myLib from 'my-lib' // or const dynamicMyLib = await import('my-lib').then(lib => lib.default || lib) ``` In ESM Modules, unlike CJS, `require`, `require.resolve`, `__filename` and `__dirname` globals are not available and should be replaced with `import()` and `import.meta.filename`. ```js [Before] const { join } = require('node:path') const newDir = join(__dirname, 'new-dir') ``` ```js [After] import { fileURLToPath } from 'node:url' const newDir = fileURLToPath(new URL('./new-dir', import.meta.url)) ``` ```js [Before] const someFile = require.resolve('./lib/foo.js') ``` ```js [After] import { resolvePath } from 'mlly' const someFile = await resolvePath('my-lib', { url: import.meta.url }) ``` ### Best Practices - Prefer named exports rather than default export. This helps reduce CJS conflicts. (see [Default exports](https://nuxt.com/docs/3.x/guide/concepts/esm#default-exports) section) - Avoid depending on Node.js built-ins and CommonJS or Node.js-only dependencies as much as possible to make your library usable in Browsers and Edge Workers without needing Nitro polyfills. - Use new `exports` field with conditional exports. ([read more](https://nodejs.org/api/packages.html#conditional-exports)). ```json { "exports": { ".": { "import": "./dist/mymodule.mjs" } } } ``` # Modules > Nuxt provides a module system to extend the framework core and simplify integrations. ## Exploring Nuxt Modules When developing production-grade applications with Nuxt you might find that the framework's core functionality is not enough. Nuxt can be extended with configuration options and plugins, but maintaining these customizations across multiple projects can be tedious, repetitive and time-consuming. On the other hand, supporting every project's needs out of the box would make Nuxt very complex and hard to use. This is one of the reasons why Nuxt provides a module system that makes it possible to extend the core. Nuxt modules are async functions that sequentially run when starting Nuxt in development mode using [`nuxt dev`](https://nuxt.com/docs/3.x/api/commands/dev) or building a project for production with [`nuxt build`](https://nuxt.com/docs/3.x/api/commands/build). They can override templates, configure webpack loaders, add CSS libraries, and perform many other useful tasks. Best of all, Nuxt modules can be distributed in npm packages. This makes it possible for them to be reused across projects and shared with the community, helping create an ecosystem of high-quality add-ons. Explore Nuxt Modules ## Add Nuxt Modules Once you have installed the modules you can add them to your [`nuxt.config.ts`](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) file under the `modules` property. Module developers usually provide additional steps and details for usage. ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ modules: [ // Using package name (recommended usage) '@nuxtjs/example', // Load a local module './modules/example', // Add module with inline-options ['./modules/example', { token: '123' }], // Inline module definition async (inlineOptions, nuxt) => { }, ], }) ``` Nuxt modules are now build-time-only, and the `buildModules` property used in Nuxt 2 is deprecated in favor of `modules`. ## Disabling Modules You can disable a module by setting its config key to `false` in your Nuxt config. This is particularly useful when you want to disable modules inherited from layers. ```ts [nuxt.config.ts] export default defineNuxtConfig({ // Disable `@nuxt/image` module image: false, }) ``` ## Create a Nuxt Module Everyone has the opportunity to develop modules and we cannot wait to see what you will build. # Nuxt Lifecycle > Understanding the lifecycle of Nuxt applications can help you gain deeper insights into how the framework operates, especially for both server-side and client-side rendering. The goal of this chapter is to provide a high-level overview of the different parts of the framework, their execution order, and how they work together. ## Server lifecycle On the server, the following steps are executed for every initial request to your application: ### Server plugins once Nuxt is powered by [Nitro](https://nitro.build/), a modern server engine. When Nitro starts, it initializes and executes the plugins under the [`/server/plugins`](https://nuxt.com/docs/3.x/directory-structure/server#server-plugins) directory. These plugins can: - Capture and handle application-wide errors. - Register hooks that execute when Nitro shuts down. - Register hooks for request lifecycle events, such as modifying responses. Nitro plugins are executed only once when the server starts. In a serverless environment, the server boots on each incoming request, and so do the Nitro plugins. However, they are not awaited. ### Server middleware After initializing the Nitro server, middleware under `server/middleware/` is executed for every request. Middleware can be used for tasks such as authentication, logging, or request transformation. Returning a value from middleware will terminate the request and send the returned value as the response. This behavior should generally be avoided to ensure proper request handling! ### App plugins The Vue and Nuxt instances are created first. Afterward, Nuxt executes its app plugins. This includes: - Built-in plugins, such as Vue Router and `unhead`. - Custom plugins located in the `plugins/` directory, including those without a suffix (e.g., `myPlugin.ts`) and those with the `.server` suffix (e.g., `myServerPlugin.server.ts`). Plugins execute in a specific order and may have dependencies on one another. For more details, including execution order and parallelism, refer to the [Plugins documentation](https://nuxt.com/docs/3.x/directory-structure/plugins). After this step, Nuxt calls the [`app:created`](https://nuxt.com/docs/3.x/api/advanced/hooks#app-hooks-runtime) hook, which can be used to execute additional logic. ### Route validation After initializing plugins and before executing middleware, Nuxt calls the `validate` method if it is defined in the `definePageMeta` function. The `validate` method, which can be synchronous or asynchronous, is often used to validate dynamic route parameters. - The `validate` function should return `true` if the parameters are valid. - If validation fails, it should return `false` or an object containing a `status` and/or `statusText` to terminate the request. For more information, see the [Route Validation documentation](https://nuxt.com/docs/3.x/getting-started/routing#route-validation). ### App middleware Middleware allows you to run code before navigating to a particular route. It is often used for tasks such as authentication, redirection, or logging. In Nuxt, there are three types of middleware: - **Global route middleware** - **Named route middleware** - **Anonymous (or inline) route middleware** Nuxt executes all global middleware on the initial page load (both on server and client) and then again before any client-side navigation. Named and anonymous middleware are executed only on the routes specified in the middleware property of the page(route) meta defined in the corresponding page components. For details about each type and examples, see the [Middleware documentation](https://nuxt.com/docs/3.x/directory-structure/middleware). Any redirection on the server will result in a `Location:` header being sent to the browser; the browser then makes a fresh request to this new location. All application state will be reset when this happens, unless persisted in a cookie. ### Page and components Nuxt renders the page and its components and fetches any required data with `useFetch` and `useAsyncData` during this step. Since there are no dynamic updates and no DOM operations occur on the server, Vue lifecycle hooks such as `onBeforeMount`, `onMounted`, and subsequent hooks are **NOT** executed during SSR. By default, Vue pauses dependency tracking during SSR for better performance. There is no reactivity on the server side because Vue SSR renders the app top-down as static HTML, making it impossible to go back and modify content that has already been rendered. You should avoid code that produces side effects that need cleanup in root scope of ` ``` On the initial request, the `counter` ref is initialized in the server since it is rendered inside the `

` tag. The contents of `handleClick` is never executed here. During hydration in the browser, the `counter` ref is re-initialized. The `handleClick` finally binds itself to the button; Therefore it is reasonable to deduce that the body of `handleClick` will always run in a browser environment. [Middlewares](https://nuxt.com/docs/3.x/directory-structure/middleware) and [pages](https://nuxt.com/docs/3.x/directory-structure/pages) run in the server and on the client during hydration. [Plugins](https://nuxt.com/docs/3.x/directory-structure/plugins) can be rendered on the server or client or both. [Components](https://nuxt.com/docs/3.x/directory-structure/components) can be forced to run on the client only as well. [Composables](https://nuxt.com/docs/3.x/directory-structure/composables) and [utilities](https://nuxt.com/docs/3.x/directory-structure/utils) are rendered based on the context of their usage. **Benefits of server-side rendering:** - **Performance**: Users can get immediate access to the page's content because browsers can display static content much faster than JavaScript-generated content. At the same time, Nuxt preserves the interactivity of a web application during the hydration process. - **Search Engine Optimization**: Universal rendering delivers the entire HTML content of the page to the browser as a classic server application. Web crawlers can directly index the page's content, which makes Universal rendering a great choice for any content that you want to index quickly. **Downsides of server-side rendering:** - **Development constraints:** Server and browser environments don't provide the same APIs, and it can be tricky to write code that can run on both sides seamlessly. Fortunately, Nuxt provides guidelines and specific variables to help you determine where a piece of code is executed. - **Cost:** A server needs to be running in order to render pages on the fly. This adds a monthly cost like any traditional server. However, the server calls are highly reduced thanks to universal rendering with the browser taking over on client-side navigation. A cost reduction is possible by leveraging [edge-side-rendering](https://nuxt.com/docs/3.x/guide/concepts/rendering#edge-side-rendering). Universal rendering is very versatile and can fit almost any use case, and is especially appropriate for any content-oriented websites: **blogs, marketing websites, portfolios, e-commerce sites, and marketplaces.** For more examples about writing Vue code without hydration mismatch, see [the Vue docs](https://vuejs.org/guide/scaling-up/ssr#hydration-mismatch). When importing a library that relies on browser APIs and has side effects, make sure the component importing it is only called client-side. Bundlers do not treeshake imports of modules containing side effects. ## Client-Side Rendering Out of the box, a traditional Vue.js application is rendered in the browser (or **client**). Then, Vue.js generates HTML elements after the browser downloads and parses all the JavaScript code containing the instructions to create the current interface. ![Users have to wait for the browser to download, parse and execute the JavaScript before seeing the page's content](https://nuxt.com/assets/docs/concepts/rendering/csr.svg) **Benefits of client-side rendering:** - **Development speed**: When working entirely on the client-side, we don't have to worry about the server compatibility of the code, for example, by using browser-only APIs like the `window` object. - **Cheaper:** Running a server adds a cost of infrastructure as you would need to run on a platform that supports JavaScript. We can host client-only applications on any static server with HTML, CSS, and JavaScript files. - **Offline:** Because code entirely runs in the browser, it can nicely keep working while the internet is unavailable. **Downsides of client-side rendering:** - **Performance**: The user has to wait for the browser to download, parse and run JavaScript files. Depending on the network for the download part and the user's device for the parsing and execution, this can take some time and impact the user's experience. - **Search Engine Optimization**: Indexing and updating the content delivered via client-side rendering takes more time than with a server-rendered HTML document. This is related to the performance drawback we discussed, as search engine crawlers won't wait for the interface to be fully rendered on their first try to index the page. Your content will take more time to show and update in search results pages with pure client-side rendering. Client-side rendering is a good choice for heavily interactive **web applications** that don't need indexing or whose users visit frequently. It can leverage browser caching to skip the download phase on subsequent visits, such as **SaaS, back-office applications, or online games**. You can enable client-side only rendering with Nuxt in your `nuxt.config.ts`: ```ts [nuxt.config.ts] export default defineNuxtConfig({ ssr: false, }) ``` If you do use `ssr: false`, you should also place an HTML file in `~/app/spa-loading-template.html` with some HTML you would like to use to render a loading screen that will be rendered until your app is hydrated. ### Deploying a Static Client-Rendered App If you deploy your app to [static hosting](https://nuxt.com/docs/3.x/getting-started/deployment#static-hosting) with the `nuxt generate` or `nuxt build --prerender` commands, then by default, Nuxt will render every page as a separate static HTML file. If you prerender your app with the `nuxt generate` or `nuxt build --prerender` commands, then you will not be able to use any server endpoints as no server will be included in your output folder. If you need server functionality, use `nuxt build` instead. If you are using purely client-side rendering, then this might be unnecessary. You might only need a single `index.html` file, plus `200.html` and `404.html` fallbacks, which you can tell your static web host to serve up for all requests. In order to achieve this we can change how the routes are prerendered. Just add this to [your hooks](https://nuxt.com/docs/3.x/api/advanced/hooks#nuxt-hooks-build-time) in your `nuxt.config.ts`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ hooks: { 'prerender:routes' ({ routes }) { routes.clear() // Do not generate any routes (except the defaults) }, }, }) ``` This will produce three files: - `index.html` - `200.html` - `404.html` The `200.html` and `404.html` might be useful for the hosting provider you are using. #### Skipping Client Fallback Generation When prerendering a client-rendered app, Nuxt will generate `index.html`, `200.html` and `404.html` files by default. However, if you need to prevent any (or all) of these files from being generated in your build, you can use the `'prerender:generate'` hook from [Nitro](https://nuxt.com/docs/3.x/getting-started/prerendering#prerendergenerate-nitro-hook). ```ts [nuxt.config.ts]twoslash // @errors: 2353 7006 export default defineNuxtConfig({ ssr: false, nitro: { hooks: { 'prerender:generate' (route) { const routesToSkip = ['/index.html', '/200.html', '/404.html'] if (routesToSkip.includes(route.route)) { route.skip = true } }, }, }, }) ``` ## Hybrid Rendering Hybrid rendering allows different caching rules per route using **Route Rules** and decides how the server should respond to a new request on a given URL. Previously every route/page of a Nuxt application and server must use the same rendering mode, universal or client-side. In various cases, some pages could be generated at build time, while others should be client-side rendered. For example, think of a content website with an admin section. Every content page should be primarily static and generated once, but the admin section requires registration and behaves more like a dynamic application. Nuxt includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route! Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using [Nitro caching layer](https://nitro.build/guide/cache). ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ routeRules: { // Homepage pre-rendered at build time '/': { prerender: true }, // Products page generated on demand, revalidates in background, cached until API response changes '/products': { swr: true }, // Product pages generated on demand, revalidates in background, cached for 1 hour (3600 seconds) '/products/**': { swr: 3600 }, // Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds) '/blog': { isr: 3600 }, // Blog post page generated on demand once until next deployment, cached on CDN '/blog/**': { isr: true }, // Admin dashboard renders only on client-side '/admin/**': { ssr: false }, // Add cors headers on API routes '/api/**': { cors: true }, // Redirects legacy urls '/old-page': { redirect: '/new-page' }, }, }) ``` ### Route Rules The different properties you can use are the following: - `redirect: string` - Define server-side redirects. - `ssr: boolean` - Disables server-side rendering of the HTML for sections of your app and make them render only in the browser with `ssr: false` - `cors: boolean` - Automatically adds cors headers with `cors: true` - you can customize the output by overriding with `headers` - `headers: object` - Add specific headers to sections of your site - for example, your assets - `swr: number | boolean` - Add cache headers to the server response and cache it on the server or reverse proxy for a configurable TTL (time to live). The `node-server` preset of Nitro is able to cache the full response. When the TTL expired, the cached response will be sent while the page will be regenerated in the background. If true is used, a `stale-while-revalidate` header is added without a MaxAge. - `isr: number | boolean` - The behavior is the same as `swr` except that we are able to add the response to the CDN cache on platforms that support this (currently Netlify or Vercel). If `true` is used, the content persists until the next deploy inside the CDN. - `prerender: boolean` - Prerenders routes at build time and includes them in your build as static assets - `noScripts: boolean` - Disables rendering of Nuxt scripts and JS resource hints for sections of your site. - `appMiddleware: string | string[] | Record` - Allows you to define middleware that should or should not run for page paths within the Vue app part of your application (that is, not your Nitro routes) Routes using `isr` or `swr` also generate `_payload.json` files alongside HTML. Client-side navigation loads these cached payloads instead of re-fetching data. Configure dynamic routes like `pages/[...slug].vue` with glob patterns: `'/**': { isr: true }`. Whenever possible, route rules will be automatically applied to the deployment platform's native rules for optimal performances (Netlify and Vercel are currently supported). Note that Hybrid Rendering is not available when using [`nuxt generate`](https://nuxt.com/docs/3.x/api/commands/generate). **Examples:** Example of a Nuxt application with hybrid rendering deployed on Vercel. ## Edge-Side Rendering Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience. With ESR, the rendering process is pushed to the 'edge' of the network - the CDN's edge servers. Note that ESR is more a deployment target than an actual rendering mode. When a request for a page is made, instead of going all the way to the original server, it's intercepted by the nearest edge server. This server generates the HTML for the page and sends it back to the user. This process minimizes the physical distance the data has to travel, **reducing latency and loading the page faster**. Edge-side rendering is possible thanks to [Nitro](https://nitro.build/), the [server engine](https://nuxt.com/docs/3.x/guide/concepts/server-engine) that powers Nuxt. It offers cross-platform support for Node.js, Deno, Cloudflare Workers, and more. The current platforms where you can leverage ESR are: - [Cloudflare Pages](https://pages.cloudflare.com) with zero configuration using the git integration and the `nuxt build` command - [Vercel Cloud](https://vercel.com/home) using the `nuxt build` command and `NITRO_PRESET=vercel-edge` environment variable - [Netlify Edge Functions](https://www.netlify.com/platform/#netlify-edge-functions) using the `nuxt build` command and `NITRO_PRESET=netlify-edge` environment variable Note that **Hybrid Rendering** can be used when using Edge-Side Rendering with route rules. # Server Engine > Nuxt is powered by a new server engine: Nitro. While building Nuxt, we created a new server engine: [Nitro](https://nitro.build/). It is shipped with many features: - Cross-platform support for Node.js, browsers, service workers and more. - Serverless support out-of-the-box. - API routes support. - Automatic code-splitting and async-loaded chunks. - Hybrid mode for static + serverless sites. - Development server with hot module reloading. ## API Layer Server [API endpoints](https://nuxt.com/docs/3.x/directory-structure/server#server-routes) and [Middleware](https://nuxt.com/docs/3.x/directory-structure/server#server-middleware) are added by Nitro that internally uses [h3](https://github.com/h3js/h3). Key features include: - Handlers can directly return objects/arrays for an automatically-handled JSON response - Handlers can return promises, which will be awaited (`res.end()` and `next()` are also supported) - Helper functions for body parsing, cookie handling, redirects, headers and more Check out [the h3 docs](https://github.com/h3js/h3) for more information. Learn more about the API layer in the `server/` directory. ## Direct API Calls Nitro allows 'direct' calling of routes via the globally-available [`$fetch`](https://nuxt.com/docs/3.x/api/utils/dollarfetch) helper. This will make an API call to the server if run on the browser, but will directly call the relevant function if run on the server, **saving an additional API call**. [`$fetch`](https://nuxt.com/docs/3.x/api/utils/dollarfetch) API is using [ofetch](https://github.com/unjs/ofetch), with key features including: - Automatic parsing of JSON responses (with access to raw response if needed) - Request body and params are automatically handled, with correct `Content-Type` headers For more information on `$fetch` features, check out [ofetch](https://github.com/unjs/ofetch). ## Typed API Routes When using API routes (or middleware), Nitro will generate typings for these routes as long as you are returning a value instead of using `res.end()` to send a response. You can access these types when using [`$fetch()`](https://nuxt.com/docs/3.x/api/utils/dollarfetch) or [`useFetch()`](https://nuxt.com/docs/3.x/api/composables/use-fetch). ## Standalone Server Nitro produces a standalone server dist that is independent of `node_modules`. The server in Nuxt 2 is not standalone and requires part of Nuxt core to be involved by running `nuxt start` (with the [`nuxt-start`](https://www.npmjs.com/package/nuxt-start) or [`nuxt`](https://www.npmjs.com/package/nuxt) distributions) or custom programmatic usage, which is fragile and prone to breakage and not suitable for serverless and service worker environments. Nuxt generates this dist when running `nuxt build` into a [`.output`](https://nuxt.com/docs/3.x/directory-structure/output) directory. The output contains runtime code to run your Nuxt server in any environment (including experimental browser service workers!) and serve your static files, making it a true hybrid framework for the JAMstack. In addition, Nuxt implements a native storage layer, supporting multi-source drivers and local assets. Read more about Nitro engine on GitHub. # TypeScript > Nuxt is fully typed and provides helpful shortcuts to ensure you have access to accurate type information when you are coding. ## Type-checking By default, Nuxt doesn't check types when you run [`nuxt dev`](https://nuxt.com/docs/3.x/api/commands/dev) or [`nuxt build`](https://nuxt.com/docs/3.x/api/commands/build), for performance reasons. To enable type-checking at build or development time, install `vue-tsc` and `typescript` as development dependency: ```bash [npm] npm install --save-dev vue-tsc typescript ``` ```bash [yarn] yarn add --dev vue-tsc typescript ``` ```bash [pnpm] pnpm add -D vue-tsc typescript ``` ```bash [bun] bun add -D vue-tsc typescript ``` ```bash [deno] deno add -D npm:vue-tsc npm:typescript ``` Then, run [`nuxt typecheck`](https://nuxt.com/docs/3.x/api/commands/typecheck) command to check your types: ```bash [Terminal] npx nuxt typecheck ``` To enable type-checking at build or development time, you can also use the [`typescript.typeCheck`](https://nuxt.com/docs/3.x/api/nuxt-config#typecheck) option in your `nuxt.config` file: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { typeCheck: true, }, }) ``` ## Auto-generated Types When you run `nuxt dev` or `nuxt build`, Nuxt generates the following files for IDE type support (and type checking): ### `.nuxt/nuxt.d.ts` This file contains the types of any modules you are using, as well as the key types that Nuxt requires. Your IDE should recognize these types automatically. Some of the references in the file are to files that are only generated within your `buildDir` (`.nuxt`) and therefore for full typings, you will need to run `nuxt dev` or `nuxt build`. ### `.nuxt/tsconfig.json` This file contains the recommended basic TypeScript configuration for your project, including resolved aliases injected by Nuxt or modules you are using, so you can get full type support and path auto-complete for aliases like `~/file` or `#build/file`. Consider using the `imports` section of [nuxt.config](https://nuxt.com/docs/3.x/api/nuxt-config#imports) to include directories beyond the default ones. This can be useful for auto-importing types which you're using across your app. Nuxt relies on this configuration, and [Nuxt modules](https://nuxt.com/docs/3.x/guide/modules) can extend it as well. For this reason, it is not recommended to modify your `tsconfig.json` file directly, as doing so could overwrite important settings. Instead, extend it via `nuxt.config.ts`. [Learn more about extending the configuration here](https://nuxt.com/docs/3.x/directory-structure/tsconfig). [Read more about how to extend this configuration](https://nuxt.com/docs/3.x/directory-structure/tsconfig). Watch a video from Daniel Roe explaining built-in Nuxt aliases. Nitro also [auto-generates types](https://nuxt.com/docs/3.x/guide/concepts/server-engine#typed-api-routes) for API routes. Plus, Nuxt also generates types for globally available components and [auto-imports from your composables](https://nuxt.com/docs/3.x/directory-structure/composables), plus other core functionality. Keep in mind that all options extended from `./.nuxt/tsconfig.json` will be overwritten by the options defined in your `tsconfig.json`. Overwriting options such as `"compilerOptions.paths"` with your own configuration will lead TypeScript to not factor in the module resolutions from `./.nuxt/tsconfig.json`. This can lead to module resolutions such as `#imports` not being recognized.

In case you need to extend options provided by `./.nuxt/tsconfig.json` further, you can use the [`alias` property](https://nuxt.com/docs/3.x/api/nuxt-config#alias) within your `nuxt.config`. Nuxt will pick them up and extend `./.nuxt/tsconfig.json` accordingly.
## Strict Checks TypeScript comes with certain checks to give you more safety and analysis of your program. [Strict checks](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks) are enabled by default in Nuxt when the [`typescript.typeCheck`](https://nuxt.com/docs/3.x/guide/concepts/typescript#type-checking) option is enabled to give you greater type safety. If you are currently converting your codebase to TypeScript, you may want to temporarily disable strict checks by setting `strict` to `false` in your `nuxt.config`: ```ts [nuxt.config.ts]twoslash export default defineNuxtConfig({ typescript: { strict: false, }, }) ``` # Vue.js Development > Nuxt uses Vue.js and adds features such as component auto-imports, file-based routing and composables for an SSR-friendly usage. Nuxt integrates Vue 3, the new major release of Vue that enables new patterns for Nuxt users. While an in-depth knowledge of Vue is not required to use Nuxt, we recommend that you read the documentation and go through some of the examples on [vuejs.org](https://vuejs.org). Nuxt has always used Vue as a frontend framework. We chose to build Nuxt on top of Vue for these reasons: - The reactivity model of Vue, where a change in data automatically triggers a change in the interface. - The component-based templating, while keeping HTML as the common language of the web, enables intuitive patterns to keep your interface consistent, yet powerful. - From small projects to large web applications, Vue keeps performing well at scale to ensure that your application keeps delivering value to your users. ## Vue with Nuxt ### Single File Components [Vueโ€™s single-file components](https://vuejs.org/guide/scaling-up/sfc) (SFC or `*.vue` files) encapsulate the markup (`