In Next.js middleware, you should use request.cookies (from the NextRequest object) rather than cookies() from next/headers because:
request.cookies API is specifically designed for this context 12.cookies() function from next/headers is intended for use within Server Components, Route Handlers, or Server Actions - not middleware 3.request.cookies in middleware gives you access to methods like get(), getAll(), has(), set(), and delete() that allow you to both read and manipulate cookies during the request lifecycle 2.For example, in middleware you would access cookies like this:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Get a specific cookie
const cookie = request.cookies.get('my-cookie')
// Check if a cookie exists
if (request.cookies.has('auth-token')) {
// Do something with authenticated requests
}
// Set a cookie on the response
const response = NextResponse.next()
response.cookies.set('visited', 'true')
return response
}This approach is optimized for the middleware execution context and provides the appropriate methods for that specific part of the request lifecycle.
The relationship between middleware and the Edge Runtime is important to understand when working with cookies:
Because middleware runs in the Edge Runtime, it has certain limitations and characteristics that affect how you work with cookies:
cookies() from next/headers 23.For example, when working with cookies in middleware for authentication:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { decrypt } from '@/app/lib/session'
export function middleware(request: NextRequest) {
// Optimistic check - only read from cookies, don't query database
const sessionCookie = request.cookies.get('session')?.value
const session = decrypt(sessionCookie)
if (!session?.userId && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}This approach aligns with the performance characteristics of the Edge Runtime, keeping middleware lightweight and fast while still providing essential functionality like authentication checks 1.