---
title: "Project Setup"
description: "Clone the starter repo, install dependencies, and tour the Nuxt 4 project structure with a side-by-side comparison to Next.js conventions."
canonical_url: "https://vercel.com/academy/nuxt-on-vercel/nuxt-project-setup"
md_url: "https://vercel.com/academy/nuxt-on-vercel/nuxt-project-setup.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-10-16T17:45:49.906Z"
content_type: "lesson"
course: "nuxt-on-vercel"
course_title: "Nuxt on Vercel"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# Project Setup

# Set Up the Hot Springs Finder

In Next.js, pages, layouts, API routes, loading states, and error boundaries all live under `app/`.

Nuxt separates client code from server code, gives layouts their own directory, and auto-imports components.

## Outcome

Scaffold a Nuxt 4 app with Tailwind CSS and understand how the project structure maps to Next.js.

## Fast Track

1. Clone the starter repo and install dependencies
2. Open the project and compare the file structure to Next.js
3. Start the dev server and confirm the home page loads

## Hands-on exercise 1.1

Clone the starter repo and get oriented in the Nuxt project structure.

The course repo lives at [vercel/academy-nuxt-on-vercel](https://github.com/vercel/academy-nuxt-on-vercel). The `main` branch is the starter, where we'll work. The [`complete`](https://github.com/vercel/academy-nuxt-on-vercel/tree/complete) branch is the finished Hot Springs Finder if you want to peek ahead.

```bash
git clone https://github.com/vercel/academy-nuxt-on-vercel.git
cd academy-nuxt-on-vercel
pnpm install
```

**Requirements:**

1. Clone the starter repo and install dependencies with `pnpm install`
2. Review the file structure, paying attention to `app/`, `server/`, and `nuxt.config.ts`
3. Start the dev server with `pnpm dev` and visit `http://localhost:3000`
4. Read through `nuxt.config.ts` and identify what each option does

**Implementation hints:**

- The `app/` directory is Nuxt 4's way of separating your client-side code from server code. In Next.js, everything lives under `app/` too, but in Nuxt, `server/` is a completely separate directory with its own auto-imports
- `nuxt.config.ts` is the equivalent of `next.config.js`, but with a lot more built in. No need for separate Tailwind config files with v4
- Nuxt auto-imports Vue utilities (`ref`, `computed`, `watch`) and its own composables (`useFetch`, `useRoute`). No import statements needed for these

Here's how the project structure maps to what you already know:

```
Nuxt 4                          Next.js
─────                           ───────
app/                            app/
  pages/                          (route files)
  components/                     components/
  layouts/                        (layout.tsx files)
  composables/                    hooks/
  assets/                        assets/
/public                         public/ or styles/
server/                         app/api/
  api/                            (route handlers)
  routes/                         (no equivalent)
  data/                           (no equivalent)
nuxt.config.ts                  next.config.js
```

Pay attention to these differences:

- **`server/` is not inside `app/`.** In Next.js, your API routes live alongside your pages. In Nuxt, the server is a separate world powered by Nitro. It has its own auto-imports, its own utilities, and it doesn't know about Vue.
- **No `layout.tsx` files inside page folders.** Nuxt uses a dedicated `layouts/` directory. As long as `app.vue` wraps `<NuxtPage />` in `<NuxtLayout>`, `default.vue` is applied to every page automatically.
- **Auto-imports cover several categories.** Components in `components/` (including subfolders), top-level composables in `composables/`, and Vue utilities are available without explicit imports. Composables in nested folders are not auto-imported.

Let's look at the config file that holds it all together:

```typescript title="nuxt.config.ts"
import tailwindcss from "@tailwindcss/vite";

export default defineNuxtConfig({
  compatibilityDate: "2025-05-01",

  css: ["~/assets/css/main.css"],

  vite: {
    plugins: [tailwindcss()],
  },
});
```

Note that the `~` in the CSS path is an alias for `app`.

Nuxt 4 uses the `app/` directory for client code and `server/` for server code by default. If you've seen older Nuxt 3 projects with everything at the project root, that's the old way. Nuxt 4 enforces the separation out of the box.

The `compatibilityDate` tells Nuxt which version of breaking-change behavior to use. Think of it like a snapshot: any breaking changes introduced after this date won't affect your app until you update the date.

Tailwind v4 doesn't need a config file. The `@tailwindcss/vite` plugin handles everything, and `main.css` just imports it:

```css title="app/assets/css/main.css"
@import "tailwindcss";
```

You do not need `tailwind.config.js` or `postcss.config.js` for this setup.

## Try It

Start the dev server:

```bash
pnpm dev
```

Visit `http://localhost:3000`. You should see the home page with "Find your next soak" and a "Browse Hot Springs" button.

Click "Browse" in the nav. The `/springs` page still shows its placeholder because data fetching comes later.

\*\*Warning: If pnpm dev fails\*\*

Make sure you ran `pnpm install` first. If you see a Vue version mismatch error, delete `node_modules` and `pnpm-lock.yaml`, then run `pnpm install` again. Nuxt 4 requires Vue 3.5+.

Check your Node version with `node -v`, too. Nuxt 4.6 needs Node 22.22.3+, 24.15+, or 26+. Older versions fail during install with an engine warning or a cryptic build error.

\*\*Note: Port already in use?\*\*

If port 3000 is taken, Nuxt will automatically try 3001. Check your terminal output for the actual URL.

## Commit

```bash
git init && git add -A && git commit -m "feat(setup): scaffold Nuxt 4 app with Tailwind"
```

## Done-When

- [ ] `pnpm dev` starts without errors
- [ ] Home page loads at `http://localhost:3000` with the Hot Springs Finder heading
- [ ] You can navigate to `/springs` and see the placeholder page
- [ ] You can explain why Nuxt 4 separates `server/` from `app/`

## Solution

The starter repo already contains the complete setup for this lesson. Your project structure should look like this:

```
hot-springs-finder/
├── app/
│   ├── app.vue
│   ├── assets/css/main.css
│   ├── components/
│   ├── composables/
│   ├── layouts/
│   │   └── default.vue
│   └── pages/
│       ├── index.vue
│       ├── favorites.vue
│       ├── visited.vue
│       ├── login.vue
│       └── springs/
│           ├── index.vue
│           └── [id].vue
├── server/
│   ├── api/
│   └── data/
│       └── springs.json
├── public/
├── nuxt.config.ts
├── package.json
└── tsconfig.json
```

```vue title="app/app.vue"
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>
```

```vue title="app/pages/index.vue"
<template>
  <div>
    <section>
      <h1>
        Find your next soak
      </h1>
      <p>
        Discover hot springs around the world. Browse by region, temperature, or
        type. Save your favorites and track the ones you've visited.
      </p>
      <div>
        <NuxtLink to="/springs">
          Browse Hot Springs
        </NuxtLink>
      </div>
    </section>
  </div>
</template>
```


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
