What is Middleware in Next.js?
Middleware in Next.js is a function that allows you to run code before a request is completed. It sits between the incoming request and the response, enabling you to execute logic before rendering a page, fetching data, or returning the response. Middleware can be used for tasks such as authentication, logging, redirecting, and rewriting URLs.
Middleware functions are defined in a middleware.js
file placed at the root of the project and are executed for every request, making them useful for global request handling.
Key Concepts of Middleware
- Runs before rendering: Middleware is triggered before the requested page is rendered or the API route is executed.
- Edge-based: Middleware runs at the edge, meaning it operates close to the user for faster execution.
- Conditional Execution: You can specify certain conditions (e.g., routes or specific headers) under which the middleware should run.
- Response Manipulation: Middleware can manipulate requests (like modifying headers or cookies) and redirect or rewrite requests to different routes.
Typical Use Cases for Middleware
- Authentication/Authorization: Redirect users if they are not authenticated.
- Custom redirects/rewrites: Dynamically rewrite URLs or redirect requests based on specific conditions.
- Analytics/Logging: Capture and log information about requests.
- Geo-based content delivery: Show specific content based on the user’s location.
Example of Middleware in Next.js
Let's go through a basic example of how to use middleware in a Next.js app for handling authentication:
-
Creating a middleware.js file: Middleware is written in the root of your Next.js project in a
middleware.js
file.import { NextResponse } from 'next/server'; export function middleware(req) { // Retrieve the URL and cookies from the incoming request const url = req.nextUrl; const token = req.cookies.get('auth-token'); // Check if the user is trying to access a protected route if (url.pathname.startsWith('/dashboard')) { // If no auth-token cookie is present, redirect to the login page if (!token) { return NextResponse.redirect('/login'); } } // Allow the request to proceed if the token exists return NextResponse.next(); }
🔄 Flow:
- The middleware intercepts every request.
- It checks whether the user is trying to access a route that starts with
/dashboard
. - If the user is not authenticated (i.e., no
auth-token
cookie), it redirects them to the/login
page. - If the user is authenticated, it allows the request to proceed with
NextResponse.next()
.
Explanation of Key Functions
NextResponse
: This is a helper function in Next.js that allows you to create responses, such as redirections or rewrites.NextResponse.next()
: Continues with the normal request flow.NextResponse.redirect('/path')
: Redirects the request to a new URL.
req.cookies.get('cookie-name')
: Fetches the value of a specific cookie from the incoming request.
More Complex Middleware Example: URL Rewriting
Middleware can also be used to rewrite URLs dynamically based on user conditions, like location or device type:
import { NextResponse } from 'next/server';
export function middleware(req) {
const country = req.headers.get('x-country'); // Assume a custom header for location
// If user is from 'US', rewrite their request to the US-specific version of the page
if (country === 'US') {
return NextResponse.rewrite(new URL('/us-homepage', req.url));
}
// For other countries, proceed as normal
return NextResponse.next();
}
🔄 Flow:
- The middleware checks the
x-country
header, which contains the user's country. - If the user is from the US, the request is rewritten to serve a US-specific homepage (
/us-homepage
). - If the user is from any other country, the request proceeds as normal.
Using Middleware Selectively
You can apply middleware to specific routes by using a matcher. Here's how to ensure the middleware runs only on /dashboard
routes:
export const config = {
matcher: ['/dashboard/:path*'], // Middleware will run for any /dashboard/* route
};
This limits the middleware to run only when the user accesses routes that match /dashboard
and its subpaths.
Middleware Flow in a Request Cycle
Client Request → Middleware → Next.js Rendering (getServerSideProps or getStaticProps) → Response to Client
In this flow:
- The client makes a request.
- Middleware intercepts the request and can modify it (e.g., adding headers, redirecting).
- After middleware executes, the request continues to the regular server-side logic (
getServerSideProps
, etc.). - Finally, the server sends a response back to the client.
Limitations of Middleware
- Edge Functions Only: Middleware runs on the edge, meaning it can't access node.js-specific modules like
fs
orprocess
. - Limited to Request Handling: Middleware cannot modify the actual response body—only the headers, redirects, or rewrites.
Conclusion
Middleware in Next.js is a powerful tool for pre-processing incoming requests, enabling tasks like authentication, URL rewriting, and analytics before the server-side rendering process. It runs at the edge, making it fast and efficient, but is limited to handling requests and headers, without direct access to response bodies or filesystem operations.