Exploring Nuxt 3 Middleware: A Comprehensive Overview

Luiz Figueiredo
3 min readMar 6, 2023

Nuxt.js Middlewares are custom functions run before rendering a page or group of pages. Checking authentication, modifying the server response, or accessing cookies are some of the most common usages of middleware.

Rendering modes

Before talking more about middleware, let’s talk about Nuxt.js rendering modes.

Client-side Only Rendering is a mode where a Vue.js application is rendered in the browser (or client), generates HTML elements after the browser downloads, and parses all the JavaScript code.

Universal Rendering involves the Server-side and Client-side Rendering of a webpage. In Universal Rendering, the server returns a fully rendered HTML page to the browser, and the JavaScript (Vue.js) code is executed in a server environment, producing an HTML document. The client then loads the JavaScript code, and Vue.js takes control of the document and enables an interactivity called “hydration.”

Nuxt.js still has other rendering modes, like Hybrid, Rendering on CDN Edge Workers, and a very granular setting control using Route Rules. Some of these are still to be officially released.

Types of Middleware

There are two types of middleware in Nuxt.js: Route Middleware executed in the Vue part of the application and Normal Middleware executed in the Nitro part.

Nuxt 3 divides the route middleware into three types: Anonymous (or inline), Named Route, and Global.

The most popular use case for Nuxt middleware is the authentication guard. Still, some use cases for server middleware in Nuxt 3 include matching route parameters, accessing request cookies, logging requests, and warming up an API.

You define the Anonymous (or Inline) Route Middleware directly on the page.

An example of a page file defining middleware:

<script setup>
definePageMeta({
middleware: defineNuxtRouteMiddleware((to, from) => {
console.log('to', to);
console.log('from', from);
}),
});
</script>
<template>

</template>

Named route middleware should be placed in the middleware/ directory and will be automatically loaded via asynchronous import when used on a page.

Example of a middleware/auth.ts:

export default defineNuxtRouteMiddleware(async (to, from) => {
console.log('middleware/auth')
console.log('to', to)
console.log('from', from)
})

Global route middleware is placed in the middleware/ directory (with a .global suffix) and will be automatically run on every route change.

Example of a middleware/auth.global.ts:

export default defineNuxtRouteMiddleware(async (to, from) => {
console.log('middleware/auth.global')
})

As you can see, there is no difference between their syntax. Still, they behave slightly differently, being the global executed on accessing any route, even not being directly called.

A Named Route Middleware

Supposing you have a file structure as proposed in the example above, your authentication guard middleware would be at middleware/auth.ts.

In your page file, you can reference this route middleware like this:

<script setup>
definePageMeta({
middleware: ["auth"]
// or middleware: 'auth'
})
</script>

One of the most significant advantages of this method is that you have better control over what pages would require the middleware.

Controlling when the Middleware Runs

If your application runs on SSR mode, Nuxt will execute the middleware for the initial page both when rendering the page and then again on the client side. Using the process object, you can control the code execution time.

The code below is from Nuxt.js official documentation and shows some possibilities for controlling the runtime.

export default defineNuxtRouteMiddleware(to => {
// skip middleware on server
if (process.server) return
// skip middleware on client side entirely
if (process.client) return
// or only skip middleware on initial client load
const nuxtApp = useNuxtApp()
if (process.client && nuxtApp.isHydrating && nuxtApp.payload.serverRendered) return
})

Parameters overview

Route middleware is directly related to navigation. They act between the current route and the following route so that you can access this information in their arguments.

export default defineNuxtRouteMiddleware((to, from) => {
if (to.params.id === '1') {
return abortNavigation()
}
return navigateTo('/')
})

Nuxt can return two globally available helpers directly from the middleware:

  • navigateTo can be used to redirect to a given route. It can be handy within plugins or middleware where you must programmatically change the user’s location. Additionally, you can also call navigateTo directly to perform page navigation.
  • abortNavigation, allows you to stop navigation altogether with an optional error message. It can be helpful in cases where you need to prevent the user from navigating to a specific page or section of your application.

Read More

--

--

Luiz Figueiredo
Luiz Figueiredo

Written by Luiz Figueiredo

Full-stack engineer with 20+ years of coding experience, bridging Brazil and Japan. Passionate about innovation, web development, and new technologies.

Responses (1)