The tail of Getting Started is where Nuxt stops being a Vue framework and becomes a deployable full-stack application. Testing and upgrading are the chapters candidates skip and interviewers do not.
server/ directory holds endpoints (server/api, server/routes), middleware (server/middleware) and plugins; Nitro provides the universal deployment presets and hybrid rendering through routeRules. Server-side $fetch to your own routes calls the handler directly without an HTTP round trip, and internal routes are typed ($fetch('/api/hello') infers the return type).extends with a relative path, an npm package or a git URL, or drop a folder in layers/ for auto-registration. Priority: the project wins, then auto-scanned layers/ (alphabetical, later names override earlier), then extends entries (earlier entries override later ones); control it by naming (1.base, 2.theme) or by using extends for explicit ordering. The Layers section has fourteen pages on this.nuxt generate (or nuxt build --prerender) starts from / and follows links; nitro.prerender.routes adds start routes, crawlLinks: false stops crawling, ignore excludes patterns. Selective: routeRules: { '/path': { prerender: true } } with nuxt build for a hybrid deployment.experimental.payloadExtraction, on by default): each prerendered page writes _payload.json, which client-side navigation loads instead of hitting a server.prerenderRoutes('/path') inside a page adds routes discovered from data; the prerender:routes Nuxt hook (routes.add(...)) and the prerender:generate Nitro hook (route.skip = true) adjust the list programmatically.node .output/server/index.mjs, configured with PORT/HOST or NITRO_PORT/NITRO_HOST; serve the same build under several base paths with NUXT_APP_BASE_URL; run under PM2 with an ecosystem file; NITRO_PRESET=node_cluster for cluster mode.nuxt generate outputs .output/public; static fallback pages 200.html and 404.html serve client-rendered routes; client-side only with ssr: false for a pure SPA.nitro.preset, NITRO_PRESET or SERVER_PRESET. CDN proxy: NUXT_APP_CDN_URL serves assets from a CDN, and proxies must forward X-Forwarded-* headers.@nuxt/test-utils, vitest, @vue/test-utils, and happy-dom or jsdom. Unit testing: vitest.config.ts with defineVitestConfig (single project) or defineVitestProject for a projects setup; the Nuxt runtime environment is enabled per file with // @vitest-environment nuxt, by naming files *.nuxt.spec.ts, or for a whole project with environment: 'nuxt'; environmentOptions.nuxt sets rootDir, domEnvironment, overrides and built-in mocks (intersectionObserver, indexedDb).test/unit (plain Node), test/nuxt (Nuxt environment; these directories are included in the app's TypeScript context), test/e2e; run one with npx vitest --project nuxt. Keep the Nuxt environment separate from end-to-end tests.mountSuspended, renderSuspended (Testing Library), mockNuxtImport, mockComponent, registerEndpoint. Browser mode via @nuxt/test-utils/browser with @vitest/browser-playwright. End-to-end: setup() from @nuxt/test-utils/e2e (options rootDir, configFile, build, server, port, host for a prebuilt server, browser, runner), then $fetch, fetch, url, createPage, useTestContext; a Playwright fixture (@nuxt/test-utils/playwright) adds goto(url, { waitUntil: 'hydration' }). @nuxt/test-utils 4 requires Vitest 4 or 5.npx nuxt upgrade --dedupe; the nightly channel for pre-releases; testing Nuxt 5 through the documented nightly or future.compatibilityVersion: 5.npx codemod@latest nuxt/4/migration-recipe. Changes: new app/ directory structure; singleton data-fetching layer (shared keys, consistent options); corrected module loading order in layers; deduplication of route metadata; normalised component names; Unhead v2; new DOM location for the SPA loading screen; parsed error.data; more granular inline styles; page meta scanned after resolution; shared prerender data; data/error default to undefined; boolean dedupe values removed; defaults respected when clearing data and useState; pending aligned with status; key-change behaviour; shallow data reactivity; absolute paths in builder:watch; window.__NUXT__ removed; directory index scanning; template compilation changes; TypeScript configuration split into project references; removal of some experimental features and of the top-level generate config; normalised page component names.import { defineConfig } from 'vitest/config'
import { defineVitestProject } from '@nuxt/test-utils/config'
export default defineConfig({
test: {
projects: [
{ test: { name: 'unit', include: ['test/unit/**/*.spec.ts'], environment: 'node' } },
await defineVitestProject({
test: {
name: 'nuxt',
include: ['test/nuxt/**/*.spec.ts'],
environment: 'nuxt',
environmentOptions: { nuxt: { domEnvironment: 'happy-dom', mock: { intersectionObserver: true } } },
},
}),
],
},
})
import { describe, expect, it } from 'vitest'
import { $fetch, createPage, setup } from '@nuxt/test-utils/e2e'
describe('home', async () => {
await setup({ browser: true })
it('renders on the server', async () => {
expect(await $fetch('/')).toContain('<h1>')
})
it('has no client errors after hydration', async () => {
const page = await createPage('/')
const errors: string[] = []
page.on('pageerror', e => errors.push(e.message))
await page.waitForLoadState('networkidle')
expect(errors).toEqual([])
})
})
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('prerender:generate', (route) => {
if (route.route?.startsWith('/preview/')) route.skip = true
})
})
Files using @nuxt/test-utils/e2e must not run in the Nuxt Vitest environment; the docs insist on separate projects (or at least separate include patterns). The symptom of mixing them is a test that hangs while setup() tries to build inside an already-running Nuxt.
The current instructions for trying Nuxt 5 (nightly channel name or compatibilityVersion) and the latest additions to the "Migrating to Nuxt 4" list.
mountSuspended test, and run each project separately.nuxt generate on a project with a dynamic route that is not linked anywhere; observe it missing, then add it with prerenderRoutes and again with the prerender:routes hook..output/server/index.mjs with NITRO_PORT=4000 and NUXT_APP_BASE_URL=/app/; confirm both took effect."With @nuxt/test-utils on Vitest. Unit tests for plain logic run in a Node environment; tests that need the Nuxt runtime, components with auto-imports and composables, run in the nuxt environment, enabled per file or per Vitest project with defineVitestProject, and use helpers such as mountSuspended, mockNuxtImport and registerEndpoint. End-to-end tests use setup() from @nuxt/test-utils/e2e, which builds and starts the app, then $fetch for server HTML and createPage for a Playwright browser, and they live in their own project because the two environments must not mix. The recommended layout is test/unit, test/nuxt and test/e2e."
Nothing yet. Notes filed here show up on this page and the section overview.
Getting started II — routing, SEO, transitions, data, state, errors
The middle Getting Started chapters — Routing, SEO and Meta, Transitions, Data Fetching, State Management and Error Handling — reduced to the statements, options and defaults the docs make.
Concepts
The Guide's Concepts chapters — Auto-imports, Nuxt Lifecycle, Vue.js Development (including Vapor interop), Rendering Modes, Server Components, Server Engine, Modules, ES Modules, TypeScript and Code Style — as statements to remember.