Skip to content
tezvyn:

Dart Streams: Single-Subscription vs. Broadcast

Source: api.dart.devHardHow cards are made

A single-subscription stream is a private channel for one listener; a broadcast stream is a public radio station for many. Use single-subscription for one-off data like a file download and broadcast for shared events like UI updates.

Why it exists

Dart needs to handle two different kinds of asynchronous event sequences. One is a process with a clear start and end for a single consumer, like reading a file. The other is a source of ongoing, independent events that multiple consumers might be interested in, like user interactions. Differentiating them prevents ambiguity and enforces correct usage patterns.

The mental model

A single-subscription stream is a direct, private data transfer. Imagine a file download: the data is meant for one recipient, and the stream starts when the download begins and stops when it's done. You wouldn't have two different parts of your app trying to consume the same raw file download stream. A broadcast stream is a public announcement system. Think of a global notification for 'user logged out.' Multiple widgets or services might need to react to this event, so the stream broadcasts it to any current listeners.

How it works

A single-subscription stream, the default for async* functions, is lazy. It won't generate events until a listener is attached. Once a listener is attached, it's exclusively theirs. If that listener cancels, the stream is considered 'used' and cannot be listened to again. It's designed for a single, complete consumption of a sequence. A broadcast stream, often created via .asBroadcastStream(), fires events as soon as they are available, regardless of listeners. New listeners only receive events fired after they subscribe; they miss the history. Any number of listeners can subscribe and unsubscribe at will.

When to use it

Use single-subscription streams for streaming large, contiguous data chunks like file I/O or network responses. Use broadcast streams for independent, sporadic events that multiple parts of an app might need to react to, such as UI events (button clicks) or global state management updates.

When not to use it

Never use a single-subscription stream when multiple widgets need to react to the same event source; you'll get an error on the second listener. Don't use a broadcast stream for data that must be delivered reliably to one consumer; if no one is listening when the event fires, it's lost forever.

One canonical example

An async* function creates a single-subscription stream. If you call myAsyncStarFunction() and try to listen() to the returned stream twice, your app will throw a StateError. This happens even if the first listener has already cancelled its subscription. To allow multiple listeners, you must convert it: mySingleSubscriptionStream.asBroadcastStream(). Now, multiple listeners can subscribe without error.

Interview question

Which outcome is expected when attempting to attach a second listener to a Dart stream that was originally created by an async* function, after its first listener has already completed?

  • a.The stream will automatically become a broadcast stream, allowing the second listener to receive new events.
  • b.The second listener will receive all events from the beginning, replaying the stream's entire history.
  • c.A StateError will be thrown, indicating the stream cannot be listened to again.Correct
  • d.The second listener will only receive events that occur after its subscription, missing past events.
Why?

Single-subscription streams, such as those from async* functions, are designed for exclusive, single consumption. After the first listener completes, the stream is considered 'used' and will throw a StateError if a second listener attempts to subscribe, as it does not automatically convert to a broadcast stream.

Just read this? Test yourself on what you have been reading.

Read the original → api.dart.dev

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on dart — each one lists the topics its interview covers.

See open roles