---
title: "Server Routes"
description: "Create server API routes using Nuxt's Nitro engine, read from a JSON data file, and compare the approach to Next.js Route Handlers."
canonical_url: "https://vercel.com/academy/nuxt-on-vercel/server-routes"
md_url: "https://vercel.com/academy/nuxt-on-vercel/server-routes.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-05-03T14:17:50.008Z"
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>

# Server Routes

# Server Routes

In Next.js, an API route is a file called `route.ts` that exports named functions: `GET`, `POST`, `PUT`, `DELETE`. The HTTP method is the function name. The file lives inside `app/api/`, right next to your pages.

Nuxt encodes the HTTP method in the filename. A file called `index.get.ts` handles GET requests. A file called `index.post.ts` handles POST. The server code lives in `server/api/`, completely separate from your Vue app. Under the hood, Nuxt uses a server engine called Nitro that compiles your routes into a standalone server, which is how it deploys to platforms like Vercel without any extra configuration.

We have 17 hot springs sitting in a JSON file. Let's give them an API.

## Outcome

Create a server route that returns all hot springs from the JSON data file.

## Fast Track

1. Create `server/api/springs/index.get.ts` with a basic event handler
2. Import and return the springs JSON data
3. Test the endpoint at `/api/springs` in the browser

## Hands-on exercise 2.1

Build the first server route for the app: a GET endpoint that returns all hot springs.

**Requirements:**

1. Create `server/api/springs/index.get.ts`
2. Import the springs data from `server/data/springs.json`
3. Return the full array of springs
4. Verify the endpoint returns JSON at `/api/springs`

**Implementation hints:**

- `defineEventHandler` is the Nuxt equivalent of exporting a `GET` function in Next.js. It's auto-imported in the `server/` directory
- You can import JSON files directly with `import springs from "~/server/data/springs.json"`
- The `~/` alias resolves to the project root in server code, just like in app code
- Return a value and Nitro automatically serializes it as JSON with the correct content type

In Next.js, a basic API route looks like this:

```typescript
// app/api/springs/route.ts — Next.js version
import { NextResponse } from "next/server";
import springs from "@/data/springs.json";

export async function GET() {
  return NextResponse.json(springs);
}
```

Here's the Nuxt version:

```typescript title="server/api/springs/index.get.ts"
import type { Spring } from "~/types/spring";
import springs from "~/server/data/springs.json";

export default defineEventHandler((event) => {
  return springs as Spring[];
});
```

That's it. No `NextResponse.json()` wrapper. No explicit status codes. Return a value and Nitro handles serialization. The `event` parameter gives you access to the request, query parameters, headers, and body, but we don't need any of that yet.

The filename does real work here. `index.get.ts` tells Nitro three things: this handles requests to the root of the `/api/springs` path (`index`), it only responds to GET requests (`.get`), and it's a TypeScript file (`.ts`). If someone sends a POST to this endpoint, Nitro returns a 405 automatically.

Compare that to Next.js, where a single `route.ts` file can export multiple methods. Nuxt's one-file-per-method approach means more files but less ambiguity. You never have to scan a file to find out which methods it handles.

\*\*Note: Server auto-imports\*\*

The `server/` directory has its own set of auto-imports, separate from the `app/` directory. `defineEventHandler`, `getQuery`, `getRouterParam`, `createError`, and other Nitro utilities are all available without imports. Vue utilities like `ref` and `computed` are NOT available here. The server doesn't know about Vue.

\*\*Warning: Don't mix up the aliases\*\*

In `server/` files, `~/` resolves to the project root. In `app/` files, `~/` resolves to the `app/` directory. This means `~/types/spring` works in both places, but for different reasons. If you try to import a Vue component from a server route, it will fail.

## Try It

Start the dev server and visit `http://localhost:3000/api/springs` in your browser. You should see a JSON array of 17 hot springs:

```json
[
  {
    "id": "breitenbush-hot-springs",
    "name": "Breitenbush Hot Springs",
    "description": "Tucked into the Willamette National Forest...",
    "location": {
      "region": "Pacific Northwest",
      "country": "US",
      "lat": 44.7896,
      "lng": -121.9815
    },
    "temperature": { "min": 98, "max": 112 },
    "type": "developed",
    "features": ["clothing-optional", "forest-setting", ...],
    "elevation": 2200,
    "imageUrl": "/images/springs/breitenbush-hot-springs.jpg"
  },
  ...
]
```

You can also test with curl:

```bash
curl http://localhost:3000/api/springs | head -c 200
```

If you see the JSON data, the route is working. If you get a 404, make sure the file is at `server/api/springs/index.get.ts`, not `app/api/springs/index.get.ts`. The server directory is a common source of misplaced files when you're coming from Next.js.

## Commit

```bash
git add -A && git commit -m "feat(api): add GET /api/springs server route"
```

## Done-When

- [ ] `server/api/springs/index.get.ts` exists and exports a default event handler
- [ ] Visiting `/api/springs` returns a JSON array of 17 hot springs
- [ ] You can explain how filename conventions (`.get.ts`, `.post.ts`) replace exported function names in Next.js

## Solution

```typescript title="server/api/springs/index.get.ts"
import type { Spring } from "~/types/spring";
import springs from "~/server/data/springs.json";

export default defineEventHandler((event) => {
  return springs as Spring[];
});
```


---

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