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

Next.js + Claude: 인증 · Edge · Server Components

~16 min · next-js, edge, server-components, rsc

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

SDK 호출이 사는 곳

Next.js App Router에서 SDK 호출은 Server Component, Server Action, Route Handler에 속해 — Client Component 절대 X. API 키가 브라우저에 도달하면 안 됨. cwk-site는 app/api/*/route.ts를 SDK 호출의 canonical 집으로.

Edge vs Node 런타임

Edge 런타임은 더 빠른 cold-start, Vercel edge 네트워크에서 도는 거. Web 표준 API(fetch, ReadableStream, Node fs X)로 제한. SDK가 Edge에서 streaming·non-streaming Messages 호출 동작. 일부 헬퍼(Files API 통한 file upload)는 Node 런타임 요구. 디폴트 Edge; SDK 기능이 요구하면 Node로 fallback.

적절한 레이어에 caching

레이어 셋 결합 — 정적 프롬프트엔 Next.js fetch 캐시, 길고 안정한 prefix엔 Anthropic API의 prompt caching, 반복되는 동일 user 입력엔 자체 응답 캐시. 각 레이어가 다른 failure 모드 처리; 한 개로 collapse하지 마.

원칙: SDK 호출은 server-side, 끝. 'use client' 컴포넌트에서 import하고 있으면 멈추고 호출 옮겨.

Code

Prompt caching 가진 Server Action·typescript
// app/actions/summarize.ts
'use server';

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();
const SYSTEM_PERSONA = await fetch(new URL('./persona.md', import.meta.url)).then(r => r.text());

export async function summarize(text: string) {
  const resp = await client.messages.create({
    model: 'claude-sonnet-4-6',
    max_tokens: 512,
    system: [
      {
        type: 'text',
        text: SYSTEM_PERSONA,
        cache_control: { type: 'ephemeral' },
      },
    ],
    messages: [{ role: 'user', content: text }],
  });
  const block = resp.content.find(b => b.type === 'text');
  return block && block.type === 'text' ? block.text : '';
}
Edge 런타임 스트리밍 Route Handler·typescript
// app/api/chat/route.ts
import Anthropic from '@anthropic-ai/sdk';

export const runtime = 'edge';
export const dynamic = 'force-dynamic';

const client = new Anthropic();

export async function POST(req: Request) {
  const { messages } = (await req.json()) as { messages: Anthropic.MessageParam[] };

  const stream = await client.messages.stream({
    model: 'claude-sonnet-4-6',
    max_tokens: 1024,
    messages,
    signal: req.signal,
  });

  return new Response(stream.toReadableStream(), {
    headers: { 'content-type': 'text/event-stream' },
  });
}

External links

Exercise

Anthropic SDK 호출 하나를 Client Component(hook으로 몰래 가져온)에서 Server Action 또는 Route Handler로 옮겨. 빌드된 .next/static에서 ANTHROPIC_API_KEY 검색해 — 거기 있으면 안 됨.
Hint
API 키가 브라우저 번들에서 더 이상 reachable 안 한지 확인.

Progress

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

댓글 0

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

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