Skip to content

RxJS

Signals did not kill RxJS. They took over one of its jobs — synchronous derived state — and left RxJS with the one it is actually good at: asynchronous event streams over time.

Use caseRecommended tool
Component state, derived valuessignal() / computed()
Inputs and outputsinput() / output()
A single HTTP callhttpResource() / resource() or toSignal()
Typeahead, debounce, cancellationRxJS
WebSockets, SSE, pollingRxJS
Combining several event sources over timeRxJS
Retry with backoff, race conditionsRxJS
Router events, form valueChangesRxJS (then toSignal)

Practical rule: RxJS at the edges, signals in the middle. Streams enter through RxJS, get converted with toSignal(), and the rest of the component works with signals.


  1. Does time matter? If not, you want computed(), not combineLatest.
  2. Can a newer value make an older one irrelevant? If yes, you need switchMap, not mergeMap.
  3. Who unsubscribes? If you cannot answer in one sentence, use the async pipe or takeUntilDestroyed().

Most application code only needs these:

  • Transform: map, switchMap, concatMap, mergeMap, exhaustMap
  • Filter: filter, distinctUntilChanged, debounceTime, take, takeUntilDestroyed
  • Combine: combineLatest, forkJoin, merge, startWith, withLatestFrom
  • Errors: catchError, retry, finalize
  • Sharing: shareReplay

Everything else is a specialisation you can look up when you need it.