Middleware runs before navigating to a route, perfect for authentication and guards.

Creating Middleware

typescript
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const { loggedIn } = useUserSession()
  
  if (!loggedIn.value) {
    return navigateTo('/login')
  }
})

Using Middleware

Per-Page

vue
<script setup>
definePageMeta({
  middleware: 'auth'
})
</script>

Multiple Middleware

vue
<script setup>
definePageMeta({
  middleware: ['auth', 'admin']
})
</script>

Global Middleware

typescript
// middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to) => {
  // Runs on every route change
  trackPageView(to.fullPath)
})

Auth Middleware Example

typescript
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
  const { status, data } = useAuth()
  
  // Skip if already on login page
  if (to.path === '/login') return
  
  // Redirect to login if not authenticated
  if (status.value !== 'authenticated') {
    return navigateTo('/login', {
      replace: true
    })
  }
})

// middleware/admin.ts
export default defineNuxtRouteMiddleware(() => {
  const { data } = useAuth()
  
  if (data.value?.role !== 'admin') {
    throw createError({
      statusCode: 403,
      message: 'Forbidden'
    })
  }
})

Inline Middleware

vue
<script setup>
definePageMeta({
  middleware: [
    function (to, from) {
      // Custom inline logic
      if (to.params.id === '0') {
        return abortNavigation('Invalid ID')
      }
    }
  ]
})
</script>
typescript
export default defineNuxtRouteMiddleware((to, from) => {
  // Allow navigation (default)
  return
  
  // Redirect
  return navigateTo('/other-page')
  
  // Redirect with options
  return navigateTo('/login', {
    replace: true,
    redirectCode: 301
  })
  
  // External redirect
  return navigateTo('https://nuxt.com', {
    external: true
  })
  
  // Abort with error
  return abortNavigation('Not allowed')
  
  // Abort with error object
  return abortNavigation(
    createError({ statusCode: 404, message: 'Not Found' })
  )
})

Async Middleware

typescript
// middleware/subscription.ts
export default defineNuxtRouteMiddleware(async (to) => {
  const { data: subscription } = await useFetch('/api/subscription')
  
  if (!subscription.value?.active) {
    return navigateTo('/subscribe')
  }
})
✓ Completed