I created a fresh Next.js using npx create-next-app@latest --typescript
. After installation (the version being 13.3.4
), without changing any files, I added a new middleware.ts
file inside the src
folder, and I only put this block of code:
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
export function middleware(request: NextRequest) {
console.log("request", JSON.stringify(request));
return NextResponse.next();
}
The console log is hit multiple times. I think it should be once, right? Is there any configuration I need to do for this fresh Next.js installation?
Note: I am going to do some cookie logic here in the middleware for authentication. Screenshot:
This is normal because a middleware
by default runs for every request, including the ones for getting assets like JavaScritp, CSS, and image files. As you can read on the doc:
Middleware will be invoked for every route in your project. The following is the execution order:
headers
fromnext.config.js
redirects
fromnext.config.js
- Middleware (
rewrites
,redirects
, etc.)beforeFiles
(rewrites
) fromnext.config.js
- Filesystem routes (
public/
,_next/static/
,pages
, etc.)afterFiles
(rewrites
) fromnext.config.js
- Dynamic Routes (
/blog/[slug]
)fallback
(rewrites
) fromnext.config.js
If you add a console.log(request.nextUrl.pathname)
, you would see the different paths for which it's running. To have it execute for some paths only, you need to use conditional statements or the matcher
config, like so:
// middleware.ts
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
export function middleware(request: NextRequest) {
console.log("Request for : ", request.nextUrl.pathname);
return NextResponse.next();
}
export const config = {
// The above middleware would only run for the "/" path
matcher: '/',
}
Another matching pattern that's used a lot is this one:
// middleware.ts
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
export function middleware(request: NextRequest) {
console.log("Request for : ", request.nextUrl.pathname);
return NextResponse.next();
}
export const config = {
matcher: [
/*
* Match all request paths except for the ones starting with:
* - api (API routes)
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
*/
'/((?!api|_next/static|_next/image|favicon.ico).*)',
],
}