How to use an asyncio loop inside another asyncio loop
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The usual answer is: do not try to run an asyncio event loop inside another asyncio event loop in the same thread. If you are already inside async code, you should await coroutines or create tasks on the current loop, not call asyncio.run() again. Most "nested loop" problems come from using the wrong entry point for the context you are already in.
Why Nested asyncio.run() Fails
asyncio.run() is a top-level entry point. It creates a loop, runs a coroutine, and closes the loop. If you call it while another loop is already running in the same thread, Python raises an error.
The fix is not to "nest the loop correctly". The fix is usually to stop trying to start a second loop.
Use await or create_task() Instead
If you are already in async code, just call the inner coroutine with await:
If you want concurrent execution, create a task on the current loop:
This is usually what people actually want when they ask about "a loop inside another loop".
The Notebook and REPL Case Is Different
In environments such as Jupyter, there is often already a running event loop. That is why asyncio.run() can fail there even when your script would work fine from the command line.
In those environments, the normal pattern is to use await directly if the environment supports it, rather than forcing another loop:
If you find yourself reaching for loop-patching libraries just to make nested asyncio.run() work, first ask whether the environment already gave you the correct async entry point.
If You Truly Need Another Loop, Put It in Another Thread
There are advanced cases where a separate loop is justified, but that normally means a separate thread, not a nested loop in the same thread.
This is a specialized tool for integrations and background services, not the normal solution for ordinary coroutine composition.
Think in Terms of One Loop, Many Tasks
The mental model that scales is:
- one event loop per thread
- many coroutines scheduled on that loop
- explicit task creation for concurrency
That model is simpler than trying to reproduce nested call-stack thinking with event loops.
Common Pitfalls
- Calling
asyncio.run()from inside a coroutine. - Using nested loops when
awaiton the current loop is all that is needed. - Confusing "I need concurrency" with "I need another event loop".
- Fighting notebook environments instead of using their existing async support.
- Creating multiple loops in one thread and then debugging mysterious scheduling problems.
Summary
- Do not try to run an asyncio event loop inside another running loop in the same thread.
- Inside async code, use
awaitorasyncio.create_task()on the current loop. - '
asyncio.run()is for top-level entry, not nested usage.' - In notebooks, use the environment's existing async support when possible.
- If a separate loop is genuinely needed, it usually belongs in another thread.

