Skip to main content
AWS SDK for JavaScript v3 is a modular rewrite of v2. Packages are split by service, the API uses promises throughout, and there is no global configuration object. This page covers the most common migration patterns.

Package structure

V3 ships one package per service. Replace the monolithic aws-sdk package with the specific client package you need.
npm install aws-sdk

Import changes

// Importing a service client
const Lambda = require("aws-sdk/clients/lambda");
const AWS = require("aws-sdk");
const S3 = AWS.S3;

No global AWS.config

In v2, all clients merged their configuration with AWS.config — a global singleton. V3 removes global configuration entirely. Pass config directly to each client constructor.
const AWS = require("aws-sdk");

// Global config affects all subsequent clients
AWS.config.update({ region: "us-east-1" });

const s3 = new AWS.S3();
const dynamo = new AWS.DynamoDB();
You can still share configuration across clients by constructing the config object once:
const sharedConfig = { region: "us-east-1", credentials: myCredentials };

const s3 = new S3Client(sharedConfig);
const dynamo = new DynamoDBClient(sharedConfig);

API style: callbacks → promises

V2 operations use Node.js-style callbacks by default, with .promise() for promise-based calls. V3 operations always return promises.
// Callback style
s3.getObject({ Bucket, Key }, (err, data) => {
  if (err) console.error(err);
  else console.log(data);
});

// Promise style
const data = await s3.getObject({ Bucket, Key }).promise();

Sending commands

V3 separates the client from the operation. Operations are Command objects passed to client.send().
const s3 = new AWS.S3({ region: "us-east-1" });

const data = await s3.getObject({ Bucket: "my-bucket", Key: "my-key" }).promise();

Configuration option changes

httpOptionsrequestHandler

The httpOptions bucket from v2 is replaced by a requestHandler constructor option.
const client = new AWS.DynamoDB({
  httpOptions: {
    connectTimeout: 5000,
    timeout: 10000,
    agent: new https.Agent({ maxSockets: 50 }),
  },
});
Individual httpOptions fields:
v2 fieldv3 equivalent
connectTimeoutrequestHandler.connectionTimeout
timeoutrequestHandler.requestTimeout
agentrequestHandler.httpsAgent
proxyConfigure via a proxy agent
xhrAsyncDeprecated — requests are always async
xhrWithCredentialsrequestHandler.credentials (FetchHttpHandler)

maxRetriesmaxAttempts

// v2
new AWS.S3({ maxRetries: 3 });

// v3 — note: maxAttempts = maxRetries + 1
new S3Client({ maxAttempts: 4 });

sslEnabledtls

// v2
new AWS.S3({ sslEnabled: false });

// v3
new S3Client({ tls: false });

s3ForcePathStyleforcePathStyle

// v2
new AWS.S3({ s3ForcePathStyle: true });

// v3
new S3Client({ forcePathStyle: true });

Deprecated options (always on in v3)

These v2 options no longer need to be set — the behavior is always enabled in v3:
v2 optionv3 status
correctClockSkewDeprecated — clock skew correction is always applied
hostPrefixEnabledDeprecated — host prefix injection is always on
signatureCacheDeprecated — signing keys are always cached
maxRedirectsDeprecated — redirects are not followed (S3 uses followRegionRedirects)
paramValidationDeprecated — no client-side runtime validation
convertResponseTypesDeprecated — not type-safe; use TypeScript types instead

Error handling

Error metadata has moved from top-level fields to subfields.
try {
  await s3.getObject({ Bucket, Key }).promise();
} catch (err) {
  console.log(err.code);          // error code at top level
  console.log(err.statusCode);    // HTTP status at top level
}

Middleware replaces event listeners

V2 lets you modify requests by attaching event listeners. V3 uses a middleware stack.
AWS.events.on("beforeSend", (req) => {
  req.httpRequest.headers["x-custom"] = "value";
});
The middleware stack has five lifecycle steps: initialize, serialize, build, finalizeRequest, and deserialize. Each middleware calls the next one in the chain, making the execution order explicit and debuggable.

S3 multipart upload

const upload = s3.upload({
  Bucket,
  Key,
  Body: readStream,
  PartSize: 10 * 1024 * 1024,
});
upload.on("httpUploadProgress", (progress) => console.log(progress));
await upload.promise();
Install @aws-sdk/lib-storage separately: npm install @aws-sdk/lib-storage.

Credential providers

const AWS = require("aws-sdk");

// Shared credentials file
new AWS.SharedIniFileCredentials({ profile: "my-profile" });

// Temporary credentials
new AWS.ChainableTemporaryCredentials({ params: { RoleArn } });
All credential providers are available from the single @aws-sdk/credential-providers package.

Pagination

V2 requires manual handling of pagination tokens. V3 provides async generator paginators.
let marker;
do {
  const page = await s3.listObjectsV2({ Bucket, ContinuationToken: marker }).promise();
  for (const object of page.Contents) {
    console.log(object.Key);
  }
  marker = page.NextContinuationToken;
} while (marker);

Build docs developers (and LLMs) love