- Next.js
- Advanced Routing & Interception
- Route Handlers, Streaming Responses & after() Lifecycle
Route Handlers, Streaming Responses & after() Lifecycle
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
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.ts2import { NextRequest } from 'next/server';3import { after } from 'next/server'; // Next.js 15+ API4import { logAuditTrail } from '@/lib/audit';56export async function POST(req: NextRequest) {7 const { prompt, userId } = await req.json();8 const startTime = Date.now();910 // 1. Create a custom streaming response11 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 delay18 }19 controller.close();20 },21 });2223 // 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 });3536 // 3. Return streaming Response immediately37 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
Does after() work in self-hosted Node.js Docker containers?
Yes, it works identically in self-hosted Node.js servers and serverless hosting environments.
How does after() differ from waitUntil in Cloudflare Workers?
`after()` is the framework-agnostic Next.js abstraction that integrates with runtime lifecycle events including `waitUntil` under the hood.
