What capacity does buffer() use by default, and what do the special Channel capacity constants mean in this context?
answer
- Default = Channel.BUFFERED = 64 (system-property overridable)
- RENDEZVOUS = 0, synchronous hand-off
- UNLIMITED = Int.MAX_VALUE, never blocks, OOM risk
- CONFLATED = keep latest, == buffer(1, DROP_OLDEST)
- CONFLATED + explicit overflow policy throws
basics
~20 sBy default buffer() holds about 64 items. You can also pass special values: 0 for no buffer (hand-off), a large unlimited buffer that never blocks, or a 1-slot conflated buffer that always keeps the newest value.
solid answer
~40 s`buffer()`'s default capacity is `Channel.BUFFERED`, which resolves to **64** unless the `kotlinx.coroutines.channels.defaultBuffer` system property changes it. You can pass any non-negative `Int`, or one of the special constants: `Channel.RENDEZVOUS` (0) — a direct hand-off where the producer suspends until the collector takes each item (no real buffering); `Channel.UNLIMITED` (Int.MAX_VALUE) — an ever-growing buffer that never applies back-pressure (memory risk); `Channel.CONFLATED` — keeps only the latest value (equivalent to capacity 1 + DROP_OLDEST), and is mutually exclusive with an explicit non-SUSPEND policy. Capacity interacts with `onBufferOverflow`: a finite buffer plus SUSPEND yields classic bounded back-pressure; a finite buffer plus DROP_* trades data for a never-blocking producer. Picking the number is a latency/throughput/memory trade-off.
go deeper
Knows buffer() has some default size and that you can pass a custom capacity.
States the default is 64 and explains RENDEZVOUS / UNLIMITED / CONFLATED meanings.
Knows the system-property override, the CONFLATED-plus-policy conflict, and the memory/latency trade-offs of sizing.
Sets capacity policy across services, weighs OOM vs back-pressure risk, and accounts for operator fusion when reasoning about effective buffering.
## The default ```kotlin fun <T> Flow<T>.buffer( capacity: Int = Channel.BUFFERED, onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND ): Flow<T> ``` The default `capacity` is `Channel.BUFFERED`, an alias that resolves to **64** at runtime (overridable via the JVM system property `kotlinx.coroutines.channels.defaultBuffer`). So a bare `buffer()` gives a 64-slot, back-pressured buffer. ## The special constants These come from the `Channel` companion and have specific integer encodings: - **`Channel.RENDEZVOUS` (0)** — no storage. Each `emit()` suspends until the collector is ready to receive that exact item; it is a synchronous hand-off. Producer and collector still run on separate coroutines (so they can interleave), but the producer can be at most one item ahead of nothing. - **`Channel.UNLIMITED` (`Int.MAX_VALUE`)** — effectively infinite. The producer **never** suspends and **never** drops, but the buffer can grow without bound, risking `OutOfMemoryError`. Overflow policy is irrelevant here. - **`Channel.CONFLATED`** — capacity that keeps only the **most recent** value; it behaves like `buffer(1, DROP_OLDEST)`. `conflate()` is the dedicated operator for this. - **`Channel.BUFFERED`** — the default, 64. ## Combining capacity with overflow ```kotlin flow.buffer() // 64 slots, SUSPEND flow.buffer(Channel.UNLIMITED) // never blocks, may OOM flow.buffer(0, BufferOverflow.SUSPEND) // rendezvous-like hand-off flow.buffer(16, BufferOverflow.DROP_OLDEST) // bounded, keep freshest 16 ``` Illegal/edge combos: passing `Channel.CONFLATED` together with an explicit non-default `onBufferOverflow` throws, because CONFLATED already implies an overflow behavior. Negative capacities other than the named constants throw `IllegalArgumentException`. ## Choosing a number - **Small capacity** → tighter coupling, lower memory, more back-pressure events. - **Large capacity** → more decoupling/throughput, higher memory and potential latency (stale items sitting in the queue). - **UNLIMITED** → only when you trust the producer to be bounded overall; otherwise it's a memory hazard. The operator also **fuses**: chained `buffer`/`flowOn` calls merge their channel rather than stacking multiple channels, and the largest requested capacity tends to win in the fused result.
- What is the risk of Channel.UNLIMITED?The buffer grows without bound if the producer outpaces the collector, risking OutOfMemoryError; there is no back-pressure.
- Can you override the default 64?Yes, globally via the kotlinx.coroutines.channels.defaultBuffer system property, or per-call by passing an explicit capacity.
saying these in an interview costs you the question
- Saying the default capacity is 1 or unlimited
- Believing RENDEZVOUS means a large buffer
- Thinking UNLIMITED applies back-pressure
- Combining CONFLATED with an explicit overflow policy without knowing it throws