Skip to main content
Middleware runs before a request is completed. It can inspect the incoming request and respond by redirecting, rewriting, setting headers, or modifying cookies.
middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}

export const config = {
  matcher: '/about/:path*',
}

Convention

Create a middleware.ts (or middleware.js) file in the root of your project (at the same level as app/ or pages/). Only one middleware file is supported per project.

Exports

middleware function

request
NextRequest
The incoming NextRequest object, which extends the Web Request API with:
  • request.nextUrl — a parsed URL object with a searchParams helper and pathname
  • request.cookies — read/write access to request cookies
  • request.headers — read access to request headers
The function should return a NextResponse or Response, or undefined to pass through.

config (optional)

Export a config object to control which paths the middleware runs on:
middleware.ts
export const config = {
  matcher: [
    '/about/:path*',
    '/dashboard/:path*',
    // Exclude static files and internal Next.js paths
    '/((?!_next/static|_next/image|favicon.ico).*)',
  ],
}
matcher accepts:
  • A single string: '/about/:path*'
  • An array of strings
  • Regular expressions (as strings)
Matcher rules:
  • Must start with /
  • Named parameters like :path match a single segment
  • :path* matches zero or more segments
  • Negative lookaheads (?!...) exclude paths

NextResponse API

Returns a redirect response to a new URL. The original URL is not loaded.
return NextResponse.redirect(new URL('/home', request.url))
return NextResponse.redirect(new URL('/login', request.url), 307)
Rewrites the request to a different URL without changing the URL visible to the user.
return NextResponse.rewrite(new URL('/proxy', request.url))
Continues the middleware chain, optionally modifying headers.
const response = NextResponse.next()
response.headers.set('x-custom-header', 'value')
return response

Examples

Redirecting unauthenticated users

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')

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: '/dashboard/:path*',
}

Rewriting requests

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

export function middleware(request: NextRequest) {
  const country = request.geo?.country ?? 'US'

  if (country === 'GB') {
    return NextResponse.rewrite(new URL('/gb' + request.nextUrl.pathname, request.url))
  }

  return NextResponse.next()
}

Setting request headers

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

export function middleware(request: NextRequest) {
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-pathname', request.nextUrl.pathname)

  return NextResponse.next({
    request: { headers: requestHeaders },
  })
}

Setting response cookies

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

export function middleware(request: NextRequest) {
  const response = NextResponse.next()
  response.cookies.set('session', 'abc123', {
    httpOnly: true,
    secure: true,
  })
  return response
}

Matching multiple paths

middleware.ts
export const config = {
  matcher: [
    // Match all paths except static files and Next.js internals
    '/((?!_next/static|_next/image|favicon.ico|.*\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
  ],
}
Middleware runs on the Edge Runtime by default. Node.js APIs are not available. Use the experimental-edge runtime config if you need them.

Build docs developers (and LLMs) love