Sparround

FutureBuilder, StreamBuilder and the alternatives

FutureBuilder and StreamBuilder display async data directly in the widget tree: a snapshot carries the state (connectionState, hasData, hasError).

Their biggest trap: if you create the future inside build, every rebuild fires a new request.

``` // no: a new request on every rebuild FutureBuilder(future: api.load(), ...)

// yes: the future is created once late final _future = api.load(); FutureBuilder(future: _future, ...) ```

This bug tends to surface late, because the screen still works — it just makes dozens of requests in the background.

ToolWhere it fitsWeakness
`FutureBuilder`A one-off load on a simple screenThe recreated-future trap; retry is awkward
`StreamBuilder`A continuous stream: real-time data, notificationsYou must mind the subscription lifetime
State management (Riverpod/Bloc)Retry, caching, shared stateAn extra layer and setup cost

Interview tip. The strong answer to "when do you use FutureBuilder?" draws the line: for a simple one-off load, yes; once you need retry, caching, shared state or use across screens, move to state management. Always mention the trap: a future created inside build means a new request on every rebuild. Naming that detail signals real experience.

📚 Sources and documentation