When working with Kotlin coroutines in Android, picking the right scope is crucial for keeping your app efficient, resilient, and leak-free. Two of the most common scopes you’ll see are SupervisorScope and viewModelScope. This article walks you through their differences, shows you concrete examples, and helps you decide which to use.

Example

class MyViewModel : ViewModel() {
  // viewModelScope: tied to ViewModel and runs on Dispatchers.Main
  fun loadUiData() {
    viewModelScope.launch {
      // Fetch user profile for the screen
      val profile = fetchUserProfile()
      // Update LiveData / UI state
    }
  }
 
  // Using SupervisorScope inside a suspending function
  suspend fun fetchAllData() = supervisorScope {
    launch { fetchOrders() }    // Task A
    launch { fetchMessages() }  // Task B
    launch { fetchSettings() }  // Task C
    // Even if fetchMessages() fails, A & C keep running
  }
}

Comparison

AspectSupervisorScopeviewModelScope
LifecycleManual—lives as long as its coroutine is activeTied to ViewModel; cancels on onCleared()
Default DispatcherInherits parent context (you choose Main, IO, or Default)Always Dispatchers.Main (UI thread)
Failure IsolationOne child fails → only that child is canceledBacked by SupervisorJob so siblings survive each other’s errors, but uncaught exceptions still bubble up and cancel the whole scope unless handled
Use CaseIndependent parallel tasks (e.g. multiple network calls)UI-related work that must stop when the screen goes away

Exception Handling

SupervisorScope

  • Use try/catch per child or attach a CoroutineExceptionHandler
  • Provides fine-grained control over error handling
  • Each child coroutine can handle its own exceptions independently

viewModelScope

  • Wrap each launch in try/catch or supply a handler to prevent scope-wide cancellation
  • Built-in error handling through SupervisorJob
  • Exceptions can still cancel the entire scope if not handled

Summary

SupervisorScope

  • Best for truly independent tasks on any dispatcher
  • One failure doesn’t kill its siblings
  • You manage its lifecycle manually

viewModelScope

  • Built into Android’s ViewModel and always runs on the main thread
  • Automatically cancels everything when the ViewModel is destroyed
  • Still lets sibling coroutines survive each other’s failures—provided you catch or handle exceptions

Bottom Line

  • Use SupervisorScope for isolated, parallel work on whatever dispatcher you need
  • Use viewModelScope for screen-tied, UI-thread coroutines that should auto-cancel when the ViewModel goes away

To learn more about coroutines and Android development: