Angular has always embraced powerful reactive programming concepts — from change detection to RxJS-based data flows. But with the introduction of Signals, Angular now offers a simpler and more intuitive way to handle reactivity natively, without relying entirely on RxJS or @Input()
bindings.
In this post, we’ll explore what Angular Signals are, how they work, and when you should use them in your applications.
⚡ What Are Signals in Angular?
Signals are a new reactive primitive introduced in Angular to track and respond to changes in state. Unlike RxJS Observables, which rely on subscriptions and streams, Signals offer a push-based, dependency-tracked model, making change detection more predictable and efficient.
Think of them as reactive variables that automatically update anything that depends on them.
🛠️ How to Use Signals
Angular’s Signals API is available via the @angular/core
package.
Defining a Signal
import { signal } from '@angular/core';
const count = signal(0);
Reading a Signal
console.log(count()); // prints 0
Updating a Signal
count.set(1);
count.update(prev => prev + 1);
🧠 Signals vs. Observables
Feature | Signals | RxJS Observables |
---|---|---|
Syntax | Simple, getter-like | Subscription-based |
Reactivity | Pull-based (automatic tracking) | Push-based |
Async support | No (designed for sync state) | Yes (built for async streams) |
Complexity | Low | Higher, especially for beginners |
Use case | Local/component state | Streams, HTTP, events |
Use Signals for: local component state, reactive templates, UI counters, form flags, etc.
Use Observables for: HTTP calls, user input streams, event handling, complex async logic.
🧪 Example: Counter Component Using Signals
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-counter',
template: `
Counter: {{ count() }}
Increment
`
})
export class CounterComponent {
count = signal(0);
increment() {
this.count.update(c => c + 1);
}
}
No need for ChangeDetectorRef
, @Input()
, or EventEmitter
— the UI auto-updates when the signal changes.
🧬 Computed and Effects
Angular also provides computed()
and effect()
APIs for more advanced logic.
computed()
— derived values
import { computed } from '@angular/core';
const count = signal(2);
const double = computed(() => count() * 2);
effect()
— run side effects
import { effect } from '@angular/core';
effect(() => {
console.log('Count changed to:', count());
});
Signals mark a major evolution in Angular’s reactivity system. They're lightweight, easy to learn, and offer fine-grained reactivity without sacrificing performance or clarity. Combined with computed and effect, they bring Angular closer to the reactivity model of frameworks like SolidJS or Vue.
If you're building new Angular apps, or looking to refactor existing components, Signals offer a clean, modern alternative to traditional state management approaches.