Nuxt Middleware — Route Protection and Navigation Guards
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
- Not using
navigateTofor redirects: UsenavigateTo(path)instead ofreturn path.navigateTohandles both client and server redirects correctly. - Forgetting
.globalsuffix for global middleware: Without.global, middleware only runs on pages that explicitly reference it. - Not handling the case where middleware doesn't redirect: If the user is authenticated, don't return anything — allow the navigation to proceed.
- Using
useStatebefore it's initialized: IfuseState('user')hasn't been set, it returnsundefined. Check for this. - Running heavy async operations: Middleware blocks page rendering. Keep async operations fast or show loading states.
Practice Questions
How do you create a middleware that runs on every route? Answer: Name the file with
.global.tssuffix:middleware/auth.global.ts. It runs on all routes automatically.How do you redirect in middleware? Answer: Return
navigateTo(path)from the middleware function. It works on both client and server.How do you apply middleware to a specific page? Answer: Use
definePageMeta({ middleware: 'name' })in the page's<script setup>.Can middleware be async? Answer: Yes. Middleware functions can be async and use
awaitfor 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
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