What is a CoroutineContext in Kotlin coroutines, and what kind of data does it hold?
answer
- Indexed set of elements keyed by Key
- Job + Dispatcher + CoroutineName + ExceptionHandler
- Immutable, combined with +
- Read via context[Key]
- coroutineContext property inside coroutines
basics
~20 sIt is a small set of settings carried by every coroutine. It bundles things like which thread pool runs the coroutine, its Job (lifecycle), and an optional name, so each coroutine knows how it should run.
solid answer
~30 sCoroutineContext is an immutable, indexed collection of Element objects, each identified by a unique Key. Every coroutine runs with one. Typical elements are the Job (lifecycle/cancellation), a CoroutineDispatcher (which thread it runs on), CoroutineName (for debugging), and CoroutineExceptionHandler. You build a context by combining elements with the + operator (e.g. Dispatchers.IO + CoroutineName("loader")) and pass it to launch/async or withContext. You look up an element by its key with context[Key]. It behaves a bit like an immutable map keyed by element type, but each element is also a context itself. Children inherit the parent context and can override individual elements.
code
kotlin · 10 linesimport kotlinx.coroutines.*
fun main() = runBlocking {
val context = Dispatchers.Default + CoroutineName("worker")
launch(context) {
println(coroutineContext[CoroutineName]) // CoroutineName(worker)
println(coroutineContext[Job]) // a Job instance
println(coroutineContext[ContinuationInterceptor]) // the dispatcher
}.join()
}go deeper
Knows a context holds the dispatcher, Job, and name, is immutable, and is combined with +.
Can read elements via context[Key], distinguish context from scope, and explain inheritance to children.
Explains the Element/Key model, that an element is itself a one-element context, and immutability's safety benefits.
Reasons about context as a foldable typed set, designing custom context elements and library APIs around it.
## What CoroutineContext is A `CoroutineContext` is an **immutable, indexed set of elements** that travels with every coroutine. Think of it as a tiny, type-safe map describing *how* a coroutine runs. Every `launch`, `async`, `runBlocking`, or `withContext` operates inside some context. ## The pieces - **Element**: a single entry in the context (e.g. a dispatcher). Each element implements `CoroutineContext.Element`, which itself extends `CoroutineContext` (a one-element context). - **Key**: a unique identifier of type `CoroutineContext.Key<E>` used to find an element. Each element exposes `key`. Looking up uses `context[SomeKey]`. ## Common elements - **`Job`** — the coroutine's lifecycle handle: tracks active/completing/cancelled state and parent-child relationships. - **`CoroutineDispatcher`** — decides which thread/pool runs the coroutine (`Dispatchers.Default`, `Dispatchers.IO`, `Dispatchers.Main`). - **`CoroutineName`** — a label shown in debugging/logs. - **`CoroutineExceptionHandler`** — last-resort handler for uncaught exceptions in root coroutines. ## Building and reading a context ```kotlin import kotlinx.coroutines.* val ctx = Dispatchers.IO + CoroutineName("loader") fun main() = runBlocking { launch(ctx) { // read an element by its key val name = coroutineContext[CoroutineName] // CoroutineName(loader) println(name?.name) }.join() } ``` `coroutineContext` is an implicit property available inside any `suspend` function/coroutine body. You combine elements with `+`; you read them by indexing with a key (here the companion object `CoroutineName` *is* the key). ## Key idea The context is **immutable**: combining with `+` returns a new context; it never mutates an existing one. This makes it safe to share and to inherit across parent/child coroutines.
- Is CoroutineContext mutable?No. It is immutable; the + operator returns a new combined context rather than modifying an existing one.
- How do you access the current context inside a suspend function?Use the implicit coroutineContext property, available in any coroutine body or suspend function.
Like a backpack each coroutine carries: it holds a few labeled items (which thread, its lifecycle Job, a name) that tell it how to run.
saying these in an interview costs you the question
- Saying the context is a mutable map you can put() into
- Confusing CoroutineContext with CoroutineScope (scope wraps a context but is not the same)
- Thinking only the dispatcher lives in the context
- Believing you must always create a context manually rather than inheriting it
- Claiming + mutates the left-hand context