Skip to main content
A client is the entry point for interacting with an AWS service. Each service has its own client class (for example, S3Client, DynamoDBClient). The client holds your configuration—region, credentials, retry settings, and more—and is responsible for sending commands to the service.
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";

const client = new S3Client({ region: "us-east-1" });
await client.send(new GetObjectCommand({ Bucket: "my-bucket", Key: "my-key" }));

Two client styles

Every service package exports two client styles. Bare-bones client (S3Client): Exposes only a .send() method. You import each command separately. Bundlers can tree-shake unused commands.
import { S3Client } from "@aws-sdk/client-s3";
import { GetObjectCommand } from "@aws-sdk/client-s3";

const client = new S3Client({});
await client.send(new GetObjectCommand({ Bucket: "...", Key: "..." }));
Aggregated client (S3): Every operation is a method directly on the client. All commands are imported at once, which increases bundle size.
import { S3 } from "@aws-sdk/client-s3";

const client = new S3({});
await client.getObject({ Bucket: "...", Key: "..." });
Prefer the bare-bones client (S3Client) in browser and Lambda environments where bundle size matters. The aggregated client is convenient for scripts and server-side tools where tree-shaking is less critical.

Constructor parameters

All constructor parameters are optional. Region and credentials can be supplied from environment variables or the ~/.aws/config and ~/.aws/credentials files, so you can construct a client with an empty object:
new S3Client({});
region
string | () => Promise<string>
The AWS region to send requests to. Accepts a region string or an async function that returns one.
new S3Client({ region: "us-west-2" });

// async provider form
new S3Client({ region: async () => "us-west-2" });
When using credential providers that create inner clients (such as fromCognitoIdentity), pass a consistent region to both the outer client and the credential provider’s clientConfig.
import { fromCognitoIdentity } from "@aws-sdk/credential-providers";

new S3Client({
  region: "us-west-2",
  credentials: fromCognitoIdentity({
    clientConfig: { region: "us-west-2" },
  }),
});
credentials
object | () => Promise<object>
AWS credentials. Accepts a literal credentials object or an async provider function.At the simplest level you can provide credentials directly, but only do this in testing.
new S3Client({
  credentials: {
    accessKeyId: "...",
    secretAccessKey: "...",
    sessionToken: "...",
  },
});
In production, use a credential provider from @aws-sdk/credential-providers:
import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";

new S3Client({
  credentials: fromTemporaryCredentials({ /* config */ }),
});
You can also supply a custom async function. Return an expiration date to enable automatic refresh:
new S3Client({
  credentials: async () => ({
    accessKeyId: "...",
    secretAccessKey: "...",
    expiration: new Date(Date.now() + 3600 * 1000),
  }),
});
endpoint
string | object | () => Promise<object>
Override the default service endpoint. Useful for local testing or compatible third-party services.
new S3Client({ endpoint: "http://localhost:8888" });
An async function returning a structured endpoint object is also accepted:
new S3Client({
  endpoint: async () => ({
    hostname: "localhost",
    path: "/",
    protocol: "http",
    port: 8888,
  }),
});
requestHandler
object
Controls how HTTP requests are made. The default handler differs by runtime: NodeHttpHandler in Node.js and FetchHttpHandler in browsers.Common Node.js options include connection and request timeouts and socket limits:
import { NodeHttpHandler } from "@aws-sdk/config/requestHandler";
import https from "https";

new S3Client({
  requestHandler: new NodeHttpHandler({
    httpsAgent: new https.Agent({
      keepAlive: true,
      maxSockets: 200,
    }),
    requestTimeout: 15_000,    // ms to wait for response
    connectionTimeout: 6_000,  // ms to establish connection
  }),
});
As of v3.521.0, you can use a shorthand object instead of instantiating the handler:
new S3Client({
  requestHandler: {
    requestTimeout: 3_000,
    httpsAgent: { maxSockets: 25 },
  },
});
In browsers, use FetchHttpHandler:
import { FetchHttpHandler } from "@aws-sdk/config/requestHandler";

new S3Client({
  requestHandler: new FetchHttpHandler({ requestTimeout: 30_000 }),
});
retryMode
string
default:"STANDARD"
Controls the retry algorithm. Accepted values are "STANDARD" (default) and "ADAPTIVE"."STANDARD" uses exponential backoff and only retries transient errors. "ADAPTIVE" additionally applies a rate limiter that slows the request rate when throttling is detected. When using retryStrategy, this option is ignored.
maxAttempts
number
Maximum number of attempts for a single operation call, including the initial attempt. Equivalent to using StandardRetryStrategy with the same count.
new S3Client({ maxAttempts: 5 });
For custom backoff computation use ConfiguredRetryStrategy:
import { ConfiguredRetryStrategy } from "@aws-sdk/config/retryStrategy";

new S3Client({
  retryStrategy: new ConfiguredRetryStrategy(
    5,
    (attempt: number) => 500 + attempt * 1_000
  ),
});
logger
object
A logger object implementing { trace, debug, info, warn, error }. Pass console directly or wrap it:
// Suppress debug and trace output
new S3Client({
  logger: {
    ...console,
    debug(...args) {},
    trace(...args) {},
  },
});
If your logger only accepts a single string argument, join the variadic args first:
new S3Client({
  logger: {
    ...console,
    info(...args) {
      yourLogger.info(args.join(" "));
    },
  },
});

Reusing clients

Do not create a new client on every operation call. Client construction resolves credentials, endpoints, and other dependencies. Recreating clients in a loop wastes compute and can trigger unnecessary credential refreshes.
Create one client per service/region combination and reuse it for multiple commands:
// ✅ Create once, reuse for all operations
const client = new S3Client({ region, credentials });

await client.send(new CreateBucketCommand({ Bucket }));

for (const item of items) {
  await client.send(new PutObjectCommand(item));
}

const objects = await client.send(new ListObjectsV2Command({ Bucket }));
// ⚠️ Avoid: new client on every iteration
for (const item of items) {
  const client = new S3Client({ region, credentials });
  await client.send(new PutObjectCommand(item));
}
If you need to make requests to multiple regions, instantiate separate clients and share a single credential provider between them:
import { fromTemporaryCredentials } from "@aws-sdk/credential-providers";

const credentials = fromTemporaryCredentials();

const s3 = {
  east: new S3Client({ region: "us-east-1", credentials }),
  west: new S3Client({ region: "us-west-2", credentials }),
};

Lambda best practices

Initialize the client outside the handler so that it is reused across warm invocations. Make API calls from inside the handler to ensure credentials are signed at execution time and avoid clock skew:
import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";

// Initialized outside the handler — reused on warm starts
const client = new STSClient({});

export const handler = async (event) => {
  try {
    const result = await client.send(new GetCallerIdentityCommand({}));
    return {
      statusCode: 200,
      body: JSON.stringify({ userId: result.UserId }),
    };
  } catch (err) {
    return { statusCode: 500, body: JSON.stringify({ message: "Error" }) };
  }
};

Reading and mutating client config

Do not read from or write to client.config after construction. The resolved config is not the same shape as the constructor input—for example, region is stored as an async function internally. Writing a string back to client.config.region will cause a TypeError at runtime.
// ⚠️ This will cause a runtime error
client.config.region = "us-west-2";
// Later: TypeError: config.region is not a function

// ⚠️ This will also throw
const endpoint = await client.config.endpoint();
// TypeError: client.config.endpoint is not a function
If you need to change regions, create additional client instances. If you need to resolve the endpoint for a given operation, use getEndpointFromInstructions from @smithy/middleware-endpoint:
import { getEndpointFromInstructions } from "@smithy/middleware-endpoint";
import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";

const config = { region: "us-west-2" };
const client = new S3Client(config);

const endpoint = await getEndpointFromInstructions(
  { Bucket: "my-bucket", Key: "my-key" },
  GetObjectCommand,
  config
);

console.log(endpoint.url.toString());
getEndpointFromInstructions is an internal API and may change between SDK versions. Do not rely on it in production code without pinning your SDK version.

Build docs developers (and LLMs) love