Middleware
Middleware is code that runs before a request reaches a page — perfect for redirecting visitors, blocking the unlogged-in, and rewriting URLs.
What you will learn
- Explain what middleware runs and when
- Write a middleware.js that redirects a request
- Limit middleware to certain routes with a matcher
A checkpoint before every page
Middleware is a function that runs on the server before a request reaches your page or route handler. Think of it as a security guard at the door of your app: every visitor passes the guard first, and the guard can wave them through, send them somewhere else, or quietly redirect them — all before the page even starts rendering.
Common jobs for middleware: send logged-out users to the login page, redirect an old URL to a new one, detect a visitor country or language, or add a header to every request.
The middleware.js file
You write one file named middleware.js in the root of your project (next to the app folder, not inside it). Next.js runs its middleware function for matching requests automatically. It receives the incoming request and can return a response — for example, a redirect.
// middleware.js (project root)
import { NextResponse } from 'next/server';
export function middleware(request) {
// pretend we check a login cookie
const isLoggedIn = request.cookies.get('session');
if (!isLoggedIn) {
// send them to the login page instead
return NextResponse.redirect(new URL('/login', request.url));
}
// logged in -> let the request continue as normal
return NextResponse.next();
}Note: Output (behaviour): - A visitor WITHOUT a session cookie -> instantly redirected to /login (the page they asked for never even renders). - A visitor WITH a session cookie -> NextResponse.next() lets them through to the page they wanted. The check happened once, at the door, for the whole app.
Limiting middleware to certain routes with a matcher
By default middleware runs on every request, which is wasteful if you only want to guard, say, the dashboard. Export a config object with a matcher to say exactly which paths it should run on.
// middleware.js
export const config = {
matcher: ['/dashboard/:path*', '/account/:path*'],
};Note: Output (behaviour): Now the middleware runs ONLY for URLs under /dashboard and /account. Public pages like /, /about and /login skip it entirely — faster, and you cannot accidentally lock people out of the login page.
The request journey with middleware, step by step
Here is exactly what happens when a logged-out visitor tries to open /dashboard:
- The visitor requests
/dashboard. Before anything renders, the request hitsmiddleware.js. - The
matchersays this path is covered, so Next.js runs themiddlewarefunction. - The function checks for a session cookie with
request.cookies.get('session'). There is none. - It returns
NextResponse.redirect(new URL('/login', request.url))— a redirect response. - The browser is sent to
/login. The dashboard page never rendered, so no protected content leaked. - Later, after the user logs in (and gets a session cookie), the same request reaches
NextResponse.next()and passes through to the dashboard.
| Return value | What it does |
|---|---|
NextResponse.next() | Let the request continue to the page |
NextResponse.redirect(url) | Send the visitor to a different URL |
NextResponse.rewrite(url) | Show a different page while keeping the URL |
Tip: Middleware runs on the lightweight Edge runtime, very early and very fast. Keep it small — checks, redirects and rewrites. Heavy work (database queries, big logic) belongs in your pages, Route Handlers and Server Actions, not in middleware.
Watch out: Middleware is a coarse first gate, not your only defence. It is great for redirecting logged-out users, but always re-check permissions where the real data is read (the page or action). A determined user must not be able to reach protected data just because a redirect was skipped.
Q. What is the right job for Next.js middleware?
✍️ Practice
- Write a
middleware.jsthat redirects every request from/oldto/new. - Add a
matcherso your middleware only runs under/dashboard.
🏠 Homework
- Build middleware that redirects visitors without a "session" cookie to
/login, limited by a matcher to the/dashboardarea.