
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.

Middleware: What It Is, How It Chains, and When to Write Your Own
Middleware is one of Laravel’s most tested certification topics because it sits at the core of the request lifecycle. This article goes beyond basic syntax to explain how middleware works internally, how the pipeline pattern processes requests, what happens when $next is skipped, and why some middleware never executes. If you want to truly understand Laravel middleware rather than just use it, this is where to start.
Steve McDougall
May 28, 2026

Rolldown and Vite 8: What Changed
Vite 8 replaced both esbuild and Rollup with Rolldown. Here's what that means for your Vue project in practice.
Reza Baar
May 27, 2026

Closures Explained: How Functions Remember Their Scope
A function in JavaScript remembers the scope it was created in, even after that scope has finished executing. Learn what closures are, why the loop bug happens, and how to use them in practice.
Martin Ferret
May 26, 2026