DEV Community

Alex Spinov
Alex Spinov

Posted on

Nuxt 3 Has a Free API — Full-Stack Vue with Auto-Imports and Nitro Server

Nuxt 3 is the full-stack Vue framework with auto-imports, file-based routing, hybrid rendering, and the Nitro server engine. Build fast websites that deploy anywhere.

Why Nuxt 3?

  • Auto-imports — components, composables, utilities — no manual imports
  • Hybrid rendering — SSR, SSG, ISR, SPA per route
  • Nitro server — deploys to 15+ platforms (Vercel, Cloudflare, Deno, etc.)
  • File-based routingpages/about.vue = /about

Quick Start

npx nuxi@latest init myapp
cd myapp
npm install
npm run dev
Enter fullscreen mode Exit fullscreen mode

Pages

<!-- pages/index.vue -->
<template>
  <div>
    <h1>Welcome</h1>
    <p>Count: {{ count }}</p>
    <button @click="count++">Increment</button>
  </div>
</template>

<script setup>
const count = ref(0); // ref is auto-imported!
</script>
Enter fullscreen mode Exit fullscreen mode
<!-- pages/users/[id].vue -->
<template>
  <div>
    <h1>{{ user.name }}</h1>
    <p>{{ user.email }}</p>
  </div>
</template>

<script setup>
const route = useRoute();
const { data: user } = await useFetch(`/api/users/${route.params.id}`);
</script>
Enter fullscreen mode Exit fullscreen mode

Server Routes (Nitro)

// server/api/users/index.get.ts
export default defineEventHandler(async () => {
  return await db.select().from(users);
});

// server/api/users/index.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);
  return await db.insert(users).values(body).returning();
});

// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id');
  return await db.select().from(users).where(eq(users.id, id));
});
Enter fullscreen mode Exit fullscreen mode

Composables

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

  const login = async (email: string, password: string) => {
    const data = await $fetch('/api/auth/login', {
      method: 'POST',
      body: { email, password },
    });
    user.value = data.user;
  };

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

  return { user, isLoggedIn, login, logout };
};
Enter fullscreen mode Exit fullscreen mode
<!-- Auto-imported! -->
<script setup>
const { user, isLoggedIn, logout } = useAuth();
</script>
Enter fullscreen mode Exit fullscreen mode

Middleware

// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
  const { isLoggedIn } = useAuth();
  if (!isLoggedIn.value && to.path !== '/login') {
    return navigateTo('/login');
  }
});
Enter fullscreen mode Exit fullscreen mode

Hybrid Rendering

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },          // Static at build
    '/blog/**': { isr: 3600 },         // Revalidate hourly
    '/dashboard/**': { ssr: false },   // SPA only
    '/api/**': { cors: true },         // CORS headers
  },
});
Enter fullscreen mode Exit fullscreen mode

Need data for your Nuxt app? Check out my Apify actors for web scraping, or email spinov001@gmail.com for custom Vue/Nuxt solutions.

Nuxt 3, Next.js, or SvelteKit — which meta-framework is best? Share below!

Top comments (0)