NextResponse vs Response

NextResponse vs Response

Standard Response (Web API)

// Basic Web Response
new Response(body, {
  status: 200,
  headers: { "Content-Type": "application/json" },
});

NextResponse (Next.js Enhanced)

import { NextResponse } from "next/server";

// 1. Basic Response
NextResponse.json({ data: "hello" });

// 2. Cookie Management
const response = NextResponse.next();
response.cookies.set("theme", "dark"); // Set
response.cookies.get("theme"); // Get
response.cookies.delete("theme"); // Delete

// 3. Redirects & Rewrites
// Redirect (changes URL in browser)
NextResponse.redirect(new URL("/login", request.url));

// Rewrite (proxies internally, URL stays same)
NextResponse.rewrite(new URL("/api/proxy", request.url));

Key Differences

  • Response: Manual header manipulation

  • NextResponse: Simple cookie methods

2. URL Handling

  • Response: Basic URL support

  • NextResponse: Advanced URL manipulation

3. Middleware Features

  • Response: No middleware support

  • NextResponse: Built-in middleware methods (next(), rewrite())

When to Use Each

// Use NextResponse when:
// 1. Working with cookies
const res = NextResponse.next();
res.cookies.set("session", token);

// 2. Doing redirects
return NextResponse.redirect("/dashboard");

// 3. In middleware
return NextResponse.next({
  headers: { "x-auth": "true" },
});

// Use standard Response when:
// 1. Simple JSON returns
return new Response(JSON.stringify(data));

// 2. Basic status codes
return new Response(null, { status: 404 });

Redirects vs Rewrites

// Redirect: Browser URL changes
// User visits /about -> gets sent to /new-about
return NextResponse.redirect(new URL("/new-about", request.url));

// Rewrite: Browser URL stays the same
// User sees /about but actually getting content from /secret-about
return NextResponse.rewrite(new URL("/secret-about", request.url));

Use cases for rewrites:

  • A/B Testing: Show different versions without changing URL

  • Internal APIs: Hide actual endpoints

  • Legacy URLs: Keep old URLs working with new content

  • Proxying: Access external content through your domain

Full route handler example

import { NextResponse } from "next/server";

export async function GET(request: Request) {
  // 1. Basic Response
  return NextResponse.json({ hello: "world" });

  // 2. With Status & Headers
  return NextResponse.json(
    { error: "Not Found" },
    {
      status: 404,
      headers: {
        "x-powered-by": "Next.js",
      },
    }
  );

  // 3. With Cookies
  const response = NextResponse.json({ data: "success" });
  response.cookies.set("session", "abc123");
  return response;
}

NextResponse next()

// In middleware.ts
import { NextResponse } from "next/server";

export function middleware(request: Request) {
  // A. Continue with modified headers
  const response = NextResponse.next({
    request: {
      headers: new Headers({
        ...request.headers,
        "x-auth": "true",
      }),
    },
  });

  // B. Continue but add response headers
  const response = NextResponse.next();
  response.headers.set("x-custom", "value");

  // C. Continue but modify cookies
  const response = NextResponse.next();
  response.cookies.set("visited", "true");

  return response;
}

Real world example combining features

// app/api/posts/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const version = searchParams.get("v");

  // A/B Testing with rewrites
  if (version === "beta") {
    return NextResponse.rewrite(new URL("/api/posts-beta", request.url));
  }

  // Authentication check
  const token = request.headers.get("authorization");
  if (!token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  try {
    const posts = await fetchPosts();
    const response = NextResponse.json(posts);

    // Add analytics cookie
    response.cookies.set("last-visited", "posts");

    return response;
  } catch (error) {
    return NextResponse.json(
      { error: "Failed to fetch posts" },
      { status: 500 }
    );
  }
}