iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Nuxt

Nuxt is the meta-framework on top of Vue: server-side rendering, file-based routing, server endpoints, data fetching, hybrid rendering modes (SSR / SSG / ISR / SPA), and a module ecosystem. Reach for Nuxt when you build a real Vue app and want SEO, fast TTFB, and a clean server story.

A small Nuxt app: pages, fetch, server route, layout

EXAMPLE
// 1) Scaffold
// npx nuxi@latest init shop
// cd shop && npm install
// npm run dev

// 2) File-based routing — pages/ becomes routes
// pages/
// ├── index.vue                  -> /
// ├── products/
// │   ├── index.vue              -> /products
// │   └── [sku].vue              -> /products/:sku
// └── account/
//     └── orders/[id].vue        -> /account/orders/:id

// 3) Layout
// layouts/default.vue
<template>
  <div>
    <header class='border-b p-3'>
      <NuxtLink to='/'>Shop</NuxtLink>
      <NuxtLink to='/products' class='ml-4'>Products</NuxtLink>
    </header>
    <main class='p-4'>
      <slot />
    </main>
  </div>
</template>

// pages/index.vue
<template>
  <h1>Welcome</h1>
  <p>Featured today: {{ featured.name }}</p>
</template>

<script setup>
// Data fetched on the SERVER for SSR, on the CLIENT for navigation
const { data: featured } = await useFetch('/api/featured');
</script>

// 4) Server endpoints — file-based, run on Node (or edge)
// server/api/featured.get.ts
export default defineEventHandler(async () => {
  return { id: 'p1', name: 'Wool Jacket', price: 19900 };
});

// server/api/products/index.get.ts
export default defineEventHandler(async (event) => {
  const query = getQuery(event);
  const status = String(query.status ?? 'active');
  // hit your DB here
  return [{ sku: 'p1', name: 'Wool Jacket', status }];
});

// server/api/products/[sku].get.ts
export default defineEventHandler(async (event) => {
  const sku = getRouterParam(event, 'sku');
  // hit your DB here
  if (!sku) throw createError({ statusCode: 400, message: 'sku required' });
  return { sku, name: 'Wool Jacket', price: 19900 };
});

// 5) Dynamic page with data fetching
// pages/products/[sku].vue
<template>
  <h1>{{ product.name }}</h1>
  <p>{{ product.price / 100 }}</p>
</template>

<script setup>
const route = useRoute();
const { data: product, error } = await useFetch('/api/products/' + route.params.sku);
if (error.value) throw createError({ statusCode: 404, message: 'Not found' });
</script>

// 6) Composable for shared logic
// composables/useCart.ts
import { ref, computed } from 'vue';
const items = ref<{ sku: string; qty: number; priceCents: number }[]>([]);

export const useCart = () => ({
  items,
  count: computed(() => items.value.reduce((s, i) => s + i.qty, 0)),
  add(sku: string, priceCents: number, qty = 1) {
    const found = items.value.find((i) => i.sku === sku);
    if (found) found.qty += qty;
    else items.value.push({ sku, qty, priceCents });
  },
});

// 7) Middleware (auth gate)
// middleware/auth.global.ts
export default defineNuxtRouteMiddleware((to) => {
  if (to.path.startsWith('/account')) {
    const user = useState('user');
    if (!user.value) return navigateTo('/login?next=' + encodeURIComponent(to.fullPath));
  }
});

// 8) Rendering modes per route
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/':                    { prerender: true },                 // SSG
    '/blog/**':             { isr: 3600 },                       // ISR (revalidate hourly)
    '/products/**':         { swr: 600 },                        // SWR
    '/api/**':              { cors: true },
    '/account/**':          { ssr: true, headers: { 'cache-control': 'no-store' } },
  },
});

// 9) Modules — the Nuxt ecosystem
// npm install @nuxtjs/tailwindcss @nuxt/image @nuxtjs/i18n @nuxtjs/seo @sidebase/nuxt-auth
// nuxt.config.ts -> modules: ['@nuxtjs/tailwindcss', '@nuxt/image']

// 10) Deploy
// Vercel / Netlify / Cloudflare Pages: auto-detect Nuxt
// Self-host: 'nuxt build' -> output/ + start with 'node .output/server/index.mjs'
// Static: 'nuxt generate' -> dispatch/' static files for any CDN

// 11) Pitfalls
// - Using browser-only APIs in setup() that runs on the server
//   -> guard with process.client or use onMounted
// - Calling fetch() instead of useFetch -> no server-side execution
// - Big bundles from missing route-level code splitting (Nuxt does it by default; verify)
// - Setting cookies via document.cookie (set them via the server response instead)

// 12) Decision matrix
// - SEO matters?                           SSR via Nuxt
// - Static content?                        Nuxt + prerender
// - Need server endpoints?                 Nuxt server/api
// - Edge runtime?                          Nuxt + Cloudflare deploy
// - Just a SPA?                            Nuxt is overkill; vue create + vite

Why it matters

Nuxt is the Vue equivalent of Next.js in 2026 — file-based routing, SSR by default, hybrid render modes per route, and a clean server/api story. Reach for it whenever the app is more than a small SPA; the SEO + TTFB win + the developer experience pay for the framework cost within a week.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// pages/index.vue
<script setup>
const { data } = await useFetch('/api/users');
</script>
<template>
    <ul><li v-for="u in data" :key="u.id">{{ u.name }}</li></ul>
</template>
Try it Yourself »

Discussion

Loading…