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
- Create
server/api/springs/index.get.tswith a basic event handler - Import and return the springs JSON data
- Test the endpoint at
/api/springsin the browser
Hands-on exercise 2.1
Build the first server route for the app: a GET endpoint that returns all hot springs.
Requirements:
- Create
server/api/springs/index.get.ts - Import the springs data from
server/data/springs.json - Return the full array of springs
- Verify the endpoint returns JSON at
/api/springs
Implementation hints:
defineEventHandleris the Nuxt equivalent of exporting aGETfunction in Next.js. It's auto-imported in theserver/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:
// 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:
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.
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.
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:
[
{
"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:
curl http://localhost:3000/api/springs | head -c 200If 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
git add -A && git commit -m "feat(api): add GET /api/springs server route"Done-When
server/api/springs/index.get.tsexists and exports a default event handler- Visiting
/api/springsreturns 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
import type { Spring } from "~/types/spring";
import springs from "~/server/data/springs.json";
export default defineEventHandler((event) => {
return springs as Spring[];
});Was this helpful?