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.

By UpgradePathAuthor · 5 min read · Updated 2026-09-27

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:

  1. Did the code become easier to understand?
  2. Did the number of manual subscriptions decrease?
  3. Did derived state become clearer?
  4. Did testing remain straightforward?
  5. 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.