AngularJS to Angular v22 Migration: The Pragmatic Incremental Path Without a Big Bang Rewrite
These articles are AI-generated summaries. Please check the original sources for full details.
The Pragmatic Migration: Moving from AngularJS to Angular v22
AngularJS (v1.x) has been officially End of Life for years, leaving enterprise systems exposed to unpatched security vulnerabilities. The British bank TSB’s failed IT migration corrupted 1.3 billion customer records, a cautionary tale of risky Big Bang rewrites.
Why This Matters
The tech industry is littered with failed migration projects—TSB’s 1.3 billion corrupted records and multi-million dollar rewrites that were scrapped. The ideal is a clean slate, but the reality is that feature development must continue, undocumented business logic spans a decade, and the business cannot afford a feature freeze. Incremental hybrid migration using ngUpgrade threads the needle, allowing organizations to modernize without stopping delivery.
Key Insights
- AngularJS is officially End of Life (EOL) as of 2022, with no security patches or official support, introducing massive risk to enterprise systems (Angular team, 2022).
- Angular v22 (released June 2026) fully embraces a ‘Zoneless’ architecture, eliminating zone.js overhead for reduced bundle sizes and faster load times.
- Signals provide fine-grained reactivity in Angular v22, allowing the framework to know exactly which DOM parts need updates, replacing complex RxJS streams and unpredictable $watchers.
- The Resource API (resource() and httpResource()) handles async data fetching declaratively without manual RxJS subscriptions or async pipe management.
- OnPush change detection is the default in Angular v22, ensuring maximum performance out-of-the-box by only checking components when input references or consumed Signals change.
Working Examples
Hybrid bootstrap: Modern Angular v22 bootstraps legacy AngularJS app
// main.ts
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { UpgradeModule } from "@angular/upgrade/static";
import { AppModule } from "./app/app.module";
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then((platformRef) => {
const upgrade = platformRef.injector.get(UpgradeModule);
upgrade.bootstrap(document.body, ["myLegacyApp"], { strictDi: true });
})
.catch((err) => console.error(err));
Downgrading an Angular v22 component for use in AngularJS templates
// 1. Your modern Angular v22 Component
import { Component, input } from "@angular/core";
@Component({
selector: "modern-user-profile",
standalone: true,
template: `
<div class="profile-card">
<h2>{{ userName() }}</h2>
<p>Status: Active</p>
</div>
`,
})
export class ModernUserProfileComponent {
userName = input.required<string>();
}
// 2. The Bridge File (downgrade.ts)
import { downgradeComponent } from "@angular/upgrade/static";
import * as angular from "angular";
import { ModernUserProfileComponent } from "./modern-user-profile.component";
angular.module("myLegacyApp").directive(
"modernUserProfile",
downgradeComponent({
component: ModernUserProfileComponent,
}) as angular.IDirectiveFactory,
);
Upgrading an AngularJS service for injection into modern Angular components
// 1. The legacy AngularJS Service
angular.module("myLegacyApp").service("LegacyAuthService", function () {
this.getToken = function () {
return localStorage.getItem("token");
};
});
// 2. The Bridge File (upgrade.ts)
import { FactoryProvider } from "@angular/core";
export function legacyAuthServiceFactory(i: any) {
return i.get("LegacyAuthService");
}
export const legacyAuthProvider: FactoryProvider = {
provide: "LegacyAuthService",
useFactory: legacyAuthServiceFactory,
deps: ["$injector"],
};
Hybrid routing setup with sink route for legacy AngularJS fallback
// app.routes.ts
import { Routes } from "@angular/router";
import { ModernDashboardComponent } from "./dashboard/modern-dashboard.component";
export const routes: Routes = [
{ path: "dashboard", component: ModernDashboardComponent },
{ path: "**", children: [] },
];
// main.ts (Updated for routing)
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { UpgradeModule } from "@angular/upgrade/static";
import { setUpLocationSync } from "@angular/router/upgrade";
import { AppModule } from "./app/app.module";
platformBrowserDynamic()
.bootstrapModule(AppModule)
.then((platformRef) => {
const upgrade = platformRef.injector.get(UpgradeModule);
upgrade.bootstrap(document.body, ["myLegacyApp"], { strictDi: true });
setUpLocationSync(upgrade);
})
.catch((err) => console.error(err));
Practical Applications
- Use the bottom-up ‘Leaf Strategy’ to port leaf components first (buttons, inputs, formatting pipes) and downgrade them via ngUpgrade for use in legacy templates, minimizing risk and enabling incremental value delivery.
- Set up hybrid routing with a sink route (path: ’**’) that falls back to AngularJS, allowing seamless transition between legacy and modernized views without breaking user navigation.
- Invest heavily in team training on Angular v22 concepts (TypeScript decorators, Signals, OnPush semantics, Standalone architecture) before migration to prevent developer burnout and skill gaps.
- Write a comprehensive E2E test suite before migrating, using frameworks like Cypress or Playwright, and run it continuously to catch regressions when upgraded components break legacy features.
References:
Continue reading
Next article
Why Merged Open Source Pull Requests Build Stronger Engineering Skills Than Solo Projects
Related Content
Angular Component Selectors: Enhancing Native Elements Without Extra DOM Nodes
Angular supports attribute and class component selectors for attaching components to native HTML elements without extra DOM nodes.
TITAN: A Zero-Dependency Token Compressor for AI Coding Agents
TITAN reduces AI agent token consumption by 70% to 85% using a multi-layer compression framework with zero external dependencies.
Combating AI Code Bloat: The Path to Zero-Slop Engineering
Developer David explores the pursuit of 'zero-slop' engineering to combat AI-generated code bloat and unreliable agent behavior.