# Table of Contents - [Installation · Get Started with Nuxt v4](#installation-get-started-with-nuxt-v4) - [Introduction · Get Started with Nuxt v4](#introduction-get-started-with-nuxt-v4) - [Views · Get Started with Nuxt v4](#views-get-started-with-nuxt-v4) - [Configuration · Get Started with Nuxt v4](#configuration-get-started-with-nuxt-v4) - [Assets · Get Started with Nuxt v4](#assets-get-started-with-nuxt-v4) - [Styling · Get Started with Nuxt v4](#styling-get-started-with-nuxt-v4) - [Routing · Get Started with Nuxt v4](#routing-get-started-with-nuxt-v4) - [SEO and Meta · Get Started with Nuxt v4](#seo-and-meta-get-started-with-nuxt-v4) - [Transitions · Get Started with Nuxt v4](#transitions-get-started-with-nuxt-v4) - [Server · Get Started with Nuxt v4](#server-get-started-with-nuxt-v4) - [Deployment · Get Started with Nuxt v4](#deployment-get-started-with-nuxt-v4) - [Layers · Get Started with Nuxt v4](#layers-get-started-with-nuxt-v4) - [Prerendering · Get Started with Nuxt v4](#prerendering-get-started-with-nuxt-v4) - [Testing · Get Started with Nuxt v4](#testing-get-started-with-nuxt-v4) - [.nuxt · Nuxt Directory Structure v4](#-nuxt-nuxt-directory-structure-v4) - [.output · Nuxt Directory Structure v4](#-output-nuxt-directory-structure-v4) - [assets · Nuxt Directory Structure v4](#assets-nuxt-directory-structure-v4) - [Upgrade Guide · Get Started with Nuxt v4](#upgrade-guide-get-started-with-nuxt-v4) - [composables · Nuxt Directory Structure v4](#composables-nuxt-directory-structure-v4) - [components · Nuxt Directory Structure v4](#components-nuxt-directory-structure-v4) - [State Management · Get Started with Nuxt v4](#state-management-get-started-with-nuxt-v4) - [Data Fetching · Get Started with Nuxt v4](#data-fetching-get-started-with-nuxt-v4) - [Error Handling · Get Started with Nuxt v4](#error-handling-get-started-with-nuxt-v4) - [layouts · Nuxt Directory Structure v4](#layouts-nuxt-directory-structure-v4) - [middleware · Nuxt Directory Structure v4](#middleware-nuxt-directory-structure-v4) - [pages · Nuxt Directory Structure v4](#pages-nuxt-directory-structure-v4) - [Introduction · Get Started with Nuxt v3](#introduction-get-started-with-nuxt-v3) - [Installation · Get Started with Nuxt v3](#installation-get-started-with-nuxt-v3) - [Assets · Get Started with Nuxt v3](#assets-get-started-with-nuxt-v3) - [Server · Get Started with Nuxt v3](#server-get-started-with-nuxt-v3) - [Testing · Get Started with Nuxt v3](#testing-get-started-with-nuxt-v3) - [Deployment · Get Started with Nuxt v3](#deployment-get-started-with-nuxt-v3) - [Transitions · Get Started with Nuxt v3](#transitions-get-started-with-nuxt-v3) - [Getting Help · Nuxt Community v3](#getting-help-nuxt-community-v3) - [Layers · Get Started with Nuxt v3](#layers-get-started-with-nuxt-v3) - [Styling · Get Started with Nuxt v3](#styling-get-started-with-nuxt-v3) - [Views · Get Started with Nuxt v3](#views-get-started-with-nuxt-v3) - [Prerendering · Get Started with Nuxt v3](#prerendering-get-started-with-nuxt-v3) - [SEO and Meta · Get Started with Nuxt v3](#seo-and-meta-get-started-with-nuxt-v3) - [Routing · Get Started with Nuxt v3](#routing-get-started-with-nuxt-v3) - [Configuration · Get Started with Nuxt v3](#configuration-get-started-with-nuxt-v3) - [State Management · Get Started with Nuxt v3](#state-management-get-started-with-nuxt-v3) - [Upgrade Guide · Get Started with Nuxt v3](#upgrade-guide-get-started-with-nuxt-v3) - [Nuxt Directory Structure · Nuxt Directory Structure v3](#nuxt-directory-structure-nuxt-directory-structure-v3) - [Error Handling · Get Started with Nuxt v3](#error-handling-get-started-with-nuxt-v3) - [pages · Nuxt Directory Structure v3](#pages-nuxt-directory-structure-v3) - [Hello World · Nuxt Examples v3](#hello-world-nuxt-examples-v3) - [Data Fetching · Get Started with Nuxt v3](#data-fetching-get-started-with-nuxt-v3) - [Nuxt Guide v3](#nuxt-guide-v3) - [Nuxt API Reference v3](#nuxt-api-reference-v3) - [Auto-imports · Nuxt Concepts v3](#auto-imports-nuxt-concepts-v3) - [.nuxt · Nuxt Directory Structure v3](#-nuxt-nuxt-directory-structure-v3) - [Reporting Bugs · Nuxt Community v3](#reporting-bugs-nuxt-community-v3) - [Auto Imports · Nuxt Examples v3](#auto-imports-nuxt-examples-v3) - [Contribution · Nuxt Community v3](#contribution-nuxt-community-v3) - [Data Fetching · Nuxt Examples v3](#data-fetching-nuxt-examples-v3) - [.output · Nuxt Directory Structure v3](#-output-nuxt-directory-structure-v3) - [Framework · Nuxt Community v3](#framework-nuxt-community-v3) - [Roadmap · Nuxt Community v3](#roadmap-nuxt-community-v3) - [Releases · Nuxt Community v3](#releases-nuxt-community-v3) - [Layouts · Nuxt Examples v3](#layouts-nuxt-examples-v3) - [Meta Tags · Nuxt Examples v3](#meta-tags-nuxt-examples-v3) - [State Management · Nuxt Examples v3](#state-management-nuxt-examples-v3) - [Universal Router · Nuxt Examples v3](#universal-router-nuxt-examples-v3) - [Pages · Nuxt Examples v3](#pages-nuxt-examples-v3) - [Layers · Nuxt Examples v3](#layers-nuxt-examples-v3) - [Middleware · Nuxt Examples v3](#middleware-nuxt-examples-v3) - [public · Nuxt Directory Structure v3](#public-nuxt-directory-structure-v3) - [WASM · Nuxt Examples v3](#wasm-nuxt-examples-v3) - [nuxt.config.ts · Nuxt Directory Structure v3](#nuxt-config-ts-nuxt-directory-structure-v3) - [content · Nuxt Directory Structure v3](#content-nuxt-directory-structure-v3) - [node_modules · Nuxt Directory Structure v3](#node-modules-nuxt-directory-structure-v3) - [modules · Nuxt Directory Structure v3](#modules-nuxt-directory-structure-v3) - [utils · Nuxt Directory Structure v3](#utils-nuxt-directory-structure-v3) - [.gitignore · Nuxt Directory Structure v3](#-gitignore-nuxt-directory-structure-v3) - [assets · Nuxt Directory Structure v3](#assets-nuxt-directory-structure-v3) - [error.vue · Nuxt Directory Structure v3](#error-vue-nuxt-directory-structure-v3) - [.nuxtignore · Nuxt Directory Structure v3](#-nuxtignore-nuxt-directory-structure-v3) - [plugins · Nuxt Directory Structure v3](#plugins-nuxt-directory-structure-v3) - [Server Engine · Nuxt Concepts v3](#server-engine-nuxt-concepts-v3) - [Code Style · Nuxt Concepts v3](#code-style-nuxt-concepts-v3) - [shared · Nuxt Directory Structure v3](#shared-nuxt-directory-structure-v3) - [ES Modules · Nuxt Concepts v3](#es-modules-nuxt-concepts-v3) - [app.vue · Nuxt Directory Structure v3](#app-vue-nuxt-directory-structure-v3) - [layouts · Nuxt Directory Structure v3](#layouts-nuxt-directory-structure-v3) - [composables · Nuxt Directory Structure v3](#composables-nuxt-directory-structure-v3) - [Rendering Modes · Nuxt Concepts v3](#rendering-modes-nuxt-concepts-v3) - [TypeScript · Nuxt Concepts v3](#typescript-nuxt-concepts-v3) - [Nightly Release Channel · Nuxt Advanced v3](#nightly-release-channel-nuxt-advanced-v3) - [server · Nuxt Directory Structure v3](#server-nuxt-directory-structure-v3) - [.env · Nuxt Directory Structure v3](#-env-nuxt-directory-structure-v3) - [components · Nuxt Directory Structure v3](#components-nuxt-directory-structure-v3) - [Module Author Guide · Nuxt Advanced v3](#module-author-guide-nuxt-advanced-v3) - [middleware · Nuxt Directory Structure v3](#middleware-nuxt-directory-structure-v3) - [clearNuxtState · Nuxt Utils v3](#clearnuxtstate-nuxt-utils-v3) - [defineRouteRules · Nuxt Utils v3](#definerouterules-nuxt-utils-v3) - [nuxt cleanup · Nuxt Commands v3](#nuxt-cleanup-nuxt-commands-v3) - [ · Nuxt Components v3](#-nuxttime-nuxt-components-v3) - [useAppConfig · Nuxt Composables v3](#useappconfig-nuxt-composables-v3) - [useSeoMeta · Nuxt Composables v3](#useseometa-nuxt-composables-v3) - [clearError · Nuxt Utils v3](#clearerror-nuxt-utils-v3) - [ · Nuxt Components v3](#-nuxterrorboundary-nuxt-components-v3) - [callOnce · Nuxt Utils v3](#callonce-nuxt-utils-v3) - [nuxt dev · Nuxt Commands v3](#nuxt-dev-nuxt-commands-v3) - [$fetch · Nuxt Utils v3](#-fetch-nuxt-utils-v3) - [ · Nuxt Components v3](#-nuxtloadingindicator-nuxt-components-v3) - [ · Nuxt Components v3](#-nuxtlayout-nuxt-components-v3) - [useRoute · Nuxt Composables v3](#useroute-nuxt-composables-v3) - [useFetch · Nuxt Composables v3](#usefetch-nuxt-composables-v3) - [Migrate to Nuxt Bridge: Overview v3](#migrate-to-nuxt-bridge-overview-v3) - [Pages · Nuxt Kit v3](#pages-nuxt-kit-v3) - [create nuxt · Nuxt Commands v3](#create-nuxt-nuxt-commands-v3) - [Lifecycle Hooks · Nuxt API v3](#lifecycle-hooks-nuxt-api-v3) - [nuxt typecheck · Nuxt Commands v3](#nuxt-typecheck-nuxt-commands-v3) - [nuxt preview · Nuxt Commands v3](#nuxt-preview-nuxt-commands-v3) - [nuxt module · Nuxt Commands v3](#nuxt-module-nuxt-commands-v3) - [nuxt info · Nuxt Commands v3](#nuxt-info-nuxt-commands-v3) - [nuxt upgrade · Nuxt Commands v3](#nuxt-upgrade-nuxt-commands-v3) - [nuxt test · Nuxt Commands v3](#nuxt-test-nuxt-commands-v3) - [Logging · Nuxt Kit v3](#logging-nuxt-kit-v3) - [Modules · Nuxt Kit v3](#modules-nuxt-kit-v3) - [Templates · Nuxt Kit v3](#templates-nuxt-kit-v3) - [Examples · Nuxt Kit v3](#examples-nuxt-kit-v3) - [Runtime Config · Nuxt Kit v3](#runtime-config-nuxt-kit-v3) - [Nitro · Nuxt Kit v3](#nitro-nuxt-kit-v3) --- # Installation · Get Started with Nuxt v4 Installation ============ Copy page Get started with Nuxt quickly with our online starters or start locally with your terminal. [Play Online](https://nuxt.com/docs/4.x/getting-started/installation#play-online) ---------------------------------------------------------------------------------- If you just want to play around with Nuxt in your browser without setting up a project, you can use one of our online sandboxes: [](https://nuxt.new/s/v4) Open on StackBlitz [](https://nuxt.new/c/v4) Open on CodeSandbox Or follow the steps below to set up a new Nuxt project on your computer. [New Project](https://nuxt.com/docs/4.x/getting-started/installation#new-project) ---------------------------------------------------------------------------------- ### [Prerequisites](https://nuxt.com/docs/4.x/getting-started/installation#prerequisites) * **Node.js** - [`20.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. * **Terminal** - In order to run Nuxt commands Additional notes for an optimal setup: * **Node.js**: Make sure to use an even numbered version (20, 22, etc.) * **Nuxtr**: Install the community-developed [Nuxtr extension](https://marketplace.visualstudio.com/items?itemName=Nuxtr.nuxtr-vscode) * **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. 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: npmyarnpnpmbundeno `npm create nuxt@latest ` `yarn create nuxt@latest ` `pnpm create nuxt@latest ` `bun create nuxt@latest ` `deno -A npm:create-nuxt@latest ` Alternatively, you can find other starters or themes by opening [nuxt.new](https://nuxt.new/) and following the instructions there. Open your project folder in Visual Studio Code: Terminal `code ` Or change directory into your new project from your terminal: `cd ` [Development Server](https://nuxt.com/docs/4.x/getting-started/installation#development-server) ------------------------------------------------------------------------------------------------ Now you'll be able to start your Nuxt app in development mode: npmyarnpnpmbundeno `npm run dev -- -o` `yarn dev --open` `pnpm dev -o` `bun run dev -o # To use the Bun runtime during development # bun --bun run dev -o` `deno run dev -o` Well done! A browser window should automatically open for [http://localhost:3000](http://localhost:3000/) . [Next Steps](https://nuxt.com/docs/4.x/getting-started/installation#next-steps) -------------------------------------------------------------------------------- Now that you've created your Nuxt project, you are ready to start building your application. [](https://nuxt.com/docs/4.x/guide/concepts) Read more in Nuxt Concepts. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/02.installation.md) [Introduction\ \ Nuxt's goal is to make web development intuitive and performant with a great Developer Experience in mind.](https://nuxt.com/docs/4.x/getting-started/introduction) [Configuration\ \ Nuxt is configured with sensible defaults to make you productive.](https://nuxt.com/docs/4.x/getting-started/configuration) MenuOn this page --- # Introduction · Get Started with Nuxt v4 Introduction ============ Copy page 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) . 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) . [Automation and Conventions](https://nuxt.com/docs/4.x/getting-started/introduction#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](https://nuxt.com/docs/4.x/getting-started/introduction#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. [](https://nuxt.com/docs/4.x/guide/concepts/rendering) Read more in Nuxt rendering modes. ### [Server engine](https://nuxt.com/docs/4.x/getting-started/introduction#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. [](https://nuxt.com/docs/4.x/guide/concepts/server-engine) Read more in Nuxt server engine. ### [Production-ready](https://nuxt.com/docs/4.x/getting-started/introduction#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. [](https://nuxt.com/docs/4.x/getting-started/deployment) Read more in Deployment section. ### [Modular](https://nuxt.com/docs/4.x/getting-started/introduction#modular) A module system allows you to extend Nuxt with custom features and integrations with third-party services. [](https://nuxt.com/docs/4.x/guide/concepts/modules) Read more in Nuxt Modules Concept. ### [Architecture](https://nuxt.com/docs/4.x/getting-started/introduction#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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/01.introduction.md)  [Installation\ \ Get started with Nuxt quickly with our online starters or start locally with your terminal.](https://nuxt.com/docs/4.x/getting-started/installation) MenuOn this page --- # Views · Get Started with Nuxt v4 Views ===== Copy page Nuxt provides several component layers to implement the user interface of your application. [`app.vue`](https://nuxt.com/docs/4.x/getting-started/views#appvue) -------------------------------------------------------------------- ![The app.vue file is the entry point of your application](https://ipx.nuxt.com/_/assets/docs/getting-started/views/app.svg) By default, Nuxt will treat this file as the **entrypoint** and render its content for every route of the application. app/app.vue `` If you are familiar with Vue, you might wonder where `main.js` is (the file that normally creates a Vue app). Nuxt does this behind the scene. [Components](https://nuxt.com/docs/4.x/getting-started/views#components) ------------------------------------------------------------------------- ![Components are reusable pieces of UI](https://ipx.nuxt.com/_/assets/docs/getting-started/views/components.svg) Most components are reusable pieces of the user interface, like buttons and menus. In Nuxt, you can create these components in the [`app/components/`](https://nuxt.com/docs/4.x/directory-structure/app/components) directory, and they will be automatically available across your application without having to explicitly import them. app/app.vueapp/components/AppAlert.vue `` `` [Pages](https://nuxt.com/docs/4.x/getting-started/views#pages) --------------------------------------------------------------- ![Pages are views tied to a specific route](https://ipx.nuxt.com/_/assets/docs/getting-started/views/pages.svg) Pages represent views for each specific route pattern. Every file in the [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory represents a different route displaying its content. To use pages, create an `app/pages/index.vue` file and add `` component to the [`app/app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) (or remove `app/app.vue` for default entry). You can now create more pages and their corresponding routes by adding new files in the [`app/pages/`](https://nuxt.com/docs/4.x/directory-structure/app/pages) directory. app/pages/index.vueapp/pages/about.vue `` `` [](https://nuxt.com/docs/4.x/getting-started/routing) Read more in Routing Section. [Layouts](https://nuxt.com/docs/4.x/getting-started/views#layouts) ------------------------------------------------------------------- ![Layouts are wrapper around pages](https://ipx.nuxt.com/_/assets/docs/getting-started/views/layouts.svg) Layouts are wrappers around pages that contain a common User Interface for several pages, such as header and footer displays. Layouts are Vue files using `` components to display the **page** content. The `app/layouts/default.vue` file will be used by default. Custom layouts can be set as part of your page metadata. If you only have a single layout in your application, we recommend using [`app/app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) with [``](https://nuxt.com/docs/4.x/api/components/nuxt-page) instead. app/app.vueapp/layouts/default.vueapp/pages/index.vueapp/pages/about.vue `` `` `` `` If you want to create more layouts and learn how to use them in your pages, find more information in the [Layouts section](https://nuxt.com/docs/4.x/directory-structure/app/layouts) . [Advanced: Extending the HTML Template](https://nuxt.com/docs/4.x/getting-started/views#advanced-extending-the-html-template) ------------------------------------------------------------------------------------------------------------------------------ If you only need to modify the ``, you can refer to the [SEO and meta section](https://nuxt.com/docs/4.x/getting-started/seo-meta) . You can have full control over the HTML template by adding a Nitro plugin that registers a hook. The callback function of the `render:html` hook allows you to mutate the HTML before it is sent to the client. server/plugins/extend-html.ts ``export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('render:html', (html, { event }) => { // This will be an object representation of the html template. console.log(html) html.head.push(``) }) // You can also intercept the response here. nitroApp.hooks.hook('render:response', (response, { event }) => { console.log(response) }) })`` [](https://nuxt.com/docs/4.x/guide/going-further/hooks) Read more in Docs > 4 X > Guide > Going Further > Hooks. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/04.views.md) [Configuration\ \ Nuxt is configured with sensible defaults to make you productive.](https://nuxt.com/docs/4.x/getting-started/configuration) [Assets\ \ Nuxt offers two options for your assets.](https://nuxt.com/docs/4.x/getting-started/assets) MenuOn this page --- # Configuration · Get Started with Nuxt v4 Configuration ============= Copy page 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](https://nuxt.com/docs/4.x/getting-started/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. nuxt.config.ts `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. [](https://nuxt.com/docs/4.x/api/configuration/nuxt-config) Every option is described in the **Configuration Reference**. 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. ### [Environment Overrides](https://nuxt.com/docs/4.x/getting-started/configuration#environment-overrides) You can configure fully typed, per-environment overrides in your nuxt.config nuxt.config.ts `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) . Watch a video from Alexander Lichter about the env-aware nuxt.config.ts 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. ### [Environment Variables and Private Tokens](https://nuxt.com/docs/4.x/getting-started/configuration#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. nuxt.config.ts.env `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', }, }, })` `# This will override the value of apiSecret NUXT_API_SECRET=api_secret_token` 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. app/pages/index.vue `` [](https://nuxt.com/docs/4.x/guide/going-further/runtime-config) Read more in Docs > 4 X > Guide > Going Further > Runtime Config. [App Configuration](https://nuxt.com/docs/4.x/getting-started/configuration#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. 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. app/pages/index.vue `` [](https://nuxt.com/docs/4.x/directory-structure/app/app-config) Read more in Docs > 4 X > Directory Structure > App > App Config. [`runtimeConfig` vs. `app.config`](https://nuxt.com/docs/4.x/getting-started/configuration#runtimeconfig-vs-appconfig) ----------------------------------------------------------------------------------------------------------------------- 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. | Feature | `runtimeConfig` | `app.config` | | --- | --- | --- | | Client Side | Hydrated | Bundled | | Environment Variables | ✅ Yes | ❌ No | | Reactive | ✅ Yes | ✅ Yes | | Types support | ✅ Partial | ✅ Yes | | Configuration per Request | ❌ No | ✅ Yes | | Hot Module Replacement | ❌ No | ✅ Yes | | Non primitive JS types | ❌ No | ✅ Yes | [External Configuration Files](https://nuxt.com/docs/4.x/getting-started/configuration#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. | Name | Config File | How To Configure | | --- | --- | --- | | [Nitro](https://nitro.build/) | ~`nitro.config.ts`~ | Use [`nitro`](https://nuxt.com/docs/4.x/api/nuxt-config#nitro)
key in `nuxt.config` | | [PostCSS](https://postcss.org/) | ~`postcss.config.js`~ | Use [`postcss`](https://nuxt.com/docs/4.x/api/nuxt-config#postcss)
key in `nuxt.config` | | [Vite](https://vite.dev/) | ~`vite.config.ts`~ | Use [`vite`](https://nuxt.com/docs/4.x/api/nuxt-config#vite)
key in `nuxt.config` | | [webpack](https://webpack.js.org/) | ~`webpack.config.ts`~ | Use [`webpack`](https://nuxt.com/docs/4.x/api/nuxt-config#webpack-1)
key in `nuxt.config` | Here is a list of other common config files: | Name | Config File | How To Configure | | --- | --- | --- | | [TypeScript](https://www.typescriptlang.org/) | `tsconfig.json` | [More Info](https://nuxt.com/docs/4.x/directory-structure/tsconfig) | | [ESLint](https://eslint.org/) | `eslint.config.js` | [More Info](https://eslint.org/docs/latest/use/configure/configuration-files) | | [Prettier](https://prettier.io/) | `prettier.config.js` | [More Info](https://prettier.io/docs/configuration.html) | | [Stylelint](https://stylelint.io/) | `stylelint.config.js` | [More Info](https://stylelint.io/user-guide/configure/) | | [TailwindCSS](https://tailwindcss.com/) | `tailwind.config.js` | [More Info](https://tailwindcss.nuxtjs.org/tailwindcss/configuration/) | | [Vitest](https://vitest.dev/) | `vitest.config.ts` | [More Info](https://vitest.dev/config/) | [Vue Configuration](https://nuxt.com/docs/4.x/getting-started/configuration#vue-configuration) ----------------------------------------------------------------------------------------------- ### [With Vite](https://nuxt.com/docs/4.x/getting-started/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) . nuxt.config.ts `export default defineNuxtConfig({ vite: { vue: { customElement: true, }, vueJsx: { mergeProps: true, }, }, })` [](https://nuxt.com/docs/4.x/api/configuration/nuxt-config#vue) Read more in Docs > 4 X > API > Configuration > Nuxt Config#vue. ### [With webpack](https://nuxt.com/docs/4.x/getting-started/configuration#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) . nuxt.config.ts `export default defineNuxtConfig({ webpack: { loaders: { vue: { hotReload: true, }, }, }, })` [](https://nuxt.com/docs/4.x/api/configuration/nuxt-config#loaders) Read more in Docs > 4 X > API > Configuration > Nuxt Config#loaders. ### [Enabling Experimental Vue Features](https://nuxt.com/docs/4.x/getting-started/configuration#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: nuxt.config.ts `export default defineNuxtConfig({ vue: { propsDestructure: true, }, })` #### [experimental `reactivityTransform` migration from Vue 3.4 and Nuxt 3.9](https://nuxt.com/docs/4.x/getting-started/configuration#experimental-reactivitytransform-migration-from-vue-34-and-nuxt-39) 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) . [](https://nuxt.com/docs/4.x/api/configuration/nuxt-config#vue-1) Read more in Docs > 4 X > API > Configuration > Nuxt Config#vue 1. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/03.configuration.md) [Installation\ \ Get started with Nuxt quickly with our online starters or start locally with your terminal.](https://nuxt.com/docs/4.x/getting-started/installation) [Views\ \ Nuxt provides several component layers to implement the user interface of your application.](https://nuxt.com/docs/4.x/getting-started/views) MenuOn this page --- # Assets · Get Started with Nuxt v4 Assets ====== Copy page 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](https://nuxt.com/docs/4.x/getting-started/assets#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](https://nuxt.com/docs/4.x/getting-started/assets#example) For example, referencing an image file in the `public/img/` directory, available at the static URL `/img/nuxt.png`: app/app.vue `` [Assets Directory](https://nuxt.com/docs/4.x/getting-started/assets#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](https://nuxt.com/docs/4.x/getting-started/assets#example-1) For example, referencing an image file that will be processed if a build tool is configured to handle this file extension: app/app.vue `` 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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/05.assets.md) [Views\ \ Nuxt provides several component layers to implement the user interface of your application.](https://nuxt.com/docs/4.x/getting-started/views) [Styling\ \ Learn how to style your Nuxt application.](https://nuxt.com/docs/4.x/getting-started/styling) MenuOn this page --- # Styling · Get Started with Nuxt v4 Styling ======= Copy page 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](https://nuxt.com/docs/4.x/getting-started/styling#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](https://nuxt.com/docs/4.x/getting-started/styling#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) . app/pages/index.vue ` ` The stylesheets will be inlined in the HTML rendered by Nuxt. ### [The CSS Property](https://nuxt.com/docs/4.x/getting-started/styling#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. 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](https://nuxt.com/docs/4.x/getting-started/styling#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()`. 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: `` ### [Stylesheets Distributed Through NPM](https://nuxt.com/docs/4.x/getting-started/styling#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. npmyarnpnpmbun `npm install animate.css` `yarn add animate.css` `pnpm install animate.css` `bun install animate.css` Then you can reference it directly in your pages, layouts and components: app/app.vue ` ` The package can also be referenced as a string in the css property of your Nuxt configuration. nuxt.config.ts `export default defineNuxtConfig({ css: ['animate.css'], })` [External Stylesheets](https://nuxt.com/docs/4.x/getting-started/styling#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: nuxt.config.ts `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](https://nuxt.com/docs/4.x/getting-started/styling#dynamically-adding-stylesheets) You can use the useHead composable to dynamically set a value in your head in your code. [](https://nuxt.com/docs/4.x/api/composables/use-head) Read more in Docs > 4 X > API > Composables > Use Head. `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](https://nuxt.com/docs/4.x/getting-started/styling#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: 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](https://nuxt.com/docs/4.x/getting-started/styling#using-preprocessors) --------------------------------------------------------------------------------------------- To use a preprocessor like SCSS, Sass, Less or Stylus, install it first. Sass & SCSSLessStylus `npm install -D sass` `npm install -D less` `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. app/pages/app.vue `` Alternatively, you can use the `css` property of your Nuxt configuration. nuxt.config.ts `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: assets/\_colors.scssassets/\_colors.sass `$primary: #49240F; $secondary: #E4A79D;` `$primary: #49240F $secondary: #E4A79D` Then in your `nuxt.config` : SCSSSASS `export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { scss: { additionalData: '@use "~/assets/_colors.scss" as *;', }, }, }, }, })` `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)](https://nuxt.com/docs/4.x/getting-started/styling#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`: `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](https://nuxt.com/docs/4.x/getting-started/styling#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](https://nuxt.com/docs/4.x/getting-started/styling#class-and-style-bindings) You can leverage Vue SFC features to style your components with class and style attributes. Ref and ReactiveComputedArrayStyle ` ` ` ` ` ` ` ` Refer to the [Vue docs](https://vuejs.org/guide/essentials/class-and-style) for more information. ### [Dynamic Styles With `v-bind`](https://nuxt.com/docs/4.x/getting-started/styling#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. ` ` ### [Scoped Styles](https://nuxt.com/docs/4.x/getting-started/styling#scoped-styles) The scoped attribute allows you to style components in isolation. The styles declared with this attribute will only apply to this component. ` ` ### [CSS Modules](https://nuxt.com/docs/4.x/getting-started/styling#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. ` ` ### [Preprocessors Support](https://nuxt.com/docs/4.x/getting-started/styling#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. SCSSSassLESSStylus `` `` `` `` 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](https://nuxt.com/docs/4.x/getting-started/styling#using-postcss) --------------------------------------------------------------------------------- Nuxt comes with postcss built-in. You can configure it in your `nuxt.config` file. 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. `` 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](https://nuxt.com/docs/4.x/getting-started/styling#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. ` ` [](https://nuxt.com/docs/4.x/directory-structure/app/layouts) Read more in Docs > 4 X > Directory Structure > App > Layouts. [Third Party Libraries And Modules](https://nuxt.com/docs/4.x/getting-started/styling#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](https://nuxt.com/docs/4.x/getting-started/styling#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](https://nuxt.com/docs/4.x/getting-started/styling#advanced) ----------------------------------------------------------------------- ### [Transitions](https://nuxt.com/docs/4.x/getting-started/styling#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) . [](https://nuxt.com/docs/4.x/getting-started/transitions) Read more in Docs > 4 X > Getting Started > Transitions. ### [Font Advanced Optimization](https://nuxt.com/docs/4.x/getting-started/styling#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](https://nuxt.com/docs/4.x/getting-started/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. 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) } } } }, }, })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/06.styling.md) [Assets\ \ Nuxt offers two options for your assets.](https://nuxt.com/docs/4.x/getting-started/assets) [Routing\ \ Nuxt file-system routing creates a route for every file in the pages/ directory.](https://nuxt.com/docs/4.x/getting-started/routing) MenuOn this page --- # Routing · Get Started with Nuxt v4 Routing ======= Copy page 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. [Pages](https://nuxt.com/docs/4.x/getting-started/routing#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: Directory StructureGenerated Router File `-| pages/ ---| about.vue ---| index.vue ---| posts/ -----| [id].vue` `{ "routes": [ { "path": "/about", "component": "pages/about.vue" }, { "path": "/", "component": "pages/index.vue" }, { "path": "/posts/:id", "component": "pages/posts/[id].vue" } ] }` [](https://nuxt.com/docs/4.x/directory-structure/app/pages) Read more in Docs > 4 X > Directory Structure > App > Pages. [Navigation](https://nuxt.com/docs/4.x/getting-started/routing#navigation) --------------------------------------------------------------------------- The [``](https://nuxt.com/docs/4.x/api/components/nuxt-link) component links pages between them. It renders an `` 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 [``](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. app/pages/index.vue `` [](https://nuxt.com/docs/4.x/api/components/nuxt-link) Read more in Docs > 4 X > API > Components > Nuxt Link. [Route Parameters](https://nuxt.com/docs/4.x/getting-started/routing#route-parameters) --------------------------------------------------------------------------------------- The [`useRoute()`](https://nuxt.com/docs/4.x/api/composables/use-route) composable can be used in a `` [](https://nuxt.com/docs/4.x/api/composables/use-route) Read more in Docs > 4 X > API > Composables > Use Route. [Route Middleware](https://nuxt.com/docs/4.x/getting-started/routing#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. 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. 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. 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: middleware/auth.tspages/dashboard.vue `export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (isAuthenticated() === false) { return navigateTo('/login') } })` ` ` [](https://nuxt.com/docs/4.x/directory-structure/app/middleware) Read more in Docs > 4 X > Directory Structure > App > Middleware. [Route Validation](https://nuxt.com/docs/4.x/getting-started/routing#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 `statusCode`/`statusMessage` to customize the error returned. If you have a more complex use case, then you can use anonymous route middleware instead. pages/posts/\[id\].vue `` [](https://nuxt.com/docs/4.x/api/utils/define-page-meta) Read more in Docs > 4 X > API > Utils > Define Page Meta. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/07.routing.md) [Styling\ \ Learn how to style your Nuxt application.](https://nuxt.com/docs/4.x/getting-started/styling) [SEO and Meta\ \ Improve your Nuxt app's SEO with powerful head config, composables and components.](https://nuxt.com/docs/4.x/getting-started/seo-meta) MenuOn this page --- # SEO and Meta · Get Started with Nuxt v4 SEO and Meta ============ Copy page 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](https://nuxt.com/docs/4.x/getting-started/seo-meta#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. This method does not allow you to provide reactive data. We recommend using `useHead()` in `app.vue`. It's good practice to set tags here that won't change such as your site title default, language and favicon. nuxt.config.ts `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/4.x/getting-started/seo-meta#types) . ### [Defaults Tags](https://nuxt.com/docs/4.x/getting-started/seo-meta#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. nuxt.config.ts `export default defineNuxtConfig({ app: { head: { // update Nuxt defaults charset: 'utf-16', viewport: 'width=device-width, initial-scale=1, maximum-scale=1', }, }, })` [`useHead`](https://nuxt.com/docs/4.x/getting-started/seo-meta#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. app/app.vue `` 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`](https://nuxt.com/docs/4.x/getting-started/seo-meta#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`. app/app.vue `` [](https://nuxt.com/docs/4.x/api/composables/use-seo-meta) Read more in Docs > 4 X > API > Composables > Use Seo Meta. [Components](https://nuxt.com/docs/4.x/getting-started/seo-meta#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: ``, `<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. 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 `` components as tags will be deduped more intuitively. [Types](https://nuxt.com/docs/4.x/getting-started/seo-meta#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. `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](https://nuxt.com/docs/4.x/getting-started/seo-meta#features) ------------------------------------------------------------------------ ### [Reactivity](https://nuxt.com/docs/4.x/getting-started/seo-meta#reactivity) Reactivity is supported on all properties, by providing a computed value, a getter, or a reactive object. useHeaduseSeoMetaapp/Components `` `` ` ` ### [Title Template](https://nuxt.com/docs/4.x/getting-started/seo-meta#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: useHead ```` 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 Params](https://nuxt.com/docs/4.x/getting-started/seo-meta#template-params) You can use `templateParams` to provide additional placeholders in your `titleTemplate` besides the default `%s`. This allows for more dynamic title generation. useHead ```` ### [Body Tags](https://nuxt.com/docs/4.x/getting-started/seo-meta#body-tags) You can use the `tagPosition: 'bodyClose'` option on applicable tags to append them to the end of the `` tag. For example: `` [Examples](https://nuxt.com/docs/4.x/getting-started/seo-meta#examples) ------------------------------------------------------------------------ ### [With `definePageMeta`](https://nuxt.com/docs/4.x/getting-started/seo-meta#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): pages/some-page.vue `` And then in your layout file, you might use the route's metadata you have previously set: layouts/default.vue ```` Read and edit a live example in [Docs > 4 X > Examples > Features > Meta Tags](https://nuxt.com/docs/4.x/examples/features/meta-tags) . [](https://nuxt.com/docs/4.x/directory-structure/app/pages/#page-metadata) Read more in Docs > 4 X > Directory Structure > App > Pages > #page Metadata. ### [Dynamic Title](https://nuxt.com/docs/4.x/getting-started/seo-meta#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: app/app.vue ```` app/app.vue ```` `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](https://nuxt.com/docs/4.x/getting-started/seo-meta#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: useHeadapp/Components `` `` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/08.seo-meta.md) [Routing\ \ Nuxt file-system routing creates a route for every file in the pages/ directory.](https://nuxt.com/docs/4.x/getting-started/routing) [Transitions\ \ Apply transitions between pages and layouts with Vue or native browser View Transitions.](https://nuxt.com/docs/4.x/getting-started/transitions) MenuOn this page --- # Transitions · Get Started with Nuxt v4 Transitions =========== Copy page 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](https://nuxt.com/docs/4.x/getting-started/transitions#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) . nuxt.config.ts `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/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) : app/app.vueapp/pages/index.vueapp/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: pages/about.vueapp/app.vue `` ` ` Moving to the about page will add the 3d rotation effect: [Layout Transitions](https://nuxt.com/docs/4.x/getting-started/transitions#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) . nuxt.config.ts `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) : app/app.vueapp/layouts/default.vueapp/layouts/orange.vueapp/pages/index.vueapp/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`: pages/about.vue `` [Global Settings](https://nuxt.com/docs/4.x/getting-started/transitions#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. nuxt.config.ts `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. pages/some-page.vue `` [Disable Transitions](https://nuxt.com/docs/4.x/getting-started/transitions#disable-transitions) ------------------------------------------------------------------------------------------------- `pageTransition` and `layoutTransition` can be disabled for a specific route: pages/some-page.vue `` Or globally in the `nuxt.config`: nuxt.config.ts `export default defineNuxtConfig({ app: { pageTransition: false, layoutTransition: false, }, })` [JavaScript Hooks](https://nuxt.com/docs/4.x/getting-started/transitions#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/) . pages/some-page.vue `` Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition#javascript-hooks) available in the `Transition` component. [Dynamic Transitions](https://nuxt.com/docs/4.x/getting-started/transitions#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`. pages/\[id\].vueapp/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](https://nuxt.com/docs/4.x/getting-started/transitions#transition-with-nuxtpage) ----------------------------------------------------------------------------------------------------------- When `` is used in `app.vue`, transitions can be configured with the `transition` prop to activate transitions globally. app/app.vue `` Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. [View Transitions API (experimental)](https://nuxt.com/docs/4.x/getting-started/transitions#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: nuxt.config.ts `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. nuxt.config.ts `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: pages/about.vue `` 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: `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](https://nuxt.com/docs/4.x/getting-started/transitions#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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/09.transitions.md) [SEO and Meta\ \ Improve your Nuxt app's SEO with powerful head config, composables and components.](https://nuxt.com/docs/4.x/getting-started/seo-meta) [Data Fetching\ \ Nuxt provides composables to handle data fetching within your application.](https://nuxt.com/docs/4.x/getting-started/data-fetching) MenuOn this page --- # Server · Get Started with Nuxt v4 Server ====== Copy page 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. [](https://nuxt.com/docs/4.x/directory-structure/server) Read more in Docs > 4 X > Directory Structure > Server. [Powered by Nitro](https://nuxt.com/docs/4.x/getting-started/server#powered-by-nitro) -------------------------------------------------------------------------------------- ![Server engine](https://ipx.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. Watch a video from Alexander Lichter to understand the responsibilities of Nuxt and Nitro in your application [Server Endpoints & Middleware](https://nuxt.com/docs/4.x/getting-started/server#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: server/api/test.ts `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. [](https://nuxt.com/docs/4.x/directory-structure/server) Read more in Docs > 4 X > Directory Structure > Server. [Universal Deployment](https://nuxt.com/docs/4.x/getting-started/server#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! [](https://nuxt.com/blog/nuxt-on-the-edge) Read more in Blog > Nuxt On The Edge. 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: [](https://deno.com/) Deno [](https://bun.com/) Bun [](https://nuxt.com/docs/4.x/getting-started/deployment) Read more in Docs > 4 X > Getting Started > Deployment. [Hybrid Rendering](https://nuxt.com/docs/4.x/getting-started/server#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). nuxt.config.ts `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 }, }, // ... }, })` [](https://nuxt.com/docs/4.x/guide/concepts/rendering#hybrid-rendering) 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. [](https://nuxt.com/docs/4.x/guide/concepts/rendering) Read more in Docs > 4 X > Guide > Concepts > Rendering. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/13.server.md) [Error Handling\ \ Learn how to catch and handle errors in Nuxt.](https://nuxt.com/docs/4.x/getting-started/error-handling) [Layers\ \ Nuxt provides a powerful system that allows you to extend the default files, configs, and much more.](https://nuxt.com/docs/4.x/getting-started/layers) MenuOn this page --- # Deployment · Get Started with Nuxt v4 Deployment ========== Copy page 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. If you are looking for a list of cloud providers that support Nuxt, see the [Hosting providers](https://nuxt.com/deploy) section. [Node.js Server](https://nuxt.com/docs/4.x/getting-started/deployment#nodejs-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 * Loads only the required chunks to render the request for optimal cold start timing * Useful for deploying Nuxt apps to any Node.js hosting ### [Entry Point](https://nuxt.com/docs/4.x/getting-started/deployment#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. Terminal `node .output/server/index.mjs` This will launch your production Nuxt server that listens on port 3000 by default. 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](https://nuxt.com/docs/4.x/getting-started/deployment#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`: ecosystem.config.cjs `module.exports = { apps: [ { name: 'NuxtAppName', port: '3000', exec_mode: 'cluster', instances: 'max', script: './.output/server/index.mjs', }, ], }` ### [Cluster Mode](https://nuxt.com/docs/4.x/getting-started/deployment#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](https://nuxt.com/docs/4.x/getting-started/deployment#learn-more) [](https://nitro.build/deploy/runtimes/node) Read more in the Nitro documentation for node-server preset. Watch Daniel Roe's short video on the topic [Static Hosting](https://nuxt.com/docs/4.x/getting-started/deployment#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 `
` 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 [``](https://nuxt.com/docs/4.x/api/components/client-only) to wrap the portions of your site that cannot be server rendered (if any). [](https://nuxt.com/docs/4.x/getting-started/prerendering) Read more in Nuxt prerendering. ### [Client-side Only Rendering](https://nuxt.com/docs/4.x/getting-started/deployment#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. nuxt.config.ts `export default defineNuxtConfig({ ssr: false, })` [Hosting Providers](https://nuxt.com/docs/4.x/getting-started/deployment#hosting-providers) -------------------------------------------------------------------------------------------- Nuxt can be deployed to several cloud providers with a minimal amount of configuration: [](https://nuxt.com/deploy) Read more in Deploy. [Presets](https://nuxt.com/docs/4.x/getting-started/deployment#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/4.x/directory-structure/nuxt-config) file: nuxt.config.ts `export default defineNuxtConfig({ nitro: { preset: 'node-server', }, })` ... or use the `NITRO_PRESET` environment variable when running `nuxt build`: Terminal `NITRO_PRESET=node-server nuxt build` 🔎 Check [the Nitro deployment](https://nitro.build/deploy) for all possible deployment presets and providers. [CDN Proxy](https://nuxt.com/docs/4.x/getting-started/deployment#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 > Optimization > Content Optimization > Disable "Rocket Loader™" 2. Speed > Optimization > Image Optimization > Disable "Mirage" 3. Scrape Shield > 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. Their location on the Cloudflare dashboard sometimes changes so don't hesitate to look around. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/16.deployment.md) [Prerendering\ \ Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics](https://nuxt.com/docs/4.x/getting-started/prerendering) [Testing\ \ How to test your Nuxt application.](https://nuxt.com/docs/4.x/getting-started/testing) MenuOn this page --- # Layers · Get Started with Nuxt v4 Layers ====== Copy page 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](https://nuxt.com/docs/4.x/getting-started/layers#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](https://nuxt.com/docs/4.x/getting-started/layers#usage) ---------------------------------------------------------------- By default, any layers within your project in the `~~/layers` directory will be automatically registered as layers in your project. Layer auto-registration was introduced in Nuxt v3.12.0. 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`. Named layer aliases were introduced in Nuxt v3.16.0. 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. 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: nuxt.config.ts `export default defineNuxtConfig({ extends: [ // per layer configuration ['github:my-themes/private-awesome', { auth: process.env.GITHUB_TOKEN }], ], })` You can override a layer's alias by specifying it in the options next to the layer source. nuxt.config.ts `export default defineNuxtConfig({ extends: [ [ 'github:my-themes/awesome', { meta: { name: 'my-awesome-theme', }, }, ], ], })` 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](https://nuxt.com/docs/4.x/getting-started/layers#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. The priority order from highest to lowest is: 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 ### [When to Use Each](https://nuxt.com/docs/4.x/getting-started/layers#when-to-use-each) * **`extends`** - Use for external dependencies (npm packages, remote repositories) or layers outside your project directory * **`~~/layers` directory** - Use for local layers that are part of your project If you need to control the order of auto-scanned layers, you can prefix them with numbers: `~/layers/1.z-layer`, `~/layers/2.a-layer`. This way `2.a-layer` will have higher priority than `1.z-layer`. ### [Example](https://nuxt.com/docs/4.x/getting-started/layers#example) nuxt.config.ts `export default defineNuxtConfig({ extends: [ // Local layer outside the project '../base', // NPM package '@my-themes/awesome', // Remote repository 'github:my-themes/awesome#v1', ], })` 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) This means your project files will override any layer, and `~~/layers/custom` will override anything in `extends`. [](https://nuxt.com/docs/4.x/guide/going-further/layers) Read more about layers in the **Layer Author Guide**. Watch a video from Learn Vue about Nuxt Layers Watch a video from Alexander Lichter about Nuxt Layers [Examples](https://nuxt.com/docs/4.x/getting-started/layers#examples) ---------------------------------------------------------------------- [](https://github.com/Atinux/content-wind) Content Wind A lightweight Nuxt theme to build a Markdown driven website. Powered by Nuxt Content, TailwindCSS and Iconify. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/14.layers.md) [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.](https://nuxt.com/docs/4.x/getting-started/server) [Prerendering\ \ Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics](https://nuxt.com/docs/4.x/getting-started/prerendering) MenuOn this page --- # Prerendering · Get Started with Nuxt v4 Prerendering ============ Copy page 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. [](https://nuxt.com/docs/4.x/guide/concepts/rendering) Read more in Nuxt rendering modes. [Crawl-based Pre-rendering](https://nuxt.com/docs/4.x/getting-started/prerendering#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. npmyarnpnpmbun `npx nuxt generate` `yarn nuxt generate` `pnpm nuxt generate` `bun x nuxt generate` 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 (`
`) 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. [](https://nuxt.com/docs/4.x/api/commands/generate#nuxt-generate) Read more about the `nuxt generate` command. ### [Selective Pre-rendering](https://nuxt.com/docs/4.x/getting-started/prerendering#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: nuxt.config.ts `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`: nuxt.config.ts `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`. [](https://nitro.build/config#prerender) Read more about pre-rendering in the Nitro documentation. Lastly, you can manually configure this using routeRules. nuxt.config.ts `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 }, }, })` [](https://nitro.build/config#routerules) Read more about Nitro's `routeRules` configuration. 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) . [](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`. app/pages/index.vue ` ` This will be translated to: nuxt.config.ts `export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, })` [Runtime Prerender Configuration](https://nuxt.com/docs/4.x/getting-started/prerendering#runtime-prerender-configuration) -------------------------------------------------------------------------------------------------------------------------- ### [`prerenderRoutes`](https://nuxt.com/docs/4.x/getting-started/prerendering#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. app/pages/index.vue ` ` [](https://nuxt.com/docs/4.x/api/utils/prerender-routes) Read more in prerenderRoutes. ### [`prerender:routes` Nuxt hook](https://nuxt.com/docs/4.x/getting-started/prerendering#prerenderroutes-nuxt-hook) This is called before prerendering for additional routes to be registered. 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](https://nuxt.com/docs/4.x/getting-started/prerendering#prerendergenerate-nitro-hook) This is called for each route during prerendering. You can use this for fine-grained handling of each route that gets prerendered. nuxt.config.ts `export default defineNuxtConfig({ nitro: { hooks: { 'prerender:generate' (route) { if (route.route?.includes('private')) { route.skip = true } }, }, }, })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/15.prerendering.md) [Layers\ \ Nuxt provides a powerful system that allows you to extend the default files, configs, and much more.](https://nuxt.com/docs/4.x/getting-started/layers) [Deployment\ \ Learn how to deploy your Nuxt application to any hosting provider.](https://nuxt.com/docs/4.x/getting-started/deployment) MenuOn this page --- # Testing · Get Started with Nuxt v4 Testing ======= Copy page 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. Watch a video from Alexander Lichter about getting started with @nuxt/test-utils [Installation](https://nuxt.com/docs/4.x/getting-started/testing#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) npmyarnpnpmbun `npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` `yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` `pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` `bun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` [Unit Testing](https://nuxt.com/docs/4.x/getting-started/testing#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](https://nuxt.com/docs/4.x/getting-started/testing#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. `export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], })` 2. Create a `vitest.config.ts` with the following content: `import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/{e2e,unit}/*.{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](https://nuxt.com/docs/4.x/getting-started/testing#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](https://nuxt.com/docs/4.x/getting-started/testing#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: `import { defineVitestConfig } from '@nuxt/test-utils/config' 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. `// @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](https://nuxt.com/docs/4.x/getting-started/testing#organizing-your-tests) With the project-based setup, you might organize your tests as follows: 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](https://nuxt.com/docs/4.x/getting-started/testing#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: 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](https://nuxt.com/docs/4.x/getting-started/testing#running-tests) With the project setup, you can run different test suites: `# 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](https://nuxt.com/docs/4.x/getting-started/testing#built-in-mocks) `@nuxt/test-utils` provides some built-in mocks for the DOM environment. #### [`intersectionObserver`](https://nuxt.com/docs/4.x/getting-started/testing#intersectionobserver) Default `true`, creates a dummy class without any functionality for the IntersectionObserver API #### [`indexedDB`](https://nuxt.com/docs/4.x/getting-started/testing#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: `import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ test: { environmentOptions: { nuxt: { mock: { intersectionObserver: true, indexedDb: true, }, }, }, }, })` ### [🛠️ Helpers](https://nuxt.com/docs/4.x/getting-started/testing#%EF%B8%8F-helpers) `@nuxt/test-utils` provides a number of helpers to make testing Nuxt apps easier. #### [`mountSuspended`](https://nuxt.com/docs/4.x/getting-started/testing#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: `// 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"', ) })` ``// 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 " `) })`` #### [`renderSuspended`](https://nuxt.com/docs/4.x/getting-started/testing#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: `// 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() })` ``// 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
" `) })`` #### [`mockNuxtImport`](https://nuxt.com/docs/4.x/getting-started/testing#mocknuxtimport) `mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useStorage`, you can do so like this: `import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useStorage', () => { return () => { return { value: 'mocked storage' } } }) // 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. `import { vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' const { useStorageMock } = vi.hoisted(() => { return { useStorageMock: vi.fn(() => { return { value: 'mocked storage' } }), } }) mockNuxtImport('useStorage', () => { return useStorageMock }) // Then, inside a test useStorageMock.mockImplementation(() => { return { value: 'something else' } })` #### [`mockComponent`](https://nuxt.com/docs/4.x/getting-started/testing#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: `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. `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`](https://nuxt.com/docs/4.x/getting-started/testing#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: `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. `import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', { method: 'POST', handler: () => ({ test: 'test-field' }), })` > **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](https://nuxt.com/docs/4.x/getting-started/testing#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` `import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useStorage', () => { return () => { return { value: 'mocked storage' } } })` `app.e2e.spec.ts` `import { $fetch, setup } from '@nuxt/test-utils/e2e' await setup({ setupTimeout: 10000, }) // ...` ### [Using `@vue/test-utils`](https://nuxt.com/docs/4.x/getting-started/testing#using-vuetest-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 npmyarnpnpmbun `npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue` `yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue` `pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue` `bun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue` 2. Create a `vitest.config.ts` with the following content: `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` `"scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" },` 4. Create a simple `` component `app/components/HelloWorld.vue` with the following content: `` 5. Create a simple unit test for this newly created component `~/components/HelloWorld.spec.ts` `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 npmyarnpnpmbun `npm run test` `yarn test` `pnpm run test` `bun run test` Congratulations, you're all set to start unit testing with `@vue/test-utils` in Nuxt! Happy testing! [End-To-End Testing](https://nuxt.com/docs/4.x/getting-started/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](https://nuxt.com/docs/4.x/getting-started/testing#setup-1) 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. test/my-test.spec.ts `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](https://nuxt.com/docs/4.x/getting-started/testing#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](https://nuxt.com/docs/4.x/getting-started/testing#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](https://nuxt.com/docs/4.x/getting-started/testing#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'` ##### 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. `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](https://nuxt.com/docs/4.x/getting-started/testing#apis) #### [`$fetch(url)`](https://nuxt.com/docs/4.x/getting-started/testing#fetchurl) Get the HTML of a server-rendered page. `import { $fetch } from '@nuxt/test-utils/e2e' const html = await $fetch('/')` #### [`fetch(url)`](https://nuxt.com/docs/4.x/getting-started/testing#fetchurl-1) Get the response of a server-rendered page. `import { fetch } from '@nuxt/test-utils/e2e' const res = await fetch('/') const { body, headers } = res` #### [`url(path)`](https://nuxt.com/docs/4.x/getting-started/testing#urlpath) Get the full URL for a given page (including the port the test server is running on.) `import { url } from '@nuxt/test-utils/e2e' const pageUrl = url('/page') // 'http://localhost:6840/page'` ### [Testing in a Browser](https://nuxt.com/docs/4.x/getting-started/testing#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)`](https://nuxt.com/docs/4.x/getting-started/testing#createpageurl) 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) . ``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](https://nuxt.com/docs/4.x/getting-started/testing#testing-with-playwright-test-runner) We also provide first-class support for testing Nuxt within [the Playwright test runner](https://playwright.dev/docs/intro) . npmyarnpnpmbun `npm i --save-dev @playwright/test @nuxt/test-utils` `yarn add --dev @playwright/test @nuxt/test-utils` `pnpm add -D @playwright/test @nuxt/test-utils` `bun add --dev @playwright/test @nuxt/test-utils` You can provide global Nuxt configuration, with the same configuration details as the `setup()` function mentioned earlier in this section. 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)), }, }, // ... })` [](https://github.com/nuxt/test-utils/blob/main/examples/app-playwright/playwright.config.ts) Read more in See full example config. Your test file should then use `expect` and `test` directly from `@nuxt/test-utils/playwright`: 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: 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!') })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/17.testing.md) [Deployment\ \ Learn how to deploy your Nuxt application to any hosting provider.](https://nuxt.com/docs/4.x/getting-started/deployment) [Upgrade Guide\ \ Learn how to upgrade to the latest Nuxt version.](https://nuxt.com/docs/4.x/getting-started/upgrade) MenuOn this page --- # .nuxt · Nuxt Directory Structure v4 .nuxt ===== Copy page Nuxt uses the .nuxt/ directory in development to generate your Vue application. 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. 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. 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) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/0.nuxt.md) [Upgrade Guide\ \ Learn how to upgrade to the latest Nuxt version.](https://nuxt.com/docs/4.x/getting-started/upgrade) [.output\ \ Nuxt creates the .output/ directory when building your application for production.](https://nuxt.com/docs/4.x/directory-structure/output) MenuOn this page --- # .output · Nuxt Directory Structure v4 .output ======= Copy page Nuxt creates the .output/ directory when building your application for production. 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. Use this directory to deploy your Nuxt application to production. [](https://nuxt.com/docs/4.x/getting-started/deployment) Read more in Docs > 4 X > Getting Started > Deployment. 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) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/0.output.md) [.nuxt\ \ Nuxt uses the .nuxt/ directory in development to generate your Vue application.](https://nuxt.com/docs/4.x/directory-structure/nuxt) [assets\ \ The assets/ directory is used to add all the website's assets that the build tool will process.](https://nuxt.com/docs/4.x/directory-structure/app/assets) MenuOn this page --- # assets · Nuxt Directory Structure v4 assets ====== Copy page 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. [](https://nuxt.com/docs/4.x/getting-started/assets) Read more in Docs > 4 X > Getting Started > Assets. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/1.app/1.assets.md) [.output\ \ Nuxt creates the .output/ directory when building your application for production.](https://nuxt.com/docs/4.x/directory-structure/output) [components\ \ The components/ directory is where you put all your Vue components.](https://nuxt.com/docs/4.x/directory-structure/app/components) MenuOn this page --- # Upgrade Guide · Get Started with Nuxt v4 Upgrade Guide ============= Copy page Learn how to upgrade to the latest Nuxt version. [Upgrading Nuxt](https://nuxt.com/docs/4.x/getting-started/upgrade#upgrading-nuxt) ----------------------------------------------------------------------------------- ### [Latest release](https://nuxt.com/docs/4.x/getting-started/upgrade#latest-release) To upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases) , use the `nuxt upgrade` command. npmyarnpnpmbun `npx nuxt upgrade` `yarn nuxt upgrade` `pnpm nuxt upgrade` `bun x nuxt upgrade` ### [Nightly Release Channel](https://nuxt.com/docs/4.x/getting-started/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](https://nuxt.com/docs/4.x/getting-started/upgrade#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](https://nuxt.com/docs/4.x/getting-started/upgrade#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: nuxt.config.ts `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 * 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. ### [Migration to Vite Environment API](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-to-vite-environment-api) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#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](https://nuxt.com/docs/4.x/getting-started/upgrade#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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps) ##### 1\. Migrate to use Vite plugins We would recommend you use a Vite plugin instead of `extendViteConfig`, `vite:configResolved` and `vite:extendConfig`. `// 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. `// 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' }, }))` [](https://vite.dev/guide/api-environment) Learn more about Vite's Environment API [Migrating to Nuxt 4](https://nuxt.com/docs/4.x/getting-started/upgrade#migrating-to-nuxt-4) --------------------------------------------------------------------------------------------- Nuxt 4 includes significant improvements and changes. This guide will help you migrate your existing Nuxt 3 application to Nuxt 4. First, upgrade to Nuxt 4: npmyarnpnpmbun `npm install nuxt@^4.0.0` `yarn add nuxt@^4.0.0` `pnpm add nuxt@^4.0.0` `bun add nuxt@^4.0.0` After upgrading, most Nuxt 4 behaviors are now the default. However, some features can still be configured if you need to maintain backward compatibility during your migration. The following sections detail the key changes and migrations needed when upgrading to Nuxt 4. Breaking or significant changes are documented below along with migration steps and available configuration options. ### [Migrating Using Codemods](https://nuxt.com/docs/4.x/getting-started/upgrade#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: npmyarnpnpmbun `# Using pinned version due to https://github.com/codemod/codemod/issues/1710 npx codemod@0.18.7 nuxt/4/migration-recipe` `# Using pinned version due to https://github.com/codemod/codemod/issues/1710 yarn dlx codemod@0.18.7 nuxt/4/migration-recipe` `# Using pinned version due to https://github.com/codemod/codemod/issues/1710 pnpm dlx codemod@0.18.7 nuxt/4/migration-recipe` `# Using pinned version due to https://github.com/codemod/codemod/issues/1710 bun 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](https://nuxt.com/docs/4.x/getting-started/upgrade#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 `app/pages/` directory, this new structure will not apply). 👉 [See full RFC](https://github.com/nuxt/nuxt/issues/26444) #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-1) * 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 `/` An example v4 folder structure. `.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/ 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 `app/components/`, `~/pages` to `app/pages/`, etc. 👉 For more details, see the [PR implementing this change](https://github.com/nuxt/nuxt/pull/27029) . #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-1) 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. Watch a video from Vue School on the new directory structure #### [Migration Steps](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-1) 1. Create a new directory called `app/`. 2. Move your `assets/`, `components/`, `composables/`, `app/layouts/`, `app/middleware/`, `app/pages/`, `app/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/` 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/` 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: 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 `router.options.ts` and `spa-loading-template.html` dir: { app: 'app', }, })`` ### [Singleton Data Fetching Layer](https://nuxt.com/docs/4.x/getting-started/upgrade#singleton-data-fetching-layer) 🚦 **Impact Level**: Moderate #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-2) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-2) These changes have been made to improve memory usage and increase consistency with loading states across calls of `useAsyncData`. #### [Migration Steps](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-2) 1. **Check for inconsistent options**: Review any components using the same key with different options or fetch functions. `// 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: app/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**: `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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { granularCachedData: false, purgeCachedData: false, }, })` ### [Corrected Module Loading Order in Layers](https://nuxt.com/docs/4.x/getting-started/upgrade#corrected-module-loading-order-in-layers) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-3) The order in which modules are loaded when using [Nuxt layers](https://nuxt.com/docs/4.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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-3) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-3) **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: `// 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/4.x/guide/modules/recipes-advanced) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#deduplication-of-route-metadata) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-4) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-4) This is a result of enabling `experimental.scanPageMeta` by default, and is a performance optimization. #### [Migration Steps](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-4) The migration should be straightforward: `const route = useRoute() - console.log(route.meta.name) + console.log(route.name)` ### [Normalized Component Names](https://nuxt.com/docs/4.x/getting-started/upgrade#normalized-component-names) 🚦 **Impact Level**: Moderate Vue will now generate component names that match the Nuxt pattern for component naming. #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-5) By default, if you haven't set it manually, Vue will assign a component name that matches the filename of the component. 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-5) 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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { normalizeComponentNames: false, }, })` ### [Unhead v2](https://nuxt.com/docs/4.x/getting-started/upgrade#unhead-v2) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-6) [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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-6) 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. `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. `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`. `-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. `export default defineNuxtConfig({ unhead: { legacy: true, }, })` ### [New DOM Location for SPA Loading Screen](https://nuxt.com/docs/4.x/getting-started/upgrade#new-dom-location-for-spa-loading-screen) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-7) 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: `
` Now, we default to rendering the template alongside the Nuxt app root: `
` #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-5) This allows the spa loading template to remain in the DOM until the Vue app suspense resolves, preventing a flash of white. #### [Migration Steps](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-7) 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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { spaLoadingTemplateLocation: 'within', }, })` ### [Parsed `error.data`](https://nuxt.com/docs/4.x/getting-started/upgrade#parsed-errordata) 🚦 **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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-8) Update your custom `error.vue` to remove any additional parsing of `error.data`: `` ### [More Granular Inline Styles](https://nuxt.com/docs/4.x/getting-started/upgrade#more-granular-inline-styles) 🚦 **Impact Level**: Moderate Nuxt will now only inline styles for Vue components, not global CSS. #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-8) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-9) 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. nuxt.config.ts `export default defineNuxtConfig({ features: { inlineStyles: true, }, })` ### [Scan Page Meta After Resolution](https://nuxt.com/docs/4.x/getting-started/upgrade#scan-page-meta-after-resolution) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-9) We now scan page metadata (defined in `definePageMeta`) _after_ calling the `pages:extend` hook rather than before. #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-6) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-10) If you want to override page metadata, do that in `pages:resolved` rather than in `pages:extend`. `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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { scanPageMeta: true, }, })` ### [Shared Prerender Data](https://nuxt.com/docs/4.x/getting-started/upgrade#shared-prerender-data) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-10) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-7) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-11) 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.) 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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { sharedPrerenderData: false, }, })` ### [Default `data` and `error` values in `useAsyncData` and `useFetch`](https://nuxt.com/docs/4.x/getting-started/upgrade#default-data-and-error-values-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-11) `data` and `error` objects returned from `useAsyncData` will now default to `undefined`. #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-8) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-12) 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`](https://nuxt.com/docs/4.x/getting-started/upgrade#removal-of-deprecated-boolean-values-for-dedupe-option-when-calling-refresh-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-12) Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`). app/app.vue `const { refresh } = await useAsyncData(() => Promise.resolve({ message: 'Hello, Nuxt!' })) async function refreshData () { await refresh({ dedupe: true }) }` #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-9) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-13) The migration should be straightforward: `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`](https://nuxt.com/docs/4.x/getting-started/upgrade#respect-defaults-when-clearing-data-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-13) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-10) 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. ### [Alignment of `pending` value in `useAsyncData` and `useFetch`](https://nuxt.com/docs/4.x/getting-started/upgrade#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](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-14) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-11) This aligns the meaning of `pending` with the `status` property, which is also `pending` when the request is in progress. #### [Migration Steps](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-14) 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. ` ` Alternatively, you can temporarily revert to the previous behavior with: nuxt.config.ts `export default defineNuxtConfig({ experimental: { pendingWhenIdle: true, }, })` ### [Key Change Behavior in `useAsyncData` and `useFetch`](https://nuxt.com/docs/4.x/getting-started/upgrade#key-change-behavior-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-15) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-12) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-15) 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. `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: `// Or globally in your Nuxt config export default defineNuxtConfig({ experimental: { alwaysRunFetchOnKeyChange: true, }, })` ### [Shallow Data Reactivity in `useAsyncData` and `useFetch`](https://nuxt.com/docs/4.x/getting-started/upgrade#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](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-16) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-13) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-16) 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: `- 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): nuxt.config.ts `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`](https://nuxt.com/docs/4.x/getting-started/upgrade#absolute-watch-paths-in-builderwatch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-17) The Nuxt `builder:watch` hook now emits a path which is absolute rather than relative to your project `srcDir`. #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-14) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-17) 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: `+ 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](https://nuxt.com/docs/4.x/getting-started/upgrade#removal-of-window__nuxt__-object) #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-18) We are removing the global `window.__NUXT__` object after the app finishes hydration. #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-15) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-18) The data is still available, but can be accessed with `useNuxtApp().payload`: `- console.log(window.__NUXT__) + console.log(useNuxtApp().payload)` ### [Directory index scanning](https://nuxt.com/docs/4.x/getting-started/upgrade#directory-index-scanning) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-19) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-16) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-19) Probably no migration is necessary but if you wish to revert to previous behavior you can add a hook to filter out these middleware: `export default defineNuxtConfig({ hooks: { 'app:resolve' (app) { app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path)) }, }, })` ### [Template Compilation Changes](https://nuxt.com/docs/4.x/getting-started/upgrade#template-compilation-changes) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-20) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-17) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-20) 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: `+ 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`: ``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](https://nuxt.com/docs/4.x/getting-started/upgrade#default-typescript-configuration-changes) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-21) `compilerOptions.noUncheckedIndexedAccess` is now `true` instead of `false`. #### [Reasons for Change](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-18) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-21) 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`: `export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedIndexedAccess: false, }, }, }, })` ### [TypeScript Configuration Splitting](https://nuxt.com/docs/4.x/getting-started/upgrade#typescript-configuration-splitting) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-22) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-19) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-22) **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. `{ // 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: `- "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: `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](https://nuxt.com/docs/4.x/getting-started/upgrade#removal-of-experimental-features) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-23) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-20) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-23) * `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](https://nuxt.com/docs/4.x/getting-started/upgrade#removal-of-top-level-generate-configuration) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/4.x/getting-started/upgrade#what-changed-24) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#reasons-for-change-21) 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](https://nuxt.com/docs/4.x/getting-started/upgrade#migration-steps-24) Replace `generate` configuration with the corresponding `nitro.prerender` options: `export default defineNuxtConfig({ - generate: { - exclude: ['/admin', '/private'], - routes: ['/sitemap.xml', '/robots.txt'] - } + nitro: { + prerender: { + ignore: ['/admin', '/private'], + routes: ['/sitemap.xml', '/robots.txt'] + } + } })` [](https://nitro.build/config#prerender) Read more about Nitro's prerender configuration options. [Nuxt 2 vs. Nuxt 3+](https://nuxt.com/docs/4.x/getting-started/upgrade#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 | ✅ | ✅ | ✅ | | ` ` 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. [](https://nuxt.com/docs/4.x/guide/concepts/auto-imports) Read more in Docs > 4 X > Guide > Concepts > Auto Imports. Read and edit a live example in [Docs > 4 X > Examples > Features > Auto Imports](https://nuxt.com/docs/4.x/examples/features/auto-imports) . [Types](https://nuxt.com/docs/4.x/directory-structure/app/composables#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. If you create a composable without having the dev server running, TypeScript will throw an error, such as `Cannot find name 'useBar'.` [Examples](https://nuxt.com/docs/4.x/directory-structure/app/composables#examples) ----------------------------------------------------------------------------------- ### [Nested Composables](https://nuxt.com/docs/4.x/directory-structure/app/composables#nested-composables) You can use a composable within another composable using auto imports: app/composables/test.ts `export const useFoo = () => { const nuxtApp = useNuxtApp() const bar = useBar() }` ### [Access plugin injections](https://nuxt.com/docs/4.x/directory-structure/app/composables#access-plugin-injections) You can access [plugin injections](https://nuxt.com/docs/4.x/directory-structure/app/plugins#providing-helpers) from composables: app/composables/test.ts `export const useHello = () => { const nuxtApp = useNuxtApp() return nuxtApp.$hello }` [How Files Are Scanned](https://nuxt.com/docs/4.x/directory-structure/app/composables#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.: 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: 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: nuxt.config.ts `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/**', ], }, })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/1.app/1.composables.md) [components\ \ The components/ directory is where you put all your Vue components.](https://nuxt.com/docs/4.x/directory-structure/app/components) [layouts\ \ Nuxt provides a layouts framework to extract common UI patterns into reusable layouts.](https://nuxt.com/docs/4.x/directory-structure/app/layouts) MenuOn this page --- # components · Nuxt Directory Structure v4 components ========== Copy page 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). Directory Structure `-| components/ ---| AppHeader.vue ---| AppFooter.vue` app/app.vue `` [Component Names](https://nuxt.com/docs/4.x/directory-structure/app/components#component-names) ------------------------------------------------------------------------------------------------ If you have a component in nested directories such as: 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: `` 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`. 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: nuxt.config.ts `export default defineNuxtConfig({ components: [ { path: '~/components', pathPrefix: false, }, ], })` This registers the components using the same strategy as used in Nuxt 2. For example, `~/components/Some/MyComponent.vue` will be usable as `` and not ``. [Dynamic Components](https://nuxt.com/docs/4.x/directory-structure/app/components#dynamic-components) ------------------------------------------------------------------------------------------------------ If you want to use the Vue `` 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: app/pages/index.vue ` ` 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. Watch Daniel Roe's short video about resolveComponent() 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. `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. The `global` option can also be set per component directory. [Dynamic Imports](https://nuxt.com/docs/4.x/directory-structure/app/components#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. app/pages/index.vue ` ` [Delayed (or Lazy) Hydration](https://nuxt.com/docs/4.x/directory-structure/app/components#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](https://nuxt.com/docs/4.x/directory-structure/app/components#hydration-strategies) Nuxt provides a range of built-in hydration strategies. Only one strategy can be used per lazy component. 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) 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`. #### [`hydrate-on-visible`](https://nuxt.com/docs/4.x/directory-structure/app/components#hydrate-on-visible) Hydrates the component when it becomes visible in the viewport. app/pages/index.vue `` [](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver) Read more about the options for `hydrate-on-visible`. Under the hood, this uses Vue's built-in [`hydrateOnVisible` strategy](https://vuejs.org/guide/components/async#hydrate-on-visible) . #### [`hydrate-on-idle`](https://nuxt.com/docs/4.x/directory-structure/app/components#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. app/pages/index.vue `` Under the hood, this uses Vue's built-in [`hydrateOnIdle` strategy](https://vuejs.org/guide/components/async#hydrate-on-idle) . #### [`hydrate-on-interaction`](https://nuxt.com/docs/4.x/directory-structure/app/components#hydrate-on-interaction) Hydrates the component after a specified interaction (e.g., click, mouseover). app/pages/index.vue `` If you do not pass an event or list of events, it defaults to hydrating on `pointerenter`, `click` and `focus`. Under the hood, this uses Vue's built-in [`hydrateOnInteraction` strategy](https://vuejs.org/guide/components/async#hydrate-on-interaction) . #### [`hydrate-on-media-query`](https://nuxt.com/docs/4.x/directory-structure/app/components#hydrate-on-media-query) Hydrates the component when the window matches a media query. app/pages/index.vue `` Under the hood, this uses Vue's built-in [`hydrateOnMediaQuery` strategy](https://vuejs.org/guide/components/async#hydrate-on-media-query) . #### [`hydrate-after`](https://nuxt.com/docs/4.x/directory-structure/app/components#hydrate-after) Hydrates the component after a specified delay (in milliseconds). app/pages/index.vue `` #### [`hydrate-when`](https://nuxt.com/docs/4.x/directory-structure/app/components#hydrate-when) Hydrates the component based on a boolean condition. app/pages/index.vue ` ` #### [`hydrate-never`](https://nuxt.com/docs/4.x/directory-structure/app/components#hydrate-never) Never hydrates the component. app/pages/index.vue `` ### [Listening to Hydration Events](https://nuxt.com/docs/4.x/directory-structure/app/components#listening-to-hydration-events) All delayed hydration components emit a `@hydrated` event when they are hydrated. app/pages/index.vue ` ` ### [Caveats and Best Practices](https://nuxt.com/docs/4.x/directory-structure/app/components#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](https://nuxt.com/docs/4.x/directory-structure/app/components#direct-imports) ---------------------------------------------------------------------------------------------- You can also explicitly import components from `#components` if you want or need to bypass Nuxt's auto-importing functionality. app/pages/index.vue ` ` [Custom Directories](https://nuxt.com/docs/4.x/directory-structure/app/components#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: nuxt.config.ts ``export default defineNuxtConfig({ components: [ // ~/calendar-module/components/event/Update.vue => { path: '~/calendar-module/components' }, // ~/user-module/components/account/UserDeleteDialog.vue => { path: '~/user-module/components', pathPrefix: false }, // ~/components/special-components/Btn.vue => { 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 => // ~/components/base/Btn.vue => '~/components', ], })`` Any nested directories need to be added first as they are scanned in order. [npm Packages](https://nuxt.com/docs/4.x/directory-structure/app/components#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. ~/modules/register-component.tsapp/app.vue `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', }) }, })` `` [Component Extensions](https://nuxt.com/docs/4.x/directory-structure/app/components#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: nuxt.config.ts `export default defineNuxtConfig({ components: [ { path: '~/components', extensions: ['.vue'], }, ], })` [Client Components](https://nuxt.com/docs/4.x/directory-structure/app/components#client-components) ---------------------------------------------------------------------------------------------------- If a component is meant to be rendered only client-side, you can add the `.client` suffix to your component. Directory Structure `| components/ --| Comments.client.vue` app/pages/example.vue `` 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. `.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. [](https://nuxt.com/docs/4.x/api/components/client-only) You can also achieve a similar result with the `` component. [Server Components](https://nuxt.com/docs/4.x/directory-structure/app/components#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) . Watch Learn Vue video about Nuxt Server Components [](https://roe.dev/blog/nuxt-server-components) Read Daniel Roe's guide to Nuxt Server Components. ### [Standalone server components](https://nuxt.com/docs/4.x/directory-structure/app/components#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: nuxt.config.ts `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. Directory Structure `-| components/ ---| HighlightedMarkdown.server.vue` app/pages/example.vue `` Server-only components use [``](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. Server components (and islands) must have a single root element. (HTML comments are considered elements as well.) 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. Be careful when nesting islands within other islands as each island adds some extra overhead. Most features for server-only components and island components, such as slots and client components, are only available for single file components. #### [Client components within server components](https://nuxt.com/docs/4.x/directory-structure/app/components#client-components-within-server-components) This feature needs `experimental.componentIslands.selectiveClient` within your configuration to be true. You can partially hydrate a component by setting a `nuxt-client` attribute on the component you wish to be loaded client-side. app/components/ServerWithClient.vue `` 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. #### [Server Component Context](https://nuxt.com/docs/4.x/directory-structure/app/components#server-component-context) When rendering a server-only or island component, `` 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). 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. Slots can be interactive and are wrapped within a `
` with `display: contents;` ### [Paired with a Client component](https://nuxt.com/docs/4.x/directory-structure/app/components#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. Directory Structure `-| components/ ---| Comments.client.vue ---| Comments.server.vue` app/pages/example.vue `` [Built-In Nuxt Components](https://nuxt.com/docs/4.x/directory-structure/app/components#built-in-nuxt-components) ------------------------------------------------------------------------------------------------------------------ There are a number of components that Nuxt provides, including `` and ``. You can read more about them in the API documentation. [](https://nuxt.com/docs/4.x/api) Read more in Docs > 4 X > API. [Library Authors](https://nuxt.com/docs/4.x/directory-structure/app/components#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: 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: `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: nuxt.config.ts `export default defineNuxtConfig({ modules: ['awesome-ui/nuxt'], })` ... and directly use the module components (prefixed with `awesome-`) in our `app/pages/index.vue`: `` It will automatically import the components only if used and also support HMR when updating your components in `node_modules/awesome-ui/components/`. Read and edit a live example in [Docs > 4 X > Examples > Features > Auto Imports](https://nuxt.com/docs/4.x/examples/features/auto-imports) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/1.app/1.components.md) [assets\ \ The assets/ directory is used to add all the website's assets that the build tool will process.](https://nuxt.com/docs/4.x/directory-structure/app/assets) [composables\ \ Use the composables/ directory to auto-import your Vue composables into your application.](https://nuxt.com/docs/4.x/directory-structure/app/composables) MenuOn this page --- # State Management · Get Started with Nuxt v4 State Management ================ Copy page 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. Watch a video from Alexander Lichter about why and when to use useState 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. [](https://nuxt.com/docs/4.x/api/composables/use-state) Read more about `useState` composable. [Best Practices](https://nuxt.com/docs/4.x/getting-started/state-management#best-practices) -------------------------------------------------------------------------------------------- Never define `const state = ref()` outside of ` ` Read and edit a live example in [Docs > 4 X > Examples > Features > State Management](https://nuxt.com/docs/4.x/examples/features/state-management) . To globally invalidate cached state, see [`clearNuxtState`](https://nuxt.com/docs/4.x/api/utils/clear-nuxt-state) util. ### [Initializing State](https://nuxt.com/docs/4.x/getting-started/state-management#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. app/app.vue `` 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. [](https://nuxt.com/docs/4.x/api/utils/call-once) Read more in Docs > 4 X > API > Utils > Call Once. ### [Usage with Pinia](https://nuxt.com/docs/4.x/getting-started/state-management#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) . app/stores/website.tsapp/app.vue `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 }, }, })` ` ` [Advanced Usage](https://nuxt.com/docs/4.x/getting-started/state-management#advanced-usage) -------------------------------------------------------------------------------------------- app/composables/locale.tsapp/app.vue `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))) }` ` ` Read and edit a live example in [Docs > 4 X > Examples > Advanced > Locale](https://nuxt.com/docs/4.x/examples/advanced/locale) . [Shared State](https://nuxt.com/docs/4.x/getting-started/state-management#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. composables/states.ts `export const useColor = () => useState('color', () => 'pink')` app/app.vue ` ` Watch a video from Daniel Roe on how to deal with global state and SSR in Nuxt [Using third-party libraries](https://nuxt.com/docs/4.x/getting-started/state-management#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 Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/11.state-management.md) [Data Fetching\ \ Nuxt provides composables to handle data fetching within your application.](https://nuxt.com/docs/4.x/getting-started/data-fetching) [Error Handling\ \ Learn how to catch and handle errors in Nuxt.](https://nuxt.com/docs/4.x/getting-started/error-handling) MenuOn this page --- # Data Fetching · Get Started with Nuxt v4 Data Fetching ============= Copy page 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`](https://nuxt.com/docs/4.x/getting-started/data-fetching#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) . Use the [Nuxt DevTools](https://devtools.nuxt.com/) to inspect this data in the **Payload tab**. app/app.vue ` ` 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](https://nuxt.com/docs/4.x/getting-started/data-fetching#suspense) Nuxt uses Vue's [``](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. You can add the [``](https://nuxt.com/docs/4.x/api/components/nuxt-loading-indicator) to add a progress bar between page navigations. [`$fetch`](https://nuxt.com/docs/4.x/getting-started/data-fetching#fetch) -------------------------------------------------------------------------- Nuxt includes the [ofetch](https://github.com/unjs/ofetch) library, and is auto-imported as the `$fetch` alias globally across your application. pages/todos.vue `` 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) . 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. [](https://nuxt.com/docs/4.x/api/utils/dollarfetch) Read more about `$fetch`. ### [Pass Client Headers to the API](https://nuxt.com/docs/4.x/getting-started/data-fetching#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`). `` `// /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`. `` You can also use [`useRequestFetch`](https://nuxt.com/docs/4.x/api/composables/use-request-fetch) to proxy headers to the call automatically. 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` [`useFetch`](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. app/app.vue ` ` This composable is a wrapper around the [`useAsyncData`](https://nuxt.com/docs/4.x/api/composables/use-async-data) composable and `$fetch` utility. Watch a video from Alexander Lichter to avoid using useFetch the wrong way [](https://nuxt.com/docs/4.x/api/composables/use-fetch) Read more in Docs > 4 X > API > Composables > Use Fetch. Read and edit a live example in [Docs > 4 X > Examples > Features > Data Fetching](https://nuxt.com/docs/4.x/examples/features/data-fetching) . [`useAsyncData`](https://nuxt.com/docs/4.x/getting-started/data-fetching#useasyncdata) --------------------------------------------------------------------------------------- The `useAsyncData` composable is responsible for wrapping async logic and returning the result once it is resolved. `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => event.$fetch(url))`. 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) .) Watch a video from Alexander Lichter to dig deeper into the difference between useFetch and useAsyncData 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 provide 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. app/pages/users.vue `` 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. 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`. 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) . app/pages/users/\[id\].vue ```` The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results. `` `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. `` [](https://nuxt.com/docs/4.x/api/composables/use-async-data) Read more about `useAsyncData`. [Return Values](https://nuxt.com/docs/4.x/getting-started/data-fetching#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"`). `data`, `error` and `status` are Vue refs accessible with `.value` in ` ` 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. `` [](https://nuxt.com/docs/4.x/api/composables/use-lazy-fetch) Read more about `useLazyFetch`. [](https://nuxt.com/docs/4.x/api/composables/use-lazy-async-data) Read more about `useLazyAsyncData`. Watch a video from Vue School on blocking vs. non-blocking (lazy) requests ### [Client-only fetching](https://nuxt.com/docs/4.x/getting-started/data-fetching#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). `/* 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](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. ` ` If you need more control or map over several objects, you can use the `transform` function to alter the result of the query. `const { data: mountains } = await useFetch('/api/mountains', { transform: (mountains) => { return mountains.map(mountain => ({ title: mountain.title, description: mountain.description })) }, })` 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. Watch a video from Vue School on minimizing payload size ### [Caching and refetching](https://nuxt.com/docs/4.x/getting-started/data-fetching#caching-and-refetching) #### [Keys](https://nuxt.com/docs/4.x/getting-started/data-fetching#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) 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/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 file name and line number of the instance of `useAsyncData` will be generated for you. To get the cached data by key, you can use [`useNuxtData`](https://nuxt.com/docs/4.x/api/composables/use-nuxt-data) Watch a video from Vue School on caching data with the key option #### [Shared State and Option Consistency](https://nuxt.com/docs/4.x/getting-started/data-fetching#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 `// ❌ 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` `// ✅ 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: `// 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](https://nuxt.com/docs/4.x/getting-started/data-fetching#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: ``// 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](https://nuxt.com/docs/4.x/getting-started/data-fetching#refresh-and-execute) If you want to fetch or refresh data manually, use the `execute` or `refresh` function provided by the composables. ` ` 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) . 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) . #### [Clear](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. `` #### [Watch](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. `` 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. ```` 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`. `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](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. `` 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. `` `` 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](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. ` ` 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](https://nuxt.com/docs/4.x/getting-started/data-fetching#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](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. 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 }` `` [Options API Support](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. `` Using ``` ### [Custom serializer function](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. 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 })` app/app.vue ```` ### [Using an alternative serializer](https://nuxt.com/docs/4.x/getting-started/data-fetching#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. 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 })` app/app.vue ```` [Recipes](https://nuxt.com/docs/4.x/getting-started/data-fetching#recipes) --------------------------------------------------------------------------- ### [Consuming SSE (Server-Sent Events) via POST request](https://nuxt.com/docs/4.x/getting-started/data-fetching#consuming-sse-server-sent-events-via-post-request) 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/) . When consuming SSE via POST request, you need to handle the connection manually. Here's how you can do it: `// Make a POST request to the SSE endpoint const response = await $fetch('/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](https://nuxt.com/docs/4.x/getting-started/data-fetching#making-parallel-requests) When requests don't rely on each other, you can make them in parallel with `Promise.all()` to boost performance. `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])` Watch a video from Vue School on parallel data fetching Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/10.data-fetching.md) [Transitions\ \ Apply transitions between pages and layouts with Vue or native browser View Transitions.](https://nuxt.com/docs/4.x/getting-started/transitions) [State Management\ \ Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state.](https://nuxt.com/docs/4.x/getting-started/state-management) MenuOn this page --- # Error Handling · Get Started with Nuxt v4 Error Handling ============== Copy page 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 **SSR** stands for **Server-Side Rendering** and **CSR** for **Client-Side Rendering**. [Vue Errors](https://nuxt.com/docs/4.x/getting-started/error-handling#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. plugins/error-handler.ts `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 that the `vue:error` hook is based on [`onErrorCaptured`](https://vuejs.org/api/composition-api-lifecycle#onerrorcaptured) lifecycle hook. [Startup Errors](https://nuxt.com/docs/4.x/getting-started/error-handling#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](https://nuxt.com/docs/4.x/getting-started/error-handling#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](https://nuxt.com/docs/4.x/getting-started/error-handling#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](https://nuxt.com/docs/4.x/getting-started/error-handling#error-page) ---------------------------------------------------------------------------------- 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. 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`). [](https://nuxt.com/docs/4.x/api/advanced/hooks) Discover all the Nuxt lifecycle hooks. Customize the default error page by adding `~/error.vue` in the source directory of your application, alongside `app.vue`. error.vue ` ` [](https://nuxt.com/docs/4.x/directory-structure/app/error) Read more about `error.vue` and its uses. 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. plugins/error-handler.ts `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). 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. 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. 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. [Error Utils](https://nuxt.com/docs/4.x/getting-started/error-handling#error-utils) ------------------------------------------------------------------------------------ ### [`useError`](https://nuxt.com/docs/4.x/getting-started/error-handling#useerror) TS Signature `function useError (): Ref` This function will return the global Nuxt error that is being handled. [](https://nuxt.com/docs/4.x/api/composables/use-error) Read more about `useError` composable. ### [`createError`](https://nuxt.com/docs/4.x/getting-started/error-handling#createerror) TS Signature `function createError (err: string | { cause, data, message, name, stack, statusCode, statusMessage, 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`. pages/movies/\[slug\].vue ```` [](https://nuxt.com/docs/4.x/api/utils/create-error) Read more about `createError` util. ### [`showError`](https://nuxt.com/docs/4.x/getting-started/error-handling#showerror) TS Signature `function showError (err: string | Error | { statusCode, statusMessage }): 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()`. [](https://nuxt.com/docs/4.x/api/utils/show-error) Read more about `showError` util. ### [`clearError`](https://nuxt.com/docs/4.x/getting-started/error-handling#clearerror) TS Signature `function clearError (options?: { redirect?: string }): Promise` 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). [](https://nuxt.com/docs/4.x/api/utils/clear-error) Read more about `clearError` util. [Render Error in Component](https://nuxt.com/docs/4.x/getting-started/error-handling#render-error-in-component) ---------------------------------------------------------------------------------------------------------------- Nuxt also provides a [``](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.) If you navigate to another route, the error will be cleared automatically. app/pages/index.vue `` Read and edit a live example in [Docs > 4 X > Examples > Advanced > Error Handling](https://nuxt.com/docs/4.x/examples/advanced/error-handling) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/1.getting-started/12.error-handling.md) [State Management\ \ Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state.](https://nuxt.com/docs/4.x/getting-started/state-management) [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.](https://nuxt.com/docs/4.x/getting-started/server) MenuOn this page --- # layouts · Nuxt Directory Structure v4 layouts ======= Copy page Nuxt provides a layouts framework to extract common UI patterns into reusable layouts. For best performance, components placed in this directory will be automatically loaded via asynchronous import when used. [Enable Layouts](https://nuxt.com/docs/4.x/directory-structure/app/layouts#enable-layouts) ------------------------------------------------------------------------------------------- Layouts are enabled by adding [``](https://nuxt.com/docs/4.x/api/components/nuxt-layout) to your [`app.vue`](https://nuxt.com/docs/4.x/directory-structure/app/app) : app/app.vue `` 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 ``. The layout name is normalized to kebab-case, so `someLayout` becomes `some-layout`. If no layout is specified, `app/layouts/default.vue` will be used. 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. 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 ``. [Default Layout](https://nuxt.com/docs/4.x/directory-structure/app/layouts#default-layout) ------------------------------------------------------------------------------------------- Add a `~/layouts/default.vue`: app/layouts/default.vue `` In a layout file, the content of the page will be displayed in the `` component. [Named Layout](https://nuxt.com/docs/4.x/directory-structure/app/layouts#named-layout) --------------------------------------------------------------------------------------- Directory Structure `-| layouts/ ---| default.vue ---| custom.vue` Then you can use the `custom` layout in your page: pages/about.vue `` [](https://nuxt.com/docs/4.x/directory-structure/app/pages#page-metadata) Learn more about `definePageMeta`. You can directly override the default layout for all pages using the `name` property of [``](https://nuxt.com/docs/4.x/api/components/nuxt-layout) : app/app.vue ` ` 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. | File | Layout Name | | --- | --- | | `~/layouts/desktop/default.vue` | `desktop-default` | | `~/layouts/desktop-base/base.vue` | `desktop-base` | | `~/layouts/desktop/index.vue` | `desktop` | For clarity, we recommend that the layout's filename matches its name: | File | Layout Name | | --- | --- | | `~/layouts/desktop/DesktopDefault.vue` | `desktop-default` | | `~/layouts/desktop-base/DesktopBase.vue` | `desktop-base` | | `~/layouts/desktop/Desktop.vue` | `desktop` | Read and edit a live example in [Docs > 4 X > Examples > Features > Layouts](https://nuxt.com/docs/4.x/examples/features/layouts) . [Changing the Layout Dynamically](https://nuxt.com/docs/4.x/directory-structure/app/layouts#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: ` ` Read and edit a live example in [Docs > 4 X > Examples > Features > Layouts](https://nuxt.com/docs/4.x/examples/features/layouts) . [Overriding a Layout on a Per-page Basis](https://nuxt.com/docs/4.x/directory-structure/app/layouts#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 `` component within the page. app/pages/index.vueapp/layouts/custom.vue ` ` `` If you use `` 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) ). Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/1.app/1.layouts.md) [composables\ \ Use the composables/ directory to auto-import your Vue composables into your application.](https://nuxt.com/docs/4.x/directory-structure/app/composables) [middleware\ \ Nuxt provides middleware to run code before navigating to a particular route.](https://nuxt.com/docs/4.x/directory-structure/app/middleware) MenuOn this page --- # middleware · Nuxt Directory Structure v4 middleware ========== Copy page 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) . Name of middleware are normalized to kebab-case: `myMiddleware` becomes `my-middleware`. 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. Watch a video from Vue School on all 3 kinds of middleware [Usage](https://nuxt.com/docs/4.x/directory-structure/app/middleware#usage) ---------------------------------------------------------------------------- Route middleware are navigation guards that receive the current route and the next route as arguments. middleware/my-middleware.ts ``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 [](https://nuxt.com/docs/4.x/api/utils/navigate-to) Read more in Docs > 4 X > API > Utils > Navigate To. [](https://nuxt.com/docs/4.x/api/utils/abort-navigation) Read more in Docs > 4 X > API > Utils > Abort Navigation. 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. [Middleware Order](https://nuxt.com/docs/4.x/directory-structure/app/middleware#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: app/middleware/ directory `-| middleware/ ---| analytics.global.ts ---| setup.global.ts ---| auth.ts` pages/profile.vue `` 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](https://nuxt.com/docs/4.x/directory-structure/app/middleware#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. Directory structure `-| middleware/ ---| 01.setup.global.ts ---| 02.analytics.global.ts ---| auth.ts` 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`. [When Middleware Runs](https://nuxt.com/docs/4.x/directory-structure/app/middleware#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: middleware/example.ts `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. 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. [Accessing Route in Middleware](https://nuxt.com/docs/4.x/directory-structure/app/middleware#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. 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. middleware/access-route.tsutils/handle-route.tsutils/dont-do-this.ts ``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() })`` `// providing the route as an argument so that it can be used in middleware correctly export function doSomethingWithRoute (route = useRoute()) { // ... }` `// ❌ this function is not suitable for use in middleware export function callsRouteInternally () { const route = useRoute() // ... }` [Adding Middleware Dynamically](https://nuxt.com/docs/4.x/directory-structure/app/middleware#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. `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](https://nuxt.com/docs/4.x/directory-structure/app/middleware#example) -------------------------------------------------------------------------------- Directory Structure `-| middleware/ ---| auth.ts` In your page file, you can reference this route middleware: `` Now, before navigation to that page can complete, the `auth` route middleware will be run. Read and edit a live example in [Docs > 4 X > Examples > Routing > Middleware](https://nuxt.com/docs/4.x/examples/routing/middleware) . [Setting Middleware at Build Time](https://nuxt.com/docs/4.x/directory-structure/app/middleware#setting-middleware-at-build-time) ---------------------------------------------------------------------------------------------------------------------------------- Instead of using `definePageMeta` on each page, you can add named route middleware within the `pages:extend` hook. nuxt.config.ts ``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) }, }, })`` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/1.app/1.middleware.md) [layouts\ \ Nuxt provides a layouts framework to extract common UI patterns into reusable layouts.](https://nuxt.com/docs/4.x/directory-structure/app/layouts) [pages\ \ Nuxt provides file-based routing to create routes within your web application.](https://nuxt.com/docs/4.x/directory-structure/app/pages) MenuOn this page --- # pages · Nuxt Directory Structure v4 pages ===== Copy page Nuxt provides file-based routing to create routes within your web application. 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) . [Usage](https://nuxt.com/docs/4.x/directory-structure/app/pages#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. app/pages/index.vuepages/index.tspages/index.tsx `` `// https://vuejs.org/guide/extras/render-function.html export default defineComponent({ render () { return h('h1', 'Index page') }, })` `// https://nuxt.com/docs/4.x/examples/advanced/jsx // https://vuejs.org/guide/extras/render-function.html#jsx-tsx export default defineComponent({ render () { return

Index page

}, })` 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 [``](https://nuxt.com/docs/4.x/api/components/nuxt-page) component to display the current page: app/app.vue `` 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: app/pages/working.vueapp/pages/bad-1.vueapp/pages/bad-2.vue `` `` `` [Dynamic Routes](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`. 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: app/pages/users-\[group\]/\[id\].vue `` Navigating to `/users-admins/123` would render: `

admins - 123

` 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. `` 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`. Use `~/pages/foo/index.vue` and `~/pages/foo/[slug].vue` to match `/foo` and `/foo/hello` with different pages,. Watch a video from Vue School on dynamic routes [Catch-all Route](https://nuxt.com/docs/4.x/directory-structure/app/pages#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. app/pages/\[...slug\].vue `` Navigating to `/hello/world` would render: `

["hello", "world"]

` [Nested Routes](https://nuxt.com/docs/4.x/directory-structure/app/pages#nested-routes) --------------------------------------------------------------------------------------- It is possible to display [nested routes](https://router.vuejs.org/guide/essentials/nested-routes) with ``. Example: Directory Structure `-| pages/ ---| parent/ -----| child.vue ---| parent.vue` This file tree will generate these routes: `[ { 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 `` component inside `app/pages/parent.vue`: pages/parent.vue `` pages/parent/child.vue `` ### [Child Route Keys](https://nuxt.com/docs/4.x/directory-structure/app/pages#child-route-keys) If you want more control over when the `` 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`: pages/parent.vue `` Or alternatively: pages/parent/child.vue `` Read and edit a live example in [Docs > 4 X > Examples > Routing > Pages](https://nuxt.com/docs/4.x/examples/routing/pages) . [Route Groups](https://nuxt.com/docs/4.x/directory-structure/app/pages#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: 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. [Page Metadata](https://nuxt.com/docs/4.x/directory-structure/app/pages#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 `` This data can then be accessed throughout the rest of your app from the `route.meta` object. `` 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**. Make sure not to reference any reactive data or functions that cause side effects. This can lead to unexpected behavior. `` ### [Special Metadata](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#keepalive) Nuxt will automatically wrap your page in [the Vue `` 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: ``. You can also set props to be passed to `` (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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#key) [See above](https://nuxt.com/docs/4.x/directory-structure/app/pages#child-route-keys) . #### [`layout`](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#layouttransition-and-pagetransition) You can define transition properties for the `` component that wraps your pages and layouts, or pass `false` to disable the `` 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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#name) You may define a name for this page's route. #### [`path`](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`](https://nuxt.com/docs/4.x/directory-structure/app/pages#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](https://nuxt.com/docs/4.x/directory-structure/app/pages#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`: 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](https://nuxt.com/docs/4.x/directory-structure/app/pages#navigation) --------------------------------------------------------------------------------- To navigate between pages of your app, you should use the [``](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: `` [](https://nuxt.com/docs/4.x/api/components/nuxt-link) Learn more about `` usage. [Programmatic Navigation](https://nuxt.com/docs/4.x/directory-structure/app/pages#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. Make sure to always `await` on `navigateTo` or chain its result by returning from functions. `` [Client-Only Pages](https://nuxt.com/docs/4.x/directory-structure/app/pages#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](https://nuxt.com/docs/4.x/directory-structure/app/pages#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. Server-only pages must have a single root element. (HTML comments are considered elements as well.) [Custom Routing](https://nuxt.com/docs/4.x/directory-structure/app/pages#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. [](https://nuxt.com/docs/4.x/guide/recipes/custom-routing) Read more in Docs > 4 X > Guide > Recipes > Custom Routing. [Multiple Pages Directories](https://nuxt.com/docs/4.x/directory-structure/app/pages#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: Directory Structure `-| some-app/ ---| nuxt.config.ts ---| pages/ -----| app-page.vue -| nuxt.config.ts` some-app/nuxt.config.ts `// some-app/nuxt.config.ts export default defineNuxtConfig({ })` nuxt.config.ts `export default defineNuxtConfig({ extends: ['./some-app'], })` [](https://nuxt.com/docs/4.x/guide/going-further/layers) Read more in Docs > 4 X > Guide > Going Further > Layers. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/main/docs/2.directory-structure/1.app/1.pages.md) [middleware\ \ Nuxt provides middleware to run code before navigating to a particular route.](https://nuxt.com/docs/4.x/directory-structure/app/middleware) [plugins\ \ Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application.](https://nuxt.com/docs/4.x/directory-structure/app/plugins) MenuOn this page --- # Introduction · Get Started with Nuxt v3 Introduction ============ Copy page 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) . 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) . [Automation and Conventions](https://nuxt.com/docs/3.x/getting-started/introduction#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](https://nuxt.com/docs/3.x/getting-started/introduction#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. [](https://nuxt.com/docs/guide/concepts/rendering) Read more in Nuxt rendering modes. ### [Server engine](https://nuxt.com/docs/3.x/getting-started/introduction#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. [](https://nuxt.com/docs/guide/concepts/server-engine) Read more in Nuxt server engine. ### [Production-ready](https://nuxt.com/docs/3.x/getting-started/introduction#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. [](https://nuxt.com/docs/getting-started/deployment) Read more in Deployment section. ### [Modular](https://nuxt.com/docs/3.x/getting-started/introduction#modular) A module system allows you to extend Nuxt with custom features and integrations with third-party services. [](https://nuxt.com/docs/guide/concepts/modules) Read more in Nuxt Modules Concept. ### [Architecture](https://nuxt.com/docs/3.x/getting-started/introduction#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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/01.introduction.md)  [Installation\ \ Get started with Nuxt quickly with our online starters or start locally with your terminal.](https://nuxt.com/docs/3.x/getting-started/installation) MenuOn this page --- # Installation · Get Started with Nuxt v3 Installation ============ Copy page Get started with Nuxt quickly with our online starters or start locally with your terminal. [Play Online](https://nuxt.com/docs/3.x/getting-started/installation#play-online) ---------------------------------------------------------------------------------- If you just want to play around with Nuxt in your browser without setting up a project, you can use one of our online sandboxes: [](https://nuxt.new/s/v4) Open on StackBlitz [](https://nuxt.new/c/v4) Open on CodeSandbox Or follow the steps below to set up a new Nuxt project on your computer. [New Project](https://nuxt.com/docs/3.x/getting-started/installation#new-project) ---------------------------------------------------------------------------------- #### [Prerequisites](https://nuxt.com/docs/3.x/getting-started/installation#prerequisites) * **Node.js** - [`20.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. * **Terminal** - In order to run Nuxt commands Additional notes for an optimal setup: * **Node.js**: Make sure to use an even numbered version (20, 22, etc.) * **Nuxtr**: Install the community-developed [Nuxtr extension](https://marketplace.visualstudio.com/items?itemName=Nuxtr.nuxtr-vscode) * **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. 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/editor/integrated-terminal) ) and use the following command to create a new starter project: npmyarnpnpmbundeno `npm create nuxt@latest -- -t v3` `yarn create nuxt@latest -t v3` `pnpm create nuxt@latest -t v3` `bun create nuxt@latest -t v3` `deno -A npm:create-nuxt@latest -t v3` Alternatively, you can find other starters or themes by opening [nuxt.new](https://nuxt.new/) and following the instructions there. Open your project folder in Visual Studio Code: Terminal `code ` Or change directory into your new project from your terminal: `cd ` [Development Server](https://nuxt.com/docs/3.x/getting-started/installation#development-server) ------------------------------------------------------------------------------------------------ Now you'll be able to start your Nuxt app in development mode: npmyarnpnpmbundeno `npm run dev -- -o` `yarn dev --open` `pnpm dev -o` `bun run dev -o # To use the Bun runtime during development # bun --bun run dev -o` `deno run dev -o` Well done! A browser window should automatically open for [http://localhost:3000](http://localhost:3000/) . [Next Steps](https://nuxt.com/docs/3.x/getting-started/installation#next-steps) -------------------------------------------------------------------------------- Now that you've created your Nuxt project, you are ready to start building your application. [](https://nuxt.com/docs/guide/concepts) Read more in Nuxt Concepts. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/02.installation.md) [Introduction\ \ Nuxt's goal is to make web development intuitive and performant with a great Developer Experience in mind.](https://nuxt.com/docs/3.x/getting-started/introduction) [Configuration\ \ Nuxt is configured with sensible defaults to make you productive.](https://nuxt.com/docs/3.x/getting-started/configuration) MenuOn this page --- # Assets · Get Started with Nuxt v3 Assets ====== Copy page 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](https://nuxt.com/docs/3.x/getting-started/assets#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](https://nuxt.com/docs/3.x/getting-started/assets#example) For example, referencing an image file in the `public/img/` directory, available at the static URL `/img/nuxt.png`: app.vue `` [Assets Directory](https://nuxt.com/docs/3.x/getting-started/assets#assets-directory) -------------------------------------------------------------------------------------- Nuxt uses [Vite](https://vite.dev/guide/assets.html) (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](https://nuxt.com/docs/3.x/getting-started/assets#example-1) For example, referencing an image file that will be processed if a build tool is configured to handle this file extension: app.vue `` 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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/05.assets.md) [Views\ \ Nuxt provides several component layers to implement the user interface of your application.](https://nuxt.com/docs/3.x/getting-started/views) [Styling\ \ Learn how to style your Nuxt application.](https://nuxt.com/docs/3.x/getting-started/styling) MenuOn this page --- # Server · Get Started with Nuxt v3 Server ====== Copy page 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. [](https://nuxt.com/docs/guide/directory-structure/server) Read more in Docs > Guide > Directory Structure > Server. [Powered by Nitro](https://nuxt.com/docs/3.x/getting-started/server#powered-by-nitro) -------------------------------------------------------------------------------------- ![Server engine](https://ipx.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. Watch a video from Alexander Lichter to understand the responsibilities of Nuxt and Nitro in your application [Server Endpoints & Middleware](https://nuxt.com/docs/3.x/getting-started/server#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: server/api/test.ts `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. [](https://nuxt.com/docs/guide/directory-structure/server) Read more in Docs > Guide > Directory Structure > Server. [Universal Deployment](https://nuxt.com/docs/3.x/getting-started/server#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! [](https://nuxt.com/blog/nuxt-on-the-edge) Read more in Blog > Nuxt On The Edge. 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/products/functions) * [Vercel Edge Network](https://vercel.com/docs/edge-network) Or for other runtimes: [](https://deno.land/) Deno [](https://bun.sh/) Bun [](https://nuxt.com/docs/getting-started/deployment) Read more in Docs > Getting Started > Deployment. [Hybrid Rendering](https://nuxt.com/docs/3.x/getting-started/server#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). nuxt.config.ts `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 }, }, // ... }, })` [](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering) 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. [](https://nuxt.com/docs/guide/concepts/rendering) Read more in Docs > Guide > Concepts > Rendering. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/13.server.md) [Error Handling\ \ Learn how to catch and handle errors in Nuxt.](https://nuxt.com/docs/3.x/getting-started/error-handling) [Layers\ \ Nuxt provides a powerful system that allows you to extend the default files, configs, and much more.](https://nuxt.com/docs/3.x/getting-started/layers) MenuOn this page --- # Testing · Get Started with Nuxt v3 Testing ======= Copy page 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/going-further/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. Watch a video from Alexander Lichter about getting started with @nuxt/test-utils [Installation](https://nuxt.com/docs/3.x/getting-started/testing#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) npmyarnpnpmbun `npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` `yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` `pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` `bun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core` [Unit Testing](https://nuxt.com/docs/3.x/getting-started/testing#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](https://nuxt.com/docs/3.x/getting-started/testing#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. `export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], })` 2. Create a `vitest.config.ts` with the following content: `import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/{e2e,unit}/*.{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](https://nuxt.com/docs/3.x/getting-started/testing#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](https://nuxt.com/docs/3.x/getting-started/testing#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: `import { defineVitestConfig } from '@nuxt/test-utils/config' 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. `// @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](https://nuxt.com/docs/3.x/getting-started/testing#organizing-your-tests) With the project-based setup, you might organize your tests as follows: 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](https://nuxt.com/docs/3.x/getting-started/testing#running-tests) With the project setup, you can run different test suites: `# 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](https://nuxt.com/docs/3.x/getting-started/testing#built-in-mocks) `@nuxt/test-utils` provides some built-in mocks for the DOM environment. #### [`intersectionObserver`](https://nuxt.com/docs/3.x/getting-started/testing#intersectionobserver) Default `true`, creates a dummy class without any functionality for the IntersectionObserver API #### [`indexedDB`](https://nuxt.com/docs/3.x/getting-started/testing#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: `import { defineVitestConfig } from '@nuxt/test-utils/config' export default defineVitestConfig({ test: { environmentOptions: { nuxt: { mock: { intersectionObserver: true, indexedDb: true, }, }, }, }, })` ### [🛠️ Helpers](https://nuxt.com/docs/3.x/getting-started/testing#%EF%B8%8F-helpers) `@nuxt/test-utils` provides a number of helpers to make testing Nuxt apps easier. #### [`mountSuspended`](https://nuxt.com/docs/3.x/getting-started/testing#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: `// 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"', ) })` ``// 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 " `) })`` #### [`renderSuspended`](https://nuxt.com/docs/3.x/getting-started/testing#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: `// 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() })` ``// 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
" `) })`` #### [`mockNuxtImport`](https://nuxt.com/docs/3.x/getting-started/testing#mocknuxtimport) `mockNuxtImport` allows you to mock Nuxt's auto import functionality. For example, to mock `useStorage`, you can do so like this: `import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useStorage', () => { return () => { return { value: 'mocked storage' } } }) // 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.html#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.html#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.html#mockrestore) before or after each test to undo mock state changes between runs. `import { vi } from 'vitest' import { mockNuxtImport } from '@nuxt/test-utils/runtime' const { useStorageMock } = vi.hoisted(() => { return { useStorageMock: vi.fn(() => { return { value: 'mocked storage' } }), } }) mockNuxtImport('useStorage', () => { return useStorageMock }) // Then, inside a test useStorageMock.mockImplementation(() => { return { value: 'something else' } })` #### [`mockComponent`](https://nuxt.com/docs/3.x/getting-started/testing#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: `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. `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`](https://nuxt.com/docs/3.x/getting-started/testing#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: `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. `import { registerEndpoint } from '@nuxt/test-utils/runtime' registerEndpoint('/test/', { method: 'POST', handler: () => ({ test: 'test-field' }), })` > **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](https://nuxt.com/docs/3.x/getting-started/testing#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` `import { mockNuxtImport } from '@nuxt/test-utils/runtime' mockNuxtImport('useStorage', () => { return () => { return { value: 'mocked storage' } } })` `app.e2e.spec.ts` `import { $fetch, setup } from '@nuxt/test-utils/e2e' await setup({ setupTimeout: 10000, }) // ...` ### [Using `@vue/test-utils`](https://nuxt.com/docs/3.x/getting-started/testing#using-vuetest-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 npmyarnpnpmbun `npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue` `yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue` `pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue` `bun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue` 2. Create a `vitest.config.ts` with the following content: `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` `"scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" },` 4. Create a simple `` component `components/HelloWorld.vue` with the following content: `` 5. Create a simple unit test for this newly created component `~/components/HelloWorld.spec.ts` `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 npmyarnpnpmbun `npm run test` `yarn test` `pnpm run test` `bun run test` Congratulations, you're all set to start unit testing with `@vue/test-utils` in Nuxt! Happy testing! [End-To-End Testing](https://nuxt.com/docs/3.x/getting-started/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](https://nuxt.com/docs/3.x/getting-started/testing#setup-1) 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. test/my-test.spec.ts `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](https://nuxt.com/docs/3.x/getting-started/testing#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](https://nuxt.com/docs/3.x/getting-started/testing#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](https://nuxt.com/docs/3.x/getting-started/testing#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. `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](https://nuxt.com/docs/3.x/getting-started/testing#apis) #### [`$fetch(url)`](https://nuxt.com/docs/3.x/getting-started/testing#fetchurl) Get the HTML of a server-rendered page. `import { $fetch } from '@nuxt/test-utils/e2e' const html = await $fetch('/')` #### [`fetch(url)`](https://nuxt.com/docs/3.x/getting-started/testing#fetchurl-1) Get the response of a server-rendered page. `import { fetch } from '@nuxt/test-utils/e2e' const res = await fetch('/') const { body, headers } = res` #### [`url(path)`](https://nuxt.com/docs/3.x/getting-started/testing#urlpath) Get the full URL for a given page (including the port the test server is running on.) `import { url } from '@nuxt/test-utils/e2e' const pageUrl = url('/page') // 'http://localhost:6840/page'` ### [Testing in a Browser](https://nuxt.com/docs/3.x/getting-started/testing#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)`](https://nuxt.com/docs/3.x/getting-started/testing#createpageurl) 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) . ``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](https://nuxt.com/docs/3.x/getting-started/testing#testing-with-playwright-test-runner) We also provide first-class support for testing Nuxt within [the Playwright test runner](https://playwright.dev/docs/intro) . npmyarnpnpmbun `npm i --save-dev @playwright/test @nuxt/test-utils` `yarn add --dev @playwright/test @nuxt/test-utils` `pnpm add -D @playwright/test @nuxt/test-utils` `bun add --dev @playwright/test @nuxt/test-utils` You can provide global Nuxt configuration, with the same configuration details as the `setup()` function mentioned earlier in this section. 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)), }, }, // ... })` [](https://github.com/nuxt/test-utils/blob/main/examples/app-playwright/playwright.config.ts) Read more in See full example config. Your test file should then use `expect` and `test` directly from `@nuxt/test-utils/playwright`: 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: 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!') })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/17.testing.md) [Deployment\ \ Learn how to deploy your Nuxt application to any hosting provider.](https://nuxt.com/docs/3.x/getting-started/deployment) [Upgrade Guide\ \ Learn how to upgrade to the latest Nuxt version.](https://nuxt.com/docs/3.x/getting-started/upgrade) MenuOn this page --- # Deployment · Get Started with Nuxt v3 Deployment ========== Copy page 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. If you are looking for a list of cloud providers that support Nuxt, see the [Hosting providers](https://nuxt.com/deploy) section. [Node.js Server](https://nuxt.com/docs/3.x/getting-started/deployment#nodejs-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 * Loads only the required chunks to render the request for optimal cold start timing * Useful for deploying Nuxt apps to any Node.js hosting ### [Entry Point](https://nuxt.com/docs/3.x/getting-started/deployment#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. Terminal `node .output/server/index.mjs` This will launch your production Nuxt server that listens on port 3000 by default. 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](https://nuxt.com/docs/3.x/getting-started/deployment#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`: ecosystem.config.cjs `module.exports = { apps: [ { name: 'NuxtAppName', port: '3000', exec_mode: 'cluster', instances: 'max', script: './.output/server/index.mjs', }, ], }` ### [Cluster Mode](https://nuxt.com/docs/3.x/getting-started/deployment#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](https://nuxt.com/docs/3.x/getting-started/deployment#learn-more) [](https://nitro.build/deploy/runtimes/node) Read more in the Nitro documentation for node-server preset. Watch Daniel Roe's short video on the topic [Static Hosting](https://nuxt.com/docs/3.x/getting-started/deployment#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 `
` 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 [``](https://nuxt.com/docs/3.x/api/components/client-only) to wrap the portions of your site that cannot be server rendered (if any). [](https://nuxt.com/docs/getting-started/prerendering) Read more in Nuxt prerendering. ### [Client-side Only Rendering](https://nuxt.com/docs/3.x/getting-started/deployment#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. nuxt.config.ts `export default defineNuxtConfig({ ssr: false, })` [Hosting Providers](https://nuxt.com/docs/3.x/getting-started/deployment#hosting-providers) -------------------------------------------------------------------------------------------- Nuxt can be deployed to several cloud providers with a minimal amount of configuration: [](https://nuxt.com/deploy) Read more in Deploy. [Presets](https://nuxt.com/docs/3.x/getting-started/deployment#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: nuxt.config.ts `export default defineNuxtConfig({ nitro: { preset: 'node-server', }, })` ... or use the `NITRO_PRESET` environment variable when running `nuxt build`: Terminal `NITRO_PRESET=node-server nuxt build` 🔎 Check [the Nitro deployment](https://nitro.build/deploy) for all possible deployment presets and providers. [CDN Proxy](https://nuxt.com/docs/3.x/getting-started/deployment#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 > Optimization > Content Optimization > Disable "Rocket Loader™" 2. Speed > Optimization > Image Optimization > Disable "Mirage" 3. Scrape Shield > 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. Their location on the Cloudflare dashboard sometimes changes so don't hesitate to look around. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/16.deployment.md) [Prerendering\ \ Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics](https://nuxt.com/docs/3.x/getting-started/prerendering) [Testing\ \ How to test your Nuxt application.](https://nuxt.com/docs/3.x/getting-started/testing) MenuOn this page --- # Transitions · Get Started with Nuxt v3 Transitions =========== Copy page Apply transitions between pages and layouts with Vue or native browser View Transitions. Nuxt leverages Vue's [``](https://vuejs.org/guide/built-ins/transition.html#the-transition-component) component to apply transitions between pages and layouts. [Page Transitions](https://nuxt.com/docs/3.x/getting-started/transitions#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) . nuxt.config.ts `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) : app.vuepages/index.vuepages/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: pages/about.vueapp.vue `` ` ` Moving to the about page will add the 3d rotation effect: [Layout Transitions](https://nuxt.com/docs/3.x/getting-started/transitions#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) . nuxt.config.ts `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) : app.vuelayouts/default.vuelayouts/orange.vuepages/index.vuepages/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`: pages/about.vue `` [Global Settings](https://nuxt.com/docs/3.x/getting-started/transitions#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.html#transition) as JSON serializable values where you can pass the `name`, `mode` and other valid transition-props of the custom CSS transition. nuxt.config.ts `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. pages/some-page.vue `` [Disable Transitions](https://nuxt.com/docs/3.x/getting-started/transitions#disable-transitions) ------------------------------------------------------------------------------------------------- `pageTransition` and `layoutTransition` can be disabled for a specific route: pages/some-page.vue `` Or globally in the `nuxt.config`: nuxt.config.ts `export default defineNuxtConfig({ app: { pageTransition: false, layoutTransition: false, }, })` [JavaScript Hooks](https://nuxt.com/docs/3.x/getting-started/transitions#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/) . pages/some-page.vue `` Learn more about additional [JavaScript hooks](https://vuejs.org/guide/built-ins/transition.html#javascript-hooks) available in the `Transition` component. [Dynamic Transitions](https://nuxt.com/docs/3.x/getting-started/transitions#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`. pages/\[id\].vuelayouts/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](https://nuxt.com/docs/3.x/getting-started/transitions#transition-with-nuxtpage) ----------------------------------------------------------------------------------------------------------- When `` is used in `app.vue`, transitions can be configured with the `transition` prop to activate transitions globally. app.vue `` Remember, this page transition cannot be overridden with `definePageMeta` on individual pages. [View Transitions API (experimental)](https://nuxt.com/docs/3.x/getting-started/transitions#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_Transitions_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 [https://nuxt-view-transitions.surge.sh](https://nuxt-view-transitions.surge.sh/) and the [source on StackBlitz](https://stackblitz.com/edit/nuxt-view-transitions) . The Nuxt integration is under active development, but can be enabled with the `experimental.viewTransition` option in your configuration file: nuxt.config.ts `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. nuxt.config.ts `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: pages/about.vue `` 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: `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](https://nuxt.com/docs/3.x/getting-started/transitions#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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/09.transitions.md) [SEO and Meta\ \ Improve your Nuxt app's SEO with powerful head config, composables and components.](https://nuxt.com/docs/3.x/getting-started/seo-meta) [Data Fetching\ \ Nuxt provides composables to handle data fetching within your application.](https://nuxt.com/docs/3.x/getting-started/data-fetching) MenuOn this page --- # Getting Help · Nuxt Community v3 Getting Help ============ Copy page 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. [](https://go.nuxt.com/discord) Discord Get real-time help, exchange with the core team and the community, and stay updated on the latest Nuxt news. [](https://nuxters.nuxt.com/) Nuxters Connect with other Nuxt enthusiasts. ["I can't figure out how to (...)."](https://nuxt.com/docs/3.x/community/getting-help#i-cant-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?"](https://nuxt.com/docs/3.x/community/getting-help#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"](https://nuxt.com/docs/3.x/community/getting-help#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/support) . 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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/5.community/2.getting-help.md) [WASM\ \ This example demonstrates the server-side support of WebAssembly in Nuxt.](https://nuxt.com/docs/3.x/examples/experimental/wasm) [Reporting Bugs\ \ One of the most valuable roles in open source is taking the time to report bugs helpfully.](https://nuxt.com/docs/3.x/community/reporting-bugs) MenuOn this page --- # Layers · Get Started with Nuxt v3 Layers ====== Copy page 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](https://nuxt.com/docs/3.x/getting-started/layers#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](https://nuxt.com/docs/3.x/getting-started/layers#usage) ---------------------------------------------------------------- By default, any layers within your project in the `~~/layers` directory will be automatically registered as layers in your project. Layer auto-registration was introduced in Nuxt v3.12.0. 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`. Named layer aliases were introduced in Nuxt v3.16.0. 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. 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: nuxt.config.ts `export default defineNuxtConfig({ extends: [ // per layer configuration ['github:my-themes/private-awesome', { auth: process.env.GITHUB_TOKEN }], ], })` You can override a layer's alias by specifying it in the options next to the layer source. nuxt.config.ts `export default defineNuxtConfig({ extends: [ [ 'github:my-themes/awesome', { meta: { name: 'my-awesome-theme', }, }, ], ], })` Nuxt uses [unjs/c12](https://c12.unjs.io/) and [unjs/giget](https://giget.unjs.io/) for extending remote layers. Check the documentation for more information and all available options. [Layer Priority](https://nuxt.com/docs/3.x/getting-started/layers#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. The priority order from highest to lowest is: 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 ### [When to Use Each](https://nuxt.com/docs/3.x/getting-started/layers#when-to-use-each) * **`extends`** - Use for external dependencies (npm packages, remote repositories) or layers outside your project directory * **`~~/layers` directory** - Use for local layers that are part of your project If you need to control the order of auto-scanned layers, you can prefix them with numbers: `~/layers/1.z-layer`, `~/layers/2.a-layer`. This way `2.a-layer` will have higher priority than `1.z-layer`. ### [Example](https://nuxt.com/docs/3.x/getting-started/layers#example) nuxt.config.ts `export default defineNuxtConfig({ extends: [ // Local layer outside the project '../base', // NPM package '@my-themes/awesome', // Remote repository 'github:my-themes/awesome#v1', ], })` 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) This means your project files will override any layer, and `~~/layers/custom` will override anything in `extends`. [](https://nuxt.com/docs/guide/going-further/layers) Read more about layers in the **Layer Author Guide**. Watch a video from Learn Vue about Nuxt Layers Watch a video from Alexander Lichter about Nuxt Layers [Examples](https://nuxt.com/docs/3.x/getting-started/layers#examples) ---------------------------------------------------------------------- [](https://github.com/Atinux/content-wind) Content Wind A lightweight Nuxt theme to build a Markdown driven website. Powered by Nuxt Content, TailwindCSS and Iconify. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/14.layers.md) [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.](https://nuxt.com/docs/3.x/getting-started/server) [Prerendering\ \ Nuxt allows pages to be statically rendered at build time to improve certain performance or SEO metrics](https://nuxt.com/docs/3.x/getting-started/prerendering) MenuOn this page --- # Styling · Get Started with Nuxt v3 Styling ======= Copy page 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](https://nuxt.com/docs/3.x/getting-started/styling#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](https://nuxt.com/docs/3.x/getting-started/styling#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/@import) . pages/index.vue ` ` The stylesheets will be inlined in the HTML rendered by Nuxt. ### [The CSS Property](https://nuxt.com/docs/3.x/getting-started/styling#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. 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](https://nuxt.com/docs/3.x/getting-started/styling#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()`. 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: `` ### [Stylesheets Distributed Through NPM](https://nuxt.com/docs/3.x/getting-started/styling#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. npmyarnpnpmbun `npm install animate.css` `yarn add animate.css` `pnpm install animate.css` `bun install animate.css` Then you can reference it directly in your pages, layouts and components: app.vue ` ` The package can also be referenced as a string in the css property of your Nuxt configuration. nuxt.config.ts `export default defineNuxtConfig({ css: ['animate.css'], })` [External Stylesheets](https://nuxt.com/docs/3.x/getting-started/styling#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: nuxt.config.ts `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](https://nuxt.com/docs/3.x/getting-started/styling#dynamically-adding-stylesheets) You can use the useHead composable to dynamically set a value in your head in your code. [](https://nuxt.com/docs/api/composables/use-head) Read more in Docs > API > Composables > Use Head. `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](https://nuxt.com/docs/3.x/getting-started/styling#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: 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/defer-non-critical-css) . [Using Preprocessors](https://nuxt.com/docs/3.x/getting-started/styling#using-preprocessors) --------------------------------------------------------------------------------------------- To use a preprocessor like SCSS, Sass, Less or Stylus, install it first. Sass & SCSSLessStylus `npm install -D sass` `npm install -D less` `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. pages/app.vue `` Alternatively, you can use the `css` property of your Nuxt configuration. nuxt.config.ts `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.html#css-preprocessoroptions) . Create some partials in your `assets` directory: assets/\_colors.scssassets/\_colors.sass `$primary: #49240F; $secondary: #E4A79D;` `$primary: #49240F $secondary: #E4A79D` Then in your `nuxt.config` : SCSSSASS `export default defineNuxtConfig({ vite: { css: { preprocessorOptions: { scss: { additionalData: '@use "~/assets/_colors.scss" as *;', }, }, }, }, })` `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)](https://nuxt.com/docs/3.x/getting-started/styling#preprocessor-workers-experimental) Vite has made available an [experimental option](https://vite.dev/config/shared-options.html#css-preprocessormaxworkers) which can speed up using preprocessors. You can enable this in your `nuxt.config`: `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](https://nuxt.com/docs/3.x/getting-started/styling#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.html) for a comprehensive reference about styling components in SFC. ### [Class And Style Bindings](https://nuxt.com/docs/3.x/getting-started/styling#class-and-style-bindings) You can leverage Vue SFC features to style your components with class and style attributes. Ref and ReactiveComputedArrayStyle ` ` ` ` ` ` ` ` Refer to the [Vue docs](https://vuejs.org/guide/essentials/class-and-style.html) for more information. ### [Dynamic Styles With `v-bind`](https://nuxt.com/docs/3.x/getting-started/styling#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. ` ` ### [Scoped Styles](https://nuxt.com/docs/3.x/getting-started/styling#scoped-styles) The scoped attribute allows you to style components in isolation. The styles declared with this attribute will only apply to this component. ` ` ### [CSS Modules](https://nuxt.com/docs/3.x/getting-started/styling#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. ` ` ### [Preprocessors Support](https://nuxt.com/docs/3.x/getting-started/styling#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. SCSSSassLESSStylus `` `` `` `` You can refer to the [Vite CSS docs](https://vite.dev/guide/features.html#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](https://nuxt.com/docs/3.x/getting-started/styling#using-postcss) --------------------------------------------------------------------------------- Nuxt comes with postcss built-in. You can configure it in your `nuxt.config` file. 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. `` 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](https://nuxt.com/docs/3.x/getting-started/styling#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. ` ` [](https://nuxt.com/docs/guide/directory-structure/layouts) Read more in Docs > Guide > Directory Structure > Layouts. [Third Party Libraries And Modules](https://nuxt.com/docs/3.x/getting-started/styling#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/going-further/modules) . Share them with the [community](https://nuxt.com/modules) if you do! ### [Easily Load Webfonts](https://nuxt.com/docs/3.x/getting-started/styling#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](https://nuxt.com/docs/3.x/getting-started/styling#advanced) ----------------------------------------------------------------------- ### [Transitions](https://nuxt.com/docs/3.x/getting-started/styling#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) . [](https://nuxt.com/docs/getting-started/transitions) Read more in Docs > Getting Started > Transitions. ### [Font Advanced Optimization](https://nuxt.com/docs/3.x/getting-started/styling#font-advanced-optimization) We would recommend using [Fontaine](https://github.com/nuxt-modules/fontaine) to reduce your [CLS](https://web.dev/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](https://nuxt.com/docs/3.x/getting-started/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/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. 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) } } } }, }, })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/06.styling.md) [Assets\ \ Nuxt offers two options for your assets.](https://nuxt.com/docs/3.x/getting-started/assets) [Routing\ \ Nuxt file-system routing creates a route for every file in the pages/ directory.](https://nuxt.com/docs/3.x/getting-started/routing) MenuOn this page --- # Views · Get Started with Nuxt v3 Views ===== Copy page Nuxt provides several component layers to implement the user interface of your application. [`app.vue`](https://nuxt.com/docs/3.x/getting-started/views#appvue) -------------------------------------------------------------------- ![The app.vue file is the entry point of your application](https://ipx.nuxt.com/_/assets/docs/getting-started/views/app.svg) By default, Nuxt will treat this file as the **entrypoint** and render its content for every route of the application. app.vue `` If you are familiar with Vue, you might wonder where `main.js` is (the file that normally creates a Vue app). Nuxt does this behind the scene. [Components](https://nuxt.com/docs/3.x/getting-started/views#components) ------------------------------------------------------------------------- ![Components are reusable pieces of UI](https://ipx.nuxt.com/_/assets/docs/getting-started/views/components.svg) Most components are reusable pieces of the user interface, like buttons and menus. In Nuxt, you can create these components in the [`components/`](https://nuxt.com/docs/3.x/directory-structure/components) directory, and they will be automatically available across your application without having to explicitly import them. app.vuecomponents/AppAlert.vue `` `` [Pages](https://nuxt.com/docs/3.x/getting-started/views#pages) --------------------------------------------------------------- ![Pages are views tied to a specific route](https://ipx.nuxt.com/_/assets/docs/getting-started/views/pages.svg) Pages represent views for each specific route pattern. Every file in the [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory represents a different route displaying its content. To use pages, create `pages/index.vue` file and add `` component to the [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app) (or remove `app.vue` for default entry). You can now create more pages and their corresponding routes by adding new files in the [`pages/`](https://nuxt.com/docs/3.x/directory-structure/pages) directory. pages/index.vuepages/about.vue `` `` [](https://nuxt.com/docs/getting-started/routing) Read more in Routing Section. [Layouts](https://nuxt.com/docs/3.x/getting-started/views#layouts) ------------------------------------------------------------------- ![Layouts are wrapper around pages](https://ipx.nuxt.com/_/assets/docs/getting-started/views/layouts.svg) Layouts are wrappers around pages that contain a common User Interface for several pages, such as header and footer displays. Layouts are Vue files using `` components to display the **page** content. The `layouts/default.vue` file will be used by default. Custom layouts can be set as part of your page metadata. If you only have a single layout in your application, we recommend using [`app.vue`](https://nuxt.com/docs/3.x/directory-structure/app) with [``](https://nuxt.com/docs/3.x/api/components/nuxt-page) instead. app.vuelayouts/default.vuepages/index.vuepages/about.vue `` `` `` `` If you want to create more layouts and learn how to use them in your pages, find more information in the [Layouts section](https://nuxt.com/docs/3.x/directory-structure/layouts) . [Advanced: Extending the HTML Template](https://nuxt.com/docs/3.x/getting-started/views#advanced-extending-the-html-template) ------------------------------------------------------------------------------------------------------------------------------ If you only need to modify the ``, you can refer to the [SEO and meta section](https://nuxt.com/docs/3.x/getting-started/seo-meta) . You can have full control over the HTML template by adding a Nitro plugin that registers a hook. The callback function of the `render:html` hook allows you to mutate the HTML before it is sent to the client. server/plugins/extend-html.ts ``export default defineNitroPlugin((nitroApp) => { nitroApp.hooks.hook('render:html', (html, { event }) => { // This will be an object representation of the html template. console.log(html) html.head.push(``) }) // You can also intercept the response here. nitroApp.hooks.hook('render:response', (response, { event }) => { console.log(response) }) })`` [](https://nuxt.com/docs/guide/going-further/hooks) Read more in Docs > Guide > Going Further > Hooks. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/04.views.md) [Configuration\ \ Nuxt is configured with sensible defaults to make you productive.](https://nuxt.com/docs/3.x/getting-started/configuration) [Assets\ \ Nuxt offers two options for your assets.](https://nuxt.com/docs/3.x/getting-started/assets) MenuOn this page --- # Prerendering · Get Started with Nuxt v3 Prerendering ============ Copy page 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. [](https://nuxt.com/docs/guide/concepts/rendering) Read more in Nuxt rendering modes. [Crawl-based Pre-rendering](https://nuxt.com/docs/3.x/getting-started/prerendering#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. npmyarnpnpmbun `npx nuxt generate` `yarn nuxt generate` `pnpm nuxt generate` `bun x nuxt generate` 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 (``) 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. [](https://nuxt.com/docs/api/commands/generate#nuxt-generate) Read more about the `nuxt generate` command. ### [Selective Pre-rendering](https://nuxt.com/docs/3.x/getting-started/prerendering#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: nuxt.config.ts `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`: nuxt.config.ts `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`. [](https://nitro.build/config#prerender) Read more about pre-rendering in the Nitro documentation. Lastly, you can manually configure this using routeRules. nuxt.config.ts `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 }, }, })` [](https://nitro.build/config#routerules) Read more about Nitro's `routeRules` configuration. 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) . [](https://nuxt.com/docs/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`. pages/index.vue ` ` This will be translated to: nuxt.config.ts `export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, }, })` [Runtime Prerender Configuration](https://nuxt.com/docs/3.x/getting-started/prerendering#runtime-prerender-configuration) -------------------------------------------------------------------------------------------------------------------------- ### [`prerenderRoutes`](https://nuxt.com/docs/3.x/getting-started/prerendering#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. pages/index.vue ` ` [](https://nuxt.com/docs/api/utils/prerender-routes) Read more in prerenderRoutes. ### [`prerender:routes` Nuxt hook](https://nuxt.com/docs/3.x/getting-started/prerendering#prerenderroutes-nuxt-hook) This is called before prerendering for additional routes to be registered. 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](https://nuxt.com/docs/3.x/getting-started/prerendering#prerendergenerate-nitro-hook) This is called for each route during prerendering. You can use this for fine-grained handling of each route that gets prerendered. nuxt.config.ts `export default defineNuxtConfig({ nitro: { hooks: { 'prerender:generate' (route) { if (route.route?.includes('private')) { route.skip = true } }, }, }, })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/15.prerendering.md) [Layers\ \ Nuxt provides a powerful system that allows you to extend the default files, configs, and much more.](https://nuxt.com/docs/3.x/getting-started/layers) [Deployment\ \ Learn how to deploy your Nuxt application to any hosting provider.](https://nuxt.com/docs/3.x/getting-started/deployment) MenuOn this page --- # SEO and Meta · Get Started with Nuxt v3 SEO and Meta ============ Copy page 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](https://nuxt.com/docs/3.x/getting-started/seo-meta#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. This method does not allow you to provide reactive data. We recommend using `useHead()` in `app.vue`. It's good practice to set tags here that won't change such as your site title default, language and favicon. nuxt.config.ts `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](https://nuxt.com/docs/3.x/getting-started/seo-meta#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. nuxt.config.ts `export default defineNuxtConfig({ app: { head: { // update Nuxt defaults charset: 'utf-16', viewport: 'width=device-width, initial-scale=1, maximum-scale=1', }, }, })` [`useHead`](https://nuxt.com/docs/3.x/getting-started/seo-meta#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. app.vue `` 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`](https://nuxt.com/docs/3.x/getting-started/seo-meta#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`. app.vue `` [](https://nuxt.com/docs/api/composables/use-seo-meta) Read more in Docs > API > Composables > Use Seo Meta. [Components](https://nuxt.com/docs/3.x/getting-started/seo-meta#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: ``, `<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. 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. [Types](https://nuxt.com/docs/3.x/getting-started/seo-meta#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. `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](https://nuxt.com/docs/3.x/getting-started/seo-meta#features) ------------------------------------------------------------------------ ### [Reactivity](https://nuxt.com/docs/3.x/getting-started/seo-meta#reactivity) Reactivity is supported on all properties, by providing a computed value, a getter, or a reactive object. useHeaduseSeoMetaComponents `` `` ` ` ### [Title Template](https://nuxt.com/docs/3.x/getting-started/seo-meta#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: useHead ```` 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](https://nuxt.com/docs/3.x/getting-started/seo-meta#template-params) You can use `templateParams` to provide additional placeholders in your `titleTemplate` besides the default `%s`. This allows for more dynamic title generation. useHead ```` ### [Body Tags](https://nuxt.com/docs/3.x/getting-started/seo-meta#body-tags) You can use the `tagPosition: 'bodyClose'` option on applicable tags to append them to the end of the `` tag. For example: `` [Examples](https://nuxt.com/docs/3.x/getting-started/seo-meta#examples) ------------------------------------------------------------------------ ### [With `definePageMeta`](https://nuxt.com/docs/3.x/getting-started/seo-meta#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): pages/some-page.vue `` And then in your layout file, you might use the route's metadata you have previously set: layouts/default.vue ```` Read and edit a live example in [Docs > Examples > Features > Meta Tags](https://nuxt.com/docs/examples/features/meta-tags) . [](https://nuxt.com/docs/guide/directory-structure/pages/#page-metadata) Read more in Docs > Guide > Directory Structure > Pages > #page Metadata. ### [Dynamic Title](https://nuxt.com/docs/3.x/getting-started/seo-meta#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: app.vue ```` app.vue ```` `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](https://nuxt.com/docs/3.x/getting-started/seo-meta#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: useHeadComponents `` `` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/08.seo-meta.md) [Routing\ \ Nuxt file-system routing creates a route for every file in the pages/ directory.](https://nuxt.com/docs/3.x/getting-started/routing) [Transitions\ \ Apply transitions between pages and layouts with Vue or native browser View Transitions.](https://nuxt.com/docs/3.x/getting-started/transitions) MenuOn this page --- # Routing · Get Started with Nuxt v3 Routing ======= Copy page 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](https://nuxt.com/docs/3.x/getting-started/routing#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: Directory StructureGenerated Router File `-| pages/ ---| about.vue ---| index.vue ---| posts/ -----| [id].vue` `{ "routes": [ { "path": "/about", "component": "pages/about.vue" }, { "path": "/", "component": "pages/index.vue" }, { "path": "/posts/:id", "component": "pages/posts/[id].vue" } ] }` [](https://nuxt.com/docs/guide/directory-structure/pages) Read more in Docs > Guide > Directory Structure > Pages. [Navigation](https://nuxt.com/docs/3.x/getting-started/routing#navigation) --------------------------------------------------------------------------- The [``](https://nuxt.com/docs/3.x/api/components/nuxt-link) component links pages between them. It renders an `` 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 [``](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. pages/index.vue `` [](https://nuxt.com/docs/api/components/nuxt-link) Read more in Docs > API > Components > Nuxt Link. [Route Parameters](https://nuxt.com/docs/3.x/getting-started/routing#route-parameters) --------------------------------------------------------------------------------------- The [`useRoute()`](https://nuxt.com/docs/3.x/api/composables/use-route) composable can be used in a `` [](https://nuxt.com/docs/api/composables/use-route) Read more in Docs > API > Composables > Use Route. [Route Middleware](https://nuxt.com/docs/3.x/getting-started/routing#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. 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. 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. 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: middleware/auth.tspages/dashboard.vue `export default defineNuxtRouteMiddleware((to, from) => { // isAuthenticated() is an example method verifying if a user is authenticated if (isAuthenticated() === false) { return navigateTo('/login') } })` ` ` [](https://nuxt.com/docs/guide/directory-structure/middleware) Read more in Docs > Guide > Directory Structure > Middleware. [Route Validation](https://nuxt.com/docs/3.x/getting-started/routing#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 `statusCode`/`statusMessage` to customize the error returned. If you have a more complex use case, then you can use anonymous route middleware instead. pages/posts/\[id\].vue `` [](https://nuxt.com/docs/api/utils/define-page-meta) Read more in Docs > API > Utils > Define Page Meta. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/07.routing.md) [Styling\ \ Learn how to style your Nuxt application.](https://nuxt.com/docs/3.x/getting-started/styling) [SEO and Meta\ \ Improve your Nuxt app's SEO with powerful head config, composables and components.](https://nuxt.com/docs/3.x/getting-started/seo-meta) MenuOn this page --- # Configuration · Get Started with Nuxt v3 Configuration ============= Copy page 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](https://nuxt.com/docs/3.x/getting-started/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. nuxt.config.ts `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. [](https://nuxt.com/docs/api/configuration/nuxt-config) Every option is described in the **Configuration Reference**. 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. ### [Environment Overrides](https://nuxt.com/docs/3.x/getting-started/configuration#environment-overrides) You can configure fully typed, per-environment overrides in your nuxt.config nuxt.config.ts `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) . Watch a video from Alexander Lichter about the env-aware nuxt.config.ts 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. ### [Environment Variables and Private Tokens](https://nuxt.com/docs/3.x/getting-started/configuration#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. nuxt.config.ts.env `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', }, }, })` `# This will override the value of apiSecret NUXT_API_SECRET=api_secret_token` 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. pages/index.vue `` [](https://nuxt.com/docs/guide/going-further/runtime-config) Read more in Docs > Guide > Going Further > Runtime Config. [App Configuration](https://nuxt.com/docs/3.x/getting-started/configuration#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. 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. pages/index.vue `` [](https://nuxt.com/docs/guide/directory-structure/app-config) Read more in Docs > Guide > Directory Structure > App Config. [`runtimeConfig` vs. `app.config`](https://nuxt.com/docs/3.x/getting-started/configuration#runtimeconfig-vs-appconfig) ----------------------------------------------------------------------------------------------------------------------- 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. | Feature | `runtimeConfig` | `app.config` | | --- | --- | --- | | Client Side | Hydrated | Bundled | | Environment Variables | ✅ Yes | ❌ No | | Reactive | ✅ Yes | ✅ Yes | | Types support | ✅ Partial | ✅ Yes | | Configuration per Request | ❌ No | ✅ Yes | | Hot Module Replacement | ❌ No | ✅ Yes | | Non primitive JS types | ❌ No | ✅ Yes | [External Configuration Files](https://nuxt.com/docs/3.x/getting-started/configuration#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. | Name | Config File | How To Configure | | --- | --- | --- | | [Nitro](https://nitro.build/) | ~`nitro.config.ts`~ | Use [`nitro`](https://nuxt.com/docs/3.x/api/nuxt-config#nitro)
key in `nuxt.config` | | [PostCSS](https://postcss.org/) | ~`postcss.config.js`~ | Use [`postcss`](https://nuxt.com/docs/3.x/api/nuxt-config#postcss)
key in `nuxt.config` | | [Vite](https://vite.dev/) | ~`vite.config.ts`~ | Use [`vite`](https://nuxt.com/docs/3.x/api/nuxt-config#vite)
key in `nuxt.config` | | [webpack](https://webpack.js.org/) | ~`webpack.config.ts`~ | Use [`webpack`](https://nuxt.com/docs/3.x/api/nuxt-config#webpack-1)
key in `nuxt.config` | Here is a list of other common config files: | Name | Config File | How To Configure | | --- | --- | --- | | [TypeScript](https://www.typescriptlang.org/) | `tsconfig.json` | [More Info](https://nuxt.com/docs/3.x/guide/concepts/typescript#nuxttsconfigjson) | | [ESLint](https://eslint.org/) | `eslint.config.js` | [More Info](https://eslint.org/docs/latest/use/configure/configuration-files) | | [Prettier](https://prettier.io/) | `prettier.config.js` | [More Info](https://prettier.io/docs/en/configuration.html) | | [Stylelint](https://stylelint.io/) | `stylelint.config.js` | [More Info](https://stylelint.io/user-guide/configure) | | [TailwindCSS](https://tailwindcss.com/) | `tailwind.config.js` | [More Info](https://tailwindcss.nuxtjs.org/tailwindcss/configuration) | | [Vitest](https://vitest.dev/) | `vitest.config.ts` | [More Info](https://vitest.dev/config/) | [Vue Configuration](https://nuxt.com/docs/3.x/getting-started/configuration#vue-configuration) ----------------------------------------------------------------------------------------------- ### [With Vite](https://nuxt.com/docs/3.x/getting-started/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) . nuxt.config.ts `export default defineNuxtConfig({ vite: { vue: { customElement: true, }, vueJsx: { mergeProps: true, }, }, })` [](https://nuxt.com/docs/api/configuration/nuxt-config#vue) Read more in Docs > API > Configuration > Nuxt Config#vue. ### [With webpack](https://nuxt.com/docs/3.x/getting-started/configuration#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) . nuxt.config.ts `export default defineNuxtConfig({ webpack: { loaders: { vue: { hotReload: true, }, }, }, })` [](https://nuxt.com/docs/api/configuration/nuxt-config#loaders) Read more in Docs > API > Configuration > Nuxt Config#loaders. ### [Enabling Experimental Vue Features](https://nuxt.com/docs/3.x/getting-started/configuration#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: nuxt.config.ts `export default defineNuxtConfig({ vue: { propsDestructure: true, }, })` #### [experimental `reactivityTransform` migration from Vue 3.4 and Nuxt 3.9](https://nuxt.com/docs/3.x/getting-started/configuration#experimental-reactivitytransform-migration-from-vue-34-and-nuxt-39) 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) . [](https://nuxt.com/docs/api/configuration/nuxt-config#vue-1) Read more in Docs > API > Configuration > Nuxt Config#vue 1. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/03.configuration.md) [Installation\ \ Get started with Nuxt quickly with our online starters or start locally with your terminal.](https://nuxt.com/docs/3.x/getting-started/installation) [Views\ \ Nuxt provides several component layers to implement the user interface of your application.](https://nuxt.com/docs/3.x/getting-started/views) MenuOn this page --- # State Management · Get Started with Nuxt v3 State Management ================ Copy page 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.html#ref) replacement. Its value will be preserved after server-side rendering (during client-side hydration) and shared across all components using a unique key. Watch a video from Alexander Lichter about why and when to use useState 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. [](https://nuxt.com/docs/api/composables/use-state) Read more about `useState` composable. [Best Practices](https://nuxt.com/docs/3.x/getting-started/state-management#best-practices) -------------------------------------------------------------------------------------------- Never define `const state = ref()` outside of ` ` Read and edit a live example in [Docs > Examples > Features > State Management](https://nuxt.com/docs/examples/features/state-management) . To globally invalidate cached state, see [`clearNuxtState`](https://nuxt.com/docs/3.x/api/utils/clear-nuxt-state) util. ### [Initializing State](https://nuxt.com/docs/3.x/getting-started/state-management#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. app.vue `` 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. [](https://nuxt.com/docs/api/utils/call-once) Read more in Docs > API > Utils > Call Once. ### [Usage with Pinia](https://nuxt.com/docs/3.x/getting-started/state-management#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) . stores/website.tsapp.vue `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 }, }, })` ` ` [Advanced Usage](https://nuxt.com/docs/3.x/getting-started/state-management#advanced-usage) -------------------------------------------------------------------------------------------- composables/locale.tsapp.vue `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))) }` ` ` Read and edit a live example in [Docs > Examples > Advanced > Locale](https://nuxt.com/docs/examples/advanced/locale) . [Shared State](https://nuxt.com/docs/3.x/getting-started/state-management#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. composables/states.ts `export const useColor = () => useState('color', () => 'pink')` app.vue ` ` Watch a video from Daniel Roe on how to deal with global state and SSR in Nuxt [Using third-party libraries](https://nuxt.com/docs/3.x/getting-started/state-management#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 Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/11.state-management.md) [Data Fetching\ \ Nuxt provides composables to handle data fetching within your application.](https://nuxt.com/docs/3.x/getting-started/data-fetching) [Error Handling\ \ Learn how to catch and handle errors in Nuxt.](https://nuxt.com/docs/3.x/getting-started/error-handling) MenuOn this page --- # Upgrade Guide · Get Started with Nuxt v3 Upgrade Guide ============= Copy page Learn how to upgrade to the latest Nuxt version. [Upgrading Nuxt](https://nuxt.com/docs/3.x/getting-started/upgrade#upgrading-nuxt) ----------------------------------------------------------------------------------- ### [Latest release](https://nuxt.com/docs/3.x/getting-started/upgrade#latest-release) To upgrade Nuxt to the [latest release](https://github.com/nuxt/nuxt/releases) , use the `nuxt upgrade` command. npmyarnpnpmbun `npx nuxt upgrade` `yarn nuxt upgrade` `pnpm nuxt upgrade` `bun x nuxt upgrade` ### [Nightly Release Channel](https://nuxt.com/docs/3.x/getting-started/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](https://nuxt.com/docs/3.x/getting-started/upgrade#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+. Watch a video from Alexander Lichter showing how to opt in to Nuxt 4's breaking changes already ### [Opting in to Nuxt 4](https://nuxt.com/docs/3.x/getting-started/upgrade#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: nuxt.config.ts `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 // } // } })` Expand code 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 will be noted here along with migration steps for backward/forward compatibility. This section is subject to change until the final release, so please check back here regularly if you are testing Nuxt 4 using `compatibilityVersion: 4`. ### [Migrating Using Codemods](https://nuxt.com/docs/3.x/getting-started/upgrade#migrating-using-codemods) To facilitate the upgrade process, we have collaborated with the [Codemod](https://github.com/codemod-com/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://go.codemod.com/codemod-registry) . You can run all the codemods mentioned in this guide using the following `codemod` recipe: npmyarnpnpmbun `# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710 npx codemod@0.18.7 nuxt/4/migration-recipe` `# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710 yarn dlx codemod@0.18.7 nuxt/4/migration-recipe` `# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710 pnpm dlx codemod@0.18.7 nuxt/4/migration-recipe` `# Using pinned version due to https://github.com/codemod-com/codemod/issues/1710 bun 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](https://nuxt.com/docs/3.x/getting-started/upgrade#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](https://nuxt.com/docs/3.x/getting-started/upgrade#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 `/` An example v4 folder structure. `.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/ server/ api/ middleware/ plugins/ routes/ utils/ nuxt.config.ts` 👉 For more details, see the [PR implementing this change](https://github.com/nuxt/nuxt/pull/27029) . #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#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. Watch a video from Vue School on the new directory structure #### [Migration Steps](https://nuxt.com/docs/3.x/getting-started/upgrade#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/` 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/` 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: 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](https://nuxt.com/docs/3.x/getting-started/upgrade#singleton-data-fetching-layer) 🚦 **Impact Level**: Moderate #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-1) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-1) These changes have been made to improve memory usage and increase consistency with loading states across calls of `useAsyncData`. #### [Migration Steps](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-1) 1. **Check for inconsistent options**: Review any components using the same key with different options or fetch functions. `// 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: 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**: `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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { granularCachedData: false, purgeCachedData: false, }, })` ### [Corrected Module Loading Order in Layers](https://nuxt.com/docs/3.x/getting-started/upgrade#corrected-module-loading-order-in-layers) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-2) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-2) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-2) **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: `// 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/going-further/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](https://nuxt.com/docs/3.x/getting-started/upgrade#deduplication-of-route-metadata) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-3) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-3) This is a result of enabling `experimental.scanPageMeta` by default, and is a performance optimization. #### [Migration Steps](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-3) The migration should be straightforward: `const route = useRoute() - console.log(route.meta.name) + console.log(route.name)` ### [Normalized Component Names](https://nuxt.com/docs/3.x/getting-started/upgrade#normalized-component-names) 🚦 **Impact Level**: Moderate Vue will now generate component names that match the Nuxt pattern for component naming. #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-4) By default, if you haven't set it manually, Vue will assign a component name that matches the filename of the component. 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-4) 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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { normalizeComponentNames: false, }, })` ### [Unhead v2](https://nuxt.com/docs/3.x/getting-started/upgrade#unhead-v2) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-5) [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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-5) 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. `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. `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`. `-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. `export default defineNuxtConfig({ unhead: { legacy: true, }, })` ### [New DOM Location for SPA Loading Screen](https://nuxt.com/docs/3.x/getting-started/upgrade#new-dom-location-for-spa-loading-screen) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-6) When rendering a client-only page (with `ssr: false`), we optionally render a loading screen (from `app/spa-loading-template.html`), within the Nuxt app root: `
` Now, we default to rendering the template alongside the Nuxt app root: `
` #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-4) This allows the spa loading template to remain in the DOM until the Vue app suspense resolves, preventing a flash of white. #### [Migration Steps](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-6) 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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { spaLoadingTemplateLocation: 'within', }, })` ### [Parsed `error.data`](https://nuxt.com/docs/3.x/getting-started/upgrade#parsed-errordata) 🚦 **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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-7) Update your custom `error.vue` to remove any additional parsing of `error.data`: `` Alternatively, you can disable this change: nuxt.config.ts `export default defineNuxtConfig({ experimental: { parseErrorData: false, }, })` ### [More Granular Inline Styles](https://nuxt.com/docs/3.x/getting-started/upgrade#more-granular-inline-styles) 🚦 **Impact Level**: Moderate Nuxt will now only inline styles for Vue components, not global CSS. #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-7) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-8) 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. nuxt.config.ts `export default defineNuxtConfig({ features: { inlineStyles: true, }, })` ### [Scan Page Meta After Resolution](https://nuxt.com/docs/3.x/getting-started/upgrade#scan-page-meta-after-resolution) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-8) We now scan page metadata (defined in `definePageMeta`) _after_ calling the `pages:extend` hook rather than before. #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-5) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-9) If you want to override page metadata, do that in `pages:resolved` rather than in `pages:extend`. `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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { scanPageMeta: true, }, })` ### [Shared Prerender Data](https://nuxt.com/docs/3.x/getting-started/upgrade#shared-prerender-data) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-9) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-6) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-10) 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.) 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: nuxt.config.ts `export default defineNuxtConfig({ experimental: { sharedPrerenderData: false, }, })` ### [Default `data` and `error` values in `useAsyncData` and `useFetch`](https://nuxt.com/docs/3.x/getting-started/upgrade#default-data-and-error-values-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-10) `data` and `error` objects returned from `useAsyncData` will now default to `undefined`. #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-7) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-11) 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: nuxt.config.ts `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`](https://nuxt.com/docs/3.x/getting-started/upgrade#removal-of-deprecated-boolean-values-for-dedupe-option-when-calling-refresh-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-11) Previously it was possible to pass `dedupe: boolean` to `refresh`. These were aliases of `cancel` (`true`) and `defer` (`false`). app.vue `const { refresh } = await useAsyncData(() => Promise.resolve({ message: 'Hello, Nuxt!' })) async function refreshData () { await refresh({ dedupe: true }) }` #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-8) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-12) The migration should be straightforward: `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`](https://nuxt.com/docs/3.x/getting-started/upgrade#respect-defaults-when-clearing-data-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-12) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-9) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-13) If you encounter any issues you can revert back to the previous behavior, for now, with: nuxt.config.ts `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`](https://nuxt.com/docs/3.x/getting-started/upgrade#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](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-13) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-10) This aligns the meaning of `pending` with the `status` property, which is also `pending` when the request is in progress. #### [Migration Steps](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-14) 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. ` ` Alternatively, you can temporarily revert to the previous behavior with: nuxt.config.ts `export default defineNuxtConfig({ experimental: { pendingWhenIdle: true, }, })` ### [Key Change Behavior in `useAsyncData` and `useFetch`](https://nuxt.com/docs/3.x/getting-started/upgrade#key-change-behavior-in-useasyncdata-and-usefetch) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-14) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-11) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-15) 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. `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: `// Or globally in your Nuxt config export default defineNuxtConfig({ experimental: { alwaysRunFetchOnKeyChange: true, }, })` ### [Shallow Data Reactivity in `useAsyncData` and `useFetch`](https://nuxt.com/docs/3.x/getting-started/upgrade#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](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-15) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-12) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-16) 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: `- 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): nuxt.config.ts `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`](https://nuxt.com/docs/3.x/getting-started/upgrade#absolute-watch-paths-in-builderwatch) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-16) The Nuxt `builder:watch` hook now emits a path which is absolute rather than relative to your project `srcDir`. #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-13) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-17) 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: `+ 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](https://nuxt.com/docs/3.x/getting-started/upgrade#removal-of-window__nuxt__-object) #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-17) We are removing the global `window.__NUXT__` object after the app finishes hydration. #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-14) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-18) The data is still available, but can be accessed with `useNuxtApp().payload`: `- console.log(window.__NUXT__) + console.log(useNuxtApp().payload)` ### [Directory index scanning](https://nuxt.com/docs/3.x/getting-started/upgrade#directory-index-scanning) 🚦 **Impact Level**: Medium #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-18) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-15) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-19) Probably no migration is necessary but if you wish to revert to previous behavior you can add a hook to filter out these middleware: `export default defineNuxtConfig({ hooks: { 'app:resolve' (app) { app.middleware = app.middleware.filter(mw => !/\/index\.[^/]+$/.test(mw.path)) }, }, })` ### [Template Compilation Changes](https://nuxt.com/docs/3.x/getting-started/upgrade#template-compilation-changes) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-19) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-16) 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](http://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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-20) 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: `+ 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`: ``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](https://nuxt.com/docs/3.x/getting-started/upgrade#default-typescript-configuration-changes) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-20) `compilerOptions.noUncheckedIndexedAccess` is now `true` instead of `false`. #### [Reasons for Change](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-17) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-21) 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`: `export default defineNuxtConfig({ typescript: { tsConfig: { compilerOptions: { noUncheckedIndexedAccess: false, }, }, }, })` ### [TypeScript Configuration Splitting](https://nuxt.com/docs/3.x/getting-started/upgrade#typescript-configuration-splitting) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-21) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-18) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-22) **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: `{ "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: `- "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 Node.js TypeScript options** if needed: `export default defineNuxtConfig({ typescript: { // Customize app/server TypeScript config tsConfig: { compilerOptions: { strict: true, }, }, // Customize build-time TypeScript config nodeTsConfig: { compilerOptions: { strict: true, }, }, }, })` 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](https://nuxt.com/docs/3.x/getting-started/upgrade#removal-of-experimental-features) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-22) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-19) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-23) * `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](https://nuxt.com/docs/3.x/getting-started/upgrade#removal-of-top-level-generate-configuration) 🚦 **Impact Level**: Minimal #### [What Changed](https://nuxt.com/docs/3.x/getting-started/upgrade#what-changed-23) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#reasons-for-change-20) 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](https://nuxt.com/docs/3.x/getting-started/upgrade#migration-steps-24) Replace `generate` configuration with the corresponding `nitro.prerender` options: `export default defineNuxtConfig({ - generate: { - exclude: ['/admin', '/private'], - routes: ['/sitemap.xml', '/robots.txt'] - } + nitro: { + prerender: { + ignore: ['/admin', '/private'], + routes: ['/sitemap.xml', '/robots.txt'] + } + } })` [](https://nitro.build/config#prerender) Read more about Nitro's prerender configuration options. [Nuxt 2 vs. Nuxt 3+](https://nuxt.com/docs/3.x/getting-started/upgrade#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 | ✅ | ✅ | ✅ | | ` ` [](https://nuxt.com/docs/3.x/directory-structure/error) Read more about `error.vue` and its uses. 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. plugins/error-handler.ts `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). 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. 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. 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. [Error Utils](https://nuxt.com/docs/3.x/getting-started/error-handling#error-utils) ------------------------------------------------------------------------------------ ### [`useError`](https://nuxt.com/docs/3.x/getting-started/error-handling#useerror) TS Signature `function useError (): Ref` This function will return the global Nuxt error that is being handled. [](https://nuxt.com/docs/api/composables/use-error) Read more about `useError` composable. ### [`createError`](https://nuxt.com/docs/3.x/getting-started/error-handling#createerror) TS Signature `function createError (err: string | { cause, data, message, name, stack, statusCode, statusMessage, 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`. pages/movies/\[slug\].vue ```` [](https://nuxt.com/docs/api/utils/create-error) Read more about `createError` util. ### [`showError`](https://nuxt.com/docs/3.x/getting-started/error-handling#showerror) TS Signature `function showError (err: string | Error | { statusCode, statusMessage }): 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()`. [](https://nuxt.com/docs/api/utils/show-error) Read more about `showError` util. ### [`clearError`](https://nuxt.com/docs/3.x/getting-started/error-handling#clearerror) TS Signature `function clearError (options?: { redirect?: string }): Promise` 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). [](https://nuxt.com/docs/api/utils/clear-error) Read more about `clearError` util. [Render Error in Component](https://nuxt.com/docs/3.x/getting-started/error-handling#render-error-in-component) ---------------------------------------------------------------------------------------------------------------- Nuxt also provides a [``](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.) If you navigate to another route, the error will be cleared automatically. pages/index.vue `` Read and edit a live example in [Docs > Examples > Advanced > Error Handling](https://nuxt.com/docs/examples/advanced/error-handling) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/12.error-handling.md) [State Management\ \ Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state.](https://nuxt.com/docs/3.x/getting-started/state-management) [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.](https://nuxt.com/docs/3.x/getting-started/server) MenuOn this page --- # pages · Nuxt Directory Structure v3 pages ===== Copy page Nuxt provides file-based routing to create routes within your web application. 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 [`app/router.options.ts`](https://nuxt.com/docs/3.x/guide/recipes/custom-routing#using-approuteroptions) . [Usage](https://nuxt.com/docs/3.x/directory-structure/pages#usage) ------------------------------------------------------------------- Pages are Vue components and can have any [valid extension](https://nuxt.com/docs/3.x/api/configuration/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. pages/index.vuepages/index.tspages/index.tsx `` `// https://vuejs.org/guide/extras/render-function.html export default defineComponent({ render () { return h('h1', 'Index page') }, })` `// https://nuxt.com/docs/examples/advanced/jsx // https://vuejs.org/guide/extras/render-function.html#jsx-tsx export default defineComponent({ render () { return

Index page

}, })` 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 [``](https://nuxt.com/docs/3.x/api/components/nuxt-page) component to display the current page: app.vue `` 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: pages/working.vuepages/bad-1.vuepages/bad-2.vue `` `` `` [Dynamic Routes](https://nuxt.com/docs/3.x/directory-structure/pages#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.html) 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`. 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: pages/users-\[group\]/\[id\].vue `` Navigating to `/users-admins/123` would render: `

admins - 123

` 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. `` 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`. Use `~/pages/foo/index.vue` and `~/pages/foo/[slug].vue` to match `/foo` and `/foo/hello` with different pages,. Watch a video from Vue School on dynamic routes [Catch-all Route](https://nuxt.com/docs/3.x/directory-structure/pages#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. pages/\[...slug\].vue `` Navigating to `/hello/world` would render: `

["hello", "world"]

` [Nested Routes](https://nuxt.com/docs/3.x/directory-structure/pages#nested-routes) ----------------------------------------------------------------------------------- It is possible to display [nested routes](https://next.router.vuejs.org/guide/essentials/nested-routes.html) with ``. Example: Directory Structure `-| pages/ ---| parent/ -----| child.vue ---| parent.vue` This file tree will generate these routes: `[ { 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 `` component inside `pages/parent.vue`: pages/parent.vue `` pages/parent/child.vue `` ### [Child Route Keys](https://nuxt.com/docs/3.x/directory-structure/pages#child-route-keys) If you want more control over when the `` 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`: pages/parent.vue `` Or alternatively: pages/parent/child.vue `` Read and edit a live example in [Docs > Examples > Routing > Pages](https://nuxt.com/docs/examples/routing/pages) . [Route Groups](https://nuxt.com/docs/3.x/directory-structure/pages#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: 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. [Page Metadata](https://nuxt.com/docs/3.x/directory-structure/pages#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 `` This data can then be accessed throughout the rest of your app from the `route.meta` object. `` 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.html#route-meta-fields) . Much like `defineEmits` or `defineProps` (see [Vue docs](https://vuejs.org/api/sfc-script-setup.html#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**. Make sure not to reference any reactive data or functions that cause side effects. This can lead to unexpected behavior. `` ### [Special Metadata](https://nuxt.com/docs/3.x/directory-structure/pages#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`](https://nuxt.com/docs/3.x/directory-structure/pages#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.html#Alias) . #### [`keepalive`](https://nuxt.com/docs/3.x/directory-structure/pages#keepalive) Nuxt will automatically wrap your page in [the Vue `` component](https://vuejs.org/guide/built-ins/keep-alive.html#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: ``. You can also set props to be passed to `` (see [a full list](https://vuejs.org/api/built-in-components.html#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`](https://nuxt.com/docs/3.x/directory-structure/pages#key) [See above](https://nuxt.com/docs/3.x/directory-structure/pages#child-route-keys) . #### [`layout`](https://nuxt.com/docs/3.x/directory-structure/pages#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`](https://nuxt.com/docs/3.x/directory-structure/pages#layouttransition-and-pagetransition) You can define transition properties for the `` component that wraps your pages and layouts, or pass `false` to disable the `` wrapper for that route. You can see [a list of options that can be passed](https://vuejs.org/api/built-in-components.html#transition) or read [more about how transitions work](https://vuejs.org/guide/built-ins/transition.html#transition) . You can set default values for these properties [in your `nuxt.config`](https://nuxt.com/docs/3.x/api/nuxt-config#layouttransition) . #### [`middleware`](https://nuxt.com/docs/3.x/directory-structure/pages#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.html#global-before-guards) ), or an array of strings/functions. [More about named middleware](https://nuxt.com/docs/3.x/directory-structure/middleware) . #### [`name`](https://nuxt.com/docs/3.x/directory-structure/pages#name) You may define a name for this page's route. #### [`path`](https://nuxt.com/docs/3.x/directory-structure/pages#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.html#custom-regex-in-params) for more information. #### [`props`](https://nuxt.com/docs/3.x/directory-structure/pages#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](https://nuxt.com/docs/3.x/directory-structure/pages#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`: 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](https://nuxt.com/docs/3.x/directory-structure/pages#navigation) ----------------------------------------------------------------------------- To navigate between pages of your app, you should use the [``](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: `` [](https://nuxt.com/docs/api/components/nuxt-link) Learn more about `` usage. [Programmatic Navigation](https://nuxt.com/docs/3.x/directory-structure/pages#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. Make sure to always `await` on `navigateTo` or chain its result by returning from functions. `` [Client-Only Pages](https://nuxt.com/docs/3.x/directory-structure/pages#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](https://nuxt.com/docs/3.x/directory-structure/pages#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. Server-only pages must have a single root element. (HTML comments are considered elements as well.) [Custom Routing](https://nuxt.com/docs/3.x/directory-structure/pages#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. [](https://nuxt.com/docs/guide/recipes/custom-routing) Read more in Docs > Guide > Recipes > Custom Routing. [Multiple Pages Directories](https://nuxt.com/docs/3.x/directory-structure/pages#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: Directory Structure `-| some-app/ ---| nuxt.config.ts ---| pages/ -----| app-page.vue -| nuxt.config.ts` some-app/nuxt.config.ts `// some-app/nuxt.config.ts export default defineNuxtConfig({ })` nuxt.config.ts `export default defineNuxtConfig({ extends: ['./some-app'], })` [](https://nuxt.com/docs/guide/going-further/layers) Read more in Docs > Guide > Going Further > Layers. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.pages.md) [node\_modules\ \ The package manager stores the dependencies of your project in the node\_modules/ directory.](https://nuxt.com/docs/3.x/directory-structure/node_modules) [plugins\ \ Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application.](https://nuxt.com/docs/3.x/directory-structure/plugins) MenuOn this page --- # Hello World · Nuxt Examples v3 Hello World =========== Copy page A minimal Nuxt application only requires the \`app.vue\` and \`nuxt.config.js\` files. [](https://nuxt.com/docs/getting-started/introduction) Read more in Docs > Getting Started > Introduction. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/0.hello-world.md) [Nuxt Configuration\ \ Discover all the options you can use in your nuxt.config.ts file.](https://nuxt.com/docs/3.x/api/nuxt-config) [Auto Imports\ \ This example demonstrates the auto-imports feature in Nuxt.](https://nuxt.com/docs/3.x/examples/features/auto-imports) MenuOn this page --- # Data Fetching · Get Started with Nuxt v3 Data Fetching ============= Copy page 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`](https://nuxt.com/docs/3.x/getting-started/data-fetching#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) . Use the [Nuxt DevTools](https://devtools.nuxt.com/) to inspect this data in the **Payload tab**. app.vue ` ` 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](https://nuxt.com/docs/3.x/getting-started/data-fetching#suspense) Nuxt uses Vue's [``](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. You can add the [``](https://nuxt.com/docs/3.x/api/components/nuxt-loading-indicator) to add a progress bar between page navigations. [`$fetch`](https://nuxt.com/docs/3.x/getting-started/data-fetching#fetch) -------------------------------------------------------------------------- Nuxt includes the [ofetch](https://github.com/unjs/ofetch) library, and is auto-imported as the `$fetch` alias globally across your application. pages/todos.vue `` 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) . 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. [](https://nuxt.com/docs/api/utils/dollarfetch) Read more about `$fetch`. ### [Pass Client Headers to the API](https://nuxt.com/docs/3.x/getting-started/data-fetching#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`). `` `// /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`. `` You can also use [`useRequestFetch`](https://nuxt.com/docs/3.x/api/composables/use-request-fetch) to proxy headers to the call automatically. 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` [`useFetch`](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. app.vue ` ` This composable is a wrapper around the [`useAsyncData`](https://nuxt.com/docs/3.x/api/composables/use-async-data) composable and `$fetch` utility. Watch a video from Alexander Lichter to avoid using useFetch the wrong way [](https://nuxt.com/docs/api/composables/use-fetch) Read more in Docs > API > Composables > Use Fetch. Read and edit a live example in [Docs > Examples > Features > Data Fetching](https://nuxt.com/docs/examples/features/data-fetching) . [`useAsyncData`](https://nuxt.com/docs/3.x/getting-started/data-fetching#useasyncdata) --------------------------------------------------------------------------------------- The `useAsyncData` composable is responsible for wrapping async logic and returning the result once it is resolved. `useFetch(url)` is nearly equivalent to `useAsyncData(url, () => event.$fetch(url))`. 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) .) Watch a video from Alexander Lichter to dig deeper into the difference between useFetch and useAsyncData 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. pages/users.vue `` 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. 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`. 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) . pages/users/\[id\].vue ```` The `useAsyncData` composable is a great way to wrap and wait for multiple `$fetch` requests to be completed, and then process the results. `` `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. `` [](https://nuxt.com/docs/api/composables/use-async-data) Read more about `useAsyncData`. [Return Values](https://nuxt.com/docs/3.x/getting-started/data-fetching#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"`). `data`, `error` and `status` are Vue refs accessible with `.value` in ` ` 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. `` [](https://nuxt.com/docs/api/composables/use-lazy-fetch) Read more about `useLazyFetch`. [](https://nuxt.com/docs/api/composables/use-lazy-async-data) Read more about `useLazyAsyncData`. Watch a video from Vue School on blocking vs. non-blocking (lazy) requests ### [Client-only fetching](https://nuxt.com/docs/3.x/getting-started/data-fetching#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). `/* 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](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. ` ` If you need more control or map over several objects, you can use the `transform` function to alter the result of the query. `const { data: mountains } = await useFetch('/api/mountains', { transform: (mountains) => { return mountains.map(mountain => ({ title: mountain.title, description: mountain.description })) }, })` 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. Watch a video from Vue School on minimizing payload size ### [Caching and refetching](https://nuxt.com/docs/3.x/getting-started/data-fetching#caching-and-refetching) #### [Keys](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. To get the cached data by key, you can use [`useNuxtData`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-data) Watch a video from Vue School on caching data with the key option #### [Shared State and Option Consistency](https://nuxt.com/docs/3.x/getting-started/data-fetching#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 `// ❌ 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` `// ✅ 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: `// 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](https://nuxt.com/docs/3.x/getting-started/data-fetching#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: ``// 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](https://nuxt.com/docs/3.x/getting-started/data-fetching#refresh-and-execute) If you want to fetch or refresh data manually, use the `execute` or `refresh` function provided by the composables. ` ` 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) . 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) . #### [Clear](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. `` #### [Watch](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. `` 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. ```` 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`. `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](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. `` In the case of more complex URL construction, you may use a callback as a [computed getter](https://vuejs.org/guide/essentials/computed.html) 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. `` `` 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](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. ` ` 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](https://nuxt.com/docs/3.x/getting-started/data-fetching#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](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. 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 }` `` [Options API Support](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. `` Using ``` ### [Custom serializer function](https://nuxt.com/docs/3.x/getting-started/data-fetching#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. 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 })` app.vue ```` ### [Using an alternative serializer](https://nuxt.com/docs/3.x/getting-started/data-fetching#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/blitz-js/superjson) as our serializer. 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 })` app.vue ```` [Recipes](https://nuxt.com/docs/3.x/getting-started/data-fetching#recipes) --------------------------------------------------------------------------- ### [Consuming SSE (Server-Sent Events) via POST request](https://nuxt.com/docs/3.x/getting-started/data-fetching#consuming-sse-server-sent-events-via-post-request) 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/) . When consuming SSE via POST request, you need to handle the connection manually. Here's how you can do it: `// Make a POST request to the SSE endpoint const response = await $fetch('/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](https://nuxt.com/docs/3.x/getting-started/data-fetching#making-parallel-requests) When requests don't rely on each other, you can make them in parallel with `Promise.all()` to boost performance. `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])` Watch a video from Vue School on parallel data fetching Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/1.getting-started/10.data-fetching.md) [Transitions\ \ Apply transitions between pages and layouts with Vue or native browser View Transitions.](https://nuxt.com/docs/3.x/getting-started/transitions) [State Management\ \ Nuxt provides powerful state management libraries and the useState composable to create a reactive and SSR-friendly shared state.](https://nuxt.com/docs/3.x/getting-started/state-management) MenuOn this page --- # Nuxt Guide v3 Nuxt Guide ========== Copy page Learn how Nuxt works with in-depth guides. [](https://nuxt.com/docs/3.x/guide/concepts) Key Concepts Discover the main concepts behind Nuxt, from auto-import, hybrid rendering to its TypeScript support. [](https://nuxt.com/docs/3.x/guide/best-practices) Best Practices Learn about best practices when developing with Nuxt [](https://nuxt.com/docs/3.x/guide/recipes) Recipes Find solutions to common problems and learn how to implement them in your Nuxt project. [](https://nuxt.com/docs/3.x/guide/going-further) Going Further Master Nuxt with advanced concepts like experimental features, hooks, modules, and more. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/3.guide/0.index.md) MenuOn this page --- # Nuxt API Reference v3 Nuxt API Reference ================== Copy page Explore all Nuxt Internals: Components, Composables, Utils, Commands and more. [](https://nuxt.com/docs/api/components/client-only) Components Explore Nuxt built-in components for pages, layouts, head, and more. [](https://nuxt.com/docs/api/composables/use-app-config) Composables Discover Nuxt composable functions for data-fetching, head management and more. [](https://nuxt.com/docs/api/utils/dollarfetch) Utils Learn about Nuxt utility functions for navigation, error handling and more. [](https://nuxt.com/docs/api/commands/add) Commands List of Nuxt CLI commands to init, analyze, build, and preview your application. [](https://nuxt.com/docs/api/kit/modules) Nuxt Kit Understand Nuxt Kit utilities to create modules and control Nuxt. [](https://nuxt.com/docs/api/advanced/hooks) Advanced Go deep in Nuxt internals with Nuxt lifecycle hooks. [](https://nuxt.com/docs/api/nuxt-config) Nuxt Configuration Explore all Nuxt configuration options to customize your application. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.api/index.md) MenuOn this page --- # Auto-imports · Nuxt Concepts v3 Auto-imports ============ Copy page 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. app.vue `` 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](https://nuxt.com/docs/3.x/guide/concepts/auto-imports#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. `` Vue exposes Reactivity APIs like `ref` or `computed`, as well as lifecycle hooks and helpers that are auto-imported by Nuxt. `` ### [Vue and Nuxt Composables](https://nuxt.com/docs/3.x/guide/concepts/auto-imports#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](https://nuxt.com/docs/3.x/guide/concepts/auto-imports#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. 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/guide/concepts/auto-imports#explicit-imports) from `#imports`. ### [Partially Disabling Auto-imports](https://nuxt.com/docs/3.x/guide/concepts/auto-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: `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](https://nuxt.com/docs/3.x/guide/concepts/auto-imports#auto-imported-components) ----------------------------------------------------------------------------------------------------------- Nuxt also automatically imports components from your `~/components` directory, although this is configured separately from auto-importing composables and utility functions. [](https://nuxt.com/docs/guide/directory-structure/components) Read more in Docs > Guide > Directory Structure > Components. 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). nuxt.config.ts `export default defineNuxtConfig({ components: { dirs: [], }, })` [Auto-import from Third-Party Packages](https://nuxt.com/docs/3.x/guide/concepts/auto-imports#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: nuxt.config.ts `export default defineNuxtConfig({ imports: { presets: [ { from: 'vue-i18n', imports: ['useI18n'], }, ], }, })` Watch a video from Alexander Lichter on how to easily set up custom auto imports Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/3.guide/1.concepts/1.auto-imports.md) [tsconfig.json\ \ Nuxt generates a .nuxt/tsconfig.json file with sensible defaults and your aliases.](https://nuxt.com/docs/3.x/directory-structure/tsconfig) [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.](https://nuxt.com/docs/3.x/guide/concepts/nuxt-lifecycle) MenuOn this page --- # .nuxt · Nuxt Directory Structure v3 .nuxt ===== Copy page Nuxt uses the .nuxt/ directory in development to generate your Vue application. 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. 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. 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) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/0.nuxt.md) [Upgrade Guide\ \ Learn how to upgrade to the latest Nuxt version.](https://nuxt.com/docs/3.x/getting-started/upgrade) [.output\ \ Nuxt creates the .output/ directory when building your application for production.](https://nuxt.com/docs/3.x/directory-structure/output) MenuOn this page --- # Reporting Bugs · Nuxt Community v3 Reporting Bugs ============== Copy page 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?](https://nuxt.com/docs/3.x/community/reporting-bugs#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](https://nuxt.com/docs/3.x/community/reporting-bugs#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](https://nuxt.com/docs/3.x/community/reporting-bugs#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. If your issue concerns Vue or Vite, please try to reproduce it first with the Vue SSR starter. **Nuxt**: [](https://nuxt.new/s/v3) Nuxt on StackBlitz [](https://nuxt.new/c/v3) Nuxt on CodeSandbox **Vue**: [](https://stackblitz.com/github/nuxt-contrib/vue3-ssr-starter/tree/main?terminal=dev) Vue SSR on StackBlitz [](https://codesandbox.io/p/sandbox/github/nuxt-contrib/vue3-ssr-starter/main) Vue SSR on CodeSandbox [](https://github.com/nuxt-contrib/vue3-ssr-starter/generate) Vue SSR Template on GitHub 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](https://nuxt.com/docs/3.x/community/reporting-bugs#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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/5.community/3.reporting-bugs.md) [Getting Help\ \ We're a friendly community of developers and we'd love to help.](https://nuxt.com/docs/3.x/community/getting-help) [Contribution\ \ Nuxt is a community project - and so we love contributions of all kinds! ❤️](https://nuxt.com/docs/3.x/community/contribution) MenuOn this page --- # Auto Imports · Nuxt Examples v3 Auto Imports ============ Copy page This example demonstrates the auto-imports feature in Nuxt. 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. [](https://nuxt.com/docs/guide/directory-structure/components) Read more in Docs > Guide > Directory Structure > Components. [](https://nuxt.com/docs/guide/directory-structure/composables) Read more in Docs > Guide > Directory Structure > Composables. [](https://nuxt.com/docs/guide/directory-structure/utils) Read more in Docs > Guide > Directory Structure > Utils. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/1.features/1.auto-imports.md) [Hello World\ \ A minimal Nuxt application only requires the \`app.vue\` and \`nuxt.config.js\` files.](https://nuxt.com/docs/3.x/examples/hello-world) [Data Fetching\ \ This example demonstrates data fetching with Nuxt using built-in composables and API routes.](https://nuxt.com/docs/3.x/examples/features/data-fetching) MenuOn this page --- # Contribution · Nuxt Community v3 Contribution ============ Copy page 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](https://nuxt.com/docs/3.x/community/contribution#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/going-further/modules/#joining-nuxt-modules-and-nuxtjs) 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](https://nuxt.com/docs/3.x/community/contribution#how-to-contribute) ---------------------------------------------------------------------------------------- ### [Triage Issues and Help Out in Discussions](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#send-a-pull-request) We always welcome pull requests! ❤️ #### [Before You Start](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#once-youve-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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#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/going-further/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](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#conventions-across-ecosystem) The following conventions are _required_ within the `nuxt/` organization and recommended for other maintainers in the ecosystem. #### [Module Conventions](https://nuxt.com/docs/3.x/community/contribution#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/going-further/modules) for more information. #### [Use Core `unjs/` Libraries](https://nuxt.com/docs/3.x/community/contribution#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 * [unbuild](https://github.com/unjs/unbuild) - rollup-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`](https://nuxt.com/docs/3.x/community/contribution#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](https://nuxt.com/docs/3.x/community/contribution#whats-corepack) [Corepack](https://nodejs.org/api/corepack.html) 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. package.json `{ "packageManager": "pnpm@7.5.0" }` #### [Use ESLint](https://nuxt.com/docs/3.x/community/contribution#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: settings.json `{ "editor.codeActionsOnSave": { "source.fixAll": "never", "source.fixAll.eslint": "explicit" } }` #### [No Prettier](https://nuxt.com/docs/3.x/community/contribution#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`, or `bun 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](https://nuxt.com/docs/3.x/community/contribution#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 Terminal `corepack enable` You only need to do this one time, after Node.js is installed on your computer. [Documentation Style Guide](https://nuxt.com/docs/3.x/community/contribution#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. Keep in mind your readers can have different backgrounds and experiences. Therefore, these words don't convey meaning and can be harmful. Simply make sure the function returns a promise. Make sure the function returns a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) . * Prefer [active voice](https://developers.google.com/tech-writing/one/active-voice) . An error will be thrown by Nuxt. Nuxt will throw an error. [](https://nuxt.com/docs/community/framework-contribution#documentation-guide) Learn how to contribute to the documentation. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/5.community/4.contribution.md) [Reporting Bugs\ \ One of the most valuable roles in open source is taking the time to report bugs helpfully.](https://nuxt.com/docs/3.x/community/reporting-bugs) [Framework\ \ Some specific points about contributions to the framework repository.](https://nuxt.com/docs/3.x/community/framework-contribution) MenuOn this page --- # Data Fetching · Nuxt Examples v3 Data Fetching ============= Copy page This example demonstrates data fetching with Nuxt using built-in composables and API routes. [](https://nuxt.com/docs/getting-started/data-fetching) Read more in Docs > Getting Started > Data Fetching. [](https://nuxt.com/docs/guide/directory-structure/server) Read more in Docs > Guide > Directory Structure > Server. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/1.features/2.data-fetching.md) [Auto Imports\ \ This example demonstrates the auto-imports feature in Nuxt.](https://nuxt.com/docs/3.x/examples/features/auto-imports) [State Management\ \ This example shows how to use the \`useState\` composable to create a reactive and SSR-friendly shared state across components.](https://nuxt.com/docs/3.x/examples/features/state-management) MenuOn this page --- # .output · Nuxt Directory Structure v3 .output ======= Copy page Nuxt creates the .output/ directory when building your application for production. 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. Use this directory to deploy your Nuxt application to production. [](https://nuxt.com/docs/getting-started/deployment) Read more in Docs > Getting Started > Deployment. 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) . Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/0.output.md) [.nuxt\ \ Nuxt uses the .nuxt/ directory in development to generate your Vue application.](https://nuxt.com/docs/3.x/directory-structure/nuxt) [assets\ \ The assets/ directory is used to add all the website's assets that the build tool will process.](https://nuxt.com/docs/3.x/directory-structure/assets) MenuOn this page --- # Framework · Nuxt Community v3 Framework ========= Copy page 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](https://nuxt.com/docs/3.x/community/framework-contribution#monorepo-guide) -------------------------------------------------------------------------------------------- * `packages/kit`: Toolkit for authoring Nuxt Modules, published as [`@nuxt/kit`](https://npmjs.com/package/@nuxt/kit) . * `packages/nuxt`: The core of Nuxt, published as [`nuxt`](https://npmjs.com/package/nuxt) . * `packages/schema`: Cross-version Nuxt typedefs and defaults, published as [`@nuxt/schema`](https://npmjs.com/package/@nuxt/schema) . * `packages/rspack`: The [Rspack](https://rspack.dev/) bundler for Nuxt, published as [`@nuxt/rspack-builder`](https://npmjs.com/package/@nuxt/rspack-builder) . * `packages/vite`: The [Vite](https://vite.dev/) bundler for Nuxt, published as [`@nuxt/vite-builder`](https://npmjs.com/package/@nuxt/vite-builder) . * `packages/webpack`: The [webpack](https://webpack.js.org/) bundler for Nuxt, published as [`@nuxt/webpack-builder`](https://npmjs.com/package/@nuxt/webpack-builder) . [Setup](https://nuxt.com/docs/3.x/community/framework-contribution#setup) -------------------------------------------------------------------------- To contribute to Nuxt, you need to set up a local environment. 1. [Fork](https://help.github.com/articles/fork-a-repo) the [`nuxt/nuxt`](https://github.com/nuxt/nuxt) repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository) it to your local device. 2. Ensure using the latest [Node.js](https://nodejs.org/en) (20.x) 3. Enable [Corepack](https://github.com/nodejs/corepack) to have `pnpm` and `yarn` Terminal `corepack enable` 4. Run `pnpm install --frozen-lockfile` to Install the dependencies with pnpm: Terminal `pnpm install --frozen-lockfile` If you are adding a dependency, please use `pnpm add`. The `pnpm-lock.yaml` file is the source of truth for all Nuxt dependencies. 5. Activate the passive development system Terminal `pnpm dev:prepare` 6. Check out a branch where you can work and commit your changes: 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](https://nuxt.com/docs/3.x/community/framework-contribution#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: Terminal `pnpm dev` 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. ### [Testing](https://nuxt.com/docs/3.x/community/framework-contribution#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: Terminal `pnpm test` ### [Linting](https://nuxt.com/docs/3.x/community/framework-contribution#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: Terminal `pnpm lint` You can use `pnpm lint --fix` to fix most of the style changes. If there are still errors left, you must correct them manually. ### [Documentation](https://nuxt.com/docs/3.x/community/framework-contribution#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). Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/3.x/community/contribution#documentation-style-guide) . ### [Final Checklist](https://nuxt.com/docs/3.x/community/framework-contribution#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](https://nuxt.com/docs/3.x/community/framework-contribution#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! Make sure to make changes according to the [Documentation Style Guide](https://nuxt.com/docs/3.x/community/contribution#documentation-style-guide) . ### [Quick Edits](https://nuxt.com/docs/3.x/community/framework-contribution#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](https://nuxt.com/docs/3.x/community/framework-contribution#longer-edits) The documentation content is inside the `docs/` directory of the [nuxt/nuxt](https://github.com/nuxt/nuxt) repository and written in markdown. To preview the docs locally, follow the steps on [nuxt/nuxt.com](https://github.com/nuxt/nuxt.com) repository. We recommend that you install the [MDC extension](https://marketplace.visualstudio.com/items?itemName=Nuxt.mdc) for VS Code. ### [Linting Docs](https://nuxt.com/docs/3.x/community/framework-contribution#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. Terminal `pnpm lint:docs` You can also run `pnpm lint:docs:fix` to highlight and resolve any lint issues. ### [Open a PR](https://nuxt.com/docs/3.x/community/framework-contribution#open-a-pr) Please make sure your PR title adheres to the [conventional commits](https://www.conventionalcommits.org/) guidelines. Example of PR title `docs: update the section about the nuxt.config.ts file` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/5.community/5.framework-contribution.md) [Contribution\ \ Nuxt is a community project - and so we love contributions of all kinds! ❤️](https://nuxt.com/docs/3.x/community/contribution) [Roadmap\ \ Nuxt is constantly evolving, with new features and modules being added all the time.](https://nuxt.com/docs/3.x/community/roadmap) MenuOn this page --- # Roadmap · Nuxt Community v3 Roadmap ======= Copy page Nuxt is constantly evolving, with new features and modules being added all the time. [](https://nuxt.com/blog) See our blog for the latest framework and ecosystem announcements. [Status Reports](https://nuxt.com/docs/3.x/community/roadmap#status-reports) ----------------------------------------------------------------------------- [](https://github.com/nuxt/nuxt/issues/13653) Documentation Progress [](https://github.com/nuxt/nuxt/discussions/16119) Rendering Optimizations: Today and Tomorrow [](https://github.com/nuxt/image/discussions/563) Nuxt Image: Performance and Status [Roadmap](https://nuxt.com/docs/3.x/community/roadmap#roadmap) --------------------------------------------------------------- In roadmap below are some features we are planning or working on at the moment. Check [Discussions](https://github.com/nuxt/nuxt/discussions) and [RFCs](https://github.com/nuxt/nuxt/discussions/categories/rfcs) for more upcoming features and ideas. | Milestone | Expected date | Notes | Description | | --- | --- | --- | --- | | SEO & PWA | 2025 | [nuxt/nuxt#18395](https://github.com/nuxt/nuxt/discussions/18395) | Migrating from [nuxt-community/pwa-module](https://github.com/nuxt-community/pwa-module)
for built-in SEO utils and service worker support | | Assets | 2025 | [nuxt/nuxt#22012](https://github.com/nuxt/nuxt/discussions/22012) | Allow developers and modules to handle loading third-party assets. | | Translations | \- | [nuxt/translations#4](https://github.com/nuxt/translations/discussions/4)
([request access](https://github.com/nuxt/nuxt/discussions/16054)
) | A collaborative project for a stable translation process for Nuxt docs. Currently pending for ideas and documentation tooling support (content v2 with remote sources). | [Core Modules Roadmap](https://nuxt.com/docs/3.x/community/roadmap#core-modules-roadmap) ----------------------------------------------------------------------------------------- In addition to the Nuxt framework, there are modules that are vital for the ecosystem. Their status will be updated below. | Module | Status | Nuxt Support | Repository | Description | | --- | --- | --- | --- | --- | | [Scripts](https://scripts.nuxt.com/) | Public Beta | 3.x, 4.x | [nuxt/scripts](https://github.com/nuxt/scripts) | Easy 3rd party script management. | | Auth Utils | Planned | 4.x, 5.x | `nuxt/auth-utils` to be announced | The temporary repository [atinux/nuxt-auth-utils](https://github.com/atinux/nuxt-auth-utils)
is available while awaiting its official integration into Nuxt via RFC. | | A11y | Planned | 4.x, 5.x | `nuxt/a11y` to be announced | Accessibility hinting and utilities [nuxt/nuxt#23255](https://github.com/nuxt/nuxt/issues/23255) | | [Hints](https://github.com/nuxt/hints) | Public Alpha | 4.x, 5.x | [nuxt/hints](https://github.com/nuxt/hints) | Guidance and suggestions for enhancing development practices. | [Release Cycle](https://nuxt.com/docs/3.x/community/roadmap#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](https://nuxt.com/docs/3.x/community/roadmap#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](https://nuxt.com/docs/3.x/community/roadmap#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 (both bug fixes and backports of features from Nuxt 4) until the end of January 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) . | Release | | Initial release | End Of Life | Docs | | --- | --- | --- | --- | --- | | **5.x** (scheduled) | | Q4 2025 (estimated) | TBA | | | **4.x** (stable) | [![Nuxt latest version](https://flat.badgen.net/npm/v/nuxt?label=)](https://www.npmjs.com/package/nuxt?activeTab=versions) | 2025-07-16 | 6 months after 5.x release | [nuxt.com](https://nuxt.com/docs/4.x) | | **3.x** (maintenance) | [![Nuxt 3.x version](https://flat.badgen.net/npm/v/nuxt/3x?label=)](https://www.npmjs.com/package/nuxt?activeTab=versions) | 2022-11-16 | 2026-01-31 | [nuxt.com](https://nuxt.com/docs/3.x) | | **2.x** (unsupported) | [![Nuxt 2.x version](https://flat.badgen.net/npm/v/nuxt/2x?label=)](https://www.npmjs.com/package/nuxt?activeTab=versions) | 2018-09-21 | 2024-06-30 | [v2.nuxt.com](https://v2.nuxt.com/docs) | | **1.x** (unsupported) | [![Nuxt 1.x version](https://flat.badgen.net/npm/v/nuxt/1x?label=)](https://www.npmjs.com/package/nuxt?activeTab=versions) | 2018-01-08 | 2019-09-21 | | ### [Support Status](https://nuxt.com/docs/3.x/community/roadmap#support-status) | Status | Description | | --- | --- | | Unsupported | This version is not maintained any more and will not receive security patches | | Maintenance | This version will only receive security patches | | Stable | This version is being developed for and will receive security patches | | Development | This version could be unstable | | Scheduled | This version does not exist yet but is planned | Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/5.community/6.roadmap.md) [Framework\ \ Some specific points about contributions to the framework repository.](https://nuxt.com/docs/3.x/community/framework-contribution) [Releases\ \ Discover the latest releases of Nuxt & Nuxt official modules.](https://nuxt.com/docs/3.x/community/changelog) MenuOn this page --- # Releases · Nuxt Community v3 Releases ======== Copy page Discover the latest releases of Nuxt & Nuxt official modules. [](https://github.com/nuxt/nuxt/releases) nuxt/nuxt Nuxt framework releases. [](https://github.com/nuxt/cli/releases) nuxt/cli Nuxt CLI (`@nuxt/cli`) releases. [](https://github.com/nuxt/content/releases) nuxt/content Nuxt Content releases. [](https://github.com/nuxt/devtools/releases) nuxt/devtools Nuxt DevTools releases. [](https://github.com/nuxt/fonts/releases) nuxt/fonts Nuxt Fonts releases. [](https://github.com/nuxt/hints/releases) nuxt/hints Nuxt Hints releases. [](https://github.com/nuxt/image/releases) nuxt/image Nuxt Image releases. [](https://github.com/nuxt/scripts/releases) nuxt/scripts Nuxt Scripts releases. [](https://github.com/nuxt/ui/releases) nuxt/ui Nuxt UI releases. [](https://github.com/nuxt) Discover the `nuxt` organization on GitHub Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/5.community/7.changelog.md) [Roadmap\ \ Nuxt is constantly evolving, with new features and modules being added all the time.](https://nuxt.com/docs/3.x/community/roadmap) [Overview\ \ Reduce the differences with Nuxt 3 and reduce the burden of migration to Nuxt 3.](https://nuxt.com/docs/3.x/bridge/overview) MenuOn this page --- # Layouts · Nuxt Examples v3 Layouts ======= Copy page This example shows how to define default and custom layouts. [](https://nuxt.com/docs/getting-started/views#layouts) Read more in Docs > Getting Started > Views#layouts. [](https://nuxt.com/docs/guide/directory-structure/layouts) Read more in Docs > Guide > Directory Structure > Layouts. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/1.features/5.layouts.md) [Meta Tags\ \ This example shows how to use the Nuxt helpers and composables for SEO and meta management.](https://nuxt.com/docs/3.x/examples/features/meta-tags) [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.](https://nuxt.com/docs/3.x/examples/routing/middleware) MenuOn this page --- # Meta Tags · Nuxt Examples v3 Meta Tags ========= Copy page This example shows how to use the Nuxt helpers and composables for SEO and meta management. [](https://nuxt.com/docs/getting-started/seo-meta) Read more in Docs > Getting Started > Seo Meta. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/1.features/4.meta-tags.md) [State Management\ \ This example shows how to use the \`useState\` composable to create a reactive and SSR-friendly shared state across components.](https://nuxt.com/docs/3.x/examples/features/state-management) [Layouts\ \ This example shows how to define default and custom layouts.](https://nuxt.com/docs/3.x/examples/features/layouts) MenuOn this page --- # State Management · Nuxt Examples v3 State Management ================ Copy page This example shows how to use the \`useState\` composable to create a reactive and SSR-friendly shared state across components. [](https://nuxt.com/docs/getting-started/state-management) Read more in Docs > Getting Started > State Management. [](https://nuxt.com/docs/api/composables/use-state) Read more in Docs > API > Composables > Use State. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/1.features/3.state-management.md) [Data Fetching\ \ This example demonstrates data fetching with Nuxt using built-in composables and API routes.](https://nuxt.com/docs/3.x/examples/features/data-fetching) [Meta Tags\ \ This example shows how to use the Nuxt helpers and composables for SEO and meta management.](https://nuxt.com/docs/3.x/examples/features/meta-tags) MenuOn this page --- # Universal Router · Nuxt Examples v3 Universal Router ================ Copy page This example demonstrates Nuxt universal routing utilities without depending on \`pages/\` and \`vue-router\`. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/2.routing/universal-router.md) [Pages\ \ This example shows how to use the pages/ directory to create application routes.](https://nuxt.com/docs/3.x/examples/routing/pages) [Layers\ \ This example shows how to use the extends key in \`nuxt.config.ts\`.](https://nuxt.com/docs/3.x/examples/advanced/config-extends) MenuOn this page --- # Pages · Nuxt Examples v3 Pages ===== Copy page This example shows how to use the pages/ directory to create application routes. [](https://nuxt.com/docs/guide/directory-structure/pages) Read more in Docs > Guide > Directory Structure > Pages. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/2.routing/pages.md) [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.](https://nuxt.com/docs/3.x/examples/routing/middleware) [Universal Router\ \ This example demonstrates Nuxt universal routing utilities without depending on \`pages/\` and \`vue-router\`.](https://nuxt.com/docs/3.x/examples/routing/universal-router) MenuOn this page --- # Layers · Nuxt Examples v3 Layers ====== Copy page This example shows how to use the extends key in \`nuxt.config.ts\`. 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. [](https://nuxt.com/docs/getting-started/layers) Read more in Docs > Getting Started > Layers. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/4.advanced/config-extends.md) [Universal Router\ \ This example demonstrates Nuxt universal routing utilities without depending on \`pages/\` and \`vue-router\`.](https://nuxt.com/docs/3.x/examples/routing/universal-router) [Error Handling\ \ This example shows how to handle errors in different contexts: pages, plugins, components and middleware.](https://nuxt.com/docs/3.x/examples/advanced/error-handling) MenuOn this page --- # Middleware · Nuxt Examples v3 Middleware ========== Copy page 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. [](https://nuxt.com/docs/guide/directory-structure/middleware) Read more in Docs > Guide > Directory Structure > Middleware. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/2.routing/middleware.md) [Layouts\ \ This example shows how to define default and custom layouts.](https://nuxt.com/docs/3.x/examples/features/layouts) [Pages\ \ This example shows how to use the pages/ directory to create application routes.](https://nuxt.com/docs/3.x/examples/routing/pages) MenuOn this page --- # public · Nuxt Directory Structure v3 public ====== Copy page 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`). Directory structure `-| public/ ---| favicon.ico ---| og-image.png ---| robots.txt` app.vue `` [](https://v2.nuxt.com/docs/directory-structure/static) This is known as the `static/` directory in Nuxt 2. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.public.md) [plugins\ \ Nuxt has a plugins system to use Vue plugins and more at the creation of your Vue application.](https://nuxt.com/docs/3.x/directory-structure/plugins) [server\ \ The server/ directory is used to register API and server handlers to your application.](https://nuxt.com/docs/3.x/directory-structure/server) MenuOn this page --- # WASM · Nuxt Examples v3 WASM ==== Copy page This example demonstrates the server-side support of WebAssembly in Nuxt. Loading Sandbox... Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/4.examples/7.experimental/wasm.md) [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.](https://nuxt.com/docs/3.x/examples/advanced/use-custom-fetch-composable) [Getting Help\ \ We're a friendly community of developers and we'd love to help.](https://nuxt.com/docs/3.x/community/getting-help) MenuOn this page --- # nuxt.config.ts · Nuxt Directory Structure v3 nuxt.config.ts ============== Copy page Nuxt can be easily configured with a single nuxt.config file. The `nuxt.config` file extension can either be `.js`, `.ts` or `.mjs`. nuxt.config.ts `export default defineNuxtConfig({ // My Nuxt config })` `defineNuxtConfig` helper is globally available without import. You can explicitly import `defineNuxtConfig` from `nuxt/config` if you prefer: nuxt.config.ts `import { defineNuxtConfig } from 'nuxt/config' export default defineNuxtConfig({ // My Nuxt config })` [](https://nuxt.com/docs/api/configuration/nuxt-config) Discover all the available options in the **Nuxt configuration** documentation. 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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/3.nuxt-config.md) [error.vue\ \ The error.vue file is the error page in your Nuxt application.](https://nuxt.com/docs/3.x/directory-structure/error) [package.json\ \ The package.json file contains all the dependencies and scripts for your application.](https://nuxt.com/docs/3.x/directory-structure/package) MenuOn this page --- # content · Nuxt Directory Structure v3 content ======= Copy page Use the content/ directory to create a file-based CMS for your application. [Nuxt Content](https://content.nuxt.com/) reads the [`content/` directory](https://nuxt.com/docs/3.x/directory-structure/content) 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. [](https://content.nuxt.com/) Learn more in **Nuxt Content** documentation. [Enable Nuxt Content](https://nuxt.com/docs/3.x/directory-structure/content#enable-nuxt-content) ------------------------------------------------------------------------------------------------- Install the `@nuxt/content` module in your project as well as adding it to your `nuxt.config.ts` with one command: Terminal `npx nuxt module add content` [Create Content](https://nuxt.com/docs/3.x/directory-structure/content#create-content) --------------------------------------------------------------------------------------- Place your markdown files inside the `content/` directory: content/index.md `# Hello Content` The module automatically loads and parses them. [Render Content](https://nuxt.com/docs/3.x/directory-structure/content#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 [``](https://content.nuxt.com/docs/components/content-renderer) component: pages/\[...slug\].vue ` ` [Documentation](https://nuxt.com/docs/3.x/directory-structure/content#documentation) ------------------------------------------------------------------------------------- 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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.content.md) [composables\ \ Use the composables/ directory to auto-import your Vue composables into your application.](https://nuxt.com/docs/3.x/directory-structure/composables) [layouts\ \ Nuxt provides a layouts framework to extract common UI patterns into reusable layouts.](https://nuxt.com/docs/3.x/directory-structure/layouts) MenuOn this page --- # node_modules · Nuxt Directory Structure v3 node\_modules ============= Copy page 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) ) creates this directory to store the dependencies of your project. 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. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.node_modules.md) [modules\ \ Use the modules/ directory to automatically register local modules within your application.](https://nuxt.com/docs/3.x/directory-structure/modules) [pages\ \ Nuxt provides file-based routing to create routes within your web application.](https://nuxt.com/docs/3.x/directory-structure/pages) MenuOn this page --- # modules · Nuxt Directory Structure v3 modules ======= Copy page 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. modules/hello/index.tsmodules/hello/runtime/api-route.ts ``// `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 { 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'), }) }, })`` `export default defineEventHandler(() => { return { hello: 'world' } })` When starting Nuxt, the `hello` module will be registered and the `/api/hello` route will be available. 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: Directory structure `modules/ 1.first-module/ index.ts 2.second-module.ts` [](https://nuxt.com/docs/guide/going-further/modules) Read more in Docs > Guide > Going Further > Modules. [](https://vueschool.io/lessons/creating-your-first-module-from-scratch?friend=nuxt) Watch Vue School video about Nuxt private modules. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.modules.md) [middleware\ \ Nuxt provides middleware to run code before navigating to a particular route.](https://nuxt.com/docs/3.x/directory-structure/middleware) [node\_modules\ \ The package manager stores the dependencies of your project in the node\_modules/ directory.](https://nuxt.com/docs/3.x/directory-structure/node_modules) MenuOn this page --- # utils · Nuxt Directory Structure v3 utils ===== Copy page 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](https://nuxt.com/docs/3.x/directory-structure/utils#usage) ------------------------------------------------------------------- **Method 1:** Using named export utils/index.ts `export const { format: formatNumber } = Intl.NumberFormat('en-GB', { notation: 'compact', maximumFractionDigits: 1, })` **Method 2:** Using default export utils/random-entry.ts or utils/randomEntry.ts `// It will be available as randomEntry() (camelCase of file name without extension) export default function (arr: Array) { return arr[Math.floor(Math.random() * arr.length)] }` You can now use auto imported utility functions in `.js`, `.ts` and `.vue` files app.vue `` [](https://nuxt.com/docs/guide/concepts/auto-imports) Read more in Docs > Guide > Concepts > Auto Imports. Read and edit a live example in [Docs > Examples > Features > Auto Imports](https://nuxt.com/docs/examples/features/auto-imports) . The way `utils/` auto-imports work and are scanned is identical to the [`composables/`](https://nuxt.com/docs/3.x/directory-structure/composables) directory. These utils are only available within the Vue part of your app. Only `server/utils` are auto-imported in the [`server/`](https://nuxt.com/docs/3.x/directory-structure/server#server-utilities) directory. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.utils.md) [shared\ \ Use the shared/ directory to share functionality between the Vue app and the Nitro server.](https://nuxt.com/docs/3.x/directory-structure/shared) [.env\ \ A .env file specifies your build/dev-time environment variables.](https://nuxt.com/docs/3.x/directory-structure/env) MenuOn this page --- # .gitignore · Nuxt Directory Structure v3 .gitignore ========== Copy page A .gitignore file specifies intentionally untracked files that git should ignore. A `.gitignore` file specifies intentionally untracked files that git should ignore. [](https://git-scm.com/docs/gitignore) Read more in the git documentation. We recommend having a `.gitignore` file that has **at least** the following entries present: .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` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/2.gitignore.md) [.env\ \ A .env file specifies your build/dev-time environment variables.](https://nuxt.com/docs/3.x/directory-structure/env) [.nuxtignore\ \ The .nuxtignore file lets Nuxt ignore files in your project’s root directory during the build phase.](https://nuxt.com/docs/3.x/directory-structure/nuxtignore) MenuOn this page --- # assets · Nuxt Directory Structure v3 assets ====== Copy page 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. [](https://nuxt.com/docs/getting-started/assets) Read more in Docs > Getting Started > Assets. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/1.assets.md) [.output\ \ Nuxt creates the .output/ directory when building your application for production.](https://nuxt.com/docs/3.x/directory-structure/output) [components\ \ The components/ directory is where you put all your Vue components.](https://nuxt.com/docs/3.x/directory-structure/components) MenuOn this page --- # error.vue · Nuxt Directory Structure v3 error.vue ========= Copy page 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. error.vue ` ` 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. The error page has a single prop - `error` which contains an error for you to handle. The `error` object provides the following fields: `interface NuxtError { statusCode: number fatal: boolean unhandled: boolean statusMessage?: string data?: unknown cause?: unknown }` If you have an error with custom fields they will be lost; you should assign them to `data` instead: `throw createError({ statusCode: 404, statusMessage: 'Page Not Found', data: { myCustomField: true, }, })` Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/3.error.md) [app.config.ts\ \ Expose reactive configuration within your application with the App Config file.](https://nuxt.com/docs/3.x/directory-structure/app-config) [nuxt.config.ts\ \ Nuxt can be easily configured with a single nuxt.config file.](https://nuxt.com/docs/3.x/directory-structure/nuxt-config) MenuOn this page --- # .nuxtignore · Nuxt Directory Structure v3 .nuxtignore =========== Copy page 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. 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. [Usage](https://nuxt.com/docs/3.x/directory-structure/nuxtignore#usage) ------------------------------------------------------------------------ .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` [](https://git-scm.com/docs/gitignore) More details about the spec are in the **gitignore documentation**. Was this helpful? 🤩🙂☹️😰 [Report an issue](https://github.com/nuxt/nuxt/issues/new/choose) or [Edit this page on GitHub](https://github.com/nuxt/nuxt/edit/3.x/docs/2.directory-structure/2.nuxtignore.md) [.gitignore\ \ A .gitignore file specifies intentionally untracked files that git should ignore.](https://nuxt.com/docs/3.x/directory-structure/gitignore) [.nuxtrc\ \ The .nuxtrc file allows you to define nuxt configurations in a flat syntax.](https://nuxt.com/docs/3.x/directory-structure/nuxtrc) MenuOn this page --- # plugins · Nuxt Directory Structure v3 plugins ======= Copy page 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. All plugins inside are auto-registered, you don't need to add them to your `nuxt.config` separately. You can use `.server` or `.client` suffix in the file name to load a plugin only on the server or client side. [Registered Plugins](https://nuxt.com/docs/3.x/directory-structure/plugins#registered-plugins) ----------------------------------------------------------------------------------------------- Only files at the top level of the directory (or index files within any subdirectories) will be auto-registered as plugins. 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`: nuxt.config.ts `export default defineNuxtConfig({ plugins: [ '~/plugins/bar/baz', '~/plugins/bar/foz', ], })` [Creating Plugins](https://nuxt.com/docs/3.x/directory-structure/plugins#creating-plugins) ------------------------------------------------------------------------------------------- The only argument passed to a plugin is [`nuxtApp`](https://nuxt.com/docs/3.x/api/composables/use-nuxt-app) . plugins/hello.ts `export default defineNuxtPlugin((nuxtApp) => { // Doing something with nuxtApp })` ### [Object Syntax Plugins](https://nuxt.com/docs/3.x/directory-structure/plugins#object-syntax-plugins) It is also possible to define a plugin using an object syntax, for more advanced use cases. For example: plugins/hello.ts ``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, }, })`` Watch a video from Alexander Lichter about the Object Syntax for Nuxt plugins 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. 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. [Registration Order](https://nuxt.com/docs/3.x/directory-structure/plugins#registration-order) ----------------------------------------------------------------------------------------------- You can control the order in which plugins are registered by prefixing with 'alphabetical' numbering to the file names. 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. 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`. [Loading Strategy](https://nuxt.com/docs/3.x/directory-structure/plugins#loading-strategy) ------------------------------------------------------------------------------------------- ### [Parallel Plugins](https://nuxt.com/docs/3.x/directory-structure/plugins#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. plugins/my-plugin.ts `export default defineNuxtPlugin({ name: 'my-plugin', parallel: true, async setup (nuxtApp) { // the next plugin will be executed immediately }, })` ### [Plugins With Dependencies](https://nuxt.com/docs/3.x/directory-structure/plugins#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. plugins/depending-on-my-plugin.ts ``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](https://nuxt.com/docs/3.x/directory-structure/plugins#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: plugins/hello.ts `export default defineNuxtPlugin((nuxtApp) => { const foo = useFoo() })` However, keep in mind there are some limitations and differences: **If a composable depends on another plugin registered later, it might not work.** 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. **If a composable depends on the Vue.js lifecycle, it won't work.** 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. [Providing Helpers](https://nuxt.com/docs/3.x/directory-structure/plugins#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. plugins/hello.tsplugins/hello-object-syntax.ts ``export default defineNuxtPlugin(() => { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } })`` ``export default defineNuxtPlugin({ name: 'hello', setup () { return { provide: { hello: (msg: string) => `Hello ${msg}!`, }, } }, })`` You can then use the helper in your components: components/Hello.vue ` ` 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. **If your plugin provides a `ref` or `computed`, it will not be unwrapped in a component `