Middleware Use Cases
Middleware is a general-purpose interception point, so it shows up in a handful of recurring patterns across real apps. This page is a tour of the most common ones.
Auth gating
The most common use case: check for a session cookie or token before letting a request reach a protected route, and redirect to a login page if it's missing.
middleware.ts — auth gating
import { NextRequest, NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
const session = request.cookies.get('session')?.value
if (!session) {
const loginUrl = new URL('/login', request.url)
loginUrl.searchParams.set('from', request.nextUrl.pathname)
return NextResponse.redirect(loginUrl)
}
return NextResponse.next()
}
export const config = {
matcher: ['/dashboard/:path*', '/account/:path*'],
}i18n locale detection and redirect
Accept-Language header (or a saved locale cookie) and redirect a visitor from an un-prefixed URL to the correct locale-prefixed one — the classic pattern behind libraries like next-intl's middleware helper.middleware.ts — locale redirect
import { NextRequest, NextResponse } from 'next/server'
const SUPPORTED_LOCALES = ['en', 'de', 'fr']
const DEFAULT_LOCALE = 'en'
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const hasLocale = SUPPORTED_LOCALES.some(
(locale) => pathname.startsWith(`/${locale}`)
)
if (hasLocale) return NextResponse.next()
const preferred = request.cookies.get('locale')?.value ?? DEFAULT_LOCALE
const url = request.nextUrl.clone()
url.pathname = `/${preferred}${pathname}`
return NextResponse.redirect(url)
}A/B testing via cookie
Assign each first-time visitor to a variant, store it in a cookie so the assignment is sticky across visits, and rewrite to the matching variant page — all without the visitor ever seeing a different URL.
middleware.ts — A/B assignment
import { NextRequest, NextResponse } from 'next/server'
export function middleware(request: NextRequest) {
const existing = request.cookies.get('ab-variant')?.value
const variant = existing ?? (Math.random() < 0.5 ? 'a' : 'b')
const response =
variant === 'b'
? NextResponse.rewrite(new URL('/landing-b', request.url))
: NextResponse.next()
if (!existing) {
response.cookies.set('ab-variant', variant, { maxAge: 60 * 60 * 24 * 30 })
}
return response
}
export const config = {
matcher: ['/landing'],
}Basic bot detection
User-Agent header and block or redirect obviously automated traffic before it reaches your page logic.middleware.ts — simple bot check
import { NextRequest, NextResponse } from 'next/server'
const BLOCKED_PATTERNS = [/curl/i, /wget/i, /scrapy/i]
export function middleware(request: NextRequest) {
const userAgent = request.headers.get('user-agent') ?? ''
if (BLOCKED_PATTERNS.some((pattern) => pattern.test(userAgent))) {
return new NextResponse('Forbidden', { status: 403 })
}
return NextResponse.next()
}Auth gating: check for a session cookie/token and redirect unauthenticated requests to a login page.
i18n detection: inspect
Accept-Languageor a saved locale cookie and redirect to the correctly localized URL.A/B testing: assign and persist a variant cookie, then rewrite to the matching variant without changing the visitor's URL.
Bot detection: filter obviously automated
User-Agentstrings for basic protection (not a substitute for real bot mitigation).In every case, keep middleware itself lightweight — fast cookie/header logic, not heavy data fetching.