DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Next.js Middleware: Auth, Rate Limiting, and Edge Logic

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).*)',
  ],
};
Enter fullscreen mode Exit fullscreen mode

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 } });
}
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

Next.js middleware with auth, rate limiting, and edge patterns is pre-configured in the AI SaaS Starter Kit.

Top comments (0)