_CORE
AI & Agentic Systems Core Information Systems Cloud & Platform Engineering Data Platform & Integration Security & Compliance QA, Testing & Observability IoT, Automation & Robotics Mobile & Digital Banking & Finance Insurance Public Administration Defense & Security Healthcare Energy & Utilities Telco & Media Manufacturing Logistics & E-commerce Retail & Loyalty
References Technologies Blog Know-how Tools
About Collaboration Careers
CS EN
Let's talk

Nuxt 3 — Full-Stack Development with Vue and Nitro Engine

27. 11. 2025 4 min read intermediate

A complete guide to full-stack development with Nuxt 3. Server routes, API layer, Nitro engine, auto-imports and edge deployment.

Introduction to Nuxt 3

Nuxt 3 is a full-stack framework built on Vue 3, powered by the Nitro engine. It provides everything needed to build modern web applications with server-side rendering, API routes, and edge deployment capabilities.

Key features of Nuxt 3: - Vue 3 & Composition API - Modern reactive framework - Nitro engine - Universal deployment and server engine - Auto-imports - Zero-config imports for components and composables - TypeScript - First-class TypeScript support - File-based routing - Automatic route generation - Server API - Built-in API layer

Project Structure

project/
├── components/          # Vue components (auto-imported)
├── pages/              # File-based routing
├── server/
│   └── api/           # API endpoints
├── composables/       # Vue composables (auto-imported)
├── middleware/        # Route middleware
├── plugins/          # Nuxt plugins
├── layouts/          # Layout components
└── nuxt.config.ts    # Configuration

Pages and Routing

File-based routing with automatic code splitting:

<!-- pages/index.vue -->
<template>
  <div>
    <h1>{{ data.title }}</h1>
    <NuxtLink to="/about">About</NuxtLink>
  </div>
</template>

<script setup>
// Auto-imported composables
const { data } = await useFetch('/api/homepage')

// SEO with built-in composables
useSeoMeta({
  title: 'My Nuxt App',
  ogDescription: 'My amazing site.',
  ogImage: '/image.png'
})
</script>

Dynamic routes with parameters:

<!-- pages/blog/[slug].vue -->
<template>
  <article>
    <h1>{{ post.title }}</h1>
    <div v-html="post.content" />
  </article>
</template>

<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)

if (!post.value) {
  throw createError({ statusCode: 404, statusMessage: 'Post not found' })
}
</script>

Server API Routes

Create API endpoints in the server/api directory:

// server/api/posts/index.get.ts
export default defineEventHandler(async (event) => {
  // Query parameters
  const query = getQuery(event)
  const limit = query.limit || 10

  // Mock data (replace with database query)
  const posts = await $fetch('https://api.example.com/posts', {
    params: { limit }
  })

  return {
    posts,
    meta: {
      total: posts.length,
      limit
    }
  }
})

POST endpoint with validation:

// server/api/posts/index.post.ts
import { z } from 'zod'

const createPostSchema = z.object({
  title: z.string().min(1),
  content: z.string().min(10),
  authorId: z.number()
})

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  // Validate input
  const result = createPostSchema.safeParse(body)
  if (!result.success) {
    throw createError({
      statusCode: 400,
      statusMessage: 'Validation failed',
      data: result.error.errors
    })
  }

  // Create post (replace with database logic)
  const post = await createPost(result.data)

  return { post }
})

Composables and State Management

Create reusable composables:

// composables/useAuth.ts
export const useAuth = () => {
  const user = useState('auth.user', () => null)
  const isLoggedIn = computed(() => !!user.value)

  const login = async (credentials: LoginCredentials) => {
    const { data } = await $fetch('/api/auth/login', {
      method: 'POST',
      body: credentials
    })
    user.value = data.user
    await navigateTo('/dashboard')
  }

  const logout = async () => {
    await $fetch('/api/auth/logout', { method: 'POST' })
    user.value = null
    await navigateTo('/login')
  }

  return {
    user,
    isLoggedIn,
    login,
    logout
  }
}

Use in components:

<template>
  <div>
    <div v-if="isLoggedIn">
      Welcome, {{ user.name }}!
      <button @click="logout">Logout</button>
    </div>
    <div v-else>
      <LoginForm @submit="login" />
    </div>
  </div>
</template>

<script setup>
const { user, isLoggedIn, login, logout } = useAuth()
</script>

Middleware and Layouts

Route middleware for authentication:

// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const { isLoggedIn } = useAuth()

  if (!isLoggedIn.value) {
    return navigateTo('/login')
  }
})

Layout with navigation:

<!-- layouts/default.vue -->
<template>
  <div class="app">
    <header class="header">
      <nav>
        <NuxtLink to="/">Home</NuxtLink>
        <NuxtLink to="/about">About</NuxtLink>
        <NuxtLink to="/blog">Blog</NuxtLink>
      </nav>
    </header>
    <main>
      <slot />
    </main>
  </div>
</template>

<style scoped>
.app {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.header {
  background: #f8f9fa;
  padding: 1rem;
}
</style>

Configuration and Deployment

Basic Nuxt configuration:

// nuxt.config.ts
export default defineNuxtConfig({
  // Development tools
  devtools: { enabled: true },

  // CSS framework
  css: ['~/assets/css/main.css'],

  // Build configuration
  nitro: {
    preset: 'vercel-edge' // or 'netlify', 'cloudflare-pages'
  },

  // Runtime config
  runtimeConfig: {
    // Private keys (server-side only)
    apiSecret: process.env.API_SECRET,

    // Public keys (exposed to client)
    public: {
      apiBase: process.env.API_BASE || '/api'
    }
  },

  // Modules
  modules: [
    '@pinia/nuxt',
    '@nuxtjs/tailwindcss'
  ]
})

Deploy to Vercel:

# Build for production
npm run build

# Deploy to Vercel
vercel --prod

Best Practices

  1. Use auto-imports - Leverage Nuxt’s zero-config imports
  2. Server-side state - Use useState for reactive server state
  3. SEO optimization - Use useSeoMeta and useHead
  4. Error handling - Implement proper error pages and handling
  5. TypeScript - Enable TypeScript for better DX
  6. Composables - Create reusable logic with composables

Nuxt 3 provides a powerful full-stack development experience with Vue 3, combining client-side reactivity with server-side capabilities in a unified framework.

vue.jsnuxt 3fullstacknitro
Share:

CORE SYSTEMS tým

Stavíme core systémy a AI agenty, které drží provoz. 15 let zkušeností s enterprise IT.