NextRequest

Extends the Web Request with cookie helpers and a nextUrl object for proxy and Route Handlers.

Signature
class NextRequest extends Request

Parameters

ParameterTypeDescription
$cookiesRequestCookiesRead or mutate the request's cookies: set(name, value), get(name), getAll(name?), delete(name), has(name) and clear().
$nextUrlNextURLThe request URL extended with Next.js properties. Also carries everything from the native URL API.
$nextUrl.basePathstringThe basePath of the URL.
$nextUrl.buildIdoptionalstring | undefinedThe build identifier of the Next.js application. Can be customized with generateBuildId.
$nextUrl.pathnamestringThe pathname of the URL.
$nextUrl.searchParamsObjectThe search parameters of the URL.

Return value

An instance handed to you by Next.js as the argument to proxy() and to Route Handler methods.

Changelog

  • PHP v15.0.0The ip and geo properties were removed. Read the client address from the x-forwarded-for header, or use your host's own headers, instead.

NextRequest is the ordinary Web Request plus two conveniences: a parsed cookies jar and nextUrl. You do not construct it in application code — Next.js passes it to proxy() and to each Route Handler export, and importing the type is what gives you autocomplete on both.

When to reach for it

Type your proxy.js argument with it whenever you need to inspect the path, read a session cookie before deciding to redirect, or pull a query parameter. nextUrl is the piece worth knowing: it is a URL, so clone(), pathname and searchParams all behave normally, and it is the object you hand to NextResponse.rewrite() or redirect().

What trips people up

  • request.ip and request.geo were removed in v15.0.0. Read x-forwarded-for instead.
  • Mutating request.nextUrl in place affects the object you later pass to rewrite(). Call clone() first when you want the original left alone.
  • cookies.get() returns { name, value } or undefined, not a bare string.
  • Setting a cookie on the request changes what runs downstream see; to change what the browser stores, set it on the NextResponse.
  • The i18n properties from the Pages Router do not exist here.

Example

Example · typescript
import { NextRequest, NextResponse } from 'next/server'

export function proxy(request: NextRequest) {
  const session = request.cookies.get('session-id')

  if (!session && request.nextUrl.pathname.startsWith('/dashboard')) {
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('from', request.nextUrl.pathname)
    return NextResponse.redirect(loginUrl)
  }

  return NextResponse.next()
}

export const config = {
  matcher: '/dashboard/:path*',
}

When to use it

  • Redirect unauthenticated visitors from proxy.js by checking a session cookie
  • Read a dynamic segment's query parameters inside a Route Handler
  • Clone nextUrl and rewrite to a different pathname while keeping the visible URL
  • Forward a request cookie downstream so pages read a value the proxy computed

Frequently asked questions

How do I get the request IP in Next.js 15?

request.ip was removed in v15.0.0, along with request.geo. Read the x-forwarded-for header — request.headers.get('x-forwarded-for') — and take the first entry, or use whatever geolocation headers your hosting platform injects.

What is the difference between request.url and request.nextUrl?

request.url is the plain string from the Web Request API, while nextUrl is a parsed URL object extended with Next.js properties like basePath and buildId. Use nextUrl for pathname and searchParams, and clone() it before mutating.

Why doesn't the cookie I set on the request reach the browser?

Because request.cookies.set() only changes what downstream pages and handlers see during this request. To store a cookie in the browser, set it on the response — response.cookies.set(...) on a NextResponse, or cookies().set() in a Server Function or Route Handler.

More examples

Reading query parameters in a Route Handler

nextUrl.searchParams is a standard URLSearchParams, so get() returns a string or null and every value needs coercing yourself. Typing the parameter as NextRequest rather than Request is what makes nextUrl visible — a plain Request only offers request.url, which you would have to parse by hand.

Example · typescript
import { NextRequest } from 'next/server'

export function GET(request: NextRequest) {
  const query = request.nextUrl.searchParams.get('q') ?? ''
  const page = Number(request.nextUrl.searchParams.get('page') ?? '1')

  return Response.json({ query, page })
}

The full cookies API on a request

Every mutation here rewrites the request as the rest of your application will see it — a page calling cookies() downstream reads 'false' for show-banner. Nothing reaches the browser: for that you must set the cookie on the NextResponse you return, which is the distinction behind most 'my cookie isn't sticking' reports.

Example · typescript
import { NextRequest, NextResponse } from 'next/server'

export function proxy(request: NextRequest) {
  request.cookies.has('experiments')       // boolean
  request.cookies.get('show-banner')       // { name, value, ... } | undefined
  request.cookies.getAll('experiments')    // array of matching cookies
  request.cookies.delete('experiments')    // true if one was removed

  // Visible to pages and handlers downstream, not to the browser
  request.cookies.set('show-banner', 'false')

  return NextResponse.next()
}

Rewriting with a cloned URL

clone() gives a detached copy, so editing pathname and searchParams cannot disturb the live request object that later handlers inspect. The browser keeps showing /legacy because this is a rewrite rather than a redirect — the URL change happens only on the server side.

Example · typescript
import { NextRequest, NextResponse } from 'next/server'

export function proxy(request: NextRequest) {
  const url = request.nextUrl.clone()

  if (url.pathname === '/legacy') {
    url.pathname = '/new'
    url.searchParams.set('migrated', '1')
    return NextResponse.rewrite(url)
  }

  return NextResponse.next()
}

Discussion

  • Be the first to comment on this lesson.