DEV Community

Alex Spinov
Alex Spinov

Posted on

Nuxt 3 Has Free Full-Stack Powers That Make Next.js Developers Jealous

Next.js has App Router complexity. Nuxt 3 has auto-imports, server routes, and zero-config — everything just works.

Auto-Imports (Zero Import Statements)

<script setup>
// No imports needed! Nuxt auto-imports:
// - Vue APIs (ref, computed, watch, onMounted)
// - Nuxt composables (useRoute, useFetch, useState)
// - Your components (from components/ directory)
// - Your composables (from composables/ directory)
// - Your utils (from utils/ directory)

const count = ref(0)  // ref is auto-imported
const route = useRoute()  // useRoute is auto-imported
const { data } = await useFetch("/api/users")  // useFetch is auto-imported
</script>
Enter fullscreen mode Exit fullscreen mode

Data Fetching

<script setup>
// SSR + client-side fetching with caching
const { data: users, pending, error, refresh } = await useFetch("/api/users", {
  query: { page: 1 },
  transform: (data) => data.map(u => ({ ...u, fullName: `${u.first} ${u.last}` })),
});

// Lazy loading (client-side only)
const { data: stats } = await useLazyFetch("/api/stats");

// With key for caching
const { data: user } = await useFetch(`/api/users/${route.params.id}`, {
  key: `user-${route.params.id}`,
});
</script>
Enter fullscreen mode Exit fullscreen mode

Server Routes (API in Your App)

// server/api/users.get.ts
export default defineEventHandler(async (event) => {
  const query = getQuery(event);
  return db.users.findMany({ take: query.limit || 10 });
});

// server/api/users.post.ts
export default defineEventHandler(async (event) => {
  const body = await readBody(event);
  return db.users.create({ data: body });
});

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

File-based API routes. GET/POST/PUT/DELETE by filename suffix.

Server Middleware

// server/middleware/auth.ts
export default defineEventHandler((event) => {
  const token = getHeader(event, "authorization");
  if (event.path.startsWith("/api/admin") && !token) {
    throw createError({ statusCode: 401, message: "Unauthorized" });
  }
});
Enter fullscreen mode Exit fullscreen mode

Rendering Modes (Per Route!)

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    "/": { prerender: true },           // Static (build time)
    "/blog/**": { swr: 3600 },          // ISR (revalidate hourly)
    "/admin/**": { ssr: false },         // SPA (client-only)
    "/api/**": { cors: true },           // API with CORS
    "/old-page": { redirect: "/new" },   // Redirect
  },
});
Enter fullscreen mode Exit fullscreen mode

Different rendering strategy per route. No workarounds needed.

Nuxt Modules (200+)

npx nuxi module add @nuxtjs/tailwindcss
npx nuxi module add @sidebase/nuxt-auth
npx nuxi module add @nuxt/image
npx nuxi module add @nuxt/content  # Markdown/MDC-based CMS
npx nuxi module add nuxt-security
Enter fullscreen mode Exit fullscreen mode

Deploy Everywhere

Nuxt uses Nitro under the hood — one build, any platform:

NITRO_PRESET=vercel npx nuxi build
NITRO_PRESET=cloudflare npx nuxi build
NITRO_PRESET=node-server npx nuxi build
Enter fullscreen mode Exit fullscreen mode

Need full-stack web development? I build web tools and data solutions. Email spinov001@gmail.com or check my Apify tools.

Top comments (0)