Search across all documentation pages
A practical checklist for typing, streaming, retries, and edge deployment with @anthropic-ai/sdk. Use it when setting up a new integration or reviewing an existing one for type safety and production readiness.
npm install @anthropic-ai/sdk and pin a version in production. The SDK is fetch-based, so it runs unmodified on Node.js and on edge runtimes like Vercel Edge, Cloudflare Workers, and Deno Deploy.ANTHROPIC_API_KEY and let the client pick it up automatically.any.type before touching block-specific fields. TextBlock, ToolUseBlock, and ThinkingBlock are a discriminated union; a switch or if on .type is what makes the narrower fields type-safe to access.tool_use block's input to any. Parse it through the same schema you used to define the tool, so a malformed input fails a runtime check instead of silently passing through.MessageParam or ContentBlock by hand is a common source of type errors that only show up at the call site, not at the definition.for await loop, not manual event listeners. client.messages.stream() returns an async iterable; looping over it is simpler to read and simpler to cancel than wiring up .on() handlers.for await loop exits and cleans up on break, which is more predictable than tearing down multiple event listeners by hand.stream.finalMessage() when you need the fully assembled response. Use this after the loop when your UI wants both the token-by-token deltas and the final combined message.tool_use.input at runtime. The compile-time type and the runtime check come from the same definition, so they cannot drift apart.timeout in milliseconds, not seconds. The TypeScript SDK's timeout option is in milliseconds, unlike the Python and Ruby SDKs, which use seconds; mixing this up silently produces a timeout that is 1000x too short or too long.maxRetries at the client level for typical calls, and override it per request for calls that are expensive to repeat.AbortController into any request the user can cancel. Passing its signal into a request lets you cancel in-flight calls cleanly, and it works the same way in Node and in the browser.BadRequestError, RateLimitError, and similar specific classes before falling back to the base APIError.APIConnectionError before the base APIError check. APIConnectionError is a subclass of APIError in the TypeScript SDK, so a catch block that checks the base class first will swallow connection errors in the wrong branch.instanceof checks against the SDK's error classes, not string matching on error.message. This gives the catch block typed access to fields like .status and .error instead of parsing free text.RateLimitError versus APIConnectionError changes the fix.client.messages.stream() into a route handler for token-by-token chat UIs. This is the common pattern for a Next.js streaming chat endpoint: the route handler streams deltas straight through to the client.ANTHROPIC_API_KEY server-side only. Edge functions still run on the server; never ship the key to a client bundle or expose it through a public endpoint without a proxy layer in front of it.The TypeScript SDK's timeout is milliseconds. If you copy a value from Python or Ruby docs (seconds) without converting, requests either time out almost immediately or effectively never time out.
Hand-written JSON Schema works, but it drifts from your TypeScript types over time. Generating the schema from a Zod object keeps validation and typing in sync from one definition.
APIConnectionError is a subclass of APIError in the TypeScript SDK. Check it first in a catch block, or a base APIError check will catch it before your more specific handling runs.
You can, but it's rarely necessary. The async iterator already exposes each delta in order, so a for await loop covers most streaming needs without extra event wiring.
It works technically, but shipping ANTHROPIC_API_KEY to a browser bundle exposes it. Keep API calls behind a server route or edge function, and only send the resulting stream to the browser.
The model can return malformed or unexpected input. Parsing it through the same Zod schema used to define the tool catches that at runtime instead of letting a bad value flow silently into your application logic.
The SDK applies a default retry policy. It's reasonable for most calls, but expensive or side-effecting calls (like ones that trigger a paid downstream action) often warrant a lower value or explicit idempotency handling.
Not every request needs one, but any request a user can navigate away from or cancel (a chat message, a long tool call) should, so you're not paying for or waiting on work nobody needs anymore.
Start with group F (typed error handling) and group E (retry/timeout). Typing issues usually just cause compiler noise; missed error handling and wrong timeout units cause production incidents.
Yes. Since the client is fetch-based, client.messages.stream() behaves the same on Vercel Edge, Cloudflare Workers, and Deno Deploy as it does in Node.
Checking for a field (like block.input) can be true for more than one block type in the future as the union grows. Narrowing by the discriminant .type field is what TypeScript's control-flow analysis actually understands.
Mixing up the timeout unit (seconds versus milliseconds) and checking APIError before APIConnectionError in a catch block are the two most common, both because they're silent until something goes wrong in production.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
@anthropic-ai/sdkTypeScript SDK (latest release). Model names, SDK versions, and pricing move quickly - verify current specifics at platform.claude.com/docs before relying on them.