Middleware

Run Code Before Every Matching Request

Middleware

A single `middleware.ts` at the project root runs on the Edge for the paths you match — perfect for auth checks, redirects, and rewrites.

5 min read Level 3/5 #nextjs#middleware#edge
What you'll learn
  • Write a `middleware.ts` file
  • Use the `config.matcher` to limit which paths it runs on
  • Use `NextResponse.redirect`, `rewrite`, and `next`

Middleware runs on the Edge for every request that matches your config. It is the right place for cross-cutting concerns: auth gates, locale detection, A/B routing, rewrites.

A Minimal Auth Gate

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

export function middleware(req: NextRequest) {
  const token = req.cookies.get('token')?.value
  if (!token) {
    const url = new URL('/login', req.url)
    return NextResponse.redirect(url)
  }
  return NextResponse.next()
}

export const config = {
  matcher: ['/app/:path*', '/account/:path*'],
}

matcher patterns are checked before the function ever runs — anything outside them skips middleware entirely, which is essential for performance.

Three Response Shapes

// Continue to the route as normal
return NextResponse.next()

// Bounce the browser to a new URL
return NextResponse.redirect(new URL('/login', req.url))

// Serve a different route under the same URL (no client redirect)
return NextResponse.rewrite(new URL('/maintenance', req.url))

rewrite is great for invisible routing — the URL stays the same but a different component renders.

Edge Runtime Constraints

Middleware runs on the Edge Runtime — a V8 sandbox with Web Standards APIs (fetch, Response, crypto.subtle) but no Node APIs (fs, child_process). Keep the work light: middleware runs on every matching request.

Cookies & Headers →