Routing

Nuxt.js automatically generates the vue-router configuration based on your file tree of Vue files inside the pages directory.

To navigate between pages, we recommend to use the <nuxt-link> component.

For example:

  1. <template>
  2. <nuxt-link to="/">Home page</nuxt-link>
  3. </template>

Basic Routes

This file tree:

  1. pages/
  2. --| user/
  3. -----| index.vue
  4. -----| one.vue
  5. --| index.vue

will automatically generate:

  1. router: {
  2. routes: [
  3. {
  4. name: 'index',
  5. path: '/',
  6. component: 'pages/index.vue'
  7. },
  8. {
  9. name: 'user',
  10. path: '/user',
  11. component: 'pages/user/index.vue'
  12. },
  13. {
  14. name: 'user-one',
  15. path: '/user/one',
  16. component: 'pages/user/one.vue'
  17. }
  18. ]
  19. }

Dynamic Routes

To define a dynamic route with a parameter, you need to define a .vue file OR a directory prefixed by an underscore.

Watch a free lesson about dynamic routes on Vue School

This file tree:

  1. pages/
  2. --| _slug/
  3. -----| comments.vue
  4. -----| index.vue
  5. --| users/
  6. -----| _id.vue
  7. --| index.vue

will automatically generate:

  1. router: {
  2. routes: [
  3. {
  4. name: 'index',
  5. path: '/',
  6. component: 'pages/index.vue'
  7. },
  8. {
  9. name: 'users-id',
  10. path: '/users/:id?',
  11. component: 'pages/users/_id.vue'
  12. },
  13. {
  14. name: 'slug',
  15. path: '/:slug',
  16. component: 'pages/_slug/index.vue'
  17. },
  18. {
  19. name: 'slug-comments',
  20. path: '/:slug/comments',
  21. component: 'pages/_slug/comments.vue'
  22. }
  23. ]
  24. }

As you can see the route named users-id has the path :id? which makes it optional, if you want to make it required, create an index.vue file in the users/_id directory instead.

Warning: dynamic routes are ignored by the generate command: API Configuration generate

Validate Route Params

Nuxt.js lets you define a validator method inside your dynamic route component.

In this example: pages/users/_id.vue

  1. export default {
  2. validate ({ params }) {
  3. // Must be a number
  4. return /^\d+$/.test(params.id)
  5. }
  6. }

If the validate method does not return true or a Promise that resolve to true, or throws an Error, Nuxt.js will automatically load the 404 error page or 500 error page in case of an error.

More information about the validate method: API Pages validate

Nested Routes

Nuxt.js lets you create nested route by using the children routes of vue-router.

To define the parent component of a nested route, you need to create a Vue file with the same name as the directory which contain your children views.

Warning: don't forget to include <nuxt-child/> inside the parent component (.vue file).

This file tree:

  1. pages/
  2. --| users/
  3. -----| _id.vue
  4. -----| index.vue
  5. --| users.vue

will automatically generate:

  1. router: {
  2. routes: [
  3. {
  4. path: '/users',
  5. component: 'pages/users.vue',
  6. children: [
  7. {
  8. path: '',
  9. component: 'pages/users/index.vue',
  10. name: 'users'
  11. },
  12. {
  13. path: ':id',
  14. component: 'pages/users/_id.vue',
  15. name: 'users-id'
  16. }
  17. ]
  18. }
  19. ]
  20. }

Dynamic Nested Routes

This scenario should not often happen, but it is possible with Nuxt.js: having dynamic children inside dynamic parents.

This file tree:

  1. pages/
  2. --| _category/
  3. -----| _subCategory/
  4. --------| _id.vue
  5. --------| index.vue
  6. -----| _subCategory.vue
  7. -----| index.vue
  8. --| _category.vue
  9. --| index.vue

will automatically generate:

  1. router: {
  2. routes: [
  3. {
  4. path: '/',
  5. component: 'pages/index.vue',
  6. name: 'index'
  7. },
  8. {
  9. path: '/:category',
  10. component: 'pages/_category.vue',
  11. children: [
  12. {
  13. path: '',
  14. component: 'pages/_category/index.vue',
  15. name: 'category'
  16. },
  17. {
  18. path: ':subCategory',
  19. component: 'pages/_category/_subCategory.vue',
  20. children: [
  21. {
  22. path: '',
  23. component: 'pages/_category/_subCategory/index.vue',
  24. name: 'category-subCategory'
  25. },
  26. {
  27. path: ':id',
  28. component: 'pages/_category/_subCategory/_id.vue',
  29. name: 'category-subCategory-id'
  30. }
  31. ]
  32. }
  33. ]
  34. }
  35. ]
  36. }

Unknown Dynamic Nested Routes

If you do not know the depth of your URL structure, you can use .vue to dynamically match nested paths.This will handle requests that do not match a _more specific request.

This file tree:

  1. pages/
  2. --| people/
  3. -----| _id.vue
  4. -----| index.vue
  5. --| _.vue
  6. --| index.vue

Will handle requests like this:

PathFile
/index.vue
/peoplepeople/index.vue
/people/123people/id.vue
/about.vue
/about/careers.vue
/about/careers/chicago.vue

Note: Handling 404 pages is now up to the logic of the _.vue page. More on 404 redirecting can be found here.

Named Views

To render named views you can use <nuxt name="top"/> or <nuxt-child name="top"/> components in your layout/page. To specify named view of page we need to extend router config in nuxt.config.js file:

  1. export default {
  2. router: {
  3. extendRoutes (routes, resolve) {
  4. const index = routes.findIndex(route => route.name === 'main')
  5. routes[index] = {
  6. ...routes[index],
  7. components: {
  8. default: routes[index].component,
  9. top: resolve(__dirname, 'components/mainTop.vue')
  10. },
  11. chunkNames: {
  12. top: 'components/mainTop'
  13. }
  14. }
  15. }
  16. }
  17. }

It require to extend interested route with 2 properties components and chunkNames. Named view in this config example has name top.

To see an example, take a look at the named-views example.

SPA fallback

You can enable SPA fallbacks for dynamic routes too. Nuxt.js will output an extra file that is the same as the index.html that would be used in mode: 'spa'. Most static hosting services can be configured to use the SPA template if no file matches. It won't include the head info or any HTML, but it will still resolve and load the data from the API.

We enable this in our nuxt.config.js file:

  1. export default {
  2. generate: {
  3. fallback: true, // if you want to use '404.html' instead of the default '200.html'
  4. fallback: 'my-fallback/file.html' // if your hosting needs a custom location
  5. }
  6. }

Locally Accessing Route Params

You can access the current route parameters within your local page or component by referencing this.$route.params.{parameterName}. For example, if you had a dynamic users page (users_id.vue) and wanted to access the id parameter to load the user or process information, you could access the variable like this: this.$route.params.id.

Implementation for Surge

Surge can handle both 200.html and 404.html. generate.fallback is set to 200.html by default, so no need to change it.

Implementation for GitHub Pages and Netlify

GitHub Pages and Netlify recognize the 404.html file automatically, so setting generate.fallback to true is all we have to do!

Implementation for Firebase Hosting

Firebase Hosting can handle the 404.html file automatically, so setting generate.fallback to true will render the error page with a default response code of 404.

Transitions

Nuxt.js uses the <transition> component to let you create amazing transitions/animations between your routes.

Global Settings

Info: Nuxt.js default transition name is "page".

To add a fade transition to every page of your application, we need a CSS file that is shared across all our routes, so we start by creating a file in the assets folder.

Our global css in assets/main.css:

  1. .page-enter-active, .page-leave-active {
  2. transition: opacity .5s;
  3. }
  4. .page-enter, .page-leave-to {
  5. opacity: 0;
  6. }

Then we add its path to the css array in our nuxt.config.js file:

  1. export default {
  2. css: [
  3. '~/assets/main.css'
  4. ]
  5. }

More information about the transition key: API Configuration transition

Page Settings

You can also define a custom transition for a specific page with the transition property.

We add a new class in our global css in assets/main.css:

  1. .test-enter-active, .test-leave-active {
  2. transition: opacity .5s;
  3. }
  4. .test-enter, .test-leave-active {
  5. opacity: 0;
  6. }

Then we use the transition property to define the class name to use for this page transition:

  1. export default {
  2. transition: 'test'
  3. }

More information about the transition property: API Pages transition

Middleware

Middleware lets you define custom functions that can be run before rendering either a page or a group of pages.

Shared middleware should be placed in the middleware/ directory. The filename will be the name of the middleware (middleware/auth.js will be the auth middleware). You can also defined page-specific middleware by using a function directly, see anonymous middleware.

A middleware receives the context as first argument:

  1. export default function (context) {
  2. context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent
  3. }

In universal mode, middlewares will be called server-side once (on the first request to the Nuxt app or when page refreshes) and client-side when navigating to further routes. In SPA mode, middlewares will be called client-side on the first request and when navigating to further routes.

The middleware will be executed in series in this order:

  • nuxt.config.js (in the order within the file)
  • Matched layouts
  • Matched pages A middleware can be asynchronous. To do this, simply return a Promise or use the 2nd callback argument:

middleware/stats.js

  1. import axios from 'axios'
  2. export default function ({ route }) {
  3. return axios.post('http://my-stats-api.com', {
  4. url: route.fullPath
  5. })
  6. }

Then, in your nuxt.config.js, use the router.middleware key:

nuxt.config.js

  1. export default {
  2. router: {
  3. middleware: 'stats'
  4. }
  5. }

Now the stats middleware will be called for every route change.

You can add your middleware (even multiple) to a specific layout or page as well:

pages/index.vue or layouts/default.vue

  1. export default {
  2. middleware: ['auth', 'stats']
  3. }

To see a real-life example using the middleware, please see example-auth0 on GitHub.