Nuxt Dynamic Routing
As a powerful framework built on top of Vue.js, Nuxt streamlines frontend development by offering a file-system based routing mechanism. While static routes work well for fixed pages like homepages and about pages, real-world applications frequently require handling variable paths—such as individual blog posts, user dashboards, or product catalogs. This is where dynamic routes become essential.
This article explores how to create, capture, and utilize dynamic routes in Nuxt, equipping you with the knowledge to handle complex navigation requirements effortlessly.
Unlike traditional Vue Router setups that rely on explicit path definitions with colons (like /user/:id), Nuxt generates routes automatically based on the file structure inside your pages directory. By wrapping filenames in square brackets ([]), you can easily designate dynamic segments.
For instance, creating a file named [id].vue instructs Nuxt to treat it as a dynamic route that captures an id parameter.
Imagine building a blogging platform where clicking on a specific article takes the reader to its respective details page. The target URL structure should look like /posts/1, /posts/2, and so on.
In Nuxt, the recommended directory structure for this scenario is:
pages/
--| index.vue
--| posts/
----| index.vue
----| [id].vue
Building the Dynamic Component
Open the pages/posts/[id].vue file. You can access the dynamic parameters using Vue's Composition API. Nuxt provides a built-in useRoute composable for inspecting the current route status.
<template>
<div class="post-container">
<h1>Article Details</h1>
<p>The current article ID is: {{ route.params.id }}</p>
<!-- Simulated async data fetching -->
<div v-if="post">
<h2>{{ post.title }}</h2>
<p>{{ post.content }}</p>
</div>
<p v-else>Loading...</p>
</div>
</template>
<script setup>
import { useRoute } from 'vue-router'
import { ref, onMounted } from 'vue'
const route = useRoute()
const post = ref(null)
onMounted(() => {
const postId = route.params.id
// In a real application, you would fetch data from an API here
post.value = {
id: postId,
title: `This is Article #${postId}`,
content: `Here is the full text content for article number ${postId}...`
}
})
</script>
In the example above, route.params.id directly corresponds to the id defined in the [id].vue filename. If a user visits /posts/42, the value of route.params.id will be 42.
Advanced Dynamic Routing Patterns
Beyond basic single-parameter matching, Nuxt supports more sophisticated routing patterns to handle complex use cases.
1. Optional Dynamic Routes
If you need a parameter to be completely optional—meaning a single component should handle both /posts and /posts/1—you can use double square brackets, such as [[id]].vue.
2. Catch-All Routes
Sometimes your application needs to match nested paths of arbitrary depth, perfect for documentation viewers or custom 404 pages. This is achieved using spread brackets with an ellipsis, commonly known as [...slug].vue.
Directory structure:
pages/
--| [...slug].vue
Accessing the parameters inside the component:
<script setup>
const route = useRoute()
// route.params.slug returns an array containing each path segment
console.log(route.params.slug)
// Visiting /docs/getting-started/installation yields ['docs', 'getting-started', 'installation']
</script>
Parameter Validation and Security
Because dynamic route segments are heavily influenced by user input, validating them before rendering the page is a crucial security and UX practice. Nuxt offers the definePageMeta macro to validate route parameters easily.
For instance, if you want to ensure that the id parameter strictly consists of numeric characters:
<script setup>
definePageMeta({
validate: async (route) => {
const id = route.params.id
// Return true only if the id is purely numeric
return /^\d+$/.test(id)
}
})
</script>
If validation fails and returns false, Nuxt will automatically trigger a 404 error page, stopping invalid requests from executing further down the lifecycle.
Conclusion
Nuxt's dynamic routing mechanism dramatically reduces configuration overhead through intuitive file-naming conventions:
- Use
[id].vueto capture basic dynamic parameters. - Use
useRoute()to access parameters anywhere within your component script. - Leverage
[...slug].vueto handle catch-all and deeply nested routes. - Combine with
definePageMetafor robust parameter validation and enhanced security.
By mastering these techniques, you will be well-prepared to design and manage complex page navigation structures in any modern Nuxt application.