skip to content

shareIn / stateIn

shareIn and stateIn upgrade a cold flow to a hot one within a scope so several collectors share a single upstream. The SharingStarted policy — especially WhileSubscribed — is what controls whether the upstream keeps running when nobody is listening.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What do the shareIn and stateIn operators do to a cold Flow, and what is the difference between their results?

level: juniorimportance: must knowfreq 70%

answer

  1. Cold restarts per collector; hot shared once
  2. shareIn -> SharedFlow (replay configurable)
  3. stateIn -> StateFlow (always has .value)
  4. Both need scope + SharingStarted
  5. stateIn needs initialValue

basics

~10 s

Both turn a normal Flow that restarts for each collector into a shared one that runs once for everybody. shareIn gives a SharedFlow; stateIn gives a StateFlow that always has a current value.

solid answer

~40 s

A cold Flow re-executes its producer block for every collector. shareIn and stateIn convert it into a hot flow whose single upstream is shared by all collectors. shareIn(scope, started, replay) returns a SharedFlow with a configurable replay cache. stateIn(scope, started, initialValue) returns a StateFlow, which is a SharedFlow specialization that always holds exactly one latest value (.value), conflates updates, and emits that value immediately to new collectors. Both need a CoroutineScope to host the shared upstream coroutine and a SharingStarted policy controlling when the upstream starts and stops. stateIn requires an initialValue (unless you use the suspending stateIn overload that waits for the first emission); shareIn does not.

code

kotlin · 3 lines
kotlin
val shared: SharedFlow<Int> = upstream.shareIn(scope, SharingStarted.Lazily, replay = 1)
val state: StateFlow<Int> = upstream.stateIn(scope, SharingStarted.Eagerly, initialValue = 0)
println(state.value) // StateFlow always has a current value

go deeper

for a junior

Knows shareIn yields SharedFlow and stateIn yields StateFlow, and that both make a cold flow shared.

for a middle

Explains cold-vs-hot precisely and why stateIn needs an initialValue while shareIn does not.

for a senior

Connects sharing to deduplicating an expensive upstream (one subscription for N collectors) and notes conflation/distinct semantics of StateFlow.

for a principal

Frames the choice as an API/lifecycle contract decision and reasons about scope ownership and resource lifetime implications.

## Cold vs hot A **cold** `Flow` is lazy: the lambda you pass to `flow { ... }` (or operators like `map`) re-runs *from scratch* for **each** collector. Two collectors mean two independent executions. A **hot** flow has a single producer running independently of collectors, and all collectors observe the *same* stream. `shareIn` and `stateIn` are the operators that **convert cold to hot** inside a `CoroutineScope`. ## shareIn ```kotlin fun <T> Flow<T>.shareIn( scope: CoroutineScope, started: SharingStarted, replay: Int = 0 ): SharedFlow<T> ``` It launches a coroutine in `scope` that collects the upstream once and re-emits items into a `SharedFlow`. `replay` is how many recent values are cached and replayed to new collectors. ## stateIn ```kotlin fun <T> Flow<T>.stateIn( scope: CoroutineScope, started: SharingStarted, initialValue: T\): StateFlow<T> ``` A `StateFlow` is a special `SharedFlow` that **always has a value** (`.value`), keeps exactly one latest value (`replay = 1`, conflated), and only emits when the value changes (distinct via `equals`). New collectors immediately get the current value. ## Why a scope and SharingStarted The shared upstream coroutine must live in some scope (e.g. `viewModelScope`). `SharingStarted` decides *when* that upstream coroutine actually starts and stops collecting — `Eagerly`, `Lazily`, or `WhileSubscribed(...)`. ## Key contrast - `shareIn` -> `SharedFlow`, replay configurable, no initial value, can have zero cached values. - `stateIn` -> `StateFlow`, always one current value, needs `initialValue`, conflates and de-duplicates.

  • Why does stateIn require an initialValue but shareIn does not?
    A StateFlow must always have a current value available via .value for any new collector, so it needs a seed before the upstream emits. SharedFlow can legitimately have zero cached values.
  • Does converting to hot change how many times the upstream runs?
    Yes — the upstream now runs at most once (shared) instead of once per collector, which is often the whole point (e.g. one network/db subscription).

Cold flow is cooking a fresh meal per guest; shareIn/stateIn is a buffet everyone shares from one kitchen.

saying these in an interview costs you the question

  • Saying shareIn and stateIn are interchangeable
  • Claiming the upstream still restarts per collector after conversion
  • Thinking StateFlow can exist without a current value
  • Forgetting that a CoroutineScope is required
  • Confusing replay count with initialValue

context

open as a page

Compare SharingStarted.Eagerly, Lazily, and WhileSubscribed. How does each control when the shared upstream starts and stops?

level: middleimportance: must knowfreq 65%

basics

~20 s

Eagerly starts the upstream right away and never stops. Lazily starts on the first collector and never stops. WhileSubscribed starts on the first collector and stops when the last one leaves, optionally after a timeout.

open as a page

Explain the replay parameter of shareIn and the initialValue of stateIn, and how a new collector experiences each.

level: middleimportance: should knowfreq 50%

basics

~10 s

shareIn's replay says how many recent values a brand-new collector instantly receives. stateIn always replays exactly the one latest value, and its initialValue is what collectors see before the upstream has emitted anything.

open as a page

With SharingStarted.WhileSubscribed, what happens to the upstream coroutine across subscriber gaps, and what are the resource and correctness implications versus Eagerly?

level: seniorimportance: should knowfreq 45%

basics

~10 s

WhileSubscribed cancels the upstream when nobody is listening (after a timeout) and restarts it when a collector returns, so expensive work pauses and resumes. Eagerly keeps it running forever, wasting resources but never restarting.

open as a page

You are designing a ViewModel exposing UI state and one-off events. How do you decide between stateIn, shareIn, and a MutableStateFlow/MutableSharedFlow, and what scope and SharingStarted do you pick?

level: principalimportance: should knowfreq 40%

basics

~10 s

Use stateIn for continuous UI state derived from a flow, shareIn for shared event streams, and a manual MutableStateFlow/SharedFlow when you push values yourself. Host them in viewModelScope and usually start with WhileSubscribed(5000).

open as a page