Skip to content

Nuxt Middleware — Route Protection and Navigation Guards

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Nuxt Middleware. We cover key concepts, practical examples, and best practices to help you master this topic.

Learn Nuxt 3 middleware for route protection, redirects, authentication checks, and running code before page rendering.

In this lesson, you'll understand how to create route middleware, apply it to pages, and handle authentication and redirects.

What You'll Learn

How to create middleware files, apply middleware to pages or globally, redirect unauthenticated users, and handle async checks.

Why It Matters

Middleware guards routes from unauthorized access, redirects users appropriately, and runs pre-rendering logic. It's essential for authentication and route protection.

flowchart LR
    A[User Navigates] --> B{Middleware Checks}
    B -->|Authenticated| C[Render Page]
    B -->|Not Authenticated| D[Redirect to Login]
    B -->|Admin Only| E{Is Admin?}
    E -->|Yes| C
    E -->|No| F[Redirect to Home]
    style B fill:#00dc82,color:#fff

Basic Middleware

Create middleware/auth.ts:

export default defineNuxtRouteMiddleware((to, from) => {
  const user = useState('user');

  if (!user.value) {
    // Redirect to login page with return URL
    return navigateTo({
      path: '/auth/login',
      query: { redirect: to.fullPath }
    });
  }
});

Apply to a page:

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

Output: When an unauthenticated user navigates to the page, they're redirected to /auth/login?redirect=/original-path.

Global Middleware

Create middleware/auth.global.ts:

// File naming: auth.global.ts runs on EVERY route
export default defineNuxtRouteMiddleware((to, from) => {
  const publicRoutes = ['/', '/auth/login', '/auth/register', '/about'];
  
  if (publicRoutes.includes(to.path)) return;

  const user = useState('user');
  
  if (!user.value) {
    return navigateTo('/auth/login');
  }
});

Output: The middleware runs on every navigation. Public routes are allowed without authentication.

Async Middleware

Handle async checks:

// middleware/verify-email.ts
export default defineNuxtRouteMiddleware(async (to, from) => {
  const user = useState('user');

  if (user.value?.emailVerified) return;

  // Check email verification status from server
  try {
    const { verified } = await $fetch('/api/user/email-status');
    
    if (!verified) {
      return navigateTo('/auth/verify-email');
    }
    
    // Update cached user state
    user.value = { ...user.value, emailVerified: true };
  } catch {
    return navigateTo('/auth/login');
  }
});

Output: The middleware fetches email verification status from the server before allowing access.

Middleware with Parameters

Pass parameters to middleware:

<script setup>
definePageMeta({
  middleware: [
    'auth',
    { name: 'role-check', params: { role: 'admin' } }
  ]
});
</script>
// middleware/role-check.ts
export default defineNuxtRouteMiddleware((to, from) => {
  // Access params from the middleware definition
  const middlewareParams = to.meta.middleware?.find(
    m => m.name === 'role-check'
  )?.params;

  const requiredRole = middlewareParams?.role || 'user';
  const user = useState('user');

  if (user.value?.role !== requiredRole) {
    return navigateTo('/unauthorized');
  }
});

Conditional Middleware

Skip middleware under certain conditions:

export default defineNuxtRouteMiddleware((to, from) => {
  // Skip middleware during initial SSR hydration
  if (import.meta.server) return;

  // Skip for specific routes
  if (to.path.startsWith('/public')) return;

  const user = useState('user');
  if (!user.value) {
    return navigateTo('/auth/login');
  }
});

Common Mistakes

  1. Not using navigateTo for redirects: Use navigateTo(path) instead of return path. navigateTo handles both client and server redirects correctly.
  2. Forgetting .global suffix for global middleware: Without .global, middleware only runs on pages that explicitly reference it.
  3. Not handling the case where middleware doesn't redirect: If the user is authenticated, don't return anything — allow the navigation to proceed.
  4. Using useState before it's initialized: If useState('user') hasn't been set, it returns undefined. Check for this.
  5. Running heavy async operations: Middleware blocks page rendering. Keep async operations fast or show loading states.

Practice Questions

  1. How do you create a middleware that runs on every route? Answer: Name the file with .global.ts suffix: middleware/auth.global.ts. It runs on all routes automatically.

  2. How do you redirect in middleware? Answer: Return navigateTo(path) from the middleware function. It works on both client and server.

  3. How do you apply middleware to a specific page? Answer: Use definePageMeta({ middleware: 'name' }) in the page's <script setup>.

  4. Can middleware be async? Answer: Yes. Middleware functions can be async and use await for API calls or database checks.

Challenge

Create a role-based middleware system: auth (checks login), role-check (checks role parameter), verified-email (checks email verification), and onboarding (redirects to onboarding if profile incomplete).

Mini Project

Build an admin dashboard with: login page, dashboard page (auth middleware), admin panel (role-check middleware), settings page (auth middleware), and a public landing page (no middleware). Include redirect back to original page after login.

FAQ

Can middleware run on the server only?

: Yes. Check import.meta.server to conditionally run code only during SSR.

Does middleware work with static generation?

: Client-side middleware works during client navigation. Server middleware doesn't run during static generation.

Can I use middleware with NuxtLink?

: Yes. Middleware runs on all navigations, including <NuxtLink> clicks.

How do I pass data from middleware to page?

: Use useState or useCookie for shared state. Modify the state in middleware and read it in the page.

What's Next

Learn about Nuxt State Management to manage application state with useState and Pinia in Nuxt 3.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro