Coroutine vs Async/Awaitable
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()
{
await Awaitable.WaitUntilAsync(() => isDone);
Debug.Log("Condition met");
}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()
{
await Awaitable.WhenAll(
DoAAsync(),
DoBAsync()
);
Debug.Log("Both complete");
}Cancellation
Coroutine
Coroutine routine;
void Start()
{
routine = StartCoroutine(MyRoutine());
}
void Cancel()
{
// No cleanup hook; just stops
StopCoroutine(routine);
}Async/Awaitable
CancellationTokenSource cts;
async void Start()
{
cts = new CancellationTokenSource();
try
{
await MyAsync(cts.Token);
}
catch (OperationCanceledException)
{
Debug.Log("Cancelled cleanly");
}
}
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 | WhenAll / WhenAny |
| Requires MonoBehaviour | Yes | No (Unity 6) |
| Unit testable | Difficult | Standard async testing |
| Available since | Unity 4+ | Unity 6 / UniTask for older |
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.