Unity Coroutine vs Async/Await
Side-by-side comparison of Unity coroutines and async/await with code for every common pattern.
Unity 6 introduced Awaitable, bringing proper async/await to the engine. But when should you use it over coroutines? This reference shows the same operations implemented both ways, so you can see the differences and decide which fits your project.
Wait for Seconds
Coroutine
IEnumerator Wait()
{
yield return new WaitForSeconds(2f);
Debug.Log("Done waiting");
}Async/Awaitable
async Awaitable WaitAsync()
{
await Awaitable.WaitForSecondsAsync(2f);
Debug.Log("Done waiting");
}Wait for Condition
Coroutine
IEnumerator WaitFor()
{
yield return new WaitUntil(() => isDone);
Debug.Log("Condition met");
}Async/Awaitable
async Awaitable WaitForAsync()
{
while (!isDone)
await Awaitable.NextFrameAsync();
Debug.Log("Condition met");
}
// Unity's built-in Awaitable does not include
// a WaitUntilAsync. Use a NextFrameAsync loop
// as shown, or use UniTask's
// UniTask.WaitUntil() if you have it installed.Sequential Operations
Coroutine
IEnumerator RunSequence()
{
yield return StartCoroutine(StepA());
yield return StartCoroutine(StepB());
yield return StartCoroutine(StepC());
Debug.Log("All steps complete");
}Async/Awaitable
async Awaitable RunSequenceAsync()
{
await StepAAsync();
await StepBAsync();
await StepCAsync();
Debug.Log("All steps complete");
}Parallel Operations
Coroutine
IEnumerator RunParallel()
{
bool aFinished = false;
bool bFinished = false;
StartCoroutine(DoA(() => aFinished = true));
StartCoroutine(DoB(() => bFinished = true));
yield return new WaitUntil(
() => aFinished && bFinished
);
Debug.Log("Both complete");
}Async/Awaitable
async Awaitable RunParallelAsync()
{
// Awaitable does not support WhenAll natively.
// Use Task.WhenAll by returning Task from each
// method, or use UniTask.WhenAll if installed.
Task a = DoAAsync();
Task b = DoBAsync();
await Task.WhenAll(a, b);
Debug.Log("Both complete");
}
// If your async methods return Awaitable,
// convert to Task via .AsTask() (Unity 6) or
// switch to UniTask for full parallel support.Cancellation
Coroutine
Coroutine routine;
void Start()
{
routine = StartCoroutine(MyRoutine());
}
void Cancel()
{
// No cleanup hook; just stops
StopCoroutine(routine);
}Async/Awaitable
CancellationTokenSource cts;
async Awaitable Start()
{
cts = new CancellationTokenSource();
try
{
await MyAsync(cts.Token);
}
catch (OperationCanceledException)
{
Debug.Log("Cancelled cleanly");
}
}
// Avoid async void in Unity. Unhandled exceptions
// in async void methods are silently swallowed.
// Use async Awaitable for MonoBehaviour entry points.
void Cancel()
{
cts.Cancel();
cts.Dispose();
}Return a Value
Coroutine
// Coroutines cannot return values directly.
// Use a callback or set a field instead.
IEnumerator LoadHP(System.Action<int> callback)
{
yield return new WaitForSeconds(1f);
callback(100);
}
// Usage
StartCoroutine(LoadHP(hp =>
{
Debug.Log("HP: " + hp);
}));Async/Awaitable
// Awaitable<T> returns a value directly.
async Awaitable<int> LoadHPAsync()
{
await Awaitable.WaitForSecondsAsync(1f);
return 100;
}
// Usage
int hp = await LoadHPAsync();
Debug.Log("HP: " + hp);Summary Comparison
| Feature | Coroutine | Async/Awaitable |
|---|---|---|
| Return values | No (use callbacks) | Yes |
| Exception handling | No try/catch | Full try/catch/finally |
| Cancellation | StopCoroutine (no cleanup) | CancellationToken (clean) |
| Parallel execution | Manual tracking | Task.WhenAll (via .AsTask()) |
| Requires MonoBehaviour | Yes | No (Unity 6) |
| Unit testable | Difficult | Standard async testing |
| Available since | Unity 4+ | Unity 2023.1+ (Awaitable) / UniTask for earlier versions |
Quick decision guide
- Use coroutines when: simple time-based sequences, working with existing coroutine code, targeting older Unity versions.
- Use async/await when: starting new code on Unity 2023.1+, need exception handling, want to use Task-based libraries, need cancellation tokens.
- Mix freely. Both are fully supported and can call into each other.
Related Tools
Scripting Order
Interactive Unity MonoBehaviour lifecycle diagram. When does Awake, Start, Update, and every callback run.
DOTween Reference
Searchable DOTween cheat sheet with copy-paste Unity C# code for every common tween method.
Object Pool Generator
Generate production-ready Unity object pooling code with configurable options.
Frequently asked questions
Should I use coroutines or async/await in Unity?
Are async methods more expensive than coroutines?
Can I await a coroutine?
What happens to a coroutine when the GameObject is disabled?
Last updated: