Under The Hood
frontend angular Angular 16+ (signals), RxJS 7+

Angular Signals vs RxJS Observables

Last updated
Prerequisites:
Angular change detection basics
RxJS Observables and operators
  • angular
  • signals
  • rxjs
  • reactivity
  • change-detection
  • zonejs

Read at your depth

The practical view

A signal holds a value and notifies its consumers when it changes: const count = signal(0); count.set(1); count.update((v) => v + 1); const doubled = computed(() => count() * 2);. In templates you write {{ count() }} — the () makes it lazy and automatically tracked. An Observable is a stream: const clicks$ = fromEvent(button, 'click'); clicks$.pipe(map(...), filter(...)).subscribe(...). Practical difference: signals are eager-by-value and synchronous; observables are lazy, async, and push values through a pipeline over time. Signals are the right tool for state owned by a component; observables remain right for streams of events, WebSocket messages, and debounced input where time-based operators are needed.

The same idea in other frameworks

react equivalent
const [count, setCount] = useState(0); // setCount triggers re-render
const doubled = count * 2;

Legacy vs modern

Shared value via Subject + async pipe vs signal with computed

Both approaches keep a UI in sync, but the signal version is synchronous, tree-local, and granular; the RxJS version is async and needs subscription lifecycle management.

before → after
RxJS Subject + async pipe
count$ = new BehaviorSubject(0); // ❌ OLD: BehaviorSubject + async pipe → async, needs subscription lifecycle
increment() { this.count$.next(this.count$.value + 1); }
Signal + computed
count = signal(0); // ✅ NEW: signal() + computed() → synchronous, granular CD
increment() { this.count.update((v) => v + 1); }

Interview gotchas

Context

Interviewers want to see that you do not treat signals as a universal replacement; they probe your judgment about async boundaries.

The mechanical answer

Signals are synchronous pull-based state — perfect for values that exist at a point in time. RxJS earns its place when values arrive over time or need time-based operators: debouncing user input, websocket streams, retry/backoff on HTTP, combining multiple async sources with combineLatest/zip, or cancellation semantics. The classic hybrid is: keep the external stream in RxJS (toSignal to enter the signal world), then derive everything downstream with computed(). Trying to model a hot event stream purely with signals means hand-rolling debounce/timing logic that operators already implement and test.

Trap

The naive answer is 'signals replace observables everywhere' or 'subscribe in a component'. Real-world Angular code still uses RxJS for inter-service messaging and async pipelines, and the Angular team explicitly positions signals as state, not streams. Saying 'signals are synchronous and observables are asynchronous' without connecting it to when each property matters (state vs event streams) reads as memorized, not understood.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.