Performance Basics
Five examples to get you comfortable with the performance and cost levers in AWS SDK code - three basic and two intermediate.
Search across all documentation pages
Five examples to get you comfortable with the performance and cost levers in AWS SDK code - three basic and two intermediate.
Each example shows the same idea in both Python (boto3) and TypeScript (AWS SDK for JavaScript v3).
pip install boto3 (boto3 1.43.x, Python 3.10+). TypeScript: npm install @aws-sdk/client-s3 @aws-sdk/client-dynamodb (Node.js 18+).aws configure, environment variables, or an IAM role.Construct the client once, outside any loop or handler, and reuse it for every call.
# --- Python (boto3) ---
import boto3
# Module scope: created once, reused for every call below
s3 = boto3.client("s3", region_name="us-east-1")
def handler(event, context):
return s3.head_object(Bucket="my-bucket", Key=event["key"])// --- TypeScript (AWS SDK v3) ---
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
// Module scope: created once, reused for every invocation
const s3 = new S3Client({ region: "us-east-1" });
export const handler = async (event: { key: string }) => {
return s3.send(new HeadObjectCommand({ Bucket: "my-bucket", Key: event.key }));
};Related: Connection Pooling & Client Reuse - why this matters and how to size the pool.
The anti-pattern: building a fresh client inside the loop that calls it.
# --- Python (boto3) ---
import time
import boto3
start = time.perf_counter()
for key in ("a.txt", "b.txt", "c.txt"):
s3 = boto3.client("s3") # anti-pattern: new client every iteration
s3.head_object(Bucket="my-bucket", Key=key)
print(f"per-call client: {time.perf_counter() - start:.3f}s")// --- TypeScript (AWS SDK v3) ---
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
const start = performance.now();
for (const key of ["a.txt", "b.txt", "c.txt"]) {
const s3 = new S3Client({}); // anti-pattern: new client every iteration
await s3.send(new HeadObjectCommand({ Bucket: "my-bucket", Key: key }));
}
console.log(`per-call client: ${(performance.now() - start).toFixed(0)}ms`);A pool that's too small makes concurrent calls queue for a free connection.
# --- Python (boto3) ---
import boto3
from botocore.config import Config
cfg = Config(max_pool_connections=25) # match expected concurrent calls
ddb = boto3.client("dynamodb", config=cfg)// --- TypeScript (AWS SDK v3) ---
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { NodeHttpHandler } from "@smithy/node-http-handler";
import { Agent } from "node:https";
const ddb = new DynamoDBClient({
requestHandler: new NodeHttpHandler({
httpsAgent: new Agent({ maxSockets: 25 }), // match expected concurrent calls
}),
});Batch APIs do the work of many calls in one round trip.
# --- Python (boto3) ---
import boto3
sqs = boto3.client("sqs")
entries = [{"Id": str(i), "MessageBody": body} for i, body in enumerate(messages)]
sqs.send_message_batch(QueueUrl=queue_url, Entries=entries) # up to 10 per call// --- TypeScript (AWS SDK v3) ---
import { SQSClient, SendMessageBatchCommand } from "@aws-sdk/client-sqs";
const sqs = new SQSClient({});
const entries = messages.map((body, i) => ({ Id: String(i), MessageBody: body }));
await sqs.send(new SendMessageBatchCommand({ QueueUrl: queueUrl, Entries: entries })); // up to 10 per callSendMessageBatch sends up to 10 messages in one billed request instead of 10 separate SendMessage calls.BatchWriteItem and S3 DeleteObjects for their respective operations.Failed/failed-entries list even on an overall success.Run several calls in parallel, but cap how many are in flight together.
# --- Python (boto3) ---
import asyncio
import aioboto3
sem = asyncio.Semaphore(10) # at most 10 concurrent calls
async def get_one(session, key):
async with sem:
async with session.client("s3") as s3:
return await s3.head_object(Bucket="my-bucket", Key=key)
async def main():
session = aioboto3.Session()
await asyncio.gather(*(get_one(session, k) for k in keys))// --- TypeScript (AWS SDK v3) ---
import pLimit from "p-limit";
import { S3Client, HeadObjectCommand } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const limit = pLimit(10); // at most 10 concurrent calls
await Promise.all(keys.map((key) => limit(() => s3.send(new HeadObjectCommand({ Bucket: "my-bucket", Key: key })))));p-limit (TypeScript) caps in-flight calls without giving up parallelism entirely.Promise.all or an unbounded task list can overrun the connection pool or trigger service-side throttling.Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 23, 2026