I'm trying to chain as well.
The docs say you can chain https://nextjs.org/docs/api-reference/next/server#static-methods
next() - Returns a NextResponse that will continue the middleware chain
Here is the source code for v12.2.2 (current at the time of writing)
https://github.com/vercel/next.js/blob/689626c6a4d509fe04aaf82c9971a5928669bcf4/packages/next/server/web/spec-extension/response.ts#L64
static next(init?: ResponseInit) {
const headers = new Headers(init?.headers)
headers.set('x-middleware-next', '1')
return new NextResponse(null, { ...init, headers })
}
If it does chain, I think it has to do something with the x-middleware-next header it is setting. I looked through the source code and I still could not determine how to chain.
The other interesting thing is next() returns a new NextResponse ,but, next() is a static method.
Since next() is static, you cannot call twice.
This does not work, response will be undefined.
const response = NextResponse.next()
response.next({
headers: {
'a-test': Math.random().toString(),
},
})
What I'm doing for now:
You set cookies by calling next() and using the public cookie property and use Map operations.
const response = NextResponse.next()
response.cookies.set('a-test', Math.random().toString())
You set headers by calling next() and passing in an object with a headers object within.
const response = NextResponse
response.next({
headers: {
'a-test': Math.random().toString(),
},
})
I first thought was to use const response = new NextResponse but that did not work, response would always be undefined. You have to use const response = NextResponse
Since you can only call next() once, the best thing I could do was call the headers function first where calling next() is required, and then calling the function that sets the cookies.
// middleware.js
import { NextResponse } from 'next/server'
const setHeaders = (response) => {
return response.next({
headers: {
'a-test': Math.random().toString(),
},
}
}
const setCookies = (response) => {
response.cookies.set('a-test', Math.random().toString())
return response
}
export async function middleware(request) {
// Limitation in config matcher, requires me to exclude here
if (request.nextUrl.pathname.startsWith('/_next')) {
return NextResponse.next()
}
let response = NextResponse
response = setHeaders(response)
response = setCookies(response)
return response
}
Hope this helps!