How to Use Nuxt: The Beginner's Guide (First Project, File-Based Routing, Data Fetching, and Deploy)

CodexFuse Team · 2026-10-31T03:57:27.257Z · 14 min read

How do you use Nuxt?

You use Nuxt by scaffolding a project with one command, adding Vue files to the app/pages directory so they become routes automatically, fetching data with the useFetch and useAsyncData composables, and building your own backend endpoints inside the server/api directory. This is how to use Nuxt for a real first project — the guide below walks the whole arc, from a blank folder to a deployed app.

If you already write Vue components, Nuxt removes the setup work around them: no router configuration, no bundler config, and no separate backend server for the basics. Once you add server routes, keep a REST API Tester handy to check each endpoint before your pages call it.

  1. Scaffold. Run npm create nuxt@latest my-nuxt-app with Node.js 22 or newer installed, answer the starter prompts, then start the dev server with npm run dev -- -o — your app opens at http://localhost:3000.
  2. Learn the app/ directory. Nuxt 4 keeps your code in app/: app.vue is the root component, app/pages/ holds your routes, server/ holds your API, and nuxt.config.ts is the single config file.
  3. Add pages, not routes. Create app/pages/about.vue and the /about URL works instantly — file-based routing means the folder structure is the router.
  4. Fetch data the SSR-safe way. Use useFetch('/api/posts') for simple calls and useAsyncData('key', fn) when you need finer control; both run on the server and hand the data to the client without refetching.
  5. Build server routes. Add server/api/hello.ts exporting a defineEventHandler and you have a working /api/hello endpoint — no separate backend to deploy.
  6. Extend with modules. Run npx nuxt module add pinia to install a feature with the dependency and config updated for you.
  7. Deploy. Run nuxt build for a Node server or nuxt generate for a fully static site.

What is Nuxt, and why do Vue developers use it?

Nuxt is the full-stack meta-framework for Vue. It takes Vue components and adds file-based routing, server-side rendering, static generation, data fetching, and a built-in API layer powered by the Nitro server engine. If Vue is the view layer, Nuxt is the whole application around it.

Vue developers reach for Nuxt for three concrete reasons. First, routing disappears as a chore — files are routes, so adding a page is adding a file. Second, pages can render on the server, which produces real HTML for search engines and fast first loads without extra architecture. Third, the server/ directory gives you API endpoints in the same project, so one developer can ship a full-stack app from one repository.

Nuxt 4 is the current major version (verified at nuxt.com on October 30, 2026). It requires Node.js 22.x or newer, keeps application code in the app/ directory, and keeps backend code in server/.

How do you create your first Nuxt 4 project?

You create a Nuxt 4 project by running npm create nuxt@latest my-nuxt-app in your terminal with Node.js 22 or newer installed, answering the starter prompts, then running the dev server. The whole thing takes about two minutes.

Before you start, install Node.js 22.x or newer — the Nuxt docs recommend the active LTS release — and a text editor. The official docs recommend Visual Studio Code with the official Vue extension (previously known as Volar), or WebStorm with its built-in Nuxt support. If your editor is not set up for JavaScript work yet, our VS Code beginner guide walks through the setup.

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

The -o flag opens your browser automatically at http://localhost:3000, where you will see the Nuxt welcome page. The starter asks a few questions — TypeScript or JavaScript, package manager, and rendering mode — and accepting the defaults is a fine beginner choice.

Before writing code, learn the directory map. This is the single most useful thing a Nuxt beginner can do, because every convention in the framework hangs off these folders:

Directory or fileWhat it is for
app/app.vueThe root component, rendered on every page
app/pages/File-based routes — every .vue file becomes a URL
app/components/Components, auto-imported anywhere without import statements
app/composables/Reusable functions, auto-imported like components
app/layouts/Shared page shells (header/footer) applied per page
server/API routes, middleware, and server utilities (Nitro)
public/Static files served as-is — public/logo.png becomes /logo.png
nuxt.config.tsThe single configuration file for the whole project

How does Nuxt file-based routing work?

Nuxt file-based routing works by turning every .vue file inside app/pages/ into a URL: the file's path relative to the pages folder is the route. You never configure a router — you add files, and the routes appear.

The mapping is literal. Here is what common files produce:

FileURL
app/pages/index.vue/
app/pages/about.vue/about
app/pages/blog/index.vue/blog
app/pages/blog/[slug].vue/blog/any-post-slug (dynamic segment)
app/pages/users/[id].vue/users/42 (dynamic segment)

Dynamic segments use square brackets: [slug].vue matches any value in that position. Inside the page, read the value with the useRoute() composable:

<script setup lang="ts">
// app/pages/blog/[slug].vue
const route = useRoute()
const slug = route.params.slug // "my-first-post" for /blog/my-first-post
</script>

Nested folders become nested paths, so app/pages/dashboard/settings.vue serves /dashboard/settings with zero configuration. This is the convention to internalize first: in Nuxt, the filesystem is the routing table.

How do you fetch data with useFetch and useAsyncData?

You fetch data in Nuxt with three tools that look similar but solve different problems: $fetch for simple requests (especially event handlers), useFetch for SSR-safe page data, and useAsyncData when you need fine-grained control over caching and async logic. Picking the right one is the core Nuxt data-fetching skill.

The reason two extra composables exist is hydration. If you call plain $fetch inside a component's setup, the request can run twice — once on the server to render the HTML, and once again in the browser when the HTML hydrates. That doubles latency and can cause hydration mismatches. useFetch and useAsyncData fix this: the server fetches once, forwards the result in the page payload, and the client reuses it without refetching.

Here is the decision rule:

ToolUse it whenExample
useFetchLoading the initial data a page needs, SSR-safeconst { data } = await useFetch('/api/posts')
useAsyncDataYou need a custom cache key, a CMS query layer, or combined requestsconst { data } = await useAsyncData('posts', () => myQuery('posts'))
$fetchEvent handlers and mutations — form submits, button clicksawait $fetch('/api/submit', { method: 'POST', body })

useFetch is a wrapper around useAsyncData and $fetch combined — it is nearly equivalent to useAsyncData(url, () => $fetch(url)), which is why it covers the most common case with one call. Both composables return the same shape:

<script setup lang="ts">
const { data, error, status, refresh } = await useFetch('/api/posts')
// data: the result (a Vue ref)
// error: set if the request failed
// status: "idle" | "pending" | "success" | "error"
// refresh: re-run the request on demand
</script>

<template>
  <div v-if="status === 'pending'">Loading posts...</div>
  <div v-else-if="error">Something went wrong.</div>
  <ul v-else>
    <li v-for="post in data" :key="post.id">{{ post.title }}</li>
  </ul>
</template>

Two options change the default behavior in useful ways. The lazy option (or the useLazyFetch / useLazyAsyncData variants) lets navigation happen immediately while the request runs in the background — you handle the loading state yourself via status. The server: false option makes the call client-only, which fits data that is not needed for the first render or SEO. And one rule from the docs: the first argument to useAsyncData is a cache key, and you should always set your own key rather than relying on the auto-generated one, especially inside shared composables.

How do you build your own API with Nuxt server routes?

You build an API in Nuxt by adding files to the server/ directory: every file in server/api/ becomes an endpoint under /api, and each file exports a handler defined with defineEventHandler(). No Express setup, no separate process — the API ships inside the same project.

If the idea of an API endpoint is new to you, read what an API is first — server routes are simply a place to write the server half of that conversation. The mapping works like this:

// server/api/hello.ts  →  GET /api/hello
export default defineEventHandler(() => {
  return { hello: 'world' }
})

Return a plain object and Nuxt serializes it as JSON. Call it from any page with the same composables you just learned:

<script setup lang="ts">
// app/pages/index.vue
const { data } = await useFetch('/api/hello')
</script>

Four conventions cover most of what beginners need. First, files in server/routes/ (instead of server/api/) register without the /api prefix, so server/routes/bonjour.ts serves /bonjour. Second, suffixing a filename with a method — users.post.ts, users.get.ts — restricts it to that HTTP method; other methods get a 405 error. Third, dynamic segments work like pages: server/api/users/[id].ts serves /api/users/42, and you read the value with getRouterParam(event, 'id'). Fourth, read request bodies with readBody(event) and throw proper errors with createError({ status: 400, statusText: '...' }):

// server/api/echo.post.ts  →  POST /api/echo
export default defineEventHandler(async (event) => {
  const body = await readBody(event)
  if (!body.message) {
    throw createError({ status: 400, statusText: 'message is required' })
  }
  return { echoed: body.message }
})

Two more directories round out the server layer. Files in server/utils/ are auto-imported helpers you can call from any route, and files in server/middleware/ run on every request — the standard place for logging or auth checks. One hard rule from the docs: never import Vue app code (components, composables) inside server routes, and never import server-only code in your app — the two sides run in different contexts.

How do you add features with Nuxt modules?

You add features with the nuxi module command: npx nuxt module add <name> installs the module as a dependency, adds it to your package.json, and updates your nuxt.config file — no manual wiring. Modules are Nuxt's plugin ecosystem: state management, image optimization, content, auth, and hundreds more.

The workflow is three commands. Search for what you need, add it, and remove it the same way:

npx nuxt module search pinia        # find modules compatible with your Nuxt version
npx nuxt module add pinia           # install + register in nuxt.config
npx nuxt module remove pinia        # uninstall + unregister

Running nuxi module add without a name opens an interactive picker of modules compatible with your Nuxt version, which is the easiest way to browse. After adding, the module's options live in the modules array (or a dedicated key) in nuxt.config.ts, and the module's composables and components become auto-imported like the rest of your app.

How do you deploy a Nuxt app?

You deploy a Nuxt app with nuxt build for a dynamic Node.js server or nuxt generate for a fully static site — the two commands cover almost every hosting target. Which one you pick depends on whether your app needs a live server at runtime.

For a dynamic app (server routes, SSR per request), run nuxt build. The output lands in .output/, and the production server starts with one command:

nuxt build
NODE_ENV=production node .output/server/index.mjs

That server listens on port 3000 by default and respects the NITRO_PORT/PORT and NITRO_HOST/HOST environment variables. Always set NODE_ENV=production — some dependencies only strip their development warnings when it is set. For a VPS or dedicated server, the Nuxt docs point to PM2 with an ecosystem file targeting ./.output/server/index.mjs, which you can also wrap in a Docker container for consistent deploys.

For a static site (blogs, docs, marketing pages), run nuxt generate. It pre-renders your routes to plain HTML at build time, emits _payload.json files so client-side navigation reuses the build-time data, and generates 200.html and 404.html fallback pages for your static host. Deploy the .output/public folder anywhere that serves static files.

For serverless and edge targets, set the Nitro preset explicitly in nuxt.config.ts or via the environment variable:

export default defineNuxtConfig({
  nitro: { preset: 'node-server' }
})
// or: NITRO_PRESET=node-server nuxt build

Nitro ships presets for the major serverless and edge providers — check the Nitro deployment docs for the full list. Two practical notes from the Nuxt docs: most developers deploy from a Git repository, so get your code into version control early with our GitHub beginner guide; and if you put Cloudflare in front of a Nuxt app, disable Rocket Loader and email-address obfuscation in the Cloudflare dashboard, because both inject scripts that can break hydration.

Nuxt vs Next.js: which should you learn?

Nuxt vs Next.js is really Vue vs React wearing different clothes. Nuxt is Vue's full-stack meta-framework and Next.js is React's; both give you file-based routing, server-side rendering, static generation, and server functions or API routes. The architecture and the mental model transfer almost one to one.

Choose Nuxt when your project, team, or existing components are Vue — that is the entire decision for most beginners. Choose Next.js when they are React. Learning one teaches you the concepts of the other: whichever you pick, you will understand file routing, SSR, data-fetching composables, and server functions in both ecosystems.

What should you learn after your first Nuxt app?

After your first Nuxt app, the highest-value next steps are a real backend, shared logic, and developer tooling. If your app needs user accounts or a database, pair Nuxt's pages with a backend-as-a-service instead of hand-rolling auth — our Supabase beginner guide shows the managed path that fits Nuxt's useFetch model well.

Then go deeper on the framework itself: move repeated logic into app/composables/ so it auto-imports everywhere, open Nuxt DevTools and inspect the Payload tab to see exactly what your server sent to the client, and add one module at a time as your app earns the complexity. That order — scaffold, pages, data, server routes, modules, deploy — is the whole beginner arc, and you now have all of it.

Sources

  • "Installation · Get Started with Nuxt v4" — npm create nuxt@latest scaffold, Node.js 22.x requirement, app/ directory, VS Code + official Vue extension: nuxt.com (checked October 30, 2026)
  • "Data Fetching · Get Started with Nuxt v4" — useFetch, useAsyncData cache keys, $fetch for event handlers, lazy and server: false options, return values: nuxt.com (checked October 30, 2026)
  • "server · Nuxt Directory Structure v4" — server/api and server/routes mapping, method suffixes, dynamic params, server/utils and server/middleware, the no-mixing-Vue-and-server-code rule: nuxt.com (checked October 30, 2026)
  • "Deployment · Get Started with Nuxt v4" — nuxt build vs nuxt generate, .output/server/index.mjs, NODE_ENV=production, NITRO_PRESET, PM2, Cloudflare Rocket Loader caveat: nuxt.com (checked October 30, 2026)
  • "nuxt module · Nuxt CLI v4" — nuxi module add/search/remove, automatic package.json and nuxt.config updates: nuxt.com (checked October 30, 2026)
  • "How to Start with Nuxt.js 3 (Expert Explanations)" — file-based routing walkthrough, layouts, definePageMeta, data-fetching examples: staticmania.com (updated about 67 days ago)

Frequently asked questions

Is Nuxt 4 hard to learn for beginners?

Nuxt 4 is gentle if you already know Vue basics — components, props, and the Composition API. The first week is just scaffolding, adding pages, and fetching data with useFetch. The harder concepts (the SSR mental model, server routes, Nitro presets) are all optional at first, so learn them only when your app needs them.

Do I need to know TypeScript to use Nuxt?

No. The starter asks whether you want TypeScript or JavaScript, and plain JavaScript works fine. Nuxt 4 projects are TypeScript-friendly by default and the official docs write examples in TypeScript, so learning the basics of types pays off — but it is not a prerequisite for your first project.

Can I use Nuxt with an external backend instead of server routes?

Yes. useFetch and $fetch can call any URL, not just your own server/api endpoints, so an external REST API or a backend-as-a-service like Supabase works directly. Add server: false for calls that should only run in the browser. Server routes are for when you want the backend in the same repository and the same deploy.

Nuxt vs Next.js — which should I learn in 2026?

Pick by your UI library: Vue means Nuxt, React means Next.js. Both are full-stack meta-frameworks with file-based routing, SSR, static generation, and server functions, so the concepts transfer. There is no objectively better framework for beginners — there is only the one that matches the components you already write.

What is the difference between nuxt build and nuxt generate?

nuxt build produces a Node.js server (.output/server/index.mjs) for apps that need server-side rendering or API routes at runtime. nuxt generate pre-renders every route to static HTML for hosts that only serve files. Build when your app is dynamic; generate when your content is known at build time.

Featured on Twelve Tools Launch Llama Tools Launch your MCP