TypeScript/JavaScript SDK Basics
11 examples to get you started with the TypeScript/JavaScript SDK, 7 basic and 4 intermediate.
Prerequisites / Quick Install
- Node.js 18+ (or an edge runtime like Vercel Edge, Cloudflare Workers, or Deno Deploy, since the SDK is fetch-based).
- Install the package:
npm install @anthropic-ai/sdk. - An API key from the Claude Console, set as the
ANTHROPIC_API_KEYenvironment variable. - TypeScript 5+ recommended so you get the SDK's built-in types without extra configuration.
Basic Examples
1. Install the Package
Add the official SDK to your project with your package manager of choice.
npm install @anthropic-ai/sdk- The SDK ships its own TypeScript types, so no separate
@typespackage is needed. - It's fetch-based under the hood, which is why it runs unmodified on Node.js and edge runtimes.
- Works with npm, pnpm, yarn, or bun, since it's published as a standard npm package.
2. Set the API Key via Environment Variable
Store your API key outside your source code and let the client pick it up automatically.
# .env.local (never commit this file)
ANTHROPIC_API_KEY=sk-ant-...- The SDK reads
process.env.ANTHROPIC_API_KEYby default, so you rarely need to pass a key explicitly in code. - Keeping the key in an environment variable avoids leaking it into version control or client-side bundles.
- In Next.js, only reference this variable from server-side code (route handlers, server actions), never in client components.
- Use a secrets manager or your hosting provider's environment variable settings in production instead of a committed
.envfile.
3. Instantiate the Client
Create an Anthropic client instance once and reuse it across requests.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// Reads ANTHROPIC_API_KEY from process.env automaticallynew Anthropic()with no arguments picks upANTHROPIC_API_KEYfrom the environment.- You can override the key explicitly with
new Anthropic({ apiKey: "..." })if you're loading it from a custom secrets source. - Create the client once at module scope and import it where needed, rather than constructing a new instance per request.
- The same client works in Node.js and edge runtimes without any conditional setup.
Related: The Anthropic TypeScript SDK Mental Model - how the client and its fetch-based transport fit together
4. Send a Basic Message
Call client.messages.create() to get a single, non-streamed response from Claude.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Explain what a closure is in one sentence." }],
});
console.log(message.content);model,max_tokens, andmessagesare the required fields for amessages.create()call.claude-sonnet-5is the default model in the current Claude lineup and a good starting point for most tasks.- The call returns a promise, so it must be awaited (or handled with
.then()). message.contentis an array of content blocks, not a plain string, since a response can mix text, tool calls, and other block types.
Related: TypeScript SDK Type Reference for Content Blocks - what's actually inside that content array
5. Read the Typed Response
Narrow the response's content blocks using the SDK's discriminated union types.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Say hello in three languages." }],
});
for (const block of message.content) {
if (block.type === "text") {
console.log(block.text);
}
}- Each content block has a
typediscriminant ("text","tool_use","thinking", and so on), which TypeScript uses to narrow the type. - Checking
block.type === "text"before readingblock.textgives you compile-time safety instead of anany-typed guess. - The response type also includes
usage,stop_reason, androle, all fully typed. - This pattern scales directly to tool use responses, where you'd check for
block.type === "tool_use"instead.
6. Hold a Multi-Turn Conversation
Build up the messages array across turns to give Claude conversation history.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const history: Anthropic.MessageParam[] = [
{ role: "user", content: "What's the capital of France?" },
{ role: "assistant", content: "The capital of France is Paris." },
{ role: "user", content: "What's its population?" },
];
const reply = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 512,
messages: history,
});Anthropic.MessageParamis the exported type for a single message entry, useful for typing arrays you build up over time.- Claude has no server-side memory of prior turns; the full conversation must be resent as
messageson every call. - Roles alternate between
"user"and"assistant", and the array should generally start with a"user"message. - Append each new reply's text to
historybefore the next call to keep the conversation growing correctly.
7. Set a System Prompt and Token Limit
Steer Claude's behavior with a system prompt, separate from the conversation itself.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const message = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 256,
system: "You are a terse assistant. Answer in a single sentence.",
messages: [{ role: "user", content: "Why is the sky blue?" }],
});systemis a top-level parameter, not a message with role"system", and applies to the whole request.max_tokenscaps the length of Claude's reply and counts against your usage, so set it to what the task actually needs.- Lowering
max_tokenstoo aggressively can cut a response off mid-thought; checkstop_reasonon the response if replies look truncated. - Swap
claude-sonnet-5forclaude-haiku-4-5on latency-sensitive paths orclaude-opus-4-8for the hardest reasoning tasks.
Intermediate Examples
8. Stream a Response with Async Iterators
Consume tokens as they arrive instead of waiting for the full response.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = client.messages.stream({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Write a haiku about databases." }],
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}client.messages.stream()returns an async iterable, sofor awaitconsumes events without manual event-listener wiring.- Each event is typed and discriminated by
event.type, mirroring the pattern used for content blocks. - The stream also exposes helper methods like
.finalMessage()if you want the assembled result after the loop ends. - Prefer streaming for anything rendered live in a UI; use
messages.create()when you only need the final text.
Related: Async Iterators for Streaming in the TypeScript SDK - a deeper look at consuming stream events
9. Catch Typed Errors
Handle API failures with the SDK's specific error classes instead of a generic catch-all.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
try {
await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
console.warn("Rate limited, back off and retry.");
} else if (error instanceof Anthropic.APIConnectionError) {
console.error("Network issue reaching the API.");
} else {
throw error;
}
}- Error classes like
RateLimitError,BadRequestError, andAPIConnectionErrorlet you branch oninstanceofwith full type narrowing. - Each error carries a
statuscode and response details, useful for logging or surfacing a specific message to users. - Re-throwing unknown errors (the
elsebranch) avoids silently swallowing bugs you didn't anticipate. - This pattern is worth wrapping in a shared helper once you have more than one or two call sites.
Related: TypeScript SDK Error Class Reference - the full list of error classes and when each one fires
10. Configure Retries, Timeouts, and Cancellation
Tune resilience settings and cancel in-flight requests with AbortController.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
maxRetries: 3,
timeout: 20_000,
});
const controller = new AbortController();
setTimeout(() => controller.abort(), 5_000);
const message = await client.messages.create(
{
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Summarize this in one line." }],
},
{ signal: controller.signal }
);maxRetriesandtimeoutare client-level defaults; both can also be overridden per request.- Passing an
AbortController'ssignalas a request option lets you cancel a call from user interaction (like a "Stop generating" button). - This works the same way in Node and browser environments, since both implement the standard
AbortControllerAPI. - Retries only kick in for retryable failures (like transient network errors or rate limits), not for validation errors.
Related: Retry, Timeout, and AbortController Patterns in the TypeScript SDK - backoff tuning and cancellation in more depth
11. Run the Same Client on an Edge Runtime
Use the identical client code in a Vercel Edge Function, Cloudflare Worker, or Node server.
export const runtime = "edge";
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
export async function POST(request: Request) {
const { prompt } = await request.json();
const message = await client.messages.create({
model: "claude-sonnet-5",
max_tokens: 512,
messages: [{ role: "user", content: prompt }],
});
return Response.json(message);
}- Because the SDK is built on
fetch, this route handler needs no Node-specific APIs and runs unchanged underexport const runtime = "edge". - The same
new Anthropic()call works whether the code executes in Node.js, Vercel Edge, Cloudflare Workers, or Deno Deploy. - Edge runtimes typically have tighter memory and execution-time limits, so keep
max_tokensand any streaming loop mindful of that. - Environment variables like
ANTHROPIC_API_KEYstill need to be configured for the edge environment specifically, since it's a separate runtime from your Node deployment.
Related: Running the Anthropic SDK on Edge Runtimes - edge-specific configuration and gotchas | Strongly Typed Tool Definitions with Zod in TypeScript - typing tool calls once you go beyond plain text messages
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.