Next.js Middleware: Auth, Rate Limiting, and Edge Logic
Next.js middleware runs at the edge, before your page or API route executes. It's the right place for auth checks, redirects, and rate limiting.
Basic Middleware Setup
// middleware.ts — in the root of your project
import { NextRequest, NextResponse } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Redirect /old-path to /new-path
if (pathname === '/old-path') {
return NextResponse.redirect(new URL('/new-path', request.url));
}
return NextResponse.next();
}
// Only run on specific paths
export const config = {
matcher: [
'/dashboard/:path*',
'/api/:path*',
'/((?!_next/static|_next/image|favicon.ico).*)',
],
};
Authentication Middleware
import { NextRequest, NextResponse } from 'next/server';
import { getToken } from 'next-auth/jwt';
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Public routes — skip auth
const publicRoutes = ['/', '/login', '/signup', '/api/auth'];
if (publicRoutes.some(r => pathname.startsWith(r))) {
return NextResponse.next();
}
// Check session token
const token = await getToken({ req: request, secret: process.env.NEXTAUTH_SECRET });
if (!token) {
const loginUrl = new URL('/login', request.url);
loginUrl.searchParams.set('callbackUrl', pathname);
return NextResponse.redirect(loginUrl);
}
// Add user info to headers for downstream routes
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-user-id', token.sub!);
requestHeaders.set('x-user-role', token.role as string);
return NextResponse.next({ request: { headers: requestHeaders } });
}
Edge Rate Limiting
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'), // 10 requests per 10 seconds
});
export async function middleware(request: NextRequest) {
// Only rate limit API routes
if (!request.nextUrl.pathname.startsWith('/api')) {
return NextResponse.next();
}
const ip = request.ip ?? '127.0.0.1';
const { success, limit, reset, remaining } = await ratelimit.limit(ip);
if (!success) {
return new NextResponse('Too many requests', {
status: 429,
headers: {
'X-RateLimit-Limit': limit.toString(),
'X-RateLimit-Remaining': remaining.toString(),
'X-RateLimit-Reset': reset.toString(),
},
});
}
return NextResponse.next();
}
A/B Testing at the Edge
export function middleware(request: NextRequest) {
const bucket = request.cookies.get('ab-bucket')?.value ??
(Math.random() < 0.5 ? 'a' : 'b');
const response = NextResponse.rewrite(
new URL(`/experiments/${bucket}${request.nextUrl.pathname}`, request.url)
);
response.cookies.set('ab-bucket', bucket, { maxAge: 60 * 60 * 24 * 30 });
return response;
}
Next.js middleware with auth, rate limiting, and edge patterns is pre-configured in the AI SaaS Starter Kit.
Top comments (0)