Loading lessons...
Dynamic Route Handlers & Streaming Responses
Dynamic Route Handlers & Streaming Responses
Route Handlers support dynamic parameter extraction (like app/api/posts/[id]/route.ts) as well as real-time response streaming using the Web Streams API.
1. Dynamic Route Parameters
Route Handlers receive a second argument containing route parameters.
// app/api/posts/[id]/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
const post = await fetchPostById(id);
if (!post) {
return NextResponse.json({ error: 'Post not found' }, { status: 404 });
}
return NextResponse.json(post);
}
2. Streaming Responses with ReadableStream
Route Handlers can stream text or binary data directly to the client using ReadableStream, perfect for AI text generation (LLMs), large data export, or live server events.
// app/api/stream/route.ts
export async function GET() {
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
controller.enqueue(encoder.encode('Streaming chunk 1...
'));
await new Promise((r) => setTimeout(r, 1000));
controller.enqueue(encoder.encode('Streaming chunk 2...
'));
await new Promise((r) => setTimeout(r, 1000));
controller.enqueue(encoder.encode('Streaming finished!'));
controller.close();
},
});
return new Response(stream, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Transfer-Encoding': 'chunked',
},
});
}
Static vs Dynamic Route Handler Matrix
| Scenario | Cache State | Opt-Out Trigger |
|---|---|---|
GET Handler with static URL | Cached | Export export const dynamic = 'force-dynamic' |
GET Handler accessing request.nextUrl | Dynamic | Automatic (accessing request object) |
POST / DELETE / PUT Handlers | Dynamic | Automatic (non-GET HTTP methods are never cached) |
Route Handler using cookies() | Dynamic | Automatic (accessing dynamic request headers) |
TL;DR
- Dynamic parameters are accessed via the
paramsprop passed as the second argument to Route Handlers. - In Next.js 15+,
paramsis a Promise that should be awaited (const { id } = await params). - Stream live data back to clients by returning a
ReadableStreamin aResponseobject. - Non-GET methods (
POST,PUT,DELETE) are never cached.