How to query aws resources using boto3 and asyncio? Is this possible?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
boto3 is synchronous by default — every API call blocks the calling thread until the response arrives. Python's asyncio provides cooperative concurrency for I/O-bound tasks, but boto3 does not natively support async/await. To use boto3 with asyncio, you have three options: run synchronous boto3 calls in a thread pool via asyncio.to_thread(), use the third-party aiobotocore library (which provides true async AWS API calls), or use aioboto3 (a higher-level async wrapper). The thread pool approach works with standard boto3 and requires no additional dependencies.
Method 1: asyncio.to_thread() (Python 3.9+)
Run synchronous boto3 calls in the default thread pool to avoid blocking the event loop.
For Python 3.7-3.8, use loop.run_in_executor() instead:
Method 2: aiobotocore (True Async)
aiobotocore is a thin async wrapper around botocore (the library underlying boto3) that provides native async/await support without threads.
Method 3: aioboto3 (High-Level Async)
aioboto3 wraps aiobotocore to provide an interface similar to boto3, including resource-level abstractions.
Paginating Async Results
Many AWS APIs return paginated results. Handle pagination in async code:
Common Pitfalls
- Creating
boto3clients inside the event loop without threading:boto3.client()andboto3.resource()are synchronous and may perform network calls (e.g., STS for credentials). Creating them inside an async function withoutto_thread()blocks the event loop. Create clients in a thread or before starting the event loop. - Sharing a single
boto3client across tasks:boto3clients are not thread-safe. When usingasyncio.to_thread()withasyncio.gather(), each task should create its own client, or use a thread-local client pattern. - Mixing
aiobotocoreandboto3in the same project:aiobotocorepins a specific version ofbotocorewhich may conflict with the versionboto3requires. This causes version conflicts duringpip install. Choose one approach per project. - Not using
async withforaiobotocoreclients:aiobotocoreclients must be used withinasync withblocks to properly close HTTP connections. Forgetting the context manager leaks connections and eventually causesConnectionErroror resource exhaustion. - Rate limiting not handled: Running many AWS API calls concurrently with
asyncio.gather()can trigger AWS throttling. Useasyncio.Semaphoreto limit concurrency:sem = asyncio.Semaphore(10)andasync with sem: await api_call().
Summary
boto3is synchronous — useasyncio.to_thread()to run it concurrently without blocking the event loop- Use
aiobotocorefor true async AWS API calls without threads - Use
aioboto3for a higher-level async interface similar toboto3 - Always use
async withcontext managers foraiobotocore/aioboto3clients - Limit concurrent API calls with
asyncio.Semaphoreto avoid AWS throttling
Related reading
- How to query cloudwatch logs using boto3 in python
- How to query distinct from AWS log insights
- How to query DynamoDB by date range key, with no obvious hash key?
- How to query DynamoDB filtering by value in a list
- How to query database by id using SqlAlchemy?
- How to raise an exception for a tensorflow out of memory error?
- How to read a csv file from an s3 bucket using Pandas in Python
- How to read data in Google Colab from my Google drive?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.