collect is a Kotlin Flow terminal operation: it starts collecting emissions, invokes a lambda for each element, and suspends until the flow finishes or its coroutine scope is cancelled. section 16.2.2 section 17.4
Collect values as they are emitted
fun main() = runBlocking { createValues().collect { value -> log(value) } } The lambda runs once for each emission, so values can be processed immediately instead of waiting for the whole sequence. Because collect suspends, the call runs inside a coroutine such as runBlocking. section 16.1.1 section 16.2.2
The collection and emission steps interleave:
- Calling collect starts the flow builder. section 16.2.4
- Each emit invokes the collector lambda and passes it the emitted value. section 16.2.4
- The collector lambda may suspend, for example while delaying, writing to a database, or making an HTTP request. section 16.2.2
- After the lambda completes, execution returns to the flow builder until the next emission or completion. section 16.2.4
Intermediate operators such as map, filter, and onEach remain lazy until collect executes the upstream chain. Calling collect again on a cold flow reruns its logic, including side effects such as network requests. section 17.2 section 16.2.2
Use collect() without a lambda when an upstream onEach already performs the per-element work. Unlike first or firstOrNull, collect normally waits for every element; an infinite flow therefore does not complete by itself. section 17.4
Handle exceptions thrown inside the collect lambda with surrounding try-catch. The catch operator handles upstream exceptions only, so downstream failures remain outside its scope. section 18.4.1 section 18.6
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlin.time.Duration.Companion.milliseconds
val letters = flow {
log("Emitting A!")
emit("A")
delay(200.milliseconds)
log("Emitting B!")
emit("B")
}
fun main() = runBlocking {
letters.collect {
log("Collecting $it")
delay(500.milliseconds)
}
}
// 27 [main @coroutine#1] Emitting A!
// 38 [main @coroutine#1] Collecting A
// 757 [main @coroutine#1] Emitting B!
// 757 [main @coroutine#1] Collecting B
Trace timestamps through emission, collection, and suspension to see how the flow builder and collector alternate within one coroutine. section 16.2.2


