Nuxt.js

Standard full-stack framework in Vue.js ecosystem. Strongly supports large-scale application development with Composition API and TypeScript integration.

frameworkVue.jsfullstackSSRSSGhybrid-renderingTypeScriptauto-import

GitHub Overview

nuxt/nuxt

The Intuitive Vue Framework.

Stars57,911
Watchers787
Forks5,339
Created:October 26, 2016
Language:TypeScript
License:MIT License

Topics

csrframeworkfull-stackhacktoberfesthybridnodenuxtserver-renderingssgssrstatic-site-generatoruniversalvue

Star History

nuxt/nuxt Star History
Data as of: 8/13/2025, 01:43 AM

Framework

Nuxt.js

Overview

Nuxt.js is a free and open-source full-stack web framework built on Vue.js. It's designed for creating type-safe, performant, and production-grade web applications and websites. The framework aims to simplify web development by providing conventions and automation, allowing developers to focus on features.

Details

Key Features

  • Multiple Rendering Modes: Supports various rendering strategies including Server-Side Rendering (SSR) by default, Static Site Generation (SSG), Hybrid Rendering, and Edge-Side Rendering
  • File-based Routing: Routes are automatically generated based on the structure of your pages/ directory, simplifying route configuration
  • Code Splitting: Automatically splits code into smaller chunks to reduce initial load times
  • Auto-imports: Vue composables, components, and utilities can be used without explicit imports, benefiting from tree-shaking and optimized JS bundles
  • Data Fetching Utilities: Provides composables for SSR-compatible data fetching
  • Zero-config TypeScript Support: Built-in TypeScript support with auto-generated types
  • Configured Build Tools: Uses Vite by default for hot module replacement (HMR) in development and optimized production builds. Also supports Webpack and Rspack as alternative bundlers
  • Server Engine (Nitro): A server engine that enables full-stack capabilities, API routes, serverless support, and cross-platform deployment

Architecture

Nuxt.js adopts a modular architecture, allowing you to select and use only the features you need. The framework's core integrates proven tools such as Vue.js, Vue Router, Vite/Webpack, h3, and Nitro.

Pros and Cons

Benefits

  • Excellent SEO: Server-side rendering allows search engines to better index pages as HTML content is immediately available
  • Faster Initial Page Load Time: SSR sends a fully rendered HTML page to the browser, improving perceived load time and user experience
  • Better Performance on Low-Powered Devices: Reduces the amount of JavaScript needed on the client-side
  • Better Accessibility: Content is immediately available, aiding assistive technologies
  • Easier Caching: Pages can be cached on the server-side, further improving performance
  • Developer Experience: Automation, conventions, and features like auto-imports and zero-config TypeScript enhance development speed
  • Full-stack Capabilities: With its server/ directory and Nitro engine, Nuxt allows building both frontend and backend functionalities within a single framework
  • Flexible Rendering: Fine-grained control over performance and deployment with universal rendering (SSR), client-side rendering (CSR), hybrid rendering with route rules, and edge-side rendering

Drawbacks

  • Development Constraints: Writing code that runs seamlessly on both server and browser environments can be tricky due to differing APIs
  • Cost: Running a server for on-the-fly rendering adds a monthly cost, though this can be mitigated by leveraging edge-side rendering
  • Learning Curve: Need to learn Nuxt.js-specific concepts and conventions in addition to Vue.js
  • Over-engineering: Might be too feature-rich for simple SPAs

Key Links

Code Examples

Hello World

<!-- pages/index.vue -->
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>Welcome to Nuxt!</p>
  </div>
</template>

<script setup>
// Composition API with auto-import
const title = 'Hello Nuxt!'

// Meta management
useHead({
  title: 'Home',
  meta: [
    { name: 'description', content: 'My amazing site.' }
  ]
})
</script>

Page Routing and Navigation

<!-- pages/about.vue -->
<template>
  <div>
    <h1>About Page</h1>
    <NuxtLink to="/">Back to Home</NuxtLink>
    <NuxtLink to="/products">Product List</NuxtLink>
  </div>
</template>

<!-- pages/products/[id].vue - Dynamic Route -->
<template>
  <div>
    <h1>Product: {{ $route.params.id }}</h1>
    <button @click="$router.back()">Back</button>
  </div>
</template>

<script setup>
// Get parameters
const route = useRoute()
const productId = route.params.id
</script>

Data Fetching

<template>
  <div>
    <h1>User List</h1>
    <div v-if="pending">Loading...</div>
    <div v-else-if="error">Error: {{ error }}</div>
    <ul v-else>
      <li v-for="user in data" :key="user.id">
        {{ user.name }} - {{ user.email }}
      </li>
    </ul>
    <button @click="refresh()">Refresh</button>
  </div>
</template>

<script setup>
// useFetch - SSR-compatible data fetching
const { data, pending, error, refresh } = await useFetch('/api/users')

// useLazyFetch - Asynchronous fetching
const { data: posts } = await useLazyFetch('/api/posts')

// $fetch - Manual fetching
const submitForm = async (formData) => {
  try {
    const result = await $fetch('/api/submit', {
      method: 'POST',
      body: formData
    })
    console.log('Submit success:', result)
  } catch (error) {
    console.error('Submit error:', error)
  }
}
</script>

State Management (Pinia)

// stores/counter.js
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  
  function increment() {
    count.value++
  }
  
  function reset() {
    count.value = 0
  }
  
  return { count, doubleCount, increment, reset }
})
<!-- pages/counter.vue -->
<template>
  <div>
    <h1>Counter: {{ counter.count }}</h1>
    <p>Double: {{ counter.doubleCount }}</p>
    <button @click="counter.increment()">+1</button>
    <button @click="counter.reset()">Reset</button>
  </div>
</template>

<script setup>
const counter = useCounterStore()
</script>

Server API

// server/api/users.js
export default defineEventHandler(async (event) => {
  const method = getMethod(event)
  
  if (method === 'GET') {
    // Get user list
    return await getUsersFromDatabase()
  }
  
  if (method === 'POST') {
    // Create new user
    const body = await readBody(event)
    return await createUser(body)
  }
})

// server/api/users/[id].js
export default defineEventHandler(async (event) => {
  const id = getRouterParam(event, 'id')
  const method = getMethod(event)
  
  if (method === 'GET') {
    return await getUserById(id)
  }
  
  if (method === 'PUT') {
    const body = await readBody(event)
    return await updateUser(id, body)
  }
  
  if (method === 'DELETE') {
    return await deleteUser(id)
  }
})

Middleware and Authentication

// middleware/auth.js
export default defineNuxtRouteMiddleware((to, from) => {
  const user = useAuthUser()
  
  if (!user.value) {
    return navigateTo('/login')
  }
})

// middleware/admin.global.js - Global Middleware
export default defineNuxtRouteMiddleware((to) => {
  if (to.path.startsWith('/admin')) {
    const user = useAuthUser()
    
    if (!user.value?.isAdmin) {
      throw createError({
        statusCode: 403,
        statusMessage: 'Access Denied'
      })
    }
  }
})
<!-- pages/profile.vue -->
<script setup>
// Apply middleware at page level
definePageMeta({
  middleware: 'auth'
})
</script>