
Aws Sdk Js V3 Usage
- 3.9k installs
- 2.2k repo stars
- Updated August 4, 2026
- aws/agent-toolkit-for-aws
aws-sdk-js-v3-usage is an agent skill that |.
About
Do not use emojis in any code comments or output when this skill is active aws sdk client one per service generated by smithy typescript https github com awslabs smithy typescript one to one with AWS services and operations aws sdk lib higher level helpers e g lib dynamodb lib storage aws sdk no prefix utility packages mostly internal don t import deep paths js import S3Client from aws sdk client s3 correct NOT import S3Client from aws sdk client s3 dist cjs S3Client Bare bones preferred smaller bundle js import S3Client GetObjectCommand from aws sdk client s3 const client new S3Client region us east 1 const output await client send new GetObjectCommand Bucket b Key k The aws sdk js v3 usage agent skill provides documented workflows prerequisites triggers and safety guidance from its SKILL md source Agents load it when user requests match the description and follow step by step instructions without inventing capabilities It integrates with standard agent tooling for the tasks inputs outputs and failure modes
- AWS SDK for JavaScript v3 development patterns. Use when writing JavaScript or TypeScript code that uses AWS services vi
- > Do not use emojis in any code, comments, or output when this skill is active.
- - `@aws-sdk/client-*` — one per service, generated by [smithy-typescript](https://github.com/awslabs/smithy-typescript);
- Follow aws-sdk-js-v3-usage SKILL.md steps and documented constraints.
- Follow aws-sdk-js-v3-usage SKILL.md steps and documented constraints.
Aws Sdk Js V3 Usage by the numbers
- 3,863 all-time installs (skills.sh)
- +503 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #202 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
aws-sdk-js-v3-usage capabilities & compatibility
- Capabilities
- aws sdk for javascript v3 development patterns. · > do not use emojis in any code, comments, or ou · `@aws sdk/client *` — one per service, generat · follow aws sdk js v3 usage skill.md steps and do
- Use cases
- orchestration
What aws-sdk-js-v3-usage says it does
AWS SDK for JavaScript v3 development patterns. Use when writing JavaScript or TypeScript code that uses AWS services via @aws-sdk/* packages (aws-sdk-js-v3), or when asked about schemas, runtime vali
> Do not use emojis in any code, comments, or output when this skill is active.
- `@aws-sdk/client-*` — one per service, generated by [smithy-typescript](https://github.com/awslabs/smithy-typescript); one-to-one with AWS services and operations
npx skills add https://github.com/aws/agent-toolkit-for-aws --skill aws-sdk-js-v3-usageAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3.9k |
|---|---|
| repo stars | ★ 2.2k |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 4, 2026 |
| Repository | aws/agent-toolkit-for-aws ↗ |
When should an agent use aws-sdk-js-v3-usage and what problem does it solve?
|
Who is it for?
Developers invoking aws-sdk-js-v3-usage as documented in the skill source.
Skip if: Skip when requirements fall outside aws-sdk-js-v3-usage documented scope.
When should I use this skill?
|
What you get
Outputs aligned with the aws-sdk-js-v3-usage SKILL.md workflow and stated deliverables.
- Tuned SDK client configuration
- HTTP handler setup code
By the numbers
- requestHandler shorthand available since AWS SDK v3.521.0
- Example configs use 15,000 ms requestTimeout and 6,000 ms connectionTimeout
- Explicit NodeHttpHandler example sets maxSockets to 200
Files
Do not use emojis in any code, comments, or output when this skill is active.
AWS SDK for JavaScript v3
Package Structure
@aws-sdk/client-*— one per service, generated by smithy-typescript; one-to-one with AWS services and operations@aws-sdk/lib-*— higher-level helpers (e.g.lib-dynamodb,lib-storage)@aws-sdk/*(no prefix) — utility packages (mostly internal; don't import deep paths)
Always import from the package root:
import { S3Client } from "@aws-sdk/client-s3"; // correct
// NOT: import { S3Client } from "@aws-sdk/client-s3/dist-cjs/S3Client"Two Client Styles
Bare-bones (preferred — smaller bundle):
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
const client = new S3Client({ region: "us-east-1" });
const output = await client.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));Aggregated (v2-style but NOT v2, larger bundle):
import { S3 } from "@aws-sdk/client-s3";
const client = new S3({ region: "us-east-1" });
const output = await client.getObject({ Bucket: "b", Key: "k" });Client Configuration
No global config in v3 — pass config to each client. region is always required; set it explicitly or via AWS_REGION env var.
const config = { region: "us-east-1", maxAttempts: 5 };
const s3 = new S3Client(config);
const dynamo = new DynamoDBClient(config);Do not read or mutate `client.config` after instantiation — it is a resolved form (e.g. region becomes an async function). See references/effective-practices.md.
For HTTP handler (NodeHttpHandler from @smithy/node-http-handler), retry strategy, endpoint details, logging, FIPS, dual-stack, protocol selection, and S3-specific options → see references/clients.md.
Credentials
All providers from @aws-sdk/credential-providers. Credentials are lazy and cached per client until ~5 min before expiry.
// Default chain (env → ini → IMDS/ECS) — use in most Node.js apps
const client = new S3Client({ credentials: fromNodeProviderChain() });
// Assume role (NOTE: fromTemporaryCredentials is correct for STS AssumeRole)
const client = new S3Client({
credentials: fromTemporaryCredentials({ params: { RoleArn: "arn:aws:iam::123456789012:role/MyRole" } }),
});
// Named profile
const client = new S3Client({ profile: "my-profile" });Share credentials and socket pool across multi-region clients:
const east = new S3Client({ region: "us-east-1" });
const { credentials, requestHandler } = east.config;
const west = new S3Client({ region: "us-west-2", credentials, requestHandler });For all providers (Cognito, SSO, web identity, custom chains, STS region priority) → see references/credentials.md.
Streams (e.g. S3 GetObject Body)
Always read or discard streaming responses — unread streams leave sockets open (socket exhaustion):
const { Body } = await client.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
const str = await Body.transformToString(); // read as string
const bytes = await Body.transformToByteArray(); // read as Uint8Array
// or discard:
await (Body.destroy?.() ?? Body.cancel?.());Streams can only be read once.
Paginators
Use paginate* functions instead of manual token handling:
import { DynamoDBClient, paginateListTables } from "@aws-sdk/client-dynamodb";
const client = new DynamoDBClient({});
const tableNames = [];
for await (const page of paginateListTables({ client }, {})) {
// page contains a single paginated output.
tableNames.push(...page.TableNames);
}DynamoDB DocumentClient
Use @aws-sdk/lib-dynamodb to work with native JS types instead of AttributeValues:
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand, PutCommand } from "@aws-sdk/lib-dynamodb";
const client = DynamoDBDocumentClient.from(new DynamoDBClient({}));
await client.send(new PutCommand({ TableName: "T", Item: { id: "1", name: "Alice" } }));
const { Item } = await client.send(new GetCommand({ TableName: "T", Key: { id: "1" } }));For marshall options, large numbers (NumberValue), pagination, and aggregated client → see references/dynamodb.md.
S3: Presigned URLs, Multipart Upload, Waiters
// Presigned GET URL
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const url = await getSignedUrl(client, new GetObjectCommand({ Bucket: "b", Key: "k" }), { expiresIn: 3600 });
// Multipart upload (large files / streams)
import { Upload } from "@aws-sdk/lib-storage";
const upload = new Upload({ client, params: { Bucket: "b", Key: "k", Body: stream } });
await upload.done();
// Waiters
import { waitUntilObjectExists } from "@aws-sdk/client-s3";
await waitUntilObjectExists({ client, maxWaitTime: 120 }, { Bucket: "b", Key: "k" });For presigned POST, signed headers, waiter options → see references/s3.md.
Error Handling
import { S3ServiceException } from "@aws-sdk/client-s3";
try {
await client.send(new GetObjectCommand({ Bucket: "b", Key: "k" }));
} catch (e) {
if (e?.$metadata) {
// SDK service error — has $metadata.httpStatusCode, e.name, e.$response
console.error(e.name, e.$metadata.httpStatusCode);
}
}Check e.name or instanceof for specific error types. See references/error-handling.md for full patterns.
For runtime validation, serialization to non-default formats, or questions about what schemas are in jsv3 → see references/schemas.md.
Performance: Parallel Workloads
// Configure maxSockets to match your parallel batch size
const client = new S3Client({
requestHandler: { httpsAgent: { maxSockets: 50 } },
cacheMiddleware: true, // skip if using custom middleware
});Streaming deadlock warning: with limited sockets, don't await the request and stream body separately — chain them. See references/performance.md.
Middleware
Add custom logic to all commands on a client:
client.middlewareStack.add(
(next, context) => async (args) => {
console.log(context.commandName, args.input);
const result = await next(args);
return result;
},
{ name: "MyMiddleware", step: "build", override: true }
);Steps (in order): initialize → serialize → build → finalizeRequest → deserialize
Abort Controller
const { AbortController } = require("@aws-sdk/abort-controller");
const { S3Client, CreateBucketCommand } = require("@aws-sdk/client-s3");
const abortController = new AbortController();
const client = new S3Client(clientParams);
const requestPromise = client.send(new CreateBucketCommand(commandParams), {
abortSignal: abortController.signal,
});
// The request will not be created if abortSignal is already aborted.
// The request will be destroyed if abortSignal is aborted before response is returned.
abortController.abort();
// This will fail with "AbortError" as abortSignal is aborted.
await requestPromise;Lambda Best Practices
Initialize clients outside the handler (container reuse), make API calls inside. For one-time async setup, use a lazy init flag inside the handler:
import { S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({}); // outside — reused across invocations
let ready = false;
export const handler = async (event) => {
if (!ready) { await prepare(); ready = true; } // lazy one-time setup inside handler
// ... API calls here
};See references/lambda.md for Lambda layers and versioning.
Node.js Version Requirements
- v3.968.0+ requires Node.js >= 20
- v3.723.0+ requires Node.js >= 18
TypeScript
Response fields are typed as T | undefined by default. Use AssertiveClient from @smithy/types to remove | undefined, or NodeJsClient / BrowserClient to narrow streaming blob types. See references/typescript.md.
SigV4a (S3 Multi-Region Access Points)
S3 MRAP and certain other features require SigV4a. You must install and side-effect-import exactly one of:
@aws-sdk/signature-v4-crt— Node.js only, better performance@aws-sdk/signature-v4a— Node.js + browsers, pure JS
import "@aws-sdk/signature-v4a"; // side-effect only — no exported values neededSee references/sigv4a.md for full details and MRAP ARN format.
Client Configuration Reference
Request Handler (HTTP)
Node.js (shorthand, v3.521.0+)
const client = new S3Client({
requestHandler: {
requestTimeout: 15_000, // ms to receive response
connectionTimeout: 6_000, // ms to establish connection
httpsAgent: { keepAlive: true, maxSockets: 50 },
},
});Node.js (explicit)
import { NodeHttpHandler } from "@smithy/node-http-handler";
import https from "node:https";
const client = new S3Client({
requestHandler: new NodeHttpHandler({
httpsAgent: new https.Agent({ keepAlive: true, maxSockets: 200 }),
requestTimeout: 15_000,
connectionTimeout: 6_000,
}),
});Default maxSockets is 50 per client. Socket exhaustion warning:
@smithy/node-http-handler:WARN - socket usage at capacity=N and M additional requests are enqueued.Browser
import { FetchHttpHandler } from "@aws-sdk/config/requestHandler";
const client = new S3Client({ requestHandler: new FetchHttpHandler({ requestTimeout: 30_000 }) });XHR (for upload progress events):
import { XhrHttpHandler } from "@aws-sdk/xhr-http-handler";
const handler = new XhrHttpHandler({ requestTimeout: 30_000 });
handler.on(XhrHttpHandler.EVENTS.UPLOAD_PROGRESS, (event) => { ... });
const client = new S3Client({ requestHandler: handler });Retry Strategy
// Simple: set max attempts
new S3Client({ maxAttempts: 5 });
// Custom backoff
import { ConfiguredRetryStrategy } from "@aws-sdk/config/retryStrategy";
new S3Client({
retryStrategy: new ConfiguredRetryStrategy(5, (attempt) => 500 + attempt * 1_000),
});
// Adaptive (rate-limiting)
new S3Client({ retryMode: "ADAPTIVE" });When retryStrategy is set, retryMode and maxAttempts are ignored.
Logging
// Enable SDK logging (suppress trace/debug)
new S3Client({
logger: { ...console, debug() {}, trace() {} },
});For full request/response logging, use middleware (see SKILL.md Middleware section).
Endpoint
// Custom endpoint (e.g. local mock)
new S3Client({ endpoint: "http://localhost:8888" });FIPS / Dual-stack
new S3Client({ useFipsEndpoint: true });
new S3Client({ useDualstackEndpoint: true });Retrieving the Endpoint Without Making a Request
This interface is not public/stable. Do not use in production, or verify it on every SDK version upgrade.
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getEndpointFromInstructions } from "@smithy/middleware-endpoint";
const client = new S3Client({ region: "us-east-1" });
/** @internal do not directly use in production. */
const endpoint = await getEndpointFromInstructions(
{ Key: "foo", Bucket: "bar" }, // 1. command input
GetObjectCommand, // 2. Command class
client.config // 3. client config
);Protocol Selection (v3.953.0+)
Most services support only one protocol. CloudWatch and SQS support multiple:
import { AwsJson1_0Protocol, AwsSmithyRpcV2CborProtocol } from "@aws-sdk/core/protocols";
new CloudWatch({ protocol: AwsJson1_0Protocol }); // default
new CloudWatch({ protocol: AwsSmithyRpcV2CborProtocol }); // CBORMiddleware Caching
// Cache middleware stack per client+command — reduces per-request overhead.
// Do not use if you modify the middleware stack after requests begin.
new S3Client({ cacheMiddleware: true });S3-Specific Options
// Retry with corrected region on 301 redirect (use only if bucket region is unknown)
new S3Client({ followRegionRedirects: true });Schemas (v3.953.0+)
See references/schemas.md.
Credentials Reference
All providers from @aws-sdk/credential-providers.
Provider Quick Reference
| Provider | Use case |
|---|---|
fromNodeProviderChain() | Default Node.js chain (env → ini → IMDS/ECS) |
fromEnv() | AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY env vars |
fromIni() | ~/.aws/credentials / ~/.aws/config profiles |
fromTemporaryCredentials() | STS AssumeRole |
fromWebToken() | STS AssumeRoleWithWebIdentity (OIDC) |
fromTokenFile() | OIDC token file (EKS IRSA) — reads AWS_WEB_IDENTITY_TOKEN_FILE + AWS_ROLE_ARN |
fromSSO() | AWS IAM Identity Center (SSO) |
fromCognitoIdentityPool() | Browser/mobile — Cognito Identity Pool |
fromInstanceMetadata() | EC2 instance profile (IMDSv1/v2) |
fromContainerMetadata() | ECS task role |
fromHttp() | Custom HTTP credential endpoint |
createCredentialChain() | Custom fallback chain |
Assume Role (STS)
import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";
const client = new S3Client({
credentials: fromTemporaryCredentials({
params: {
RoleArn: "arn:aws:iam::123456789012:role/MyRole",
RoleSessionName: "my-session", // optional, auto-generated if omitted
DurationSeconds: 3600, // optional
},
// clientConfig: { region: "us-east-1" } // override STS region if needed
}),
});Chained role assumption:
credentials: fromTemporaryCredentials({
masterCredentials: fromTemporaryCredentials({
params: { RoleArn: "arn:aws:iam::123456789012:role/RoleA" },
}),
params: { RoleArn: "arn:aws:iam::123456789012:role/RoleB" },
})Named Profile
// Simplest — sets profile for both client config and credentials
const client = new S3Client({ profile: "my-profile" });
// Explicit — credentials only
import { fromIni } from "@aws-sdk/credential-providers";
const client = new S3Client({ credentials: fromIni({ profile: "my-profile" }) });Web Identity / OIDC (fromWebToken)
import { fromWebToken } from "@aws-sdk/credential-providers";
const client = new S3Client({
credentials: fromWebToken({
roleArn: "arn:aws:iam::123456789012:role/MyRole",
webIdentityToken: await getTokenFromIdP(),
roleSessionName: "session", // optional
}),
});Cognito Identity Pool (browser/mobile)
import { fromCognitoIdentityPool } from "@aws-sdk/credential-providers";
const client = new S3Client({
region: "us-east-1",
credentials: fromCognitoIdentityPool({
identityPoolId: "us-east-1:1699ebc0-7900-4099-b910-2df94f52a030",
logins: { "accounts.google.com": googleIdToken }, // optional, for authenticated identities
}),
});Custom Chain
import { createCredentialChain, fromEnv, fromIni } from "@aws-sdk/credential-providers";
const client = new S3Client({
credentials: createCredentialChain(fromEnv(), fromIni({ profile: "fallback" })),
});STS Region Priority
When a credential provider uses STS internally, region is resolved in this order:
1. clientConfig.region passed to the provider 2. Profile region — if resolving from config file, this beats AWS_REGION 3. Outer client's region 4. AWS_REGION env var 5. Profile region — if not resolving from config file, this is lower than AWS_REGION 6. us-east-1 fallback
To pin the STS region explicitly:
fromTemporaryCredentials({
params: { RoleArn: "..." },
clientConfig: { region: "us-east-1" },
})DynamoDB Reference
DocumentClient (lib-dynamodb)
@aws-sdk/lib-dynamodb marshals native JS types to/from DynamoDB AttributeValues automatically.
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { DynamoDBDocumentClient, GetCommand, PutCommand, QueryCommand, DeleteCommand } from "@aws-sdk/lib-dynamodb";
const client = DynamoDBDocumentClient.from(new DynamoDBClient({ region: "us-east-1" }));
// Put
await client.send(new PutCommand({ TableName: "MyTable", Item: { id: "1", name: "Alice", age: 30 } }));
// Get
const { Item } = await client.send(new GetCommand({ TableName: "MyTable", Key: { id: "1" } }));
// Query
const { Items } = await client.send(new QueryCommand({
TableName: "MyTable",
KeyConditionExpression: "id = :id",
ExpressionAttributeValues: { ":id": "1" },
}));
// Delete
await client.send(new DeleteCommand({ TableName: "MyTable", Key: { id: "1" } }));Type Mapping
| JS type | DynamoDB type |
|---|---|
| string | S |
| number / bigint / NumberValue | N |
| boolean | BOOL |
| null | NULL |
| Array | L |
| Object | M |
| Uint8Array / Buffer / Blob / File... | B |
| Set\<string\> | SS |
| Set\<number\> / Set\<bigint\> / Set\<NumberValue\> | NS |
| Set\<Uint8Array\> / Set\<Blob\>... | BS |
Marshall Options
const client = DynamoDBDocumentClient.from(new DynamoDBClient({}), {
marshallOptions: {
removeUndefinedValues: true, // strip undefined from objects/arrays
convertEmptyValues: false, // convert "" / empty sets to null
convertClassInstanceToMap: false,
allowImpreciseNumbers: false, // true = allow numbers > MAX_SAFE_INTEGER (loses precision)
},
unmarshallOptions: {
wrapNumbers: false, // true = return NumberValue instead of JS number
},
});Large Numbers
Numbers exceeding Number.MAX_SAFE_INTEGER throw by default. Use NumberValue for precision:
import { NumberValue, DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
await client.send(new PutCommand({
TableName: "MyTable",
Item: { id: "1", bigNum: NumberValue.from("1000000000000000000000.000000001") },
}));Custom unmarshalling with BigInt:
const client = DynamoDBDocumentClient.from(new DynamoDBClient({}), {
unmarshallOptions: { wrapNumbers: (str) => BigInt(str) },
});Pagination (Scan / Query)
import { paginateScan } from "@aws-sdk/lib-dynamodb";
for await (const page of paginateScan({ client }, { TableName: "MyTable", Limit: 100 })) {
console.log(page.Items);
}Aggregated (full) Client
import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb";
const doc = DynamoDBDocument.from(new DynamoDBClient({}));
await doc.put({ TableName: "MyTable", Item: { id: "1" } });
await doc.get({ TableName: "MyTable", Key: { id: "1" } });Destroy
ddbDocClient.destroy() is a no-op. Call destroy() on the underlying DynamoDBClient.
Effective Practices Reference
Client Reuse
Create one client per region+credentials combination. Don't create clients inside loops:
// WRONG:
for (const item of items) {
const client = new S3Client({ region, credentials });
await client.send(new PutObjectCommand(item));
}
// OK:
const client = new S3Client({ region, credentials });
for (const item of items) {
await client.send(new PutObjectCommand(item));
}Don't Read or Mutate client.config
client.config is a resolved form — region becomes async () => "us-east-1", credentials are wrapped, etc. Reading or writing it directly will cause errors:
// WRONG: — throws "config.region is not a function"
client.config.region = "us-west-2";
// WRONG: — throws "client.config.endpoint is not a function"
const endpoint = await client.config.endpoint();To use multiple regions, create separate clients (share credentials to avoid duplicate resolution):
import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";
const creds = fromTemporaryCredentials({ params: { RoleArn: "..." } });
const east = new S3Client({ region: "us-east-1", credentials: creds });
const west = new S3Client({ region: "us-west-2", credentials: creds });To get the resolved endpoint for a specific operation:
import { getEndpointFromInstructions } from "@smithy/middleware-endpoint";
const endpoint = await getEndpointFromInstructions(
{ Bucket, Key },
GetObjectCommand,
{ region: "us-west-2", useDualstackEndpoint: false, useFipsEndpoint: false }
);
console.log(endpoint.url.toString());Always Read or Discard Streaming Responses
Unread streams hold sockets open → socket exhaustion / memory leak:
const { Body } = await client.send(new GetObjectCommand({ Bucket, Key }));
// OK: read
const bytes = await Body.transformToByteArray();
// OK: pipe
await client.send(new PutObjectCommand({ Bucket: dest, Key, Body }));
// OK: discard
await (Body.destroy?.() ?? Body.cancel?.());
// WRONG: — socket stays open
// (no action on Body)Cross-Region Connection Timeouts (Node.js 20+)
For cross-region requests that hit ETIMEDOUT / AggregateError:
import net from "node:net";
net.setDefaultAutoSelectFamilyAttemptTimeout(500); // default is 250msError Handling Reference
Service Errors
Non-2xx responses are thrown as JavaScript Errors with SDK-specific fields:
try {
await client.send(new CreateFunctionCommand({ ... }));
} catch (e) {
if (e?.$metadata) {
// e.name — error code string (e.g. "ResourceNotFoundException")
// e.$metadata.httpStatusCode — HTTP status
// e.$response — raw HTTP response object
// e.$responseBodyText — set when SDK fails to parse the error body (unexpected format)
console.error(e.name, e.$metadata.httpStatusCode);
}
}Checking Specific Error Types
By name or instanceof (both safe — SDK overrides Symbol.hasInstance):
import { NoSuchKeyException } from "@aws-sdk/client-s3";
if (e.name === "NoSuchKeyException") { ... }
if (e instanceof NoSuchKeyException) { ... }Unparseable Error Bodies
If the error body can't be parsed (e.g. a proxy returned HTML), the message will say:
"Deserialization error: to see the raw response, inspect the hidden field {error}.$response"
Inspect with:
if (e.$responseBodyText) console.debug(e.$responseBodyText);TypeScript: Version Mismatch Compilation Error
If you see:
error TS2345: Argument of type 'X' is not assignable to parameter of type 'Y'
'A' is assignable to the constraint of type 'B', but 'B' could be instantiated with a different subtypeThis is caused by mismatched @smithy/types / @aws-sdk/types versions across clients. Fix by pinning all @aws-sdk/client-* packages to the same version range:
{
"@aws-sdk/client-s3": "<=3.800.0",
"@aws-sdk/client-dynamodb": "<=3.800.0"
}Lambda Reference
SDK Version in Lambda Runtimes
Lambda bundles a specific SDK version — not the latest. To control the version, bundle the SDK with your function or use a Lambda layer.
Check the installed version:
const pkg = require("@aws-sdk/client-s3/package.json");
exports.handler = () => JSON.stringify(pkg);Creating a Lambda Layer
// package.json for layer content
{
"dependencies": {
"@aws-sdk/client-s3": "<=3.750.0",
"@aws-sdk/client-dynamodb": "<=3.750.0"
}
}Run npm install, then zip as:
layer_content.zip
└ nodejs/node_modules/@aws-sdk/...Deploy:
import { Lambda } from "@aws-sdk/client-lambda";
import fs from "node:fs";
const lambda = new Lambda();
await lambda.publishLayerVersion({
LayerName: "my-sdk-layer",
Content: { ZipFile: fs.readFileSync("./layer_content.zip") },
CompatibleRuntimes: ["nodejs20.x", "nodejs22.x"],
CompatibleArchitectures: ["x86_64", "arm64"],
});One-Time Async Initialization
Don't call async setup outside the handler — signed requests may expire during provisioned concurrency pre-warming. Use a lazy flag inside the handler instead:
// WRONG: risky — network requests may be frozen pre-flight
const ready = prepare();
export const handler = async (event) => { await ready; ... };
// OK: lazy init inside handler
let client = null;
export const handler = async (event) => {
if (!client) client = await prepare();
return client.getItem({ ... });
};SDK clients themselves (no async setup) are safe to initialize outside the handler:
const s3 = new S3Client({}); // OK: outside handler — reused across invocations
export const handler = async (event) => {
return s3.send(new GetObjectCommand({ ... }));
};Performance Reference
Parallel Workloads (Node.js)
Socket Configuration
Set maxSockets to match your parallel batch size:
import { NodeHttpHandler } from "@aws-sdk/config/requestHandler";
import { Agent } from "node:https";
const client = new S3Client({
cacheMiddleware: true, // cache middleware resolution — only if not adding custom middleware
requestHandler: new NodeHttpHandler({
httpsAgent: new Agent({ keepAlive: true, maxSockets: 50 }),
}),
});
// Shorthand (v3.521.0+):
const client = new S3Client({
requestHandler: { requestTimeout: 3_000, httpsAgent: { maxSockets: 50 } },
});Too few sockets → queuing slowdown. Too many → new socket overhead + risk of EMFILE (too many open files).
Sharing Credentials and Socket Pool
const primary = new S3Client({ region: "us-east-1" });
const { credentials, requestHandler } = primary.config;
const secondary = new S3Client({ region: "us-west-2", credentials, requestHandler });Streaming Deadlock
With limited sockets, don't await the request before setting up stream consumption:
// WRONG: deadlock with maxSockets: 1
const responses = await Promise.all([
s3.getObject({ Bucket, Key: "1" }),
s3.getObject({ Bucket, Key: "2" }),
]);
await Promise.all(responses.map((r) => r.Body.transformToByteArray()));
// OK: chain stream handling before awaiting
const responses = [s3.getObject({ Bucket, Key: "1" }), s3.getObject({ Bucket, Key: "2" })];
const objects = responses.map((get) => get.Body.transformToByteArray());
await Promise.all(objects);Batch Upload Example
const BATCH_SIZE = 100;
const client = new S3Client({ requestHandler: { httpsAgent: { maxSockets: 100 } } });
const promises = [];
while (files.length) {
promises.push(...files.splice(0, BATCH_SIZE).map((f) =>
client.send(new PutObjectCommand({ Bucket: "b", Key: f.name, Body: f.contents }))
));
await Promise.all(promises);
promises.length = 0;
}S3 Reference
Presigned URLs (GET / PUT)
import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
const client = new S3Client({ region: "us-east-1" });
// GET — default expiry 900s
const getUrl = await getSignedUrl(client, new GetObjectCommand({ Bucket: "b", Key: "k" }), { expiresIn: 3600 });
// PUT
const putUrl = await getSignedUrl(client, new PutObjectCommand({ Bucket: "b", Key: "k" }), { expiresIn: 3600 });Signing non-x-amz headers (e.g. Content-Type):
const url = await getSignedUrl(client, new PutObjectCommand({ Bucket: "b", Key: "k", ContentType: "image/png" }), {
signableHeaders: new Set(["content-type"]),
expiresIn: 3600,
});Signing x-amz-* headers (must use unhoistableHeaders):
const url = await getSignedUrl(client, new PutObjectCommand({ Bucket: "b", Key: "k", ChecksumSHA256: sha }), {
unhoistableHeaders: new Set(["x-amz-checksum-sha256"]),
expiresIn: 3600,
});Presigned POST (browser file upload)
import { createPresignedPost } from "@aws-sdk/s3-presigned-post";
const { url, fields } = await createPresignedPost(client, {
Bucket: "b",
Key: "uploads/${filename}", // ${filename} replaced by browser
Expires: 600,
Conditions: [["content-length-range", 0, 10485760]],
Fields: { acl: "bucket-owner-full-control" },
});
// Use url + fields in an HTML <form> or FormData POSTMultipart Upload (lib-storage)
Use @aws-sdk/lib-storage for large files, streams, or unknown-size bodies:
import { Upload } from "@aws-sdk/lib-storage";
import { S3Client } from "@aws-sdk/client-s3";
const upload = new Upload({
client: new S3Client({}),
params: { Bucket: "b", Key: "k", Body: readableStream },
queueSize: 4, // parallel part uploads (default 4)
partSize: 5 * 1024 * 1024, // min 5MB per part
leavePartsOnError: false,
});
upload.on("httpUploadProgress", (progress) => console.log(progress));
await upload.done();Waiters
import { S3Client } from "@aws-sdk/client-s3";
import { waitUntilBucketExists, waitUntilObjectExists } from "@aws-sdk/client-s3";
const client = new S3Client({});
await waitUntilBucketExists({ client, maxWaitTime: 60 }, { Bucket: "my-bucket" });
await waitUntilObjectExists({ client, maxWaitTime: 120 }, { Bucket: "my-bucket", Key: "my-key" });Available S3 waiters: waitUntilBucketExists, waitUntilBucketNotExists, waitUntilObjectExists, waitUntilObjectNotExists.
Waiter config: maxWaitTime (seconds, required), minDelay (default 5s), maxDelay (default 120s).
Other services export their own waitUntil* functions from the same client package.
Schemas Reference (v3.953.0+)
Schemas are runtime objects that describe the data structures of modeled shapes. Used internally by the SDK for serialization/deserialization, and available for runtime validation or serialization to non-default formats. Not needed for basic SDK usage.
Each exported interface has a corresponding schema suffixed with $:
import { type PutBucketAclRequest, PutBucketAclRequest$ } from "@aws-sdk/client-s3";Use case 1: Runtime validation
import { NormalizedSchema } from "@smithy/core/schema";
const $ = NormalizedSchema.of(PutBucketAclRequest$);
// Use $.isStringSchema(), $.isStructSchema(), $.structIterator(), etc.
// to walk the schema and validate an object at runtime.Useful when accepting unknown user input. Note: schemas do not include required-field or numeric-range constraints (by design — the SDK favors server-side validation).
Use case 2: Serialization to non-default formats
import { JsonCodec } from "@aws-sdk/core/protocols";
import { PutItemInput$ } from "@aws-sdk/client-dynamodb";
const codec = new JsonCodec({ timestampFormat: { useTrait: true, default: 7 }, jsonName: false });
const serializer = codec.createSerializer();
serializer.write(PutItemInput$, myData);
const json = serializer.flush(); // serialize DynamoDB input to JSON string
const deserializer = codec.createDeserializer();
const result = await deserializer.read(PutItemInput$, json);A schema is required (rather than dynamic heuristics) because serialized representations can be ambiguous — e.g. a number could be a timestamp, a base64 string could be a Uint8Array. CBOR is also supported via CborCodec from @smithy/core/cbor.
SigV4a and S3 Multi-Region Access Points
SigV4a (multi-region signing) is required for:
- S3 Multi-Region Access Points (MRAP)
- S3 Object Integrity with certain checksum types
- CloudFront KeyValueStore
Without it you get: Neither CRT nor JS SigV4a implementation is available.
Two implementations — pick one
Option A: CRT (Node.js only, better performance)
npm install @aws-sdk/signature-v4-crtimport "@aws-sdk/signature-v4-crt"; // side-effect import only — registers itself
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const client = new S3Client({ region: "us-east-1" });
await client.send(new PutObjectCommand({
Bucket: "arn:aws:s3::123456789012:accesspoint/mfzwi23gnjvgw.mrap",
Key: "my-key",
Body: "hello",
}));Option B: JavaScript / non-CRT (Node.js + browsers)
npm install @aws-sdk/signature-v4aimport "@aws-sdk/signature-v4a"; // side-effect import only — registers itself
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
const client = new S3Client({ region: "us-east-1" });
// same usage as aboveKey rules
- The import is a side-effect only — do not use any exported values. Just
import "...". - Do NOT install both. If both are present, CRT takes precedence.
- CRT version does not work in browsers. Use JS version for browser environments.
- JS version in browsers is not recommended due to large bundle size.
- The MRAP bucket ARN format:
arn:aws:s3::<account-id>:accesspoint/<alias>.mrap
TypeScript Reference
Remove | undefined from Response Structures
SDK response fields are typed as T | undefined by default. To opt out of this for a client:
import { S3Client } from "@aws-sdk/client-s3";
import type { AssertiveClient } from "@smithy/types";
const client = new S3Client({}) as AssertiveClient<S3Client>;
// Response fields are no longer unioned with undefinedSee @smithy/types docs for AssertiveClient and UncheckedClient (skips all runtime checks).
Narrow Streaming Blob Types
GetObjectCommand Body is typed as a union because the runtime type depends on the request handler (Node.js vs browser). To narrow it:
import { S3Client } from "@aws-sdk/client-s3";
import type { NodeJsClient } from "@smithy/types";
const client = new NodeJsClient<S3Client>(new S3Client({}));
// Body is now typed as NodeJsRuntimeStreamingBlob (Readable) instead of a unionMinimum TypeScript Version
No official minimum. Use a recent version. The SDK's own TypeScript version is in the root package.json of the aws-sdk-js-v3 repo.
Related skills
How it compares
Pick aws-sdk-js-v3-usage over generic AWS docs when tuning Node.js-specific HTTP handlers, socket pools, and timeouts for agent workloads.
FAQ
What is aws-sdk-js-v3-usage?
|
When should I use aws-sdk-js-v3-usage?
|
Is aws-sdk-js-v3-usage safe to install?
Review the Security Audits panel on this page before production use.