Vitest configuration for Nuxt with multiple test projects
Create vitest.config.ts with defineConfig and test.projects array. Configure separate projects for: unit tests (test/unit/*.{test,spec}.ts, environment: 'node'), e2e tests (test/e2e/*.{test,spec}.ts, environment: 'node'), and nuxt tests (test/nuxt/*.{test,spec}.ts, environment: 'nuxt' using defineVitestProject from @nuxt/test-utils/config). defineVitestProject is only for Nuxt-environment tests; e2e tests use regular 'node' environment.
Configure Nuxt server in Playwright test file
import { expect, test } from '@nuxt/test-utils/playwright'
import { fileURLToPath } from 'node:url'
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!')
})
Playwright config.ts with Nuxt global configuration
import { fileURLToPath } from 'node:url'
import { defineConfig, devices } from '@playwright/test'
import type { ConfigOptions } from '@nuxt/test-utils/playwright'
export default defineConfig<ConfigOptions>({
use: {
nuxt: {
rootDir: fileURLToPath(new URL('.', import.meta.url)),
},
},
// ...
})
E2E setup() runner, logLevel, and server log options
runner: Test runner ('vitest' | 'jest' | 'cucumber', default 'vitest', Vitest recommended); logLevel: Override consola log level for server subprocess (number, default 1, override with NUXT_TEST_LOG_LEVEL env var); captureServerLogs: Capture server output instead of inheriting stdio (boolean, default true; false restores inherit-stdio behaviour)
E2E setup() feature options: build and server
build: Whether to run separate build step (boolean, default true; false if browser/server disabled or host provided); server: Whether to launch server (boolean, default true; false if host provided)
Nuxt configuration loading with unjs/jiti and unjs/c12
Nuxt configuration is loaded using unjs/jiti and unjs/c12 libraries.
Use defineNuxtConfig function
Nuxt 3 requires using the defineNuxtConfig function for configuration instead of exporting a plain object. This function provides a typed configuration schema.
Nuxt 3 is ESM native, avoid require and module.exports
Nuxt 3 is an ESM native framework. In nuxt.config files, avoid using require and module.exports. Change module.exports to export default, and change const lib = require('lib') to import lib from 'lib'.
Async configuration is deprecated
Async config syntax is deprecated in Nuxt 3 to make Nuxt loading behavior more predictable. Use Nuxt hooks for async operations instead.
Built-in support for .env files
Nuxt has built-in support for loading .env files. Avoid directly importing .env from nuxt.config.
static/ directory renamed to public/
The static/ directory for storing static assets has been renamed to public/ in Nuxt 3. You can either rename your static directory to public, or keep the name by setting dir.public in your nuxt.config.
Nuxt 3 uses Unhead for meta tag management
Nuxt 3 currently uses Unhead (https://github.com/unjs/unhead) to manage meta tags, though implementation details may change in the future.
useHead composable example with reactive title and description
Example of useHead in Nuxt 3: const title = ref('My App'); const description = ref('My App Description'); useHead({ title, meta: [{ name: 'description', content: description }] });
Options API head() method with defineNuxtComponent
When using the Options API in Nuxt 3, you must use defineNuxtComponent to access the head() method. The head() method receives the Nuxt app as a parameter but cannot access the component instance, so it cannot be reactive to component data.
useHead composable for reactive meta tags
The useHead composable allows you to manage meta tags and make them reactive based on component state. Unlike Nuxt 2's head() method, useHead works directly with reactive refs and does not require the 'hid' key for deduplication.
Meta components for managing meta tags in templates
Nuxt 3 provides meta components (Head, Title, Meta, etc.) that can be used in templates to manage meta tags. These components look similar to HTML tags but are provided by Nuxt. They can be placed anywhere in your template and do not require a script section.
Meta component example with Head, Title, and Meta
Example of meta components in Nuxt 3: <Head><Title>My App</Title><Meta name="description" content="My app description" /></Head>
Three ways to manage meta tags in Nuxt 3
Nuxt 3 provides three different ways to manage meta tags: through your nuxt.config, through the useHead composable, or through global meta components.
Customizable meta tag properties
You can customize the following meta tag properties: title, titleTemplate, base, script, noscript, style, meta, link, htmlAttrs, and bodyAttrs.
compatibilityDate configuration resolution
To resolve the NUXT_B5001 error, add compatibilityDate to your nuxt.config file using today's date to opt in to the current defaults. The configuration should be: export default defineNuxtConfig({ compatibilityDate: 'YYYY-MM-DD', }) where YYYY-MM-DD is replaced with the actual date when the line is added.
Runtime config structure in nuxt.config
Define runtime config in the runtimeConfig property of nuxt.config. Variables at the top level are private and only available on the server. Variables nested under the public property are exposed to both client and server.
Runtime config migration example
Example of migrating runtime config from Nuxt 2 to Nuxt 3:
In nuxt.config.ts:
export default defineNuxtConfig({
runtimeConfig: {
apiSecret: '123',
public: {
apiBase: '/api',
},
},
})
In components (pages/index.vue):
const config = useRuntimeConfig()
console.log(config.public.apiBase) // instead of process.env
In server code (server/api/hello.ts):
const config = useRuntimeConfig()
console.log(config.apiSecret) // only available on server
console.log(config.public.apiBase)
In .env file:
NUXT_API_SECRET=api_secret_token
NUXT_PUBLIC_API_BASE=https://nuxtjs.org
Migrate process.env to useRuntimeConfig
When migrating from Nuxt 2 to Nuxt 3, replace all process.env references in the Vue part of your app with useRuntimeConfig. Access private config directly on the config object (e.g., config.apiSecret) and public config via config.public (e.g., config.public.apiBase).
Reference environment variables in Nuxt 3
To reference environment variables within a Nuxt 3 app, you must use runtime config instead of process.env.
useRuntimeConfig in components and setup
When referencing runtime config variables within components, you must use the useRuntimeConfig composable in your setup method or in a Nuxt plugin.
useRuntimeConfig in server code
In the server/ portion of your app, you can use useRuntimeConfig without any import.
Environment variable naming for runtime config
Runtime config values are automatically replaced by matching environment variables at runtime. Environment variables must be prefixed with NUXT_. For nested properties like public.apiBase, use NUXT_PUBLIC_API_BASE. For top-level properties like apiSecret, use NUXT_API_SECRET.
Enable app manifest in nuxt.config
To resolve NUXT_E5001, enable the app manifest by setting `experimental.appManifest: true` in the nuxt.config file. Example configuration: export default defineNuxtConfig({ experimental: { appManifest: true, }, })
giget now optional for remote layers in Nuxt 5
`giget` is no longer installed by default and is now an optional peer dependency, needed only to download a layer via `extends: ['github:my-org/my-theme']`. Local layers, layers in `~~/layers/`, and layers installed as packages are unaffected. Preferred approach: move remote layers to package.json as git dependencies and extend by package name. Otherwise, install `giget` with `npm install -D giget`, `yarn add -D giget`, `pnpm add -D giget`, or `bun add -D giget`.
useRuntimeConfig no longer accepts event in Nitro v3
In Nitro v3, `useRuntimeConfig()` no longer requires or accepts an `event` argument in server routes. Change from `const config = useRuntimeConfig(event)` to `const config = useRuntimeConfig()`.
Vue Options API disabled by default in Nuxt 5
With `compatibilityVersion: 5`, Nuxt sets Vue's `__VUE_OPTIONS_API__` feature flag to `false`, compiling Vue's Options API runtime out of the client bundle. This shrinks client bundle by approximately 6 kB minified / 2 kB gzipped. If components use Options API, re-enable with `vue.optionsApi: true` in nuxt.config. `defineNuxtComponent` is unaffected.
jiti optional peer dependency for Nuxt 5
`jiti` is now an optional peer dependency of Nuxt 5. If needed, install it with `npm i -D jiti`, `yarn add -D jiti`, `pnpm add -D jiti`, or `bun add -D jiti`. Nuxt will pick it up automatically as a fallback if the runtime cannot load a file. A `nuxt.schema` file always needs `jiti` regardless of Node version.
Test Nuxt 5 with future.compatibilityVersion
Nuxt 5 is currently in development. To test Nuxt 5 breaking changes from Nuxt 4.2+, set `future.compatibilityVersion: 5` in nuxt.config.ts. This enables Nuxt 5 behavior defaults including Vite Environment API, case-sensitive routing, normalized page names, clearNuxtState defaults, non-async callHook, comment node placeholders, stricter side-effect imports, Vue Options API disabled, typed pages enabled, and TypeScript baseUrl ignored.
Import defineNuxtConfig from nuxt/config
You can explicitly import defineNuxtConfig from 'nuxt/config' if you prefer, using: import { defineNuxtConfig } from 'nuxt/config'
defineNuxtConfig helper is globally available
The defineNuxtConfig helper is globally available without requiring an import statement.
nuxt.config file extensions
The nuxt.config file can use the .js, .ts, or .mjs extension.
Nuxt detects configuration changes for full restart
Nuxt will perform a full restart when detecting changes in the main configuration file (nuxt.config), the .env file, the .nuxtignore file, or the .nuxtrc file.
nuxt.config example structure
A basic nuxt.config.ts file structure: export default defineNuxtConfig({ // My Nuxt config })
app:rendered hook called after HTML generation
After rendering the Vue application to HTML, Nuxt calls the app:rendered hook.
app:created hook called after app plugins
After app plugins execute on the server, Nuxt calls the app:created hook, which can be used to execute additional logic.
app:mounted hook called after mounting Vue app
After mounting the Vue application, Nuxt calls the app:mounted hook.
app:beforeMount hook called before mounting Vue app
Before mounting the Vue application, Nuxt calls the app:beforeMount hook.
render:html hook called before finalizing HTML
Before finalizing and sending the HTML, Nitro calls the render:html hook. This hook allows you to manipulate the generated HTML, such as injecting additional scripts or modifying meta tags.