Signal vs Observable in Angular: Key Differences and Usage
Signal is a new reactive primitive for synchronous state tracking and change detection, while Observable is a stream-based asynchronous data source used for events and async operations. Signals provide simpler, fine-grained reactivity with automatic updates, whereas Observables offer powerful operators for complex async workflows.Quick Comparison
This table summarizes the main differences between Signal and Observable in Angular.
| Aspect | Signal | Observable |
|---|---|---|
| Type | Synchronous reactive primitive | Asynchronous data stream |
| Change Detection | Automatic and fine-grained | Requires subscription and manual handling |
| Use Case | State tracking and UI reactivity | Async events, HTTP, user input streams |
| API Complexity | Simple getter/setter pattern | Rich operators and multicasting |
| Memory Management | Automatic cleanup with Angular | Must unsubscribe to avoid leaks |
| Introduced In | Angular 16+ | Angular core since early versions |
Key Differences
Signal is designed for synchronous state management inside Angular components. It tracks dependencies automatically and triggers UI updates when its value changes, making it ideal for simple and efficient reactivity without manual subscriptions.
Observable represents a stream of asynchronous data that can emit multiple values over time. It requires explicit subscription and unsubscription, and it supports powerful operators for transforming and combining streams, which is useful for complex async workflows like HTTP requests or event handling.
While Signal focuses on simplicity and performance for state tracking, Observable offers flexibility for asynchronous programming but with more boilerplate and potential for memory leaks if not managed properly.
Code Comparison
Here is how you create and use a Signal to track a counter value and update the UI reactively.
import { Component, signal } from '@angular/core'; @Component({ selector: 'app-counter-signal', template: ` <button (click)="increment()">Increment</button> <p>Count: {{ count() }}</p> ` }) export class CounterSignalComponent { count = signal(0); increment() { this.count.set(this.count() + 1); } }
Observable Equivalent
This example shows the same counter using an Observable with a BehaviorSubject to hold the state and manual subscription in the template.
import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Component({ selector: 'app-counter-observable', template: ` <button (click)="increment()">Increment</button> <p>Count: {{ count$ | async }}</p> ` }) export class CounterObservableComponent { private countSubject = new BehaviorSubject(0); count$ = this.countSubject.asObservable(); increment() { this.countSubject.next(this.countSubject.value + 1); } }
When to Use Which
Choose Signal when you want simple, synchronous state tracking with automatic UI updates and minimal boilerplate, especially for component-local state.
Choose Observable when you need to handle asynchronous data streams, complex event sequences, or use RxJS operators for advanced data transformations.
Signals are great for new Angular apps focusing on performance and simplicity, while Observables remain essential for legacy code and complex async scenarios.