skip to content

What is StateFlow in Kotlin coroutines, and how does it differ from a plain (cold) Flow?

level: juniorimportance: must knowfreq 80%

answer

  1. Always has .value
  2. Hot, not cold
  3. New collector gets current value first
  4. MutableStateFlow -> asStateFlow() to expose
  5. Idiomatic UI state holder

basics

~10 s

StateFlow is a flow that always holds one current value you can read at any time through .value. A plain Flow holds nothing on its own and only produces values when someone collects it.

solid answer

~40 s

StateFlow<T> is a hot, state-holder Flow from kotlinx.coroutines. It always has a current value exposed by the .value property, so you can read state synchronously without collecting. It is 'hot': the value exists independently of collectors. New collectors immediately receive the current value (replay of 1) and then every subsequent change. By contrast, a cold Flow built with flow { } is inert until collect() runs, re-executes its producer block per collector, and has no .value. StateFlow is read-only; you produce one via MutableStateFlow(initial) and expose it as a StateFlow with asStateFlow(). It is the idiomatic observable-state holder for UI (e.g. ViewModel exposing UI state).

code

kotlin · 4 lines
kotlin
val state = MutableStateFlow("idle")
println(state.value)          // idle, read synchronously
state.value = "loading"        // update
// any collector started now first sees "loading"

go deeper

for a junior

Knows StateFlow holds a current .value and is hot vs a cold flow that needs collection.

for a middle

Explains the private-mutable / public-readonly idiom and replay-of-1 behaviour for new collectors.

for a senior

Contrasts cold-flow per-collector semantics with StateFlow's shared single value and discusses where reading .value vs collecting is appropriate.

for a principal

Frames StateFlow as the observable-state primitive in a unidirectional-data-flow architecture and weighs it against alternatives.

## What StateFlow Is `StateFlow<T>` is an interface in `kotlinx.coroutines.flow`. It is a **hot** flow that models a single, always-present piece of observable state. - **Hot** means the data exists on its own, independent of whether anyone is collecting. A **cold** flow (created with `flow { ... }`) does nothing until a collector calls `collect`, and runs its producer block fresh for each collector. - StateFlow always has a **current value**, readable synchronously via the `.value` property — no coroutine or suspension needed to read it. ## Reading vs collecting Two ways to consume state: - `stateFlow.value` — read the latest value right now, synchronously. - `stateFlow.collect { ... }` — a suspending call that emits the **current** value immediately, then every later change. ## Read-only vs mutable - `StateFlow<T>` is read-only (no way to set the value). - `MutableStateFlow<T>` adds a settable `.value` and `update { }` helpers. The idiom is to keep a private `MutableStateFlow` and expose a public read-only `StateFlow` using `asStateFlow()`. ```kotlin class CounterViewModel { private val _count = MutableStateFlow(0) val count: StateFlow<Int> = _count.asStateFlow() fun increment() { _count.value += 1 } } ``` ## Cold Flow vs StateFlow at a glance - Cold `flow { }`: inert until collected; no `.value`; re-runs per collector. - StateFlow: always live; has `.value`; shares one value among all collectors; new collectors get the current value first. ## Why it matters StateFlow is the standard way to represent screen/UI state because the UI can read the current value synchronously (e.g. on configuration change) and also react to updates.

  • How do you turn a MutableStateFlow into a read-only StateFlow for the public API?
    Call asStateFlow() on it, or declare the public property type as StateFlow<T>; both prevent callers from writing .value.
  • Does a new collector of a StateFlow miss the current value?
    No. StateFlow has replay of 1, so a new collector immediately receives the current value, then subsequent updates.

A cold Flow is a recipe you must cook each time; a StateFlow is a dish always sitting on the counter — anyone walking up sees what's there right now.

saying these in an interview costs you the question

  • Saying StateFlow is cold and only runs when collected
  • Claiming you must collect to read the current value
  • Confusing StateFlow with LiveData semantics in detail
  • Thinking each collector re-runs a producer block like a cold flow
  • Exposing the MutableStateFlow directly as the public type

context