JS Guide
HomeQuestionsTopicsCompaniesResources
BookmarksSearch

Built for developers preparing for JavaScript, React & TypeScript interviews.

ResourcesQuestionsSupport
HomeQuestionsSearchProgress
HomeTopicsnextjsMiddleware
PrevNext
nextjs
advanced
10 min read

Middleware

a-b-testing
authentication
edge
geolocation
middleware
nextjs
routing
security-headers

Next.js middleware runs before every request at the edge — defined in a single middleware.ts file at the project root, it can redirect, rewrite, set headers/cookies, and return responses, using a limited edge runtime without Node.js APIs like fs or native modules.

Key Points

1Pre-Request Execution

Runs before any rendering or route handler — intercepts requests to redirect, rewrite, modify headers, or return responses.

2Single File + Matcher

Defined in one middleware.ts at the project root. config.matcher controls which routes trigger it — without matcher, runs on every request.

3Edge Runtime

Runs in a lightweight edge environment — Web APIs only, no Node.js (fs, path, native modules). Fast, globally distributed.

4Common Patterns

Authentication redirects, internationalization routing, A/B testing via rewrites, security headers, and geolocation-based content.

What You'll Learn

  • Implement middleware for authentication and route protection
  • Configure matchers to control which routes trigger middleware
  • Understand edge runtime limitations and what APIs are available
  • Know when to use middleware vs Server Components vs Route Handlers

Deep Dive

Middleware in Next.js runs before a request is completed — it sits between the incoming request and your routes, allowing you to intercept, modify, or redirect requests globally.

How Middleware Works

Middleware is defined in a single middleware.ts (or .js) file at the root of your project (next to app/ or pages/). It exports a function that receives a NextRequest and returns a NextResponse:

JavaScript
import { NextRequest, NextResponse } from 'next/server';
 
export function middleware(request: NextRequest) {
  // Check authentication
  const token = request.cookies.get('session');
  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}
 
export const config = {
  matcher: ['/dashboard/:path*', '/api/:path*'],
};

Middleware runs on every matching request before any rendering or route handler execution.

Matcher Configuration

The config.matcher array specifies which routes trigger the middleware. Without a matcher, middleware runs on every route (including static assets, which you usually don't want). Matchers support path patterns:

  • /dashboard/:path* — matches /dashboard and all sub-paths
  • /api/:path* — matches all API routes
  • /((?!_next|static|favicon.ico).*) — regex to exclude internal routes

What Middleware Can Do

  • Redirect: NextResponse.redirect(url) — send users to a different page (auth redirects, localization)
  • Rewrite: NextResponse.rewrite(url) — serve a different page without changing the URL (A/B testing, feature flags)
  • Set headers: response.headers.set('x-custom', 'value') — add security headers, CORS
  • Set cookies: response.cookies.set('name', 'value') — session management, preferences
  • Return response: Return a NextResponse directly — rate limiting, blocking

Edge Runtime Limitations

Middleware runs in the edge runtime — a lightweight JavaScript environment optimized for speed and global distribution. It does NOT have access to:

  • Node.js APIs: fs, path, crypto (use Web Crypto API instead), child_process
  • Native Node modules or packages that depend on them
  • Long-running operations (middleware has strict execution time limits)

The edge runtime supports Web APIs: fetch, Request/Response, Headers, URL, TextEncoder, crypto.subtle, and ReadableStream.

Common Use Cases

  • Authentication: Redirect unauthenticated users to login; verify JWT/session tokens
  • Internationalization: Detect user's locale from Accept-Language header and redirect to localized route
  • A/B Testing: Rewrite requests to different page variants based on a cookie
  • Bot Protection: Check User-Agent or rate-limit suspicious patterns
  • Security Headers: Add CSP, X-Frame-Options, HSTS headers to all responses
  • Geolocation: Use request.geo (Vercel) to route users to regional content

Middleware vs Server Components vs Route Handlers

  • Middleware: Pre-request logic — authentication checks, redirects, header manipulation. Runs on every matched request.
  • Server Components: Rendering logic — fetch data, generate HTML. Runs during page rendering.
  • Route Handlers: API endpoint logic — handle HTTP methods, return JSON. Runs when the API endpoint is called.

Don't put heavy computation or data fetching in middleware — it runs on every request and should be fast.

Key Interview Distinction

Middleware runs before every matched request at the edge. It can redirect, rewrite, set headers/cookies, and return responses. Defined in a single middleware.ts file with a matcher config. Uses the edge runtime (Web APIs only, no Node.js). Common uses: authentication redirects, i18n, A/B testing, security headers. Keep it lightweight — it runs on every request.

Fun Fact

Next.js middleware was originally envisioned as per-route middleware files (middleware.ts inside each route folder), but the design was changed to a single global middleware file before the stable release. The single-file approach was chosen because middleware needs to run before routing decisions are made — per-route files would require parsing the route first, defeating the purpose.

Learn These First

Next.js Fundamentals

beginner

File-Based Routing

intermediate

Continue Learning

Route Handlers & API Routes

intermediate

Navigation & Linking

beginner

Practice What You Learned

How does Middleware work in Next.js and what are common use cases?
senior
middleware
Next.js Middleware runs before a request is completed, executing at the Edge for low latency. It can rewrite URLs, redirect users, modify headers, and implement authentication checks. Defined in `middleware.ts` at the project root, it runs on every matched route and is ideal for cross-cutting concerns.
Previous
Data Fetching
Next
Navigation & Linking
PrevNext