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
1. Cookie Handling
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 }
);
}
}