Angular Signals vs Observables: A Deep Dive into Modern Reactivity

calendar_todayschedule3 min read
— Originally published at dev.to

With the release of Angular 16, the framework introduced a powerful new reactive primitive: signals. Signals provide a new way to manage reactivity in your applications, enabling more predictable and efficient UI updates. But how do they compare with the well-established observables? When should you use one over the other? And how do features like computed() come into play?

In this post, we’ll explore Angular signals in depth, compare them with observables, and provide practical use cases to guide your decision-making.

What Are Angular Signals?

Signals are reactive values that notify dependents when their value changes. They are designed to be synchronous, fine-grained, and easy to use.

A signal is created using the signal() function and acts as a state container:

import { signal } from '@angular/core';

const count = signal(0);

console.log(count());   // Reading value: 0
count.set(5);           // Setting value
count.update(c => c + 1); // Updating value: 6

Key Characteristics:

  • Synchronous: Reading a signal gives you its value immediately.
  • Dependency Tracking: When used inside a computed signal or an effect, it registers itself as a dependency.
  • Reactive: Automatically propagates changes to anything that depends on it.

Using computed() with Signals

One of the most powerful aspects of signals is the computed() function. It allows you to create derived signals, similar to computed properties in other reactive frameworks like Vue.js.

import { signal, computed } from '@angular/core';

const price = signal(100);
const quantity = signal(2);

const total = computed(() => price() * quantity());

console.log(total()); // Output: 200

quantity.set(3);
console.log(total()); // Output: 300

The computed signal automatically recalculates when any of its dependencies change. No manual subscriptions are needed.

Signals vs Observables

Let’s compare Angular signals with RxJS observables across different dimensions:
Image description

When to Use Signals

✅ Use Signals When:

  • Managing local UI state (e.g. toggle, counters, forms)
  • Creating computed values that derive from other signals
  • You need fine-grained change detection (only dependent parts re-render)
  • You want simpler and more declarative reactivity

Example: Component-local state

@Component({
  selector: 'app-counter',
  template: `
    <button (click)="increment()">Add</button>
    <p>Count: {{ count() }}</p>
  `
})
export class CounterComponent {
  count = signal(0);

  increment() {
    this.count.update(c => c + 1);
  }
}

Avoid Signals When:

  • You’re dealing with asynchronous data (e.g. HTTP requests, WebSocket streams)
  • You need to compose multiple async streams using RxJS operators (mergeMap, switchMap, etc.)
  • You’re integrating with libraries heavily based on RxJS

When to Use Observables

✅ Use Observables When:

  • Working with asynchronous streams (e.g. user inputs, API responses)
  • Using RxJS operators to transform streams
  • Handling event-based programming (e.g. WebSockets, form events)
  • Managing global app state with side effects (e.g. NgRx)

Example: Async HTTP data

@Component({
  selector: 'app-data',
  template: `
    <ng-container *ngIf="data$ | async as data">
      <p>{{ data.title }}</p>
    </ng-container>
  `
})
export class DataComponent {
  data$ = this.http.get('/api/data');

  constructor(private http: HttpClient) {}
}

Interoperability: Signals and Observables

Angular provides utility functions to convert between signals and observables:

toSignal() – Observable to Signal

import { toSignal } from '@angular/core/rxjs-interop';

const signalFromObservable = toSignal(myObservable$, { initialValue: null });

toObservable() – Signal to Observable

import { toObservable } from '@angular/core';

const observableFromSignal = toObservable(mySignal);

This enables seamless integration of both paradigms.

Use Case Summary

Image description

Final Thoughts

Signals represent a shift toward synchronous, declarative state management in Angular. While Observables will always have a place—especially for async operations—signals make state management in UI components much simpler and more intuitive.

Use signals for local, synchronous UI state and computed values. Use observables for asynchronous workflows and complex stream operations. And when needed, bridge the two with Angular’s interop utilities.

The future of Angular is signal-first but observables aren’t going anywhere. Choosing the right tool for the job is key.

🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelski - Apr 23

I’m a Senior Dev and I’ve Forgotten How to Think Without a Prompt

Karol Modelski - Mar 19

The Senior Angular Take‑Home That Made Me Rethink Tech Interviews

Karol Modelski - Apr 2

How I Built a React Portfolio in 7 Days That Landed ₹1.2L in Freelance Work

Dharanidharan - Feb 9

Comparison: Universal Import vs. Plaid/Yodlee

Pocket Portfolio - Mar 12
chevron_left
176 Points5 Badges
3Posts
0Comments
Raju Dandigam is an accomplished Engineering Manager and Staff Engineer with over 15 years of experi... Show more

Related Jobs

View all jobs →

Commenters (This Week)

1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!