Bird
Raised Fist0
NextJSframework~15 mins

Request modification in NextJS - Deep Dive

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Overview - Request modification
What is it?
Request modification in Next.js means changing the details of an incoming web request before it reaches your page or API route. This can include changing headers, URL paths, or query parameters. It helps you control how requests are handled and customize responses based on those changes.
Why it matters
Without request modification, you would have less control over how your app responds to users. For example, you couldn't easily redirect users, add security headers, or rewrite URLs to cleaner paths. This would make your app less flexible and harder to maintain, especially as it grows.
Where it fits
Before learning request modification, you should understand basic Next.js routing and API routes. After mastering it, you can explore middleware, server components, and advanced caching strategies to optimize your app.
Mental Model
Core Idea
Request modification is like a traffic cop who redirects or changes incoming cars (requests) so they reach the right destination with the right information.
Think of it like...
Imagine a mailroom clerk who opens incoming letters, changes the address or adds notes, then sends them on to the correct department. This ensures the message gets handled properly even if the original letter was unclear or incomplete.
┌───────────────┐
│ Incoming      │
│ Request       │
└──────┬────────┘
       │
       ▼  (Modify URL, headers, query)
┌───────────────┐
│ Modified      │
│ Request       │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Next.js       │
│ Page/API      │
└───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Next.js Requests
🤔
Concept: Learn what a request is in Next.js and what parts it contains.
A request is what a browser sends to your Next.js app when you visit a page or call an API. It includes the URL, headers (extra info like language or cookies), and sometimes a body (data sent with POST requests). Next.js receives this request and decides what to do next.
Result
You know the basic pieces of a request and how Next.js gets them.
Understanding the parts of a request is essential before you can change or modify them.
2
FoundationBasic Routing and API Handling
🤔
Concept: Learn how Next.js routes requests to pages and API routes.
Next.js uses the file system to decide which page or API route handles a request. For example, a request to '/about' loads the 'pages/about.js' file. API routes work similarly but handle data requests. This routing is automatic and based on the URL path.
Result
You can predict which code runs for a given URL.
Knowing routing helps you understand where and when to modify requests.
3
IntermediateUsing Middleware for Request Modification
🤔Before reading on: do you think middleware runs before or after your page code? Commit to your answer.
Concept: Middleware runs before your page or API code and can change the request or response.
Next.js middleware is a special function that runs on every request (or selected ones). It can rewrite URLs, add headers, or redirect users. Middleware runs before your page or API route code, so it can change the request details before your app sees them.
Result
You can intercept and modify requests early in the process.
Knowing middleware runs first explains why it's the perfect place to modify requests.
4
IntermediateRewriting and Redirecting Requests
🤔Before reading on: do you think rewriting a URL changes what the user sees in the browser? Commit to your answer.
Concept: Rewriting changes the request URL internally without changing the browser's address; redirecting sends the user to a new URL visibly.
Rewrites let you serve content from a different URL without changing what the user sees. Redirects tell the browser to go to a new URL, changing the address bar. Both are ways to modify requests to improve user experience or organize content.
Result
You can control where requests go and what users see.
Understanding the difference between rewrites and redirects helps you choose the right tool for request modification.
5
IntermediateModifying Request Headers
🤔
Concept: Learn how to add or change headers in requests or responses.
Headers carry extra information like cookies or language preferences. Middleware can add security headers to responses or read headers from requests to customize behavior. For example, you can add a header to tell browsers to block certain content or check a header to serve different content based on language.
Result
You can enhance security and personalization by changing headers.
Headers are powerful for controlling how browsers and servers communicate, so modifying them is key for advanced apps.
6
AdvancedConditional Request Modification
🤔Before reading on: do you think you can modify requests differently based on user location or device? Commit to your answer.
Concept: You can inspect request details and modify them differently depending on conditions like user location, device type, or cookies.
Middleware can check request headers or cookies to detect if a user is on mobile or from a certain country. Based on that, it can rewrite URLs, redirect, or add headers. This allows personalized experiences and optimized content delivery.
Result
Your app can serve different content or routes based on who is visiting.
Conditional modification unlocks dynamic, user-focused web experiences.
7
ExpertPerformance and Caching Impacts of Request Modification
🤔Before reading on: do you think modifying requests always slows down your app? Commit to your answer.
Concept: Request modification can affect caching and performance, so it must be done carefully to avoid slowing down your app.
Middleware runs on every request it matches, which can add latency. Also, rewriting URLs or changing headers can affect how caching works, possibly reducing cache hits. Experts design middleware to be fast and cache-friendly, sometimes limiting modifications to only necessary requests or using edge caching strategies.
Result
You understand how to balance request modification with app speed and caching.
Knowing the performance tradeoffs helps you write efficient request modifications that scale well.
Under the Hood
Next.js middleware runs on the Edge Runtime, a lightweight JavaScript environment close to users. When a request arrives, middleware intercepts it before routing. It can read and modify the request URL and headers. After middleware finishes, Next.js routes the modified request to the appropriate page or API handler. This early interception allows changes without waiting for full server processing.
Why designed this way?
Middleware was designed to run on the Edge to reduce latency and improve user experience by handling common tasks early. Running before routing allows centralized control of requests, avoiding duplication in pages or APIs. Alternatives like modifying requests inside pages would be slower and less consistent. The Edge Runtime limits some Node.js features for speed and security, balancing power and performance.
┌───────────────┐
│ User Request  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Edge Runtime  │
│ (Middleware)  │
└──────┬────────┘
       │ Modified Request
       ▼
┌───────────────┐
│ Next.js       │
│ Router        │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Page or API   │
│ Handler       │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does rewriting a URL change what the user sees in their browser address bar? Commit to yes or no.
Common Belief:Rewriting a URL changes the browser's address bar to the new URL.
Tap to reveal reality
Reality:Rewriting changes the URL internally on the server but keeps the original URL visible in the browser.
Why it matters:Confusing rewrites with redirects can cause unexpected user experience issues, like users not seeing the URL they expect.
Quick: Can middleware modify the request body in Next.js? Commit to yes or no.
Common Belief:Middleware can freely modify the request body before it reaches the page or API route.
Tap to reveal reality
Reality:Next.js middleware cannot modify the request body because it runs on the Edge Runtime, which does not support body parsing or modification.
Why it matters:Trying to modify the body in middleware leads to errors or ignored changes, causing bugs in request handling.
Quick: Does adding middleware always slow down your Next.js app? Commit to yes or no.
Common Belief:Any middleware will significantly slow down your app because it adds extra processing.
Tap to reveal reality
Reality:Well-designed middleware on the Edge Runtime is very fast and often adds negligible delay, but poorly designed or unnecessary middleware can impact performance.
Why it matters:Assuming all middleware is slow might prevent developers from using powerful request modifications that improve user experience.
Quick: Can you modify requests after the page or API route starts running? Commit to yes or no.
Common Belief:You can modify the request at any point, even after the page or API code starts executing.
Tap to reveal reality
Reality:Request modification must happen before the page or API route runs, typically in middleware; once the handler starts, the request is fixed.
Why it matters:Trying to modify requests too late leads to confusion and bugs because changes won't take effect.
Expert Zone
1
Middleware runs on the Edge Runtime, which limits Node.js APIs, so you must use Web APIs and lightweight code.
2
Rewrites do not trigger a new request from the browser, so client-side analytics tools may not see the internal URL changes unless handled carefully.
3
Conditional middleware logic should be optimized to avoid unnecessary runs, improving cache hit rates and reducing latency.
When NOT to use
Avoid request modification when you need to change the request body or perform heavy server-side logic; instead, handle those inside API routes or server components. Also, if your app does not need dynamic routing or personalization, simpler static routing is better for performance.
Production Patterns
In production, middleware is often used for authentication redirects, locale-based routing, A/B testing by rewriting URLs, and adding security headers like Content Security Policy. Teams combine middleware with caching strategies to keep apps fast while flexible.
Connections
HTTP Protocol
Request modification builds on HTTP request and response structure.
Understanding HTTP headers and status codes helps you modify requests and responses correctly in Next.js middleware.
Edge Computing
Next.js middleware runs on the Edge, a form of distributed computing close to users.
Knowing Edge computing principles explains why middleware is fast and how it differs from traditional server code.
Traffic Routing in Networks
Request modification is like routing network packets to different paths based on rules.
Seeing request modification as routing helps understand conditional rewrites and redirects as traffic control.
Common Pitfalls
#1Trying to modify the request body in middleware.
Wrong approach:export function middleware(request) { const newBody = JSON.stringify({foo: 'bar'}); request.body = newBody; // This does nothing return NextResponse.next(); }
Correct approach:export function middleware(request) { // Cannot modify body here; handle body changes inside API routes instead return NextResponse.next(); }
Root cause:Middleware runs on Edge Runtime which does not support request body modification.
#2Using redirect when you meant to rewrite, causing URL to change unexpectedly.
Wrong approach:export function middleware(request) { return NextResponse.redirect('/new-path'); }
Correct approach:export function middleware(request) { return NextResponse.rewrite('/new-path'); }
Root cause:Confusing redirect (changes browser URL) with rewrite (internal URL change).
#3Running heavy logic or database calls inside middleware causing slow responses.
Wrong approach:export async function middleware(request) { const data = await fetch('https://slow-api.example.com'); return NextResponse.next(); }
Correct approach:export function middleware(request) { // Keep middleware fast; do heavy work inside API routes or server components return NextResponse.next(); }
Root cause:Middleware should be lightweight to maintain fast edge response times.
Key Takeaways
Request modification in Next.js lets you change incoming requests early using middleware before they reach your pages or APIs.
Middleware runs on the Edge Runtime, enabling fast, global request handling but with some limitations like no body modification.
Rewrites change the request URL internally without changing the browser address, while redirects send users to a new URL visibly.
Modifying headers and conditionally rewriting or redirecting requests allows personalized and secure user experiences.
Understanding performance impacts and middleware design helps you build scalable, fast Next.js applications.

Practice

(1/5)
1. In Next.js, what is the main purpose of modifying a request in middleware?
easy
A. To change request details like headers or body before the app processes it
B. To directly send a response to the client without processing
C. To update the database with request data
D. To log request details only without changing anything

Solution

  1. Step 1: Understand middleware role in Next.js

    Middleware runs before the app processes a request, allowing changes to the request.
  2. Step 2: Identify what request modification means

    Modifying means changing headers, body, or other request parts before the app sees it.
  3. Final Answer:

    To change request details like headers or body before the app processes it -> Option A
  4. Quick Check:

    Request modification = change request details [OK]
Hint: Middleware changes requests before app sees them [OK]
Common Mistakes:
  • Confusing request modification with sending responses
  • Thinking middleware updates databases directly
  • Assuming middleware only logs requests
2. Which of the following is the correct way to return a modified request in Next.js middleware?
easy
A. return NextResponse.next(request);
B. return NextResponse.next(new Request(request));
C. return NextResponse.redirect('/new-path');
D. return NextResponse.next(new Request(request, { headers: { 'x-new': 'value' } }));

Solution

  1. Step 1: Understand how to modify requests in Next.js middleware

    You must create a new Request object with changes (like new headers) and pass it to NextResponse.next().
  2. Step 2: Check each option

    return NextResponse.next(request); passes original request without changes. return NextResponse.next(new Request(request)); creates a new Request but without changes. return NextResponse.next(new Request(request, { headers: { 'x-new': 'value' } })); creates a new Request with modified headers correctly. return NextResponse.redirect('/new-path'); redirects instead of modifying request.
  3. Final Answer:

    return NextResponse.next(new Request(request, { headers: { 'x-new': 'value' } })); -> Option D
  4. Quick Check:

    New Request with changes + NextResponse.next() = D [OK]
Hint: Wrap new Request with changes inside NextResponse.next() [OK]
Common Mistakes:
  • Returning original request without changes
  • Using redirect instead of next() for modification
  • Not creating a new Request object for changes
3. Given this middleware code snippet, what will be the value of the header 'x-user' in the request seen by the app?
import { NextResponse } from 'next/server';
export function middleware(request) {
  const newHeaders = new Headers(request.headers);
  newHeaders.set('x-user', 'alice');
  const newRequest = new Request(request.url, { headers: newHeaders });
  return NextResponse.next(newRequest);
}
medium
A. null
B. undefined
C. alice
D. original header value if any

Solution

  1. Step 1: Analyze header modification in middleware

    The code creates new headers from the original, sets 'x-user' to 'alice', then creates a new Request with these headers.
  2. Step 2: Determine header value passed to app

    The app receives the new Request with 'x-user' header set to 'alice', so the value is 'alice'.
  3. Final Answer:

    alice -> Option C
  4. Quick Check:

    Header 'x-user' set to 'alice' in new Request [OK]
Hint: Headers set in new Request appear in app request [OK]
Common Mistakes:
  • Assuming original headers remain unchanged
  • Thinking header is removed or null
  • Confusing middleware response headers with request headers
4. Identify the error in this Next.js middleware code that tries to add a custom header:
import { NextResponse } from 'next/server';
export function middleware(request) {
  request.headers.set('x-custom', '123');
  return NextResponse.next(request);
}
medium
A. Headers are immutable; cannot modify request.headers directly
B. NextResponse.next() cannot accept a Request object
C. Missing await keyword for asynchronous header setting
D. Middleware must return a Response, not NextResponse

Solution

  1. Step 1: Check how headers can be modified in Next.js middleware

    Request headers are immutable; you cannot change them directly on the original request object.
  2. Step 2: Identify correct way to modify headers

    You must create a new Headers object, modify it, then create a new Request with those headers.
  3. Final Answer:

    Headers are immutable; cannot modify request.headers directly -> Option A
  4. Quick Check:

    Request.headers immutable = B [OK]
Hint: Request.headers are read-only; create new Headers to modify [OK]
Common Mistakes:
  • Trying to set headers directly on request.headers
  • Assuming NextResponse.next() rejects Request objects
  • Confusing async code requirement for headers
5. You want to add a custom header 'x-trace-id' with a unique value to every request in Next.js middleware, but only if the header is not already present. Which code snippet correctly implements this?
hard
A. import { NextResponse } from 'next/server'; export function middleware(request) { const headers = request.headers; if (!headers.has('x-trace-id')) { headers.set('x-trace-id', crypto.randomUUID()); } return NextResponse.next(request); }
B. import { NextResponse } from 'next/server'; export function middleware(request) { if (!request.headers.has('x-trace-id')) { const headers = new Headers(request.headers); headers.set('x-trace-id', crypto.randomUUID()); const newRequest = new Request(request.url, { headers }); return NextResponse.next(newRequest); } return NextResponse.next(); }
C. import { NextResponse } from 'next/server'; export function middleware(request) { const newRequest = new Request(request.url, { headers: { 'x-trace-id': crypto.randomUUID() } }); return NextResponse.next(newRequest); }
D. import { NextResponse } from 'next/server'; export function middleware(request) { const headers = new Headers(); headers.set('x-trace-id', crypto.randomUUID()); const newRequest = new Request(request.url, { headers }); return NextResponse.next(newRequest); }

Solution

  1. Step 1: Identify the correct conditional logic and immutable handling

    Check !request.headers.has('x-trace-id'), then const headers = new Headers(request.headers); headers.set('x-trace-id', crypto.randomUUID()); const newRequest = new Request(request.url, { headers }); return NextResponse.next(newRequest); else return NextResponse.next().
  2. Step 2: Why it works

    Clones headers immutably, adds conditionally if missing, preserves other headers, forwards new request or original.
  3. Step 3: Why others fail

    Direct set on request.headers throws immutable error. new Request with { headers: { 'x-trace-id': ... } } replaces all headers. new Headers() starts empty, loses original headers.
  4. Final Answer:

    import { NextResponse } from 'next/server'; export function middleware(request) { if (!request.headers.has('x-trace-id')) { const headers = new Headers(request.headers); headers.set('x-trace-id', crypto.randomUUID()); const newRequest = new Request(request.url, { headers }); return NextResponse.next(newRequest); } return NextResponse.next(); } -> Option B
  5. Quick Check:

    Check header, clone headers, set new, return new Request = A [OK]
Hint: Clone headers, check presence, set if missing, return new Request [OK]
Common Mistakes:
  • Modifying request.headers directly
  • Overwriting all headers instead of cloning
  • Not checking if header already exists