When people hear "full-stack," they usually think of a separate frontend and backend applications. But what if you could build a complete full-stack app without setting up a separate backend? Thanks to Nuxt Server Routes, you totally can.
In this article, we'll dive into what Nuxt Server Routes are, why they feel magical, and how to build a simple full-stack app that talks directly to a database — no separate server needed
Enjoy!
🤔 What Are Nuxt Server Routes?
In Nuxt 3, anything you export inside the /server
directory automatically becomes a server-side API route.
Let's take a look at the following example. Creating a file like /server/api/hello.ts
:
export default defineEventHandler(() => {
return { message: 'Hello from the server!' }
})
And now visiting /api/hello
in the browser returns:
{ "message": "Hello from the server!" }
Mind-blowing simplicity, right?
Using Nuxt Server Routes comes with several benefits such as:
- No need for a separate backend repo
- Faster API development
- Perfect for JAMstack deployments
- Seamless TypeScript support out of the box
- Great for "backend-lite" apps: blogs, dashboards, SaaS MVPs
Let's try it out in the real app example below.
🟢 Building a Simple Notes App ✍️
Imagine building a tiny "Notes" app where users can create and list notes. For our technology stack, we will use Nuxt both on the frontend and the backend and Prisma (ORM) with SQLite for super lightweight database.
1.Set Up the Nuxt App
npx nuxi init nuxt-notes-app
cd nuxt-notes-app
npm install
2.Install prisma and initialize sqlite provider:
npm install prisma @prisma/client
npx prisma init --datasource-provider sqlite
3.Set up your prisma/schema.prisma
:
datasource db {
provider = "sqlite"
url = "file:./dev.db"
}
generator client {
provider = "prisma-client-js"
}
model Note {
id Int @id @default(autoincrement())
title String
body String
}
4.Generate the Prisma client:
npx prisma generate
npx prisma db push
Now you have a working database.
5.Create Server Route /server/api/notes/index.ts
to handle read operation:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export default defineEventHandler(async (event) => {
return await prisma.note.findMany()
})
6.Create Server Route /server/api/notes/create.ts
to handle write operation:
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return await prisma.note.create({
data: {
title: body.title,
body: body.body,
},
})
})
7.Create Homepage /pages/index.vue
:
<script setup lang="ts">
const notes = ref([])
const newNote = ref({ title: '', body: '' })
async function fetchNotes() {
notes.value = await useFetch('/api/notes')
}
async function createNote() {
await useFetch('/api/notes/create', {
method: 'POST',
body: newNote.value,
})
newNote.value = { title: '', body: '' }
await fetchNotes()
}
onMounted(fetchNotes)
script>
<template>
My Notes
@submit.prevent="createNote">
v-model="newNote.title" placeholder="Title"/>
v-model="newNote.body" placeholder="Body"/>
type="submit">Add Note
v-for="note in notes" :key="note.id">
{{ note.title }}
{{ note.body }}
template>
Regarding deployment of our tutorial application, platforms like Vercel or Netlify automatically recognize the /server
directory and there is no need to configure anything extra — just deploy! For database use something like Railway, PlanetScale, or Supabase instead of local SQLite.
📖 Learn more
If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:
It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉
✅ Summary
Nuxt Server Routes feel almost like cheating — in the best way possible. If you're building side projects, MVPs, or even production apps that don't need a heavy backend, Nuxt is an amazing good choice.
Take care and see you next time!
And happy coding as always 🖥️