Next.js Middleware Explained in 5 Minutes
What is Next.js Middleware?
According to the official Next.js Middleware Docs:
"Middleware allows you to run code before a request is completed. Then, based on the incoming request, you can modify the response by rewriting, redirecting, modifying the request or response headers, or responding directly."
It's very important to understand this definition well in order to master Next.js Middleware, so let's visualize it!
Knowing this, we'll now write 2 middleware functions to understand how it works in Next.js.
So without further ado… Let's dive right in!
1. Matcher
The matcher is used to configure the middleware to run for particular routes.
By default, Next.js middleware will be invoked for every route, which is not always necessary (E.g. you don't need middleware for an about page).
Lets imagine a client is trying to access the /account page but they are not authenticated.
In this case, we would expect the client to be redirected to another page, e.g. /login.
We can configure the matcher to ensure the middleware will only run for the login and account page to perform these checks.
Below is the code to make this happen; lets break it down step-by-step:
领英推荐
Copyimport { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
// Make sure to implement authentication properly.
// This variable is set for instructional purposes.
const authenticated = false
const requestPath = request.nextUrl.pathname
if (requestPath.startsWith("/login") && authenticated) {
return NextResponse.redirect(new URL("/account", request.url))
} else if (requestPath.startsWith("/account") && !authenticated) {
return NextResponse.redirect(new URL("/login", request.url))
}
return NextResponse.next()
}
// Here is the matcher config.
// Set an array of paths that are able to invoke middleware.
// Also accepts wildcard paths.
export const config = {
matcher: ["/login", "/account"],
}
NOTE: Middleware can only run on the Edge Runtime. It is currently not available in the Node.js Runtime.
2. Auth
In the last example we didn't implement auth. So let's do that now.
We will be implementing basic refresh token authentication here for demonstrational purposes.
In practice, an authentication library like next-auth would be a safer choice.
Copyimport { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
import { and, eq, gt } from "drizzle-orm"
import { db } from "./db"
import { sessions } from "./db/schema"
export async function middleware(request: NextRequest) {
const token = request.cookies.get("token")
// Validate the token. This is a placeholder function.
// You should replace it with your actual token validation logic.
const isAuthenticated = await validateToken(token?.value)
const requestPath = request.nextUrl.pathname
if (requestPath.startsWith("/login") && isAuthenticated) {
return NextResponse.redirect(new URL("/account", request.url))
} else if (requestPath.startsWith("/account") && !isAuthenticated) {
return NextResponse.redirect(new URL("/login", request.url))
}
return NextResponse.next()
}
// Validating a session stored in a Database using DrizzleORM
async function validateToken(token: string | undefined): Promise<boolean> {
if (!token) return false
// Is the session token valid?
// Using DrizzleORM syntax
const result = await db
.select()
.from(sessions)
.where(
and(eq(sessions.sessionToken, token), gt(sessions.expires, new Date()))
)
return result.length > 0
}
export const config = {
matcher: ["/login", "/account"],
}
Conclusion
Next.js Middleware is an advanced topic, and there is much more to explore.
While I covered the most common use cases, there are alternative options to configure to cover edge cases, such as:
And if you want to get really deep into this topic, I recommend checking out the Advanced Middleware Flags for advanced use cases.
If you enjoyed this article, please make sure to Subscribe, Clap, Comment and Connect with me today! ??
It's impressive how middleware capabilities in Next.js can greatly enhance the response handling process. The ability to customize requests and responses opens up a lot of possibilities for developers. How have you found middleware impacting your projects?