skip to content

SharedFlow & MutableSharedFlow

SharedFlow is a configurable broadcast stream with no initial value, a replay cache, and a buffer overflow policy, plus a non-suspending tryEmit. Interviewers ask when to choose it over StateFlow, and one-off events are the answer.

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

questions

5

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

level: juniorimportance: must knowfreq 70%

answer

  1. Hot + multicast = SharedFlow
  2. Cold flow { } restarts per collector
  3. MutableSharedFlow = producer side (emit/tryEmit)
  4. asSharedFlow() to expose read-only
  5. No initial value unlike StateFlow

basics

~10 s

SharedFlow is a hot stream that broadcasts the same values to all collectors at the same time. A regular Flow is cold and re-runs its code separately for each collector.

solid answer

~40 s

A SharedFlow is a hot Flow: it stays active independently of collectors and broadcasts each emitted value to all current subscribers simultaneously. A cold Flow (built with flow { }) is inert until collected and restarts its producer block for every collector, so each collector gets its own independent run. SharedFlow is created via MutableSharedFlow(...), you push values with emit (suspending) or tryEmit (non-suspending), and read-only consumers see it typed as SharedFlow. It has no current value by default and no initial value, which makes it a natural event bus for one-off events (navigation, toasts, signals). It is the broadcast superclass of StateFlow.

go deeper

for a junior

Can state hot vs cold and that SharedFlow broadcasts to all collectors.

for a middle

Explains the read-only/mutable split and asSharedFlow() encapsulation, and the no-initial-value contrast with StateFlow.

for a senior

Frames SharedFlow as an event bus, mentions replay/buffer knobs and never-completes semantics, and knows it's StateFlow's superclass.

for a principal

Reasons about when broadcast-event semantics fit the architecture vs StateFlow/Channel and the lifecycle/back-pressure implications of a never-completing hot stream.

## Cold vs Hot A **cold** Flow (created with `flow { ... }`) is just a recipe: nothing runs until you call `collect`, and the producer block runs **separately for each collector**. Two collectors each get their own independent execution. A **hot** Flow exists and runs independently of whether anyone is collecting. `SharedFlow` is the canonical hot, multicast (broadcast) Flow: a single emitter feeds **all** active collectors the same values at the same time. ## SharedFlow vs MutableSharedFlow - `SharedFlow<T>` is the **read-only** interface a consumer collects from. - `MutableSharedFlow<T>` adds the producer side: `emit` and `tryEmit`. - You typically keep a private `MutableSharedFlow` and expose it as a public `SharedFlow` via `asSharedFlow()` so outsiders can't emit. ```kotlin private val _events = MutableSharedFlow<UiEvent>() val events: SharedFlow<UiEvent> = _events.asSharedFlow() suspend fun signal() { _events.emit(UiEvent.Refresh) } ``` ## Key properties - **No initial value / no current value**: unlike `StateFlow`, a fresh `SharedFlow` has nothing to show a new subscriber unless `replay > 0`. - **Multicast**: every collector observes the same emissions; the flow never terminates on its own. - **Buffering**: configurable via `replay`, `extraBufferCapacity`, and `onBufferOverflow`. ## When to use it Use `SharedFlow` for **events** that should fire once and be delivered to whoever is listening: navigation commands, snackbars, analytics signals. Use `StateFlow` for **state** (a single current value). For turning a cold Flow hot, prefer the `shareIn` operator (a sibling topic) rather than manual emission.

  • Why expose MutableSharedFlow as SharedFlow with asSharedFlow()?
    To enforce encapsulation: external code can collect but cannot emit, keeping the producer the single source of emissions.
  • Does a SharedFlow ever complete?
    No, by design it never completes on its own; collectors stay subscribed until their coroutine is cancelled.

A cold Flow is a vending machine each person operates themselves; a SharedFlow is a live radio broadcast everyone tuned in hears at once.

saying these in an interview costs you the question

  • Claiming SharedFlow re-runs a producer block per collector (that's cold flow)
  • Saying SharedFlow always has a current value (it doesn't unless replay>0)
  • Confusing SharedFlow with Channel and assuming exactly-once-per-consumer delivery
  • Thinking collect() on a SharedFlow eventually returns normally

context

open as a page

Explain the three MutableSharedFlow constructor parameters: replay, extraBufferCapacity, and onBufferOverflow. How do they interact?

level: middleimportance: must knowfreq 65%

basics

~10 s

replay sets how many recent values new collectors get. extraBufferCapacity adds room for emitters when collectors are slow. onBufferOverflow decides what happens when both are full: suspend, drop oldest, or drop newest.

open as a page

When would you choose SharedFlow over StateFlow? Give concrete scenarios and the trade-offs.

level: seniorimportance: must knowfreq 60%

basics

~10 s

Use StateFlow for a current value (state) that the UI reads. Use SharedFlow for one-off events like navigation or toasts, where there's no meaningful current value and you don't want conflation or re-delivery.

open as a page

What is the difference between emit and tryEmit on a MutableSharedFlow, and when can tryEmit return false?

level: middleimportance: should knowfreq 55%

basics

~10 s

emit is a suspend function that waits if the buffer is full. tryEmit is non-suspending and returns true/false: it returns false when it would have to suspend to deliver the value.

open as a page

What does MutableSharedFlow.subscriptionCount give you, and what is resetReplayCache used for? Sketch a use case.

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

subscriptionCount is a StateFlow of how many collectors are active right now. resetReplayCache empties the cache of recent values so new subscribers don't get old ones. You use subscriptionCount to start/stop upstream work on demand.

open as a page