TypeScript/JavaScript SDK Best Practices
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.
- Work through each lettered group in order: setup first, then typing, then the runtime concerns (streaming, retries, errors, deployment).
- Treat each item as a checkbox during code review, not just a one-time read.
- Revisit the retry/timeout and error-handling groups whenever you add a new call site or move a feature to an edge runtime.
- Pair this list with the Type Reference for Content Blocks and Error Class Reference for the exact types behind each rule.
Why does the timeout unit matter so much?
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.
Do I need Zod, or can I hand-write JSON Schema for tools?
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.
What's the difference between `APIConnectionError` and `APIError`?
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.
Can I use `for await` and event listeners together?
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.
Is the SDK safe to use directly in a browser?
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.
Why avoid casting `tool_use.input` to `any`?
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.
What happens if I don't set `maxRetries`?
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.
Should every request pass an `AbortController` signal?
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.
Which group should I check first when reviewing an existing integration?
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.
Do edge runtimes support streaming the same way Node does?
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.
Why narrow content blocks by `.type` instead of checking for a field's existence?
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.
What's the most common mistake teams make with this SDK?
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/sdk TypeScript SDK (latest release). Model names, SDK versions, and pricing move quickly - verify current specifics at platform.claude.com/docs before relying on them.