Nuxt 3 is a meta-framework built on Vue 3 that provides SSR, SSG, file-based routing, and much more — out of the box, with no configuration. Think of it as the autopilot system of the NOVA LAB station — everything is configured and ready to go.
1npx nuxi@latest init nova-lab-app
2cd nova-lab-app
3npm install
4npm run devIn Nuxt 3, you don't configure the router manually. The file structure in the
pages/ folder automatically creates routes:1pages/
2├── index.vue → /
3├── about.vue → /about
4├── crew/
5│ ├── index.vue → /crew
6│ └── [id].vue → /crew/123
7└── modules/
8 └── [...slug].vue → /modules/any/nested/pathThe
index.vue file is the main page of a given directory. Files with square brackets [id].vue are dynamic parameters.Layouts define the shared structure of pages (navigation, footer):
1<!-- layouts/default.vue -->
2<template>
3 <div class="station">
4 <nav class="nav">
5 <NuxtLink to="/">Home</NuxtLink>
6 <NuxtLink to="/about">About</NuxtLink>
7 <NuxtLink to="/crew">Crew</NuxtLink>
8 </nav>
9
10 <main>
11 <slot />
12 </main>
13
14 <footer>NOVA LAB © 2087</footer>
15 </div>
16</template>Pages automatically use the
default layout. You can change the layout on a specific page:1<!-- pages/dashboard.vue -->
2<script setup lang="ts">
3definePageMeta({
4 layout: 'admin'
5})
6</script>useFetch is a Nuxt composable for fetching data. It works both on the server (SSR) and on the client:1<script setup lang="ts">
2interface CrewMember {
3 id: number
4 name: string
5 role: string
6}
7
8// useFetch works on server and client
9const { data: crew, pending, error } = await useFetch<CrewMember[]>(
10 '/api/crew'
11)
12</script>
13
14<template>
15 <div v-if="pending">Loading...</div>
16 <div v-else-if="error">Error: {{ error.message }}</div>
17 <ul v-else>
18 <li v-for="member in crew" :key="member.id">
19 {{ member.name }} — {{ member.role }}
20 </li>
21 </ul>
22</template>useFetch automatically:pending, error, data, refresh statesuseAsyncData gives full control over the data fetching logic:1<script setup lang="ts">
2const { data: stats } = await useAsyncData('station-stats', () => {
3 return $fetch('/api/stats')
4})
5
6// With data transformation
7const { data: modules } = await useAsyncData(
8 'modules',
9 () => $fetch('/api/modules'),
10 {
11 transform: (data) => data.filter(m => m.active),
12 watch: [selectedSector] // automatic refresh
13 }
14)
15</script>Nuxt 3 automatically imports:
ref, computed, watch...)useFetch, useRoute, useState...)components/utils/ and composables/No need to write
import { ref } from 'vue' — Nuxt does it for us!1<script setup lang="ts">
2// No imports! Nuxt auto-imports ref, computed, useFetch
3const count = ref(0)
4const doubled = computed(() => count.value * 2)
5
6const { data } = await useFetch('/api/data')
7</script>1nova-lab-app/
2├── pages/ # File-based routing
3├── components/ # Auto-imported components
4├── composables/ # Auto-imported composables
5├── layouts/ # Page layouts
6├── server/ # API endpoints (Nitro)
7│ └── api/ # /api/* routes
8├── public/ # Static files
9├── app.vue # Root component
10└── nuxt.config.ts # Nuxt configurationNuxt 3 uses Nitro to handle API endpoints:
1// server/api/crew.ts
2export default defineEventHandler((event) => {
3 return [
4 { id: 1, name: 'Dr. Nova', role: 'Commander' },
5 { id: 2, name: 'Atlas', role: 'Navigator' },
6 { id: 3, name: 'Echo', role: 'Engineer' }
7 ]
8})