
Migrating from RxJS to Signals in Angular? This guide breaks down common patterns, practical tips, and step-by-step strategies to help you transition smoothly from reactive streams to a signals-based architecture.
Alain Chautard
May 5, 2026
RxJS has been around for a long time in Angular applications, which means migrating to signals can seem daunting at first. In this post, I'll cover common patterns, tips, and tricks for migrating your application from RxJS-based to Signal-based in a step-by-step fashion.
First and foremost, the Angular CLI supports several automated migrations, including ones that will turn your input and output decorators into Signal-friendly code, as well as ViewChild content queries.
Here are the commands you need to run:
ng generate @angular/core:signal-input-migration
ng generate @angular/core:output-migration
ng generate @angular/core:signal-queries-migration
If you're using Reactive Forms or other APIs that return Observables, you're one function call away from turning them into Signals:
// Before
data$ = this.http.get(this.API_URL);
// Converting to Signal
data = toSignal(this.data$);
PRO TIP: The above code will create a Signal that has an undefined value initially (Signal<DataType | undefined>), which is hard to work with, as you'll need to check for undefined values with conditions such as @if, data?.property, or data?. something ?? "defaultValue".
You can eliminate such complexity by providing a good default value to toSignal. For instance, if you expect an array of values, a good default value would be an empty array .
Here is an example where I expect a simple object and provide a meaningful default value instead:
// Without default value
rates: Signal<Rates | undefined> = toSignal(this.rates$);
// With default value
rates: Signal<Rates> = toSignal(this.rates$,
{initialValue: {USD: 1, EUR: 1, GBP: 1}}
);

Note that HTTP requests can be replaced with rxResource or httpResource (full HTTP resource tutorial here), but these APIs are still experimental at the time of this writing and thus not recommended for production use yet.
We can convert Subjects to Signals using toSignal(), but removing the Subject entirely is even easier:
// Subject version
currentCurrency = new BehaviorSubject<CurrencySymbol>(DEFAULT_CURRENCIES[0]);
// Signal version
currentCurrency = signal<CurrencySymbol>(DEFAULT_CURRENCIES[0]);
Almost all RxJs operators that combine Observables can be replaced with a computed signal that combines Signals.
Here is an example where I want to get the exchange rate for the currently selected currency, all of which are dynamic and can be changed asynchronously:
// RxJs code
currentExchangeRate$ = combineLatest([
this.exchangeRates$,
this.currentCurrency$
]).pipe(
map(([rates, current]) => rates[current.code as keyof ExchangeRates])
);
// Equivalent Signal based version
currentExchangeRate = computed(
() => this.exchangeRates()[this.currentCurrency().code]
);
And yes, the computed version looks much lighter than the RxJs one!
Sometimes though, we want to keep some of the RxJs logic because it works well and uses features that don't have a direct Signal-based equivalent (here timer). In that case, toSignal does the trick to expose a Signal and "hide" our RxJs business logic from components:
// RxJs code
exchangeRates$: Observable<ExchangeRates> = timer(0, 3600000)
.pipe(
switchMap(() => this.http.get<any>(this.API_URL)),
map(data => ({
USD: 1,
EUR: data.rates.EUR,
GBP: data.rates.GBP
}))
);
// Simple Signal conversion with toSignal()
exchangeRates = toSignal(this.exchangeRates$);
For more comparisons, here is a Stackblitz of a service entirely written with Subjects and RxJs operators, and then its equivalent Stackblitz migrated to Signals.
Migrating from RxJS to Angular Signals isn’t a big bang rewrite — and it shouldn’t be. Angular was designed to let both coexist, and that’s a feature, not a compromise.
The pragmatic approach: migrate what’s painful first. Start with BehaviorSubject-based state in services — those are the easiest wins and the most immediate readability improvements: Services only expose signals, which simplifies your components — No more subscriptions, operators, async pipes, etc.
And remember that Signal forms are around the corner (still experimental at the time of this writing), so don't spend too much time migrating Reactive forms just yet.
Get the latest news and updates on developer certifications. Content is updated regularly, so please make sure to bookmark this page or sign up to get the latest content directly in your inbox.

Cómo funciona realmente el bucle del trabajador de la cola
Domina las colas de Laravel comprendiendo qué ocurre entre bastidores cuando se envían y procesan las tareas. Esta guía analiza los trabajadores de colas, la serialización de modelos, los reintentos, las tareas fallidas, el encadenamiento y el procesamiento por lotes: conceptos clave para crear aplicaciones fiables y superar con éxito los exámenes de certificación de Laravel.
Steve McDougall
25 de junio de 2026

Primeros pasos con rstore en Vue
Una guía paso a paso sobre rstore, el almacén de datos reactivo para Vue con almacenamiento en caché normalizado, consultas tipadas y un sistema de complementos.
Reza Baar
24 de junio de 2026

Promise.withResolvers(): el patrón «Deferred» integrado
Promise.withResolvers() sustituye al patrón «deferred» manual en JavaScript. Una sola desestructuración, sin ejecutor, sin «let». ES2024, compatible con todos los entornos de ejecución modernos.
Martin Ferret
23 de junio de 2026