Pages and File Routing
File-based routing in pages/, dynamic routes, layouts, and navigating with NuxtLink.
File-based routing in pages/
Each .vue file inside pages/ becomes a route, matching its path within the folder to a URL:
pages/
├── index.vue → /
├── about.vue → /about
└── users/
├── index.vue → /users
└── [id].vue → /users/:id
<!-- pages/index.vue -->
<template>
<h1>Welcome home</h1>
</template>
Dynamic routes
A filename wrapped in square brackets captures a dynamic URL segment, read with the useRoute() composable:
<!-- pages/users/[id].vue -->
<script setup lang="ts">
const route = useRoute();
const userId = route.params.id; // e.g. "42" for /users/42
</script>
<template>
<h1>User {{ userId }}</h1>
</template>
A catch-all works the same way it does across most file-based routers — pages/shop/[...slug].vue matches /shop/a, /shop/a/b, and so on, with route.params.slug as an array of the matched segments.
Layouts
A layout is a shared shell — navigation, footer, page structure — that wraps page content via a <slot />. The file layouts/default.vue applies automatically to every page that doesn't specify otherwise:
<!-- layouts/default.vue -->
<template>
<div>
<nav>My Site</nav>
<slot />
<footer>© 2026</footer>
</div>
</template>
A page opts into a different, named layout with definePageMeta:
<!-- layouts/admin.vue -->
<template>
<div class="admin-shell">
<aside>Admin sidebar</aside>
<slot />
</div>
</template>
<!-- pages/admin/dashboard.vue -->
<script setup lang="ts">
definePageMeta({ layout: 'admin' });
</script>
<template>
<h1>Dashboard</h1>
</template>
Navigating with NuxtLink
<NuxtLink> replaces a plain <a> tag for internal navigation — it renders an actual <a> under the hood, but handles client-side routing and automatically prefetches the linked page:
<template>
<nav>
<NuxtLink to="/">Home</NuxtLink>
<NuxtLink to="/about">About</NuxtLink>
<NuxtLink :to="`/users/${userId}`">View user</NuxtLink>
</nav>
</template>
Common mistakes
- Forgetting
<NuxtPage />inapp.vue— the single most common reason a fresh Nuxt project's routes appear to "not work." - Using a plain
<a href="...">for internal links instead of<NuxtLink>, losing client-side navigation and prefetching. - Expecting a custom layout to apply automatically the way
default.vuedoes — any layout other thandefaultmust be explicitly selected per-page withdefinePageMeta({ layout: '...' }).