Next.js Middleware runs before a request is completed, executing at the Edge for low latency. It can rewrite URLs, redirect users, modify headers, and implement authentication checks. Defined in `middleware.ts` at the project root, it runs on every matched route and is ideal for cross-cutting concerns.
Middleware is code that runs before a request is completed. It:
fs)project-root/
├── middleware.ts // Must be at project root (same level as app/ or pages/)
├── app/
└── pages/
Middleware runs on Edge Runtime, which means:
fs, path, etc.)fetch, Request, Response)Use config.matcher to specify which routes trigger middleware:
export const config = {
matcher: [
'/dashboard/:path*', // All dashboard routes
'/api/:path*', // All API routes
'/((?!_next/static|favicon.ico).*)', // All except static
],
};
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
const { pathname } = request.nextUrl;
// Public routes that don't need auth
const publicRoutes = ['/login', '/signup', '/forgot-password'];
if (publicRoutes.includes(pathname)) {
// If logged in, redirect away from auth pages
if (token) {
return NextResponse.redirect(new URL('/dashboard', request.url));
}
return NextResponse.next();
}
// Protected routes - require auth
if (!token) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('callbackUrl', pathname);
return NextResponse.redirect(loginUrl);
}
return NextResponse.next();
}
export const config = {
matcher: [
'/dashboard/:path*',
'/settings/:path*',
'/login',
'/signup',
],
};