Paginators and waiters

boto3 · Practical · 10 min

List APIs return pages, and code that ignores pagination silently processes only the first 1000 items.

Most AWS list operations return results in pages: up to 1000 keys from list_objects_v2, 100 items from many others, with a continuation token (NextContinuationToken, NextToken, Marker; it varies). Writing the token loop yourself is error-prone.

A paginator handles it: client.get_paginator("list_objects_v2").paginate(Bucket=..., Prefix=...) returns an iterable of pages; loop over pages, then over items in each.

  • PaginationConfig={"MaxItems": 500, "PageSize": 100} caps the total and page size.
  • page_iterator.search("Contents[?Size > 1000].Key") applies a JMESPath expression across all pages and yields matching values lazily.
  • client.can_paginate("list_objects_v2") tells you whether a paginator exists.

Resource collections (bucket.objects.filter(Prefix=...)) paginate automatically too.

A waiter polls until a resource reaches a state: client.get_waiter("bucket_exists").wait(Bucket=...), or for EC2 instance_running, for DynamoDB table_exists, for CloudFormation stack_create_complete. WaiterConfig={"Delay": 5, "MaxAttempts": 40} tunes polling; a WaiterError is raised on failure or timeout. client.waiter_names lists what's available.

Waiters are for scripts and infrastructure automation. In request-handling code, prefer event-driven designs to blocking polls.

Example

import boto3

s3 = boto3.client("s3", region_name="us-east-1")
s3.create_bucket(Bucket="demo-pages-2026")
s3.get_waiter("bucket_exists").wait(Bucket="demo-pages-2026", WaiterConfig={"Delay": 1, "MaxAttempts": 10})
for i in range(2500):
    s3.put_object(Bucket="demo-pages-2026", Key=f"logs/{i:05}.txt", Body=b"x" * (i % 3))

first = s3.list_objects_v2(Bucket="demo-pages-2026", Prefix="logs/")
print(first["KeyCount"], first["IsTruncated"])         # 1000 True: only page 1!

pages = s3.get_paginator("list_objects_v2").paginate(Bucket="demo-pages-2026", Prefix="logs/")
total = sum(len(page.get("Contents", [])) for page in pages)
print(total)                                            # 2500

pages = s3.get_paginator("list_objects_v2").paginate(Bucket="demo-pages-2026", Prefix="logs/")
print(sum(1 for _ in pages.search("Contents[?Size > `1`].Key")))   # 833

Remember

  • List APIs return pages; use get_paginator(...).paginate(...)
  • PaginationConfig caps items and page size
  • .search('JMESPath') filters across all pages lazily
  • Waiters poll until a resource reaches a state

Watch out for

  • Calling list_objects_v2 once and assuming you got every key.

Check yourself

  1. A bucket has 4,200 objects. What does a single list_objects_v2 call return?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: boto3.amazonaws.com/v1/documentation/api/latest/guide/paginators.html

Builds on

Unlocks

Nothing builds on this yet.