Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/vinext/llms.txt

Use this file to discover all available pages before exploring further.

The next/server module provides Web-standard request/response wrappers and middleware utilities that work across runtimes (Node.js, Cloudflare Workers, Deno).

Import

import {
  NextRequest,
  NextResponse,
  NextURL,
  NextFetchEvent,
  userAgent,
  after,
  connection,
} from 'next/server'

import type {
  NextMiddleware,
  NextMiddlewareResult,
  UserAgent,
} from 'next/server'

NextRequest

Extends the standard Request with Next.js-specific conveniences.
export class NextRequest extends Request {
  nextUrl: NextURL
  cookies: RequestCookies
  ip?: string
  geo?: GeoData
}

Constructor

const req = new NextRequest(input, init?)
input
URL | RequestInfo
required
URL string, URL object, or Request object.
init
RequestInit
Standard Request options (method, headers, body, etc.).

Properties

nextUrl
NextURL
Enhanced URL object with pathname helpers.
req.nextUrl.pathname  // "/api/users"
req.nextUrl.searchParams.get('id')
cookies
RequestCookies
Read-only cookie accessor.
const session = req.cookies.get('session')
// { name: 'session', value: 'abc123' }

const all = req.cookies.getAll()
// [{ name: 'session', value: 'abc123' }, ...]

req.cookies.has('theme')  // boolean
ip
string | undefined
Client IP address (from trusted headers).Priority:
  1. CF-Connecting-IP (Cloudflare)
  2. X-Real-IP
  3. X-Forwarded-For (first entry)
console.log('Request from IP:', req.ip)
geo
GeoData | undefined
Geolocation data (platform-dependent).
if (req.geo) {
  console.log(`Request from ${req.geo.city}, ${req.geo.country}`)
}
Available fields:
  • country?: string — ISO country code
  • city?: string
  • region?: string — State/province
  • latitude?: string
  • longitude?: string

Usage Example

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  const sessionCookie = req.cookies.get('session')
  
  if (!sessionCookie) {
    return NextResponse.redirect(new URL('/login', req.url))
  }
  
  // Check geolocation
  if (req.geo?.country === 'US') {
    return NextResponse.rewrite(new URL('/us-version', req.url))
  }
  
  return NextResponse.next()
}

NextResponse

Extends the standard Response with Next.js middleware helpers.
export class NextResponse extends Response {
  cookies: ResponseCookies
  
  static json<T>(body: T, init?: ResponseInit): NextResponse<T>
  static redirect(url: string | URL, status?: number): NextResponse
  static rewrite(destination: string | URL, init?): NextResponse
  static next(init?): NextResponse
}

Constructor

const res = new NextResponse(body?, init?)

Static Methods

json
<T>(body: T, init?: ResponseInit) => NextResponse<T>
Create a JSON response.
return NextResponse.json(
  { message: 'Success' },
  { status: 200 }
)
redirect
(url: string | URL, status?: number) => NextResponse
Create a redirect response.
// 307 Temporary Redirect (default)
return NextResponse.redirect('https://example.com')

// 301 Permanent Redirect
return NextResponse.redirect('https://example.com', 301)

// 308 Permanent Redirect (preserves method)
return NextResponse.redirect('https://example.com', 308)
rewrite
(destination: string | URL, init?) => NextResponse
Rewrite to a different URL (proxy pattern).
// Serve /api/v2/users but show /api/users in the browser
return NextResponse.rewrite(new URL('/api/v2/users', req.url))
The client sees the original URL; the server fetches from the destination.
next
(init?: MiddlewareResponseInit) => NextResponse
Continue to the next handler.
// Pass through unchanged
return NextResponse.next()

// Pass through with modified headers
return NextResponse.next({
  headers: {
    'x-custom-header': 'value'
  }
})

// Modify request headers for downstream handlers
return NextResponse.next({
  request: {
    headers: new Headers({
      'x-user-id': '123'
    })
  }
})

Properties

cookies
ResponseCookies
Cookie setter for responses.
const res = NextResponse.json({ ok: true })

res.cookies.set('session', 'abc123', {
  httpOnly: true,
  secure: true,
  sameSite: 'lax',
  maxAge: 60 * 60 * 24 * 7  // 1 week
})

res.cookies.delete('old-cookie')

return res
Methods:
  • set(name, value, options?) — Set a cookie
  • delete(name) — Delete a cookie (sets Max-Age=0)
  • get(name) — Read a cookie (from Set-Cookie headers)
  • getAll() — Read all cookies

Usage Examples

// Route handler: /app/api/users/route.ts
import { NextRequest, NextResponse } from 'next/server'

export async function GET(req: NextRequest) {
  const users = await getUsers()
  
  return NextResponse.json(users, {
    headers: {
      'Cache-Control': 'max-age=60'
    }
  })
}

export async function POST(req: NextRequest) {
  const body = await req.json()
  const user = await createUser(body)
  
  const res = NextResponse.json(user, { status: 201 })
  res.cookies.set('user-id', user.id, { httpOnly: true })
  
  return res
}
// Middleware: /middleware.ts
import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  // Add custom header
  const res = NextResponse.next()
  res.headers.set('x-pathname', req.nextUrl.pathname)
  return res
}

NextURL

Lightweight URL wrapper with pathname helpers.
const url = new NextURL('/api/users?page=1', 'https://example.com')

console.log(url.pathname)        // "/api/users"
console.log(url.searchParams.get('page'))  // "1"
console.log(url.href)            // "https://example.com/api/users?page=1"

// Modify
url.pathname = '/api/v2/users'
url.searchParams.set('page', '2')

Properties

href
string
Full URL string.
origin
string
Protocol + hostname + port (e.g., https://example.com:3000).
pathname
string
URL path (e.g., /api/users).
Query string with ? prefix (e.g., ?page=1).
searchParams
URLSearchParams
URLSearchParams instance for reading/writing query params.
hash
string
Hash fragment with # prefix (e.g., #section-2).

Methods

clone
() => NextURL
Create a copy of the URL.
const newUrl = url.clone()
newUrl.pathname = '/different-path'
toString
() => string
Convert to string (same as .href).

NextFetchEvent

Middleware event object (provides waitUntil for background work).
export function middleware(req: NextRequest, event: NextFetchEvent) {
  // Schedule background work
  event.waitUntil(
    logRequest(req).catch(console.error)
  )
  
  return NextResponse.next()
}
waitUntil
(promise: Promise<any>) => void
Register a promise to keep the runtime alive after the response is sent.Useful for:
  • Logging
  • Analytics
  • Cache warming
event.waitUntil(
  fetch('https://analytics.example.com/log', {
    method: 'POST',
    body: JSON.stringify({ path: req.nextUrl.pathname })
  })
)

Utility Functions

userAgent

Parse User-Agent header.
import { userAgent } from 'next/server'

export function middleware(req: NextRequest) {
  const { isBot, browser, device, os } = userAgent(req)
  
  if (isBot) {
    return NextResponse.rewrite(new URL('/bot-version', req.url))
  }
  
  console.log('Browser:', browser.name, browser.version)
  console.log('Device:', device.type, device.vendor)
  console.log('OS:', os.name, os.version)
  
  return NextResponse.next()
}
isBot
boolean
Whether the user agent is a known bot/crawler.
browser
{ name?: string; version?: string; major?: string }
Browser information.
device
{ model?: string; type?: string; vendor?: string }
Device information.
os
{ name?: string; version?: string }
Operating system information.
vinext’s UA parser is minimal. For production use, install ua-parser-js or similar.

after

Schedule work after the response is sent (Next.js 15+).
import { after } from 'next/server'

export async function GET() {
  // Send response immediately
  const res = NextResponse.json({ ok: true })
  
  // Log after response is sent
  after(async () => {
    await logAnalytics()
  })
  
  return res
}
In vinext, after() runs as a microtask (best-effort). For guaranteed background execution, use waitUntil in middleware.

connection

Signal that the response requires a live connection (opt out of ISR).
import { connection } from 'next/server'

export async function GET() {
  connection()  // Mark as dynamic
  
  const data = await getRealTimeData()
  return NextResponse.json(data)
}
Sets Cache-Control: no-store and bypasses ISR caching.
interface CookieOptions {
  path?: string         // Cookie path (default: "/")
  domain?: string       // Cookie domain
  maxAge?: number       // Max age in seconds
  expires?: Date        // Expiration date
  httpOnly?: boolean    // HttpOnly flag (default: false)
  secure?: boolean      // Secure flag (default: false in dev, true in prod)
  sameSite?: 'Strict' | 'Lax' | 'None'  // SameSite attribute
}

Middleware Type

export type NextMiddleware = (
  request: NextRequest,
  event: NextFetchEvent,
) => NextMiddlewareResult | Promise<NextMiddlewareResult>

export type NextMiddlewareResult =
  | NextResponse
  | Response
  | null
  | undefined
  | void
Returning null, undefined, or void is equivalent to NextResponse.next().

Runtime Compatibility

All APIs use Web-standard primitives and work across:
  • Node.js (18+)
  • Cloudflare Workers
  • Deno
  • Vercel Edge Runtime
  • Any WinterCG-compatible runtime

Source

View source code → Implementation: /home/daytona/workspace/source/packages/vinext/src/shims/server.ts