Next.js Middleware: Edge Functions, Redirects, and Request Interception | SoniNow Blog

Limited TimeLearn More

next.jsmiddlewareedge functionsredirectsweb development

Next.js Middleware: Edge Functions, Redirects, and Request Interception

Published

2026-06-23

Read Time

4 mins

Next.js Middleware: Edge Functions, Redirects, and Request Interception

Next.js Middleware runs on the Edge Runtime, intercepting every request before it reaches your application. This means you can redirect users, rewrite URLs, check authentication, and serve different content based on geography — all at the CDN edge with sub-millisecond latency. Here is how to wield it effectively.

Middleware Fundamentals

A middleware.ts file at the root of your Next.js project exports a single middleware function. Every incoming request passes through it before hitting your pages or API routes.

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

export function middleware(request: NextRequest) {
  const country = request.geo?.country || 'US'
  const response = NextResponse.next()
  response.cookies.set('country', country)
  return response
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}

The matcher config is critical. Without it, middleware runs on every request including static assets, wasting edge execution budget. Always define a narrow matcher pattern.

Authentication and Authorization at the Edge

Checking authentication in middleware prevents unauthenticated users from ever reaching your pages. The pattern integrates naturally with NextAuth.js, Clerk, or custom JWT flows.

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const PUBLIC_PATHS = ['/login', '/signup', '/api/auth']

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

  if (PUBLIC_PATHS.some((path) => pathname.startsWith(path))) {
    return NextResponse.next()
  }

  if (!token) {
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('redirect', pathname)
    return NextResponse.redirect(loginUrl)
  }

  return NextResponse.next()
}

For session validation, consider using a lightweight JWT with short expiration (15 minutes) validated via a refresh token pattern. Avoid database lookups in middleware to maintain edge performance.

Geolocation Routing

Next.js Middleware has access to the request's geographic information through request.geo. Use this for region-specific content, currency display, or regulatory compliance.

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

  // Redirect EU users to GDPR-compliant subdomain
  const euCountries = ['DE', 'FR', 'IT', 'ES', 'NL', 'BE', 'AT']
  if (euCountries.includes(country ?? '')) {
    const url = request.nextUrl.clone()
    url.hostname = 'eu.soninow.com'
    return NextResponse.rewrite(url)
  }

  return NextResponse.next()
}

NextResponse.rewrite is subtly different from redirect. A rewrite serves content from the target URL without changing the browser's address bar. Use redirect when you want the URL to change, rewrite when you want to serve different content at the same URL.

A/B Testing at the Edge

Distribute traffic between page variants without client-side flickering. Store the variant assignment in a cookie so users see a consistent experience across visits.

export function middleware(request: NextRequest) {
  const variant = request.cookies.get('ab-variant')?.value ?? 
    (Math.random() < 0.5 ? 'control' : 'treatment')
  
  const response = NextResponse.next()
  
  if (!request.cookies.get('ab-variant')) {
    response.cookies.set('ab-variant', variant, {
      maxAge: 60 * 60 * 24 * 30, // 30 days
      secure: true,
    })
  }

  if (variant === 'treatment' && request.nextUrl.pathname === '/pricing') {
    return NextResponse.rewrite(
      new URL('/pricing-treatment', request.url)
    )
  }

  return response
}

Request and Response Transformation

Middleware can modify request headers, add response headers, and transform responses. This is useful for adding CSP headers, injecting subresource integrity hashes, or handling CORS for API routes.

export function middleware(request: NextRequest) {
  // Bypass for API routes needing CORS handling
  if (request.nextUrl.pathname.startsWith('/api/')) {
    const response = NextResponse.next()
    response.headers.set('Access-Control-Allow-Origin', '*')
    response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE')
    response.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
    return response
  }

  // Security headers for page routes
  const response = NextResponse.next()
  response.headers.set(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
  )
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')

  return response
}

Performance Budget and Best Practices

Middleware runs on every matched request, so execution budget is tight. Vercel's Edge Runtime has a 25 ms CPU time limit per request. Keep these rules in mind:

  • No heavy computation or large library imports
  • Use URL and Headers APIs — they run natively on the edge
  • Access request.cookies and request.headers synchronously
  • Prefer simple pattern matching over complex logic
  • Cache computed results in request.cookies or query parameters

Edge-Scale Request Handling

Next.js Middleware turns edge computing from a buzzword into a practical tool. Authentication, geolocation, A/B testing, and security headers happen before your application code runs — faster than any client-side or server-side alternative.

At SoniNow, we build Next.js applications that leverage edge middleware for performance and personalization. Our web development services cover middleware optimization, edge deployment strategies, and full-stack Next.js development.

Move logic to the edge. Partner with SoniNow to maximize your Next.js application's performance.