SDKs & Developer Experience

Async and Concurrent SDK Calls: asyncio, Promises, and goroutines

Claude calls are network-bound and often take seconds — which makes them ideal candidates for concurrency, and terrible candidates for unbounded concurrency.

Claude 3P 101 · Updated July 2026 · Unofficial guide

A single Claude request spends nearly all of its wall-clock time waiting on the network and the model. If you need to process fifty documents, running them one after another wastes that waiting time fifty times over. Every official SDK lets you overlap requests using its language's native concurrency primitive — the pattern is the same everywhere; only the syntax changes.

Python: threads or asyncio

The simplest concurrent Python pattern needs nothing beyond the standard library — the synchronous client from the SDK plus a thread pool:

from concurrent.futures import ThreadPoolExecutor
from anthropic import Anthropic

client = Anthropic()  # reads ANTHROPIC_API_KEY
docs = ["First document...", "Second document...", "Third document..."]

def summarize(text):
    return client.messages.create(
        model="claude-haiku-4-5", max_tokens=1024,
        messages=[{"role": "user", "content": f"Summarize: {text}"}],
    )

with ThreadPoolExecutor(max_workers=5) as pool:
    results = list(pool.map(summarize, docs))

Threads work well here precisely because the work is I/O-bound. If your application is already built on asyncio, the Python SDK also ships async support — the repository README and the platform docs cover the async client; pair it with asyncio.gather the same way you would any awaitable, and keep the semaphore-bounded pattern described below. Whichever you choose, keep a single client instance shared across workers rather than constructing one per call: the client is where connection reuse lives, and per-call construction throws that away. The same fan-out shape works unchanged against the third-party platform clients — swap Anthropic() for AnthropicBedrockMantle(aws_region="us-east-1") or AnthropicVertex(project_id="...", region="global") and the concurrency pattern is identical.

TypeScript: promises are already concurrent

The TypeScript SDK's client.messages.create({...}) returns a promise (the README's minimal example is await client.messages.create({ max_tokens: 1024, messages: [...], model: ... })). Concurrency therefore costs one idiom: build an array of those promises without awaiting them individually, then Promise.all (or Promise.allSettled, which doesn't abandon the batch when one request fails) to collect results. There is no separate async client to import — JavaScript's runtime model gives you the overlap for free.

Go: goroutines and contexts

The Go SDK's request method takes a context as its first argument — client.Messages.New(ctx, anthropic.MessageNewParams{...}) — which is the hook that makes Go concurrency composable: launch one goroutine per request, share a cancellable context so a failure or timeout can stop the whole batch, and collect results over a channel or an errgroup. This is standard Go fan-out; the SDK doesn't need anything special because blocking calls plus goroutines is Go's async model.

The part everyone skips: bounding concurrency

Your account has rate limits that vary by usage tier (Start, Build, Scale on the Claude API; Claude Platform on AWS limits are likewise managed by Anthropic, and new organizations start on the Start tier). Unbounded fan-out converts "fifty documents" into a burst of 429 responses, and naive retry loops then amplify the burst. Three rules keep concurrent workloads healthy:

Is concurrency even the right tool? If the work is offline and latency-tolerant, batch processing beats client-side fan-out: Anthropic's Message Batches API prices at a 50% discount to synchronous calls. Note the platform wrinkle — that API is available on the first-party API and Claude Platform on AWS but not on Bedrock or Vertex AI, which instead offer their own cloud-native batch inference (S3-based on Bedrock; BigQuery/GCS-based on Vertex AI, also at 50% batch pricing). Reserve client-side concurrency for interactive workloads that need answers now.

Where to go next

Concurrent code multiplies whatever error handling you have, so read error handling patterns across SDK languages and configuring retries next. Language basics live in the Python, TypeScript, and Go quickstarts.

Sources