NextjsMiddleware Use Cases

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

TSX
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
Middleware can inspect the 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

TSX
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

TSX
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
For lightweight bot filtering (not a security-grade defense), middleware can inspect the User-Agent header and block or redirect obviously automated traffic before it reaches your page logic.

middleware.ts — simple bot check

TSX
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()
}
Note
Whatever the use case, keep the logic itself lightweight — cookie and header checks, simple redirects and rewrites. Middleware runs on the Edge Runtime for every matching request, so anything slow or Node-dependent belongs in the page or Route Handler it forwards to, not in the middleware function itself.
  • Auth gating: check for a session cookie/token and redirect unauthenticated requests to a login page.

  • i18n detection: inspect Accept-Language or 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-Agent strings 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.