Middleware in Next.js: Route Protection, Geo-blocking, and Redirects
Next.js Middleware provides a powerful mechanism to run code before a request is completed on the server. By intercepting incoming requests at the Edge, developers can inspect headers, cookies, and IP locations to modify responses, enforce authentication, handle redirects, or implement geo-blocking.
This comprehensive guide explores how to configure Next.js Middleware, implement robust route protection, handle conditional redirects, and restrict access based on user geographic regions.
Understanding Edge Execution and Request Lifecycle
Next.js Middleware executes in the Edge Runtime, a lightweight environment operating closer to your users across global CDN nodes. Because middleware runs before any page or route handler is rendered, it can inspect and manipulate incoming requests with minimal latency.
To use middleware, create a file named `middleware.ts` (or `middleware.js`) at the root of your project directory (at the same level as `app` or `pages`).
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Intercept request and return a response or rewrite
return NextResponse.next();
}
// Configure paths where middleware should execute
export const config = {
matcher: ['/dashboard/:path*', '/admin/:path*'],
};
Securing Private Routes and Authentication
Middleware is ideal for verifying session tokens or authentication cookies before granting access to protected sections of your web application, such as user dashboards or admin panels.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
// If token is missing, redirect user to login page
if (!token) {
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*',
};
Handling Conditional Redirects and URL Rewrites
Beyond authentication, middleware enables dynamic redirects based on user roles, legacy paths, or A/B testing configurations without modifying server code or static generation outputs.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const userRole = request.headers.get('x-user-role');
if (request.nextUrl.pathname.startsWith('/admin') && userRole !== 'ADMIN') {
return NextResponse.redirect(new URL('/unauthorized', request.url));
}
return NextResponse.next();
}
Restricting Access Using Geographic Data
Vercel and other modern hosting providers inject geographic information into request headers automatically (such as `x-vercel-ip-country`). You can use these headers in your middleware to implement geo-blocking or localized content redirection.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const country = request.geo?.country || request.headers.get('x-vercel-ip-country') || 'US';
// Block requests originating from restricted regions
const restrictedCountries = ['XX', 'YY'];
if (restrictedCountries.includes(country)) {
return new NextResponse('Access Denied: Region Not Supported', { status: 403 });
}
return NextResponse.next();
}
Summary
Next.js Middleware executes code at the Edge before requests complete, empowering developers to build secure, high-performance applications.
By leveraging middleware for route protection, conditional redirects, and geo-blocking, you can enforce security policies and personalize user experiences globally with zero noticeable latency.