UPGRADEPATH / DEVELOPER GUIDES
Angular Signals Migration: What to Change and What Can Stay
A practical guide to adopting Angular Signals without rewriting your entire reactive architecture. Learn which state is a good fit for Signals, where RxJS still makes sense, and how to migrate incrementally.
Angular Signals Migration: What to Change and What Can Stay
Signals have become an important part of modern Angular development, but adopting them does not mean replacing every Observable in an existing application.
For many projects, the better migration strategy is much simpler: identify where Signals improve synchronous application state, keep RxJS where asynchronous streams are a natural fit, and modernize the application gradually.
This guide looks at how to approach that decision without turning an Angular upgrade into an unnecessary rewrite.
Start by Classifying Your Existing State
Before changing code, identify what kind of state your application actually has.
A typical Angular application may contain:
- Local component state
- Values derived from other state
- HTTP request streams
- Form state
- Router events
- User interaction streams
- Shared application state
- WebSocket or real-time data
- Complex asynchronous workflows
These problems do not all require the same reactive primitive.
The goal of a Signals migration should not be to remove RxJS. It should be to use each tool where its model fits naturally.
Good Candidates for Signals
Signals are particularly useful for synchronous state that is read directly by components and templates.
Common candidates include:
- Loading and visibility flags
- Selected items
- UI preferences
- Local counters and values
- Derived component state
- State calculated from other Signals
For example, a component that stores a selected filter and derives a filtered result can often express that relationship clearly with Signals.
The important characteristic is that the state is synchronous and has a clear current value.
Derived State Is Especially Interesting
Derived values are one of the areas where Signals can simplify component code.
Instead of manually updating several dependent properties whenever the source value changes, derived state can describe the relationship directly.
When the source changes, the derived value follows.
During a migration, look for code where multiple properties are manually synchronized. Those areas may be good candidates for a signal-based model.
Do Not Replace RxJS Just Because Signals Exist
RxJS still solves problems that Signals are not intended to replace.
Examples include:
- HTTP request pipelines
- Cancellation
- Debouncing
- Combining asynchronous events
- WebSockets
- Retry strategies
- Complex event streams
- Time-based operations
An Observable represents a stream of values over time.
A Signal represents reactive state with a current value.
Those models overlap in some situations, but they are not identical.
A migration that replaces working RxJS pipelines only to remove RxJS can increase complexity instead of reducing it.
Signals and RxJS Can Work Together
A modern Angular application does not have to choose one reactive model for everything.
A practical architecture can use:
- RxJS for asynchronous streams and event composition
- Signals for synchronous application and UI state
- Conversion at clear boundaries when necessary
This allows existing applications to modernize incrementally without rewriting stable functionality.
Avoid the Big-Bang Migration
If your application already works, converting the entire state architecture at once creates unnecessary risk.
A safer approach is to migrate feature by feature.
Start with a component or isolated feature where the state model is easy to understand.
Then evaluate:
- Did the code become easier to understand?
- Did the number of manual subscriptions decrease?
- Did derived state become clearer?
- Did testing remain straightforward?
- Did the migration actually remove complexity?
If the answer is yes, continue with the next suitable feature.
Review Component Boundaries
Signals are also a good reason to review how state moves through your component tree.
During the migration, look for:
- State duplicated across components
- Inputs copied unnecessarily into local properties
- Derived values stored instead of calculated
- Components coordinating state manually
- Effects being used where derived state would be simpler
Do not migrate syntax without reviewing the underlying state model.
Otherwise, old architectural problems simply receive new APIs.
Be Careful With Effects
Effects are useful when a state change needs to trigger a real side effect.
Examples might include synchronization with an external API or another system boundary.
They should not become the default way to propagate state through the application.
If one value can be calculated from another, derived state is usually easier to reason about than manually synchronizing values through effects.
Testing After the Migration
Changing the reactive model can affect more than TypeScript syntax.
After migrating a feature, verify:
- Initial state
- State updates
- Derived values
- Template rendering
- User interactions
- Error states
- Loading states
- Existing asynchronous behavior
Keep existing regression and end-to-end tests running while the migration progresses.
This is another reason incremental migration is safer than rewriting the entire application at once.
Migration Checklist
Use this checklist when reviewing an existing Angular feature:
- Identify local synchronous state
- Identify derived state
- Separate synchronous state from asynchronous streams
- Keep complex RxJS workflows unless migration provides a clear benefit
- Review component boundaries
- Avoid unnecessary effects
- Migrate one feature at a time
- Verify existing behavior with tests
- Measure whether the new implementation is actually simpler
- Remove old reactive code only after the replacement is verified
The Goal Is Not to Remove RxJS
A successful Signals migration is not measured by how many Observables disappear.
It is successful when the application's state becomes easier to understand, maintain and test.
For many Angular applications, the end result will intentionally contain both Signals and RxJS.
The important decision is not:
Signals or RxJS?
It is:
Which reactive model best represents this particular piece of state or asynchronous behavior?
That question leads to a much safer migration strategy than attempting to rewrite everything at once.