“Signals don’t replace RxJS — but they definitely reshape how we think about reactivity in Angular.”
When Angular introduced Signals in v16, many teams (including ours) faced the same question:
Should we migrate our existing RxJS-based state and component logic to Signals?
As a Lead Frontend Engineer working with large Angular applications, I’ve gone through that transition — and in this post, I’ll share what we learned, what we changed, and what we kept.
🔍 Why Signals?
RxJS has been the heart of Angular’s reactivity for years — and for good reason. It’s powerful, composable, and battle-tested.
But it also came with a cost: steep learning curve, boilerplate, and sometimes “subscription spaghetti” in components.
Signals were designed to simplify reactive state by making reactivity explicit and local — something that developers can reason about without diving deep into streams.
// ✅ Signals make component state local and reactive
import { signal, computed } from '@angular/core';
export class CounterComponent {
count = signal(0);
doubleCount = computed(() => this.count() * 2);
increment() {
this.count.update(c => c + 1);
}
}
Here, no Observables, no subscriptions — yet Angular’s change detection stays perfectly in sync.
⚙️ How We Approached Migration
Instead of a full migration, we followed an incremental hybrid strategy:
1. Keep RxJS in Effects and Services
We retained RxJS for side effects, API calls, and async streams.
These are still best handled via Observable.
2. Use Signals in Components and Local State
Component-level data, UI toggles, or derived states — all replaced with Signals.
This drastically reduced subscriptions and async pipes in templates.
3. Bridge RxJS and Signals with toSignal() and toObservable()
These helpers helped us migrate smoothly:
import { toSignal, toObservable } from '@angular/core/rxjs-interop';
userSignal = toSignal(this.userService.user$);
user$ = toObservable(this.userSignal);
This allowed old and new logic to coexist while we gradually migrated features.
🧩 Lessons Learned
✅ Signals improve readability.
Component logic feels synchronous — no need for subscribe or async pipe clutter.
✅ RxJS still matters.
Streams, complex event coordination, and API interactions are still more expressive with Observables.
✅ You can mix both.
Angular’s rxjs-interop utilities make hybrid migration smooth and safe.
✅ Performance gains are real.
Signals update only when data changes — reducing unnecessary re-renders and detection cycles.
💬 Final Thoughts
If your team is building new features, start adopting Signals for local state — it’ll make your codebase cleaner and more intuitive.
But for complex async workflows, keep RxJS — it’s still an essential part of Angular’s DNA.
This isn’t an “RxJS vs Signals” story.
It’s about choosing the right reactive tool for each part of your app.
🧠 Want to discuss Angular architecture or Signals migration?
Drop a comment below or connect with me on LinkedIn!
Top comments (0)