The existing internals section explains Nuxt from a tooling author's point of view: hooks, kit, the build. This section is the other half, the one most Nuxt interviews actually test: how you build applications with it. Where does code go, how does a request flow, how do you fetch data without fetching it twice, where does state live, how do errors surface, how do you decide what to render where.
The snapshot is Nuxt 4.5 on Vue 3.5, Nitro 2 and Vite 8. Nuxt 5 is expected in the last quarter of 2026 and the landscape section tracks what it changes; the pages here note the differences with a Nuxt 5 badge where they matter.
app/ is the Vue application (pages/, layouts/, components/, composables/, utils/, middleware/, plugins/, assets/, app.vue, error.vue, app.config.ts); server/ is Nitro (api/, routes/, middleware/, plugins/, utils/); shared/ is code both sides may import; public/ is served as-is; content/, layers/, modules/ are what their names say. Nuxt 4 moved the app code into app/ so the server and client trees are visibly separate and so that file watchers and IDEs do not index the server code as part of the Vue app.<Suspense>. The HTML ships with a serialised payload (#__NUXT_DATA__). The client boots the same app, hydrates against that HTML, and reuses the payload instead of refetching. Every later navigation is client-side.#imports gives you the explicit form, imports.autoImport: false turns it off. Knowing where the scanner looks (top level of composables/ and utils/, recursive for components/) explains the "not defined" bugs.nuxt.config.ts for build and framework options, runtimeConfig for values that change per environment (overridable with NUXT_* variables at runtime, private by default, public for the client), app.config.ts for reactive public configuration such as theme tokens.routeRules switch individual routes to prerendered, cached (swr), incrementally regenerated (isr), client-only or redirected. <ClientOnly>, .client.vue, server components and lazy hydration refine what ships to the browser.$fetch directly in setup (it runs on the server and again on the client, and nothing lands in the payload) and putting per-user state in a module-level variable (shared between requests on the server).| Page | What it prepares you for |
|---|---|
| Routing and pages | File-based routes, definePageMeta, layouts, middleware, NuxtLink, typed routes, route rules |
| Data fetching | useFetch vs useAsyncData vs $fetch, the payload, keys, caching, headers, interceptors |
| State and runtime config | useState, runtimeConfig, app.config, useCookie, what is safe to serialise |
| Plugins and auto-imports | Plugin order and provide, app hooks, callOnce, component and composable scanning |
| Error handling | createError, error.vue, NuxtErrorBoundary, fatal vs non-fatal, server route errors |
| SEO, head and media | useSeoMeta, Unhead, OG images and sitemaps, @nuxt/image, @nuxt/fonts, @nuxt/scripts |
| Rendering strategies | SSR, SSG, ISR/SWR, SPA per route, islands, lazy hydration, streaming, and how to choose |
| Internationalisation | @nuxtjs/i18n strategies, lazy messages, SEO tags, formatting, RTL |
The request lifecycle as a sequence, which is worth being able to narrate:
Browser GET /products/42
→ Nitro: server/middleware/* (auth headers, request id)
→ routeRules for /products/** (swr? prerender? ssr:false?)
→ Vue app created for this request
plugins (server) in order → app:created
router resolves /products/[id]
route middleware (global, then page's) → may redirect/abort
layout + page setup inside <Suspense>
useAsyncData/useFetch run on the server, results → payload
render to HTML, head tags from Unhead
← HTML + #__NUXT_DATA__ payload + preload hints
Browser
→ entry chunk, plugins (client), app:created
→ hydrate against existing DOM (payload reused, no refetch) → app:mounted
→ later: <NuxtLink> navigation runs middleware + page setup client-side
The 3.x and 4.x docs live at different paths (/docs/3.x/... vs /docs/4.x/...) and defaults differ (data is undefined not null, useAsyncData is shallow, app/ is the source directory). When a Stack Overflow answer disagrees with what you see, check which major it is talking about before "fixing" your code.
npm create nuxt@latest app and add one file to each directory listed above until you can explain, without looking, what each directory contributes to the request lifecycle.console.log calls in a server plugin, a client plugin, a global middleware, a layout and a page; load the page directly and then navigate to it from another page. Write down the two orders."Nitro receives the request and runs server middleware and route rules first; a route rule might serve a prerendered or cached page and skip rendering altogether. Otherwise Nuxt creates a fresh Vue app for the request, runs the server plugins, resolves the route, runs global and page middleware, and renders the layout and page inside Suspense so useAsyncData calls can complete on the server. The results are serialised into the payload, the head tags are generated by Unhead, and the HTML goes out. In the browser the same app boots, runs the client plugins, and hydrates against the existing DOM using the payload, so nothing is fetched twice. From then on navigation is client-side: middleware and page setup run in the browser and data is fetched from the API."
Nothing yet. Notes filed here show up on every page of this section.
Designing a team layer
The senior-craft page for layers - defining a small public surface, theming through app.config, override recipes, performance and security costs per app, governance, and rolling out breaking changes.
Routing and pages
File-based routing in Nuxt 4, definePageMeta, layouts, route middleware on server and client, NuxtLink prefetching, typed routes and the route rules that live in Nitro.