The SDK version bundled with Lambda
AWS Lambda Node.js runtimes include a specific minor version of the AWS SDK — not the latest. To see which version is included with your runtime, check the runtime-included SDK versions in the Lambda Developer Guide.
Do not rely on the Lambda-provided SDK for production functions. The bundled version is pinned and will not receive updates. Bundle the SDK with your function code or use a Lambda layer to control the exact version you depend on.
To discover the installed version at runtime:
const pkgJson = require("@aws-sdk/client-s3/package.json");
exports.handler = function (event) {
console.log(pkgJson.version);
return JSON.stringify(pkgJson);
};
Credentials in Lambda
You do not need to provide explicit AWS credentials in Lambda. The SDK automatically uses the function’s execution role via instance metadata (IMDS). Pass an empty config object to the client constructor:
import { S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({}); // credentials resolved from execution role
Client initialization best practices
Initialize clients outside the handler
Create SDK clients at module scope, outside the handler function. Lambda reuses the same container across invocations (container reuse / warm starts), so the client is initialized once and reused.import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
// Initialized once per container lifecycle
const client = new STSClient({});
export const handler = async (event) => {
const results = await client.send(new GetCallerIdentityCommand({}));
return {
statusCode: 200,
body: JSON.stringify({ userId: results.UserId }),
};
};
Make API calls inside the handler
Always invoke client.send(...) from within the handler, not at module scope. This ensures requests are signed at execution time, after the container is “hot”, avoiding signing time skew.
One-time setup inside the handler
If your initialization involves async work (fetching secrets, assuming a role), you may be tempted to run it at module scope:
// Risky: network requests made outside the handler may be frozen mid-flight
// during provisioned concurrency pre-warming
const ready = prepare();
export async function handler(event) {
await ready;
// ...
}
This is risky. Lambda’s provisioned concurrency can freeze the execution context between the module initialization and actual invocation. Time-sensitive signed requests made during prepare() may expire before the function is invoked.
Recommended pattern: run setup inside the handler, but only once:
let ready = false;
export async function handler(event) {
if (!ready) {
await prepare();
ready = true;
}
// ...
}
A practical example with lazy client initialization:
import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";
import { DynamoDB } from "@aws-sdk/client-dynamodb";
async function prepare() {
const credentials = fromTemporaryCredentials({})();
return new DynamoDB({ credentials });
}
let client: DynamoDB | null = null;
export async function handler(event) {
if (!client) client = await prepare();
return client.getItem({
TableName: "my-table",
Key: { id: { S: "1" } },
});
}
Creating a Lambda layer for the SDK
Using a Lambda layer lets multiple functions share the same SDK version without bundling it in each deployment package.
1. Create the layer content
In a clean directory, install the SDK packages you need:
{
"dependencies": {
"@aws-sdk/client-s3": "<=3.750.0",
"@aws-sdk/client-dynamodb": "<=3.750.0",
"@aws-sdk/lib-dynamodb": "<=3.750.0",
"@aws-sdk/client-lambda": "<=3.750.0"
}
}
Run npm install, then zip the node_modules folder into the required structure:
layer_content.zip
└── nodejs/
└── node_modules/
└── @aws-sdk/
2. Publish the layer
import { Lambda } from "@aws-sdk/client-lambda";
import fs from "node:fs";
const lambda = new Lambda();
await lambda.publishLayerVersion({
LayerName: "AWS-SDK-JavaScript-v3-layer",
Description: "AWS SDK v3 dependencies",
Content: {
ZipFile: fs.readFileSync("./layer_content.zip"),
},
CompatibleRuntimes: ["nodejs18.x", "nodejs20.x", "nodejs22.x"],
CompatibleArchitectures: ["x86_64", "arm64"],
});
3. Attach the layer to a function
import { Lambda } from "@aws-sdk/client-lambda";
const lambda = new Lambda();
const { Layers } = await lambda.listLayers({});
const layerArn = Layers.find(
(l) => l.LayerName === "AWS-SDK-JavaScript-v3-layer"
).LatestMatchingVersion.LayerVersionArn;
await lambda.updateFunctionConfiguration({
FunctionName: "MY_FUNCTION",
Layers: [layerArn],
});
Bundling your Lambda function with esbuild or a similar tool significantly reduces cold start time. A bundled v3 application on Node.js 18+ has measurably faster cold starts than v2. See the AWS blog post on reducing Lambda cold start times for benchmarks.
For parallel request workloads inside Lambda handlers, see Performance.