Next.js Curriculum
HardAdvanced Routing100% Free35 min read

Route Handlers, Streaming Responses & after() Lifecycle

The 30-Second Interview Answer

Route Handlers (route.ts) replace API routes in App Router, supporting web standard Request and Response objects. They can stream AI text generation or large payloads using ReadableStream and Server-Sent Events (SSE). In Next.js 15+, the after() API allows developers to schedule asynchronous side-effects (logging, audit trails, analytics) that execute after the response has finished streaming, without blocking the client response.

Learning Objectives

Implement custom HTTP handlers using standard Web APIs (Request, Response, Headers).

Stream real-time AI responses using ReadableStream and TransformStream.

Schedule asynchronous post-response work using the Next.js 15 after() function.

Explain the reliability boundaries and deployment requirements for after().

Prerequisites & Background Knowledge
Web Streams API (ReadableStream)Server-Sent Events (SSE)HTTP status codes and headers

Why Interviewers Care

Essential for generative AI applications (ChatGPT clones, streaming endpoints) and high-throughput logging architectures.

The Challenge

Demonstrate how to build a streaming Route Handler in Next.js that pipes chunks to the client. Use the Next.js 15 after() API to log audit events after the stream completes without delaying the response.

Code Architecture & Implementation

1// app/api/chat/route.ts
2import { NextRequest } from 'next/server';
3import { after } from 'next/server'; // Next.js 15+ API
4import { logAuditTrail } from '@/lib/audit';
5
6export async function POST(req: NextRequest) {
7 const { prompt, userId } = await req.json();
8 const startTime = Date.now();
9
10 // 1. Create a custom streaming response
11 const encoder = new TextEncoder();
12 const stream = new ReadableStream({
13 async start(controller) {
14 const words = ['Artificial', 'Intelligence', 'Streaming', 'in', 'Next.js', '15!'];
15 for (const word of words) {
16 controller.enqueue(encoder.encode(`data: ${word}\n\n`));
17 await new Promise((res) => setTimeout(res, 100)); // Simulate LLM token delay
18 }
19 controller.close();
20 },
21 });
22
23 // 2. Schedule non-blocking work with after()
24 // Executes AFTER the HTTP response has been sent to the client!
25 after(async () => {
26 const duration = Date.now() - startTime;
27 console.log(`[AUDIT] Request finished in ${duration}ms. Persisting log...`);
28 await logAuditTrail({
29 userId,
30 promptLength: prompt.length,
31 durationMs: duration,
32 timestamp: new Date(),
33 });
34 });
35
36 // 3. Return streaming Response immediately
37 return new Response(stream, {
38 headers: {
39 'Content-Type': 'text/event-stream',
40 'Cache-Control': 'no-cache',
41 Connection: 'keep-alive',
42 },
43 });
44}

Architectural Explanation

Prior to Next.js 15, performing asynchronous cleanup (like analytics or database logging) required either awaiting the operation (delaying client response time) or using unreliable background promises that could be terminated immediately upon response completion in serverless environments. The after() API tells the Next.js runtime to keep the serverless execution context alive until the scheduled task finishes, even though the HTTP response stream has already closed for the client.

Common Mistakes & Anti-Patterns

Using `after()` for mission-critical financial transactions that require absolute transactional durability (use message queues like SQS/RabbitMQ instead).

Awaiting long background operations before returning the `new Response()`, penalizing client TTFB.

Forgetting that Route Handlers inside route.ts cannot coexist with page.tsx in the same folder.

Interview Follow-Up Traps

The interviewer asks: "Can route.ts and page.tsx live in the same directory?" No! They conflict at the same route path; Next.js will throw a build error.

Frequently Asked Questions

Can after() be called inside Server Actions and Server Components?

Yes! `after()` can be called in Server Components, Server Actions, and Route Handlers.

Yes, it works identically in self-hosted Node.js servers and serverless hosting environments.

`after()` is the framework-agnostic Next.js abstraction that integrates with runtime lifecycle events including `waitUntil` under the hood.