Server routes
Nuxt includes its own server called Nitro. It serves pages, and it can also answer API requests like a separate backend. Its code lives in the server/ folder in the project root: every file in server/api/ handles one address.
The first handler
Create server/api/posts.get.ts (the server/ and server/api/ folders do not exist yet, so create them too):
// server/api/posts.get.ts
export default defineEventHandler(() => {
return [
{ id: 1, title: 'First post', text: 'Hello, world!' },
{ id: 2, title: 'Learning Nuxt', text: 'Pages from files.' }
]
})defineEventHandler describes a request handler, and whatever the function returns goes into the response. Nitro turns arrays and objects into JSON itself. Open http://localhost:3000/api/posts and the browser shows the list of posts as JSON.
File and address
| File | Method and address |
|---|---|
server/api/hello.ts | Any method, /api/hello |
server/api/posts.get.ts | GET /api/posts |
server/api/posts.post.ts | POST /api/posts |
server/api/posts/[id].get.ts | GET /api/posts/5 |
server/api/posts/[id].delete.ts | DELETE /api/posts/5 |
server/routes/rss.xml.ts | GET /rss.xml, without the /api prefix |
The HTTP method goes before the extension: .get, .post, .put, .patch, .delete. Without a method the handler answers any of them.
An async handler
A handler can be asynchronous, for example waiting for a database or another API:
// server/api/time.get.ts
export default defineEventHandler(async () => {
await new Promise((resolve) => setTimeout(resolve, 500))
return { now: new Date().toISOString() }
})The address /api/time answers after half a second with an object holding the current time.
How server code differs
Code in app/ | Code in server/ |
|---|---|
| Runs on the server and in the browser | Runs only on the server |
| Visible to users in the downloaded JavaScript | Not visible to users |
| Cannot keep secrets | Can reach the database and keep API keys |
Server functions (defineEventHandler, getQuery, readBody and others) are imported automatically as well. Page composables (useRoute, useState), however, are not available here: it is a different environment.
Shared server code
Functions needed by several handlers go into server/utils/. They are imported automatically too, but only in server code. You will use this in the next lessons.
Common mistake
Putting the server folder inside app/, next to the pages. Nuxt 4 looks for server code only in the project root: a handler in app/server/api/ does not work, and a request to /api/posts returns 404. The server/ folder must sit next to app/, not inside it.