GUIDE MIGRATION

AngularJS to Angular migration guide

Move from AngularJS to Angular with a plan grounded in dependency risk, architectural boundaries, and production acceptance criteria. Compare migration strategies, sequence the work, and avoid turning a temporary hybrid application into permanent infrastructure.

Why AngularJS migration is an architectural decision

This angularjs to angular migration guide helps engineering leaders and practitioners replace an aging application without losing critical behavior. AngularJS and Angular share a name, but migrating between them is not a routine version upgrade: dependency injection, templates, change detection, routing, forms, and build tooling all change.

AngularJS official support ended in January 2022. That creates maintenance and security exposure, but it does not automatically justify a rushed rewrite. A successful program balances risk reduction against feature delivery, team capacity, and the cost of operating two frameworks.

For MyDiscussions readers evaluating legacy modernization, the central question is not simply “How do we convert controllers?” It is which migration boundary lets us deliver independently, prove correctness, and eventually remove AngularJS completely?

Establish the migration scope and business case

Start with a written decision record. Explain why Angular is the target, what the migration must preserve, and which improvements are intentionally excluded.

Angular may fit particularly well when an organization already uses TypeScript, wants standardized framework conventions, or maintains several Angular applications. However, AngularJS familiarity alone is not sufficient justification: modern Angular requires a different development model.

Define measurable completion criteria

Avoid treating “all screens rewritten” as the only success measure. Set acceptance criteria covering:

  • Functional parity: Critical journeys, permissions, validation rules, and error handling work as specified.
  • Operational parity: Logging, tracing, deployment, rollback, and support workflows remain effective.
  • Performance: Representative routes meet agreed loading and interaction budgets on target devices.
  • Accessibility: Keyboard navigation, focus management, labels, and assistive technology behavior are verified.
  • Retirement: AngularJS runtime dependencies, obsolete bundles, and legacy build jobs are removed.

Separate mandatory parity from optional redesign. Reworking navigation, changing APIs, and introducing a new design system simultaneously makes regressions harder to diagnose.

Assign ownership and funding

Name an accountable migration lead, owners for feature domains, and reviewers for security and accessibility. Reserve capacity for business-as-usual fixes.

Budget for more than component development. Dependency replacement, test fixtures, temporary interoperability, deployment changes, and production investigation often determine the critical path.

Audit the application before estimating

An inventory should describe behavior and coupling, not just count files.

AreaWhat to inspectWhy it changes the plan
AngularJS architectureControllers, directives, components, scope inheritanceComponent boundaries are easier to migrate than shared scope trees
RoutingngRoute, UI-Router states, resolves, deep linksDetermines whether routes can move independently
Shared state$rootScope, mutable singletons, browser storageReveals hidden cross-feature dependencies
UI dependenciesAngularJS wrappers, jQuery plugins, custom widgetsUnsupported packages may require replacement
API integration$http interceptors, authentication, uploadsCross-cutting behavior must survive the transition
Build and testsGulp, Grunt, webpack, Karma, ProtractorLegacy tooling may obstruct supported Node.js versions

Use package manifests and lockfiles alongside code searches. Search for $scope, $rootScope, $watch, $compile, direct DOM manipulation, and global event handlers. Trace where each is used rather than assuming every occurrence has equal risk.

Classify dependencies as retain, replace, isolate, or remove. An AngularJS wrapper around a charting library might be replaced while retaining the underlying library. A directive tightly coupled to scope inheritance may require redesign.

Read the official AngularJS end-of-life information when documenting support risk. Commercial extended support can be a temporary control, but it does not remove architectural debt or replace an exit plan.

Choose a migration strategy

There are three practical approaches. Select one using application size, coupling, release constraints, and the strength of existing tests.

Full replacement

Build a separate Angular application and switch traffic when it meets acceptance criteria.

Best fit: A small application, a replaceable internal tool, or a bounded product area with stable requirements.

Advantages: Clean architecture, no in-process framework bridge, and a straightforward final runtime.

Trade-offs: Feature duplication during development, delayed feedback, and a potentially difficult cutover. If the old application keeps changing, the replacement target keeps moving.

Require a credible parity backlog and a mechanism for keeping both implementations aligned.

Hybrid migration with ngUpgrade

Run AngularJS and Angular together, using @angular/upgrade/static to bridge components and services.

Best fit: A large application that must keep shipping and has boundaries suitable for incremental replacement.

Advantages: Small production releases and gradual retirement of legacy code.

Trade-offs: Both runtimes ship, debugging becomes more complex, and dependency injection and change detection cross framework boundaries.

Consult the official Angular upgrade guide before designing the bridge. Verify that your target Angular version, bootstrap model, and change-detection configuration work with the chosen interoperability approach.

Set an exit condition for every bridge. A hybrid application is a transition architecture, not a modernization outcome.

Route-level replacement

Move complete routes or business areas into a separate Angular application. A reverse proxy, application shell, or ordinary navigation can direct users to the appropriate implementation.

Best fit: Applications with distinct areas such as administration, reporting, and account management.

Advantages: Strong isolation, independent deployment, and less runtime interoperability.

Trade-offs: Shared authentication, navigation, design consistency, and cross-application state require deliberate coordination.

This approach does not inherently require module federation or a microfrontend platform. Prefer simple URL-based separation when it satisfies the requirements.

Step-by-step AngularJS to Angular migration process

Step 1: Capture critical behavior

Before changing frameworks, document and test the workflows that sustain the business: signing in, editing records, submitting payments, exporting data, or approving requests.

Use Playwright or Cypress for browser-level tests. Assert observable outcomes rather than controller implementation details. Include failed requests, expired sessions, validation errors, and unauthorized access.

Where automated coverage is absent, create a small reliable regression suite first. Recording every historical behavior is unnecessary; protecting high-impact behavior is essential.

Step 2: Select a supported target and build foundation

Choose a supported Angular release and check its required Node.js, TypeScript, and RxJS versions against the official Angular compatibility table.

Create the Angular workspace with Angular CLI. Establish:

  • Reproducible dependency installation and CI builds.
  • TypeScript checking and lint rules.
  • Environment-specific configuration without embedded secrets.
  • Unit and browser testing.
  • Production error reporting and source-map handling.
  • Security scanning and artifact retention.

Nx can help when multiple applications and shared libraries need coordinated boundaries and tasks. It is optional, not a migration prerequisite.

Use contemporary Angular conventions where appropriate, but validate hybrid-specific constraints before enabling every new runtime feature.

Step 3: Reduce coupling in AngularJS

Prepare the legacy application for extraction before translating it.

Move business rules out of controllers into explicit services or framework-independent TypeScript modules. Replace implicit scope inheritance with declared inputs and callbacks. Convert suitable screens to AngularJS components if that creates a useful migration seam.

Do not clean up the entire legacy codebase first. Refactor only enough to make the next migration slice predictable.

For example, a pricing calculation used by several controllers can become a tested pure function. Both frameworks can then call the same implementation without synchronizing duplicate business logic.

Step 4: Design interoperability and state ownership

For a hybrid migration, decide which framework bootstraps the application and how upgraded or downgraded services are registered.

Draw a dependency map. Each shared state domain should have one authoritative owner. Avoid an Angular service and an AngularJS service independently maintaining the same customer record.

Define boundary contracts:

  • Inputs and outputs for bridged components.
  • Service interfaces and asynchronous return types.
  • Authentication and authorization behavior.
  • Error propagation and logging.
  • Subscription and event-listener cleanup.

Pay particular attention to callbacks outside framework-managed execution. Test whether updates trigger rendering and whether bridge behavior creates unnecessary change-detection work.

Step 5: Migrate a representative vertical slice

Choose a feature that is meaningful but not existentially risky. A read-only detail page with navigation and API access is often a better pilot than either a trivial banner or checkout.

Move its template, component logic, services, tests, and operational instrumentation together. This exposes the real migration cost.

Translate concepts rather than syntax:

  • Controllers and $scope become components with explicit state.
  • $http calls become HttpClient integrations with reviewed error handling.
  • $q usage becomes promises or RxJS streams according to the workflow.
  • Directive behavior becomes components, directives, or framework-independent utilities.
  • AngularJS filters become pipes or precomputed values where appropriate.

Avoid replacing every watcher with a subscription. Angular signals, computed state, and explicit events may better express local UI behavior.

Step 6: Migrate routing, forms, and shared UI deliberately

Treat routing as an integration project. Preserve deep links, query parameters, redirects, browser history, route authorization, and unsaved-change warnings.

Do not let Angular Router and the AngularJS router compete for the same URL space without explicit coordination.

For complex forms, evaluate Angular reactive forms for explicit models and testable validation. Check subtle differences in touched, dirty, disabled, and pending states. Preserve server-side validation and error-message placement.

Choose shared UI replacements early. Angular Material, PrimeNG, and commercial component suites can replace legacy widgets, but compare accessibility, theming, licensing, localization, and data-grid behavior before committing.

Step 7: Release incrementally and measure

Use feature flags or route-based exposure to control rollout where feasible. Compare real workflows under production-like data and permissions.

Monitor client errors, failed API requests, route-loading behavior, and task completion signals. Check bundle growth during hybrid operation; a temporary increase is plausible, but it needs a budget and removal plan.

For route-separated applications, test direct navigation and session expiration in both applications—not just navigation through the shared menu.

Step 8: Remove the legacy runtime

After the final feature moves, remove AngularJS packages, upgrade adapters, legacy routes, compatibility services, and obsolete test infrastructure.

Inspect generated bundles and dependency trees to confirm the runtime is gone. Archive necessary operational knowledge, then delete dead code rather than leaving it “for safety.”

Finish with updated ownership documentation and a routine Angular upgrade cadence. Migration should restore maintainability, not start another long version freeze.

Estimate with evidence and govern delivery

Do not estimate solely from controller counts or lines of code. Use the pilot to calibrate effort by feature class:

  • Simple display screens with stable APIs.
  • Stateful editing workflows.
  • Complex forms and authorization rules.
  • Custom directives and third-party widgets.
  • Cross-cutting infrastructure.

Track remaining legacy capability, not just newly written Angular components. A growing component count can coexist with little actual retirement.

Useful checkpoints include:

  • Pilot accepted by product, operations, and engineering.
  • Routing and authentication contracts validated.
  • High-risk dependency replacements proven.
  • No new AngularJS features without an approved exception.
  • Final decommissioning work funded and scheduled.

Plan rollback per release. Re-enabling an old route is useful only if API and data changes remain backward compatible.

Common mistakes that derail migration

  • Treating Angular as AngularJS with TypeScript: Carrying over shared mutable scope patterns recreates legacy coupling.
  • Choosing the easiest components first indefinitely: Leaf widgets demonstrate progress but may not retire any routes or dependencies.
  • Rewriting the backend simultaneously: This obscures whether failures come from the framework migration or changed contracts.
  • Ignoring HTTP differences: Interceptors, cancellation, retries, cookie handling, and subscription behavior need explicit testing.
  • Replacing Protractor mechanically: Rewrite tests around user behavior rather than reproducing obsolete synchronization assumptions.
  • Making the hybrid bridge permanent: Every adapter needs an owner and a removal trigger.
  • Skipping dependency licensing checks: A replacement grid or editor may introduce procurement requirements late in delivery.
  • Testing only happy paths: Authentication expiry, validation failures, and navigation interruption often reveal integration defects.

For related planning approaches, browse more Migration topics.

Frequently asked questions

Can AngularJS be upgraded directly to Angular?

No. Angular is a different framework, not a drop-in AngularJS release. Templates, components, dependency injection, and infrastructure require adaptation. Some framework-independent JavaScript, business logic, styles, assets, and API contracts can be reused.

Is ngUpgrade required for migration?

No. ngUpgrade supports running both frameworks within one application. A full replacement or route-separated migration can avoid it. Use a hybrid bridge when incremental in-page migration justifies the additional runtime and operational complexity.

How long does an AngularJS to Angular migration take?

There is no reliable universal duration. Coupling, custom directives, dependency replacements, test coverage, and available team capacity dominate the estimate. Complete a representative pilot, measure the work required, and extrapolate by feature complexity rather than using a fixed duration per screen.

Should migration include a complete UI redesign?

Usually not by default. Preserve behavior first unless a redesign is necessary to replace unsupported widgets or meet accessibility requirements. If both initiatives must proceed together, maintain separate acceptance criteria so framework parity and design changes can be reviewed independently.

Have a question about this topic?

Ask the community and get answers from practitioners.

Start a discussion