Skip to content

What is Nuxt? A guide to the Vue full-stack framework

10 min read

Vue has quietly become one of the most widely used component frameworks on the web, and Nuxt is a full-stack Vue framework that turns that foundation into production applications. It packages server rendering, file-based routing, data fetching, and an HTTP server into one project, so Vue teams spend their time on the product instead of wiring infrastructure together.

This guide covers how Nuxt works under the hood, the rendering modes you can mix inside a single project, what changed in Nuxt 4, and how to deploy on Vercel.

Link to headingWhat is Nuxt?

Nuxt is a full-stack Vue framework that adds server-side rendering, file-based routing, a server engine, and auto-imports on top of Vue 3. It pairs Vue for components with Vite for the build pipeline and Nitro for the server, producing a single project that renders, routes, and responds to API calls.

The difference from plain Vue is where rendering happens. A standalone Vue single-page application ships an empty HTML shell and waits for JavaScript to load before content appears. Nuxt defaults to universal rendering, sending fully rendered HTML that the browser hydrates into an interactive app. On the React side, the closest architectural equivalent is Next.js, which pairs file-based routing and SSR with React instead of Vue.

Link to headingHow Nuxt works

Nuxt layers three technologies into one build: Vue for components, Vite for the build pipeline, and Nitro for the server. Each layer handles a different problem, and the conventions connecting them make Nuxt feel like one framework rather than a toolkit.

Link to headingBuilt on Vue, Vite, and Nitro

Vue 3 handles component rendering and reactivity. The Vue compiler separates static and dynamic markup at build time, so static fragments are generated once, cached, and reused on every render. During SSR, Vue disables its reactivity system, since there is nothing interactive to track on the server.

Vite is the dev server and bundler. It pre-bundles dependencies, serves source over native ES modules, and updates only the changed module on Hot Module Replacement. The Nitro engine is the HTTP server and build toolkit, built on h3 for runtime portability. It compiles to multiple targets, including Vercel Functions, Node, and static hosting, with no changes to application code.

Link to headingFile-based routing and auto-imports

Every .vue file inside app/pages/ maps to a URL. pages/index.vue renders at /, pages/about.vue at /about, and pages/users/[id].vue creates a dynamic route at /users/:id. Server routes follow the same filesystem convention, and files in server/api/ map to /api/* endpoints, with the HTTP method encoded in the filename. For example, server/api/users.get.ts handles GET /api/users, server/api/users.post.ts handles POST /api/users, and a method-less server/api/users.ts responds to any HTTP method.

Auto-imports pull Vue APIs like ref() and computed(), every component under components/, and every composable under composables/ into scope without explicit import statements. The engine behind this is unimport, and Nuxt generates TypeScript declarations for each auto-imported symbol so IDEs still resolve types correctly.

Link to headingThe SSR request flow

Nitro receives an incoming request and matches it against a compile-time routing table. Nuxt then runs data-fetching composables on the server. Inside SSR, $fetch('/api/...') calls short-circuit to the matching handler directly, skipping an extra HTTP round-trip, while the same code path makes a real network request when it runs in the browser.

Vue renders the component tree to an HTML string, and Nitro streams that HTML back to the browser along with the fetched data in the payload. The browser downloads the JavaScript bundle and hydrates the existing DOM by attaching event listeners, which avoids a full re-render on the client.

Link to headingNuxt rendering modes

Nuxt supports four rendering strategies and lets you mix them at the route level through routeRules. The tradeoff between modes comes down to when HTML is generated and how much work happens at request time versus build time.

Link to headingServer-side rendering

Universal rendering is the default. For each request, Nitro renders the page on the server, returns HTML, and the browser hydrates it into a full Vue app. SSR keeps the first paint content-rich for SEO and slower devices, at the cost of a running function per request.

Link to headingStatic site generation

SSG pre-renders pages at build time into static HTML files. The output serves directly from a global CDN with no server at runtime. Content changes require a rebuild, so SSG fits pages where data is stable between deployments, such as marketing content and versioned documentation.

Link to headingHybrid rendering with route rules

routeRules in nuxt.config.ts assigns a rendering and caching strategy to each route pattern. A blog path can be pre-rendered, a pricing page can be cached and revalidated in the background, and a dashboard route can render on demand. Most production Nuxt apps end up here, since different routes have different freshness and interactivity needs.

Link to headingKey features of Nuxt

Nuxt's feature set includes primitives on both the Vue frontend and the Nitro backend. That coverage is what makes it a full-stack framework rather than only a rendering layer, and a few primitives carry most of the day-to-day work.

Link to headingNitro server engine and server routes

Nitro is an open-source TypeScript server from the unified JavaScript ecosystem, built on the h3 HTTP framework for portability across runtimes. Server routes in server/api/ become HTTP endpoints, server/routes/ handles non-API routes, and server/middleware/ runs before any handler. Nitro also provides storage, caching, and scheduled-task APIs that behave the same across deployment targets.

Link to headingData fetching with useFetch and useAsyncData

useFetch and useAsyncData are the two primitives for fetching data inside a page or component. Data fetched during SSR is forwarded to the browser in the rendered payload, so hydration does not trigger a second network request for the same data.

useFetch wraps useAsyncData around a $fetch call with a sensible default key. useAsyncData gives you explicit control over the key, which Nuxt uses for deduplication, sharing data across components, and cache invalidation.

Link to headingModules, layers, and the ecosystem

The Nuxt module registry covers most integration work you'd otherwise write by hand. @nuxt/content adds a headless CMS, @nuxt/image handles responsive image optimization, and @nuxt/ui ships a component library powered by Reka UI and Tailwind CSS. Layers let one Nuxt project extend another's pages, composables, and server routes, which is useful for sharing setup across multiple apps in a monorepo.

Link to headingWhat's new in Nuxt 4?

The Nuxt 4 release reorganizes project structure, data fetching, and the TypeScript experience. The overall direction is a clearer separation between client code, server code, and code shared between them.

Nuxt 4 introduces a handful of changes that affect how projects are structured and how data moves through them:

  • New app/ directory: Client-side code, including pages/, components/, composables/, layouts/, middleware/, and plugins/, moves inside app/, while server/, shared/, public/, and nuxt.config.ts stay at the project root.

  • shared/ directory for cross-context code: Files under shared/utils/ and shared/types/ auto-import into both the Vue app and the Nitro server, which replaces the previous pattern of reaching across the client/server boundary with relative imports.

  • Shared data by key: Multiple components calling useAsyncData or useFetch with the same key share the same reactive data, error, status, and pending refs, so duplicate requests across the component tree collapse into one.

  • Shallow reactivity by default: The data returned from useAsyncData and useFetch uses shallowRef, with deep reactivity available by passing deep: true per call or as a global setting in nuxt.config.ts.

Each of these changes makes a previously hidden runtime explicitly default in code.

Link to headingWhat you can build with Nuxt

Nuxt's hybrid rendering and full-stack primitives cover a range of project types, from read-heavy sites to dashboards with authenticated APIs. A few categories come up most often.

Common Nuxt project types include:

  • Content sites and blogs: SSG pairs with @nuxt/content to author posts in markdown and build them to static HTML, so reads serve from a CDN without a running function.

  • Ecommerce storefronts: Hybrid rendering pre-renders product listings for speed and SEO while cart and checkout flows run dynamically, often backed by a payments provider like

    Stripe on Vercel.

  • SaaS dashboards: routeRules lets a single project serve public marketing pages via SSG and authenticated dashboard views via client-side rendering behind the same domain.

  • Marketing sites and landing pages: Pages known at build time ship as static HTML, and Nuxt modules add the extras these sites usually need, including image optimization and structured SEO metadata.

Each category can evolve into the others over time, since a single Nuxt project can serve all four rendering patterns as requirements change.

Link to headingGetting started with Nuxt

Creating a Nuxt project takes a single command, and the starter application includes routing, auto-imports, and a dev server out of the box. The main ramp-up is understanding how Nuxt 4 separates app code, server code, and shared code.

Link to headingInstalling Nuxt and scaffolding a project

Node.js 20 or newer is required. The following commands scaffold a Nuxt 4 project and start the dev server on http://localhost:3000:

npm create nuxt@latest my-app
cd my-app
npm run dev -- -o

The scaffold includes a working home page, TypeScript config, and the default app/ and server/ directories.

Link to headingUnderstanding the project structure

A Nuxt 4 project puts client code in app/, server code in server/, and cross-context code in shared/. Pages, components, composables, layouts, middleware, and plugins live under app/. API routes, server middleware, and Nitro plugins go in server/, while utilities and types that both sides import sit in shared/utils/ and shared/types/.

A <NuxtPage /> component in app/app.vue turns on routing, and a new file at app/pages/index.vue becomes the home route. A useFetch call inside that page fetches data on the server during SSR and forwards the result to the browser, so hydration doesn't issue a duplicate request.

Link to headingHow to deploy Nuxt on Vercel

Vercel auto-detects Nuxt projects during import and configures the build without a vercel.json. The same project can deploy its Nitro server as a Vercel Function and its static assets to the global CDN, which is what makes Nuxt's hybrid rendering practical in production.

A Vercel deployment for a Nuxt project includes:

  • Zero-config build detection: Vercel runs nuxt build and deploys /server/api, /server/routes, and /server/middleware as a single Vercel Function.

  • Preview deployments per pull request: Every PR gets a unique preview URL so teams can review rendered output before merging to production.

  • Fluid compute for SSR functions: Nitro runs inside Fluid compute with pre-warmed instances and in-function concurrency, and bills for Active CPU only during execution rather than idle I/O wait.

  • Incremental Static Regeneration through route rules: Setting isr: 60 on a route in routeRules serves the cached HTML and refreshes it in the background every 60 seconds, with generated pages cached and persisted to durable storage.

  • Zero-config image optimization: @nuxt/image integrates with Vercel's image optimization without additional setup, so responsive variants generate on the fly.

For routes that need regional placement, Nitro exposes Vercel-specific overrides through vercel.functionRules in nuxt.config.ts, which assigns one or more regions to a specific route pattern. That is useful when a route reads from a database in a particular region, and you want the function to run near it.

Link to headingShip Nuxt apps on Vercel

Nuxt gives Vue teams one framework where rendering strategy, server logic, and frontend code sit in the same project. Hybrid rendering lets each route pick its own mode, so a product that starts as a static marketing site can add dashboards and APIs without switching frameworks. Conventions around files, auto-imports, and typed composables reduce the infrastructure code you have to maintain along the way.

Vercel fits that model through framework detection, preview deployments, Fluid compute, ISR, and built-in image optimization. A new project can start from one of the Nuxt templates to go from git push to a deployed URL in minutes, and Speed Insights tracks Core Web Vitals from real visitors once traffic is live.

Link to headingFrequently asked questions about Nuxt

Link to headingIs Nuxt the same as Vue?

No. Vue is a UI library for building components with declarative rendering and reactivity. Nuxt is a full-stack framework built on Vue that adds file-based routing, server-side rendering, a Nitro-powered server, and auto-imports. A Nuxt project contains Vue inside it; a Vue project does not contain Nuxt.

Link to headingIs Nuxt better than Next.js?

Neither framework is universally better. Nuxt is built on Vue, and Next.js is built on React, so the choice usually starts with which component library your team already knows. Both ship with file-based routing, server-side rendering, and hybrid static/dynamic output, and both deploy on Vercel without extra configuration.

Link to headingIs Nuxt frontend or backend?

Both. Nuxt is a full-stack framework with a Vue-based frontend layer and a Nitro-powered server layer in a single codebase. The server/ directory contains API routes and middleware, and those handlers deploy as Vercel Functions in production.

Link to headingDo you need to know Vue to learn Nuxt?

Not to start, but it helps. You can scaffold a Nuxt project and follow the getting-started guide without Vue experience, since Nuxt handles most of the boilerplate. Vue concepts like single-file components, the Composition API, and vue-router apply directly once you move past the starter, so reading the Vue docs alongside Nuxt's is worth the time.