Next.js Middleware

Run code before requests complete for auth, redirects, and headers

Overview

Middleware runs at the edge before a request reaches your routes. Place middleware.ts at the project root (or src/). Use it for authentication gates, geolocation redirects, A/B tests, and rewriting URLs.

Syntax / Usage

// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const token = request.cookies.get('session')?.value

  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/dashboard/:path*', '/api/protected/:path*'],
}

Examples

Add security headers:

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  return response
}

Locale prefix rewrite:

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl
  if (pathname.startsWith('/en') || pathname.startsWith('/es')) {
    return NextResponse.next()
  }
  return NextResponse.redirect(new URL(`/en${pathname}`, request.url))
}

Common Mistakes

  • Running heavy database logic in middleware—keep it fast
  • Overly broad matcher patterns hitting static assets unnecessarily
  • Assuming Node.js APIs are available—middleware runs on the Edge runtime
  • Infinite redirect loops when auth and login paths overlap

See Also

routing api-routes app-router metadata