Each example shows the same operation in both Python (boto3) and TypeScript (AWS SDK for JavaScript v3). By the end you can walk a multi-page list and let the SDK ride out a throttling error for you.
## Prerequisites
- Python: `pip install boto3` (boto3 1.43.x, Python 3.10+). TypeScript: `npm install @aws-sdk/client-s3` (Node.js 18+; install the client for whichever service you use).
- Credentials configured via `aws configure`, environment variables, or an IAM role - the SDK finds them automatically.
- A default region set with `AWS_REGION`, or passed per client. Examples use S3, but the same shape applies to any list operation.
---
## Basic Examples
### 1. Paginate a List Operation
Instead of one `list_objects_v2` call, ask the SDK for a paginator and iterate every page.
<CodeGroup labels="Python (boto3), TypeScript (AWS SDK v3)">
```python
# --- Python (boto3) ---
import boto3
s3 = boto3.client("s3")
paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket="my-bucket"):
for obj in page.get("Contents", []):
print(obj["Key"])
```
```typescript
// --- TypeScript (AWS SDK v3) ---
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
for await (const page of paginateListObjectsV2({ client: s3 }, { Bucket: "my-bucket" })) {
for (const obj of page.Contents ?? []) console.log(obj.Key);
}
```
</CodeGroup>
- boto3 exposes `get_paginator("operation_name")`, then `.paginate(**input)` yields page dicts.
- SDK v3 ships a `paginate<Operation>` helper per operation that returns an async iterator of pages.
- Each yielded value is a full page response; loop its items with the normal result key.
- Neither version touches `NextToken` / `ContinuationToken` - the paginator advances it for you.
> **Related:** [Paginators in boto3 & SDK v3](./paginators-in-boto3-and-sdk-v3.md) - automatic iteration versus manual tokens.
---
### 2. Cap the Page Size
Control how many items each request returns, to bound memory and consumed capacity.
<CodeGroup labels="Python (boto3), TypeScript (AWS SDK v3)">
```python
# --- Python (boto3) ---
import boto3
s3 = boto3.client("s3")
paginator = s3.get_paginator("list_objects_v2")
pages = paginator.paginate(
Bucket="my-bucket",
PaginationConfig={"PageSize": 100, "MaxItems": 500},
)
for page in pages:
for obj in page.get("Contents", []):
print(obj["Key"])
```
```typescript
// --- TypeScript (AWS SDK v3) ---
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const pages = paginateListObjectsV2(
{ client: s3, pageSize: 100 },
{ Bucket: "my-bucket" },
);
for await (const page of pages) {
for (const obj of page.Contents ?? []) console.log(obj.Key);
}
```
</CodeGroup>
- boto3 takes `PaginationConfig` with `PageSize` (per request) and `MaxItems` (overall stop).
- SDK v3 takes `pageSize` in the first config argument to the paginator.
- Smaller pages mean more requests but lower peak memory - a real trade-off.
- `PageSize` maps to the operation's `MaxKeys` / `Limit` under the hood.
---
### 3. Let the SDK Retry Throttling
Throttling is expected under load. Both SDKs retry it automatically with exponential backoff - you just configure how hard they try.
<CodeGroup labels="Python (boto3), TypeScript (AWS SDK v3)">
```python
# --- Python (boto3) ---
import boto3
from botocore.config import Config
cfg = Config(retries={"max_attempts": 5, "mode": "standard"})
s3 = boto3.client("s3", config=cfg)
# Throttling and transient 5xx now retry up to 5 attempts with backoff.
s3.list_buckets()
```
```typescript
// --- TypeScript (AWS SDK v3) ---
import { S3Client, ListBucketsCommand } from "@aws-sdk/client-s3";
// maxAttempts counts the first try plus retries.
const s3 = new S3Client({ maxAttempts: 5 });
await s3.send(new ListBucketsCommand({}));
```
</CodeGroup>
- boto3 configures retries through `botocore.config.Config(retries={...})`.
- `max_attempts` and `maxAttempts` both count the initial attempt plus retries.
- `mode: "standard"` retries throttling and transient errors with backoff; `adaptive` adds client-side rate limiting.
- You rarely write a retry loop yourself - you tune these knobs instead.
> **Related:** [Exponential Backoff & Jitter Configuration](./exponential-backoff-and-jitter-configuration.md) - the retry strategies in depth.
---
### 4. Handle a Throttling Error Explicitly
Sometimes you want to react to throttling yourself - to log it or slow a batch job.
<CodeGroup labels="Python (boto3), TypeScript (AWS SDK v3)">
```python
# --- Python (boto3) ---
from botocore.exceptions import ClientError
try:
s3.list_objects_v2(Bucket="my-bucket")
except ClientError as err:
code = err.response["Error"]["Code"]
if code in ("Throttling", "ThrottlingException", "SlowDown"):
print("throttled - backing off")
else:
raise
```
```typescript
// --- TypeScript (AWS SDK v3) ---
import { ListObjectsV2Command } from "@aws-sdk/client-s3";
try {
await s3.send(new ListObjectsV2Command({ Bucket: "my-bucket" }));
} catch (err) {
const name = (err as { name?: string }).name;
if (name === "ThrottlingException" || name === "SlowDown") {
console.log("throttled - backing off");
} else {
throw err;
}
}
```
</CodeGroup>
- boto3 surfaces the code at `err.response["Error"]["Code"]`.
- SDK v3 puts the service error code in `error.name`.
- S3 uses `SlowDown` for throttling; most services use `Throttling` / `ThrottlingException`.
- Re-raise anything you did not expect, so real failures still surface.
---
## Intermediate Examples
### 5. Flatten Pages with a Search Expression (boto3) / Collect Across Pages (SDK v3)
Often you want one flat stream of items, not a stream of pages.
<CodeGroup labels="Python (boto3), TypeScript (AWS SDK v3)">
```python
# --- Python (boto3) ---
import boto3
s3 = boto3.client("s3")
paginator = s3.get_paginator("list_objects_v2")
# .search runs a JMESPath expression across every page and yields items.
for key in paginator.paginate(Bucket="my-bucket").search("Contents[].Key"):
print(key)
```
```typescript
// --- TypeScript (AWS SDK v3) ---
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
const keys: string[] = [];
for await (const page of paginateListObjectsV2({ client: s3 }, { Bucket: "my-bucket" })) {
for (const obj of page.Contents ?? []) if (obj.Key) keys.push(obj.Key);
}
console.log(keys);
```
</CodeGroup>
- boto3's `.search(jmespath)` flattens results across all pages into one iterator.
- SDK v3 has no `.search`; you accumulate items yourself while iterating pages.
- `Contents[].Key` pulls just the key from each object across the whole listing.
- Both stay memory-friendly if you process items as they arrive rather than building a giant list.
---
### 6. Count Total Items Without Buffering
Walk every page and total the items, without holding them all in memory.
<CodeGroup labels="Python (boto3), TypeScript (AWS SDK v3)">
```python
# --- Python (boto3) ---
import boto3
s3 = boto3.client("s3")
paginator = s3.get_paginator("list_objects_v2")
total = 0
for page in paginator.paginate(Bucket="my-bucket"):
total += page.get("KeyCount", 0)
print(f"{total} objects")
```
```typescript
// --- TypeScript (AWS SDK v3) ---
import { S3Client, paginateListObjectsV2 } from "@aws-sdk/client-s3";
const s3 = new S3Client({});
let total = 0;
for await (const page of paginateListObjectsV2({ client: s3 }, { Bucket: "my-bucket" })) {
total += page.KeyCount ?? 0;
}
console.log(`${total} objects`);
```
</CodeGroup>
- `KeyCount` is the number of keys in each S3 page; sum it instead of collecting objects.
- The pattern generalizes: add `len(page["Items"])` or `page.Items?.length` for other services.
- Because you never buffer the full result, this scales to millions of items.
- The paginator still handles throttling and token advancement between pages.
---
## FAQs
<details>
<summary>Do I still need to handle NextToken myself?</summary>
No. That is exactly what the paginator removes. `get_paginator` in boto3 and the `paginate<Operation>` helpers in SDK v3 advance the continuation token internally.
</details>
<details>
<summary>Does the SDK retry throttling by default?</summary>
Yes. Both SDKs retry throttling and transient errors with exponential backoff out of the box. You configure the attempt count and mode; you do not have to write the loop.
</details>
<details>
<summary>What does max_attempts count?</summary>
The initial attempt plus retries. `max_attempts: 5` means one original call and up to four retries, for five total attempts.
</details>
<details>
<summary>What is the difference between PageSize and MaxItems?</summary>
`PageSize` caps items per request. `MaxItems` caps the total the paginator will yield across all pages before stopping.
</details>
<details>
<summary>Why iterate pages instead of collecting everything?</summary>
Iterating keeps memory bounded. Collecting an entire large listing into one array can exhaust memory and adds no benefit if you process items as they arrive.
</details>
<details>
<summary>Does SDK v3 have an equivalent of boto3's .search?</summary>
Not built in. You accumulate or filter items yourself while iterating the async pages, which is a couple of lines of code.
</details>
<details>
<summary>What error code does S3 use for throttling?</summary>
`SlowDown`. Most other services use `Throttling` or `ThrottlingException`. Match the codes relevant to the services you call.
</details>
<details>
<summary>Should I use standard or adaptive retry mode?</summary>
Start with `standard`. Switch to `adaptive` when a workload is frequently throttled, since it adds client-side rate estimation to reduce throttles.
</details>
## Related
- [Why AWS SDKs Need Paginators, Waiters & Retry Logic](./why-aws-sdks-need-paginators-waiters-and-retry-logic.md) - the concepts behind these examples.
- [Paginators in boto3 & SDK v3](./paginators-in-boto3-and-sdk-v3.md) - deeper on automatic versus manual pagination.
- [Structured Error Handling: ClientError vs SDK v3 Exceptions](./structured-error-handling-clienterror-vs-sdk-v3-exceptions.md) - catching specific error codes.
- [Pagination, Waiters & Retries Best Practices](./best-practices.md) - the defaults to set explicitly.
> **Stack versions:** This page was written for **boto3 1.43.x** (Python 3.10+) and the **AWS SDK for JavaScript v3** (Node.js 18+).
</content>
<span class="text-xs italic text-foreground/55" aria-hidden="true">636f64656775696465732e696f7c6367696f313130337c323032363037</span>