C.W.K.
Stream
Lesson 02 of 06 · published

Node·Next.js에서 스트리밍

~16 min · streaming, next-js, route-handler

Level 0Observer
0 XP0/64 lessons0/13 achievements
0/150 XP to next level150 XP to go0% complete

Async iterator

TypeScript SDK가 스트리밍을 client.messages.stream(...)로 노출 — typed 이벤트의 async iterator + finalMessage() promise. for await로 iterate; usage엔 finalMessage await. Python과 같은 모양, typed.

Next.js Route Handler와 ReadableStream

Next.js App Router Route Handler가 ReadableStream 바디 가진 Response 반환 가능. SDK 텍스트 스트림을 Response 스트림으로 pipe하면 브라우저가 토큰 도착하는 대로 봄. cwk-site가 이 패턴 사용; 같은 모양이 Vercel Edge에서 동작.

Backpressure와 cancellation

Stream 중간 클라이언트 disconnect 시 토큰 절약 위해 생성 멈추고 싶지. 요청의 AbortSignal을 SDK 호출에 wire해서 브라우저 탭 닫히면 server-side 생성 halt. SDK가 모든 메서드에 signal 받음.

원칙: Streaming은 transport plumbing. 다른 HTTP 작업에 쓸 abort signal 같은 거 hook, SDK가 나머지 알아서.

Code

Typed 이벤트로 stream iteration·typescript
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic();

const stream = await client.messages.stream({
  model: 'claude-sonnet-4-6',
  max_tokens: 1024,
  messages: [{ role: 'user', content: 'Three streaming tips.' }],
});

for await (const event of stream) {
  if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
    process.stdout.write(event.delta.text);
  }
}
const final = await stream.finalMessage();
console.log('\nusage:', final.usage);
Next.js App Router 스트리밍 Route Handler·typescript
// app/api/chat/route.ts (Next.js 16, App Router)
import Anthropic from '@anthropic-ai/sdk';

export const runtime = 'nodejs'; // 또는 테스트했으면 'edge'

const client = new Anthropic();

export async function POST(req: Request) {
  const { user } = await req.json();

  const stream = new ReadableStream<Uint8Array>({
    async start(controller) {
      const enc = new TextEncoder();
      const upstream = await client.messages.stream({
        model: 'claude-sonnet-4-6',
        max_tokens: 2048,
        messages: [{ role: 'user', content: user }],
        signal: req.signal, // 브라우저 disconnect 시 upstream 취소
      });
      try {
        for await (const event of upstream) {
          if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
            controller.enqueue(enc.encode(event.delta.text));
          }
        }
      } finally {
        controller.close();
      }
    },
  });

  return new Response(stream, {
    headers: { 'content-type': 'text/plain; charset=utf-8' },
  });
}

External links

Exercise

Claude 응답을 클라이언트로 stream하고 요청 cancel되면 upstream abort하는 Next.js Route Handler 빌드. 응답 중간 브라우저 탭 닫고 서버 로그에서 abort 확인.
Hint
Upstream abort 안 보이면 messages.stream()에 req.signal 전달 잊은 거.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.