{"id":3389,"library":"aiodataloader","title":"Asyncio DataLoader for Python","description":"Asyncio DataLoader is a Python port of the JavaScript DataLoader, a generic utility for efficient data fetching. It provides a consistent API over various data sources, leveraging batching to coalesce multiple individual load requests into a single operation within an event loop tick and per-request caching to prevent redundant data loads. The current version is 0.4.3, with releases occurring periodically to address bug fixes and add minor features, typically a few times a year.","status":"active","version":"0.4.3","language":"python","source_language":"en","source_url":"https://github.com/syrusakbary/aiodataloader","tags":["asyncio","dataloader","graphql","batching","caching","data-fetching"],"install":[{"cmd":"pip install aiodataloader","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"symbol":"DataLoader","correct":"from aiodataloader import DataLoader"}],"quickstart":{"code":"import asyncio\nfrom aiodataloader import DataLoader\n\n# A mock batch loading function for demonstration\nasync def fetch_users_from_db(user_ids: list[int]) -> list[dict | None]:\n    print(f\"Fetching users with IDs: {user_ids}\")\n    # Simulate an async database call\n    await asyncio.sleep(0.01)\n    # In a real scenario, this would query a database (e.g., ORM, API)\n    users_data = {\n        1: {\"id\": 1, \"name\": \"Alice\"},\n        2: {\"id\": 2, \"name\": \"Bob\"},\n        3: {\"id\": 3, \"name\": \"Charlie\"},\n    }\n    # Important: return values in the same order as keys, with None for missing\n    return [users_data.get(uid) for uid in user_ids]\n\nclass UserLoader(DataLoader):\n    def __init__(self):\n        super().__init__(self.batch_load_fn)\n\n    async def batch_load_fn(self, keys: list[int]) -> list[dict | None]:\n        return await fetch_users_from_db(keys)\n\nasync def main():\n    user_loader = UserLoader()\n\n    # Load individual users concurrently\n    # These three loads will be coalesced into a single call to fetch_users_from_db\n    user1_task = user_loader.load(1)\n    user2_task = user_loader.load(2)\n    user3_task = user_loader.load(1) # This will be served from cache (for ID 1) from the first load\n\n    user1, user2, user3 = await asyncio.gather(user1_task, user2_task, user3_task)\n\n    print(f\"User 1 (from first load): {user1}\")\n    print(f\"User 2: {user2}\")\n    print(f\"User 3 (from cache): {user3}\") \n\n    # Example of loading many\n    users_many = await user_loader.load_many([2, 3, 4]) # ID 4 will result in None\n    print(f\"Users (many): {users_many}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())","lang":"python","description":"Create a `DataLoader` by subclassing it and implementing `batch_load_fn`, which receives a list of keys and must return a list of values in the same order. Individual `load()` calls made within the same event loop tick are automatically batched."},"warnings":[{"fix":"Upgrade your Python environment to 3.7 or higher.","message":"Python 3.6 support was dropped in `v0.3.0` and `v0.4.0`. Users on Python 3.6 must upgrade to Python 3.7 or newer to use these versions.","severity":"breaking","affected_versions":">=0.3.0"},{"fix":"Ensure a valid, non-None key is always provided to `DataLoader.load()`.","message":"In `v0.4.0`, the `key` argument to `DataLoader.load()` no longer has a default value of `None`. Code explicitly passing `key=None` may now raise a `TypeError`.","severity":"breaking","affected_versions":">=0.4.0"},{"fix":"Instantiate a new `DataLoader` (or a factory to provide one) for each incoming request, ensuring its lifecycle is tied to the request.","message":"`aiodataloader` implements per-request, in-memory caching, not an application-wide shared cache. Creating a single, long-lived `DataLoader` instance and sharing it across multiple distinct requests or users can lead to incorrect data being served (stale data, cross-user data leaks). Instances should typically be created per web request or GraphQL execution context.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Always map the input `keys` list to the output `values` list, maintaining order and using `None` for unresolved keys.","message":"The `batch_load_fn` must return a list of values that directly correspond (one-to-one, same order) to the list of keys it received. If a key cannot be resolved to a value, `None` must be returned at that key's corresponding position in the list.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Invalidate relevant cache entries using `loader.clear(key)` or `loader.clear_all()` after operations that modify underlying data.","message":"After a data mutation or update, any existing cached values in `DataLoader` for the modified keys may become stale. To ensure fresh data is loaded, explicitly call `loader.clear(key)` for specific keys or `loader.clear_all()` to invalidate the entire loader's cache.","severity":"gotcha","affected_versions":"All versions"},{"fix":"When `cache=False`, ensure your `batch_load_fn` can handle and return values for duplicate keys as they appear in the input list.","message":"If `DataLoader` is instantiated with `cache=False` (disabling memoization caching), the `batch_load_fn` may receive duplicate keys. In this scenario, the batch function is responsible for returning a value for *each instance* of the requested key, not just unique keys.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-05-21T13:10:18.332Z","next_check":"2026-07-10T00:00:00.000Z","problems":[{"fix":"Install the package using pip: 'pip install aiodataloader'.","cause":"The 'aiodataloader' package is not installed in the Python environment.","error":"ModuleNotFoundError: No module named 'aiodataloader'"},{"fix":"Use the correct import statement: 'from aiodataloader import DataLoader'.","cause":"The import statement is incorrect; 'DataLoader' should be imported directly from 'aiodataloader'.","error":"ImportError: cannot import name 'DataLoader' from 'aiodataloader'"},{"fix":"Ensure that the coroutine is awaited: 'result = await dataloader.load(key)'.","cause":"Attempting to iterate over a coroutine without awaiting it.","error":"TypeError: 'coroutine' object is not iterable"},{"fix":"Use 'await' directly in the interactive environment or manage the event loop appropriately.","cause":"Calling 'asyncio.run()' inside an already running event loop, often in interactive environments like Jupyter notebooks.","error":"RuntimeError: This event loop is already running"},{"fix":"Use the correct method: 'await dataloader.load(key)'.","cause":"The 'DataLoader' class does not have a 'load_many' method; the correct method is 'load'.","error":"AttributeError: 'DataLoader' object has no attribute 'load_many'"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"install_tag":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"0.4.3","cli_name":"","cli_version":null,"type":"library","homepage":null,"github":"https://github.com/syrusakbary/aiodataloader","docs":null,"changelog":null,"pypi":"https://pypi.org/project/aiodataloader/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["database","http-networking","workflow"],"base_url":null,"auth_type":null,"install_checks":{"last_tested":"2026-05-21","tag":null,"tag_description":null,"installed_version":"0.4.3","pypi_latest":"0.4.3","is_stale":false,"results":[{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.08,"mem_mb":4,"disk_size":"18.1M"},{"runtime":"python:3.10-alpine","python_version":"3.10","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.1,"mem_mb":4,"disk_size":"18.1M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.06,"mem_mb":4,"disk_size":"19M"},{"runtime":"python:3.10-slim","python_version":"3.10","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.06,"mem_mb":4,"disk_size":"19M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.15,"mem_mb":4.9,"disk_size":"20.0M"},{"runtime":"python:3.11-alpine","python_version":"3.11","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.23,"mem_mb":4.9,"disk_size":"20.0M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.14,"mem_mb":4.9,"disk_size":"21M"},{"runtime":"python:3.11-slim","python_version":"3.11","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.14,"mem_mb":4.9,"disk_size":"21M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.36,"mem_mb":8.2,"disk_size":"11.9M"},{"runtime":"python:3.12-alpine","python_version":"3.12","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.56,"mem_mb":8.2,"disk_size":"11.9M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.5,"import_time_s":0.32,"mem_mb":8.2,"disk_size":"12M"},{"runtime":"python:3.12-slim","python_version":"3.12","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.39,"mem_mb":8.2,"disk_size":"12M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.39,"mem_mb":8.7,"disk_size":"11.6M"},{"runtime":"python:3.13-alpine","python_version":"3.13","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.51,"mem_mb":8.7,"disk_size":"11.5M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.6,"import_time_s":0.33,"mem_mb":8.7,"disk_size":"12M"},{"runtime":"python:3.13-slim","python_version":"3.13","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.4,"mem_mb":8.7,"disk_size":"12M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":null,"import_time_s":0.08,"mem_mb":4.3,"disk_size":"17.6M"},{"runtime":"python:3.9-alpine","python_version":"3.9","os_libc":"alpine (musl)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.09,"mem_mb":4.3,"disk_size":"17.6M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":"wheel","failure_reason":null,"import_side_effects":"clean","install_time_s":1.9,"import_time_s":0.08,"mem_mb":4.3,"disk_size":"18M"},{"runtime":"python:3.9-slim","python_version":"3.9","os_libc":"slim (glibc)","variant":"aiodataloader","exit_code":0,"wheel_type":null,"failure_reason":null,"import_side_effects":null,"install_time_s":null,"import_time_s":0.08,"mem_mb":4.3,"disk_size":"18M"}]},"_links":{"self":"https://checklist.day/api/registry/aiodataloader","v1":"https://checklist.day/v1/registry/aiodataloader","v1_install":"https://checklist.day/v1/registry/aiodataloader/install","v1_imports":"https://checklist.day/v1/registry/aiodataloader/imports","v1_compatibility":"https://checklist.day/v1/registry/aiodataloader/compatibility","v1_quickstart":"https://checklist.day/v1/registry/aiodataloader/quickstart","docs":"https://checklist.day/docs"}}