angular-migration
wshobson/agents
Migrate AngularJS apps to Angular using hybrid mode, incremental rewriting, and dependency injection updates.
What is angular-migration?
This skill guides AngularJS to Angular migration using three strategies: big bang rewrite, incremental hybrid approach, or vertical slice. Use it when upgrading legacy AngularJS applications, planning framework migrations, or modernizing Angular code with best practices.
- Set up hybrid AngularJS/Angular applications using ngUpgrade for side-by-side execution
- Convert AngularJS controllers and directives to Angular components with proper TypeScript syntax
- Migrate AngularJS services to Angular services with dependency injection
- Downgrade Angular services for use in AngularJS and upgrade AngularJS services for Angular consumption
- Migrate routing from AngularJS $routeProvider to Angular RouterModule
- Choose between big bang, incremental, and vertical slice migration strategies
How to install angular-migration
npx skills add https://github.com/wshobson/agents --skill angular-migration- Angular 2+ installed and configured
- AngularJS 1.x application as migration source
- @angular/upgrade package for hybrid app support
- Understanding of AngularJS controllers, directives, and services
How to use angular-migration
- 1.Choose a migration strategy (big bang, incremental, or vertical slice) based on app size and delivery needs
- 2.Set up hybrid app bootstrap using UpgradeModule to run AngularJS and Angular side-by-side
- 3.Migrate one component at a time: convert AngularJS controllers to Angular components
- 4.Update services to Angular pattern with HttpClient and Observable
- 5.Use downgradeInjectable and upgradeInjectable to share services between frameworks
- 6.Migrate routing from $routeProvider to Angular RouterModule
- 7.Test hybrid app thoroughly before removing AngularJS dependencies
Use cases
- Incrementally migrate a large AngularJS monolith to Angular while maintaining continuous delivery
- Convert an AngularJS directive library to reusable Angular components
- Modernize legacy AngularJS applications by running Angular features alongside old code
- Update dependency injection patterns when moving from AngularJS to Angular services
- Migrate routing systems from AngularJS routes to Angular Router configuration
- Backend developers maintaining legacy AngularJS applications
- Frontend teams planning framework upgrades
- Developers modernizing older Angular codebases
- Teams managing large applications requiring gradual migration
angular-migration FAQ
The incremental (hybrid) approach is best for large apps. Run AngularJS and Angular side-by-side using ngUpgrade, migrate feature by feature, and gradually replace old code. This enables continuous delivery without a risky big bang rewrite.
Use downgradeInjectable to make Angular services available to AngularJS, and upgradeInjectable to make AngularJS services available to Angular. Both are provided by @angular/upgrade/static.
Yes, using the hybrid app setup with UpgradeModule. Bootstrap Angular first, then bootstrap AngularJS within the same application. This allows gradual migration without rewriting everything at once.
AngularJS directives become Angular components. Use @Component decorator, @Input/@Output for bindings, and event binding syntax (click) instead of ng-click.
Replace $routeProvider.when() calls with Angular Routes array, use RouterModule.forRoot(), and replace ng-view with <router-outlet>. Map old route paths to new Angular components.
Full instructions (SKILL.md)
Source of truth, from wshobson/agents.
name: angular-migration description: Migrate from AngularJS to Angular using hybrid mode, incremental component rewriting, and dependency injection updates. Use when upgrading AngularJS applications, planning framework migrations, or modernizing legacy Angular code.
Angular Migration
Master AngularJS to Angular migration, including hybrid apps, component conversion, dependency injection changes, and routing migration.
When to Use This Skill
- Migrating AngularJS (1.x) applications to Angular (2+)
- Running hybrid AngularJS/Angular applications
- Converting directives to components
- Modernizing dependency injection
- Migrating routing systems
- Updating to latest Angular versions
- Implementing Angular best practices
Migration Strategies
1. Big Bang (Complete Rewrite)
- Rewrite entire app in Angular
- Parallel development
- Switch over at once
- Best for: Small apps, green field projects
2. Incremental (Hybrid Approach)
- Run AngularJS and Angular side-by-side
- Migrate feature by feature
- ngUpgrade for interop
- Best for: Large apps, continuous delivery
3. Vertical Slice
- Migrate one feature completely
- New features in Angular, maintain old in AngularJS
- Gradually replace
- Best for: Medium apps, distinct features
Hybrid App Setup
// main.ts - Bootstrap hybrid app
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);
// Bootstrap AngularJS
upgrade.bootstrap(document.body, ["myAngularJSApp"], { strictDi: true });
});
// app.module.ts
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { UpgradeModule } from "@angular/upgrade/static";
@NgModule({
imports: [BrowserModule, UpgradeModule],
})
export class AppModule {
constructor(private upgrade: UpgradeModule) {}
ngDoBootstrap() {
// Bootstrapped manually in main.ts
}
}
Component Migration
AngularJS Controller → Angular Component
// Before: AngularJS controller
angular
.module("myApp")
.controller("UserController", function ($scope, UserService) {
$scope.user = {};
$scope.loadUser = function (id) {
UserService.getUser(id).then(function (user) {
$scope.user = user;
});
};
$scope.saveUser = function () {
UserService.saveUser($scope.user);
};
});
// After: Angular component
import { Component, OnInit } from "@angular/core";
import { UserService } from "./user.service";
@Component({
selector: "app-user",
template: `
<div>
<h2>{{ user.name }}</h2>
<button (click)="saveUser()">Save</button>
</div>
`,
})
export class UserComponent implements OnInit {
user: any = {};
constructor(private userService: UserService) {}
ngOnInit() {
this.loadUser(1);
}
loadUser(id: number) {
this.userService.getUser(id).subscribe((user) => {
this.user = user;
});
}
saveUser() {
this.userService.saveUser(this.user);
}
}
AngularJS Directive → Angular Component
// Before: AngularJS directive
angular.module("myApp").directive("userCard", function () {
return {
restrict: "E",
scope: {
user: "=",
onDelete: "&",
},
template: `
<div class="card">
<h3>{{ user.name }}</h3>
<button ng-click="onDelete()">Delete</button>
</div>
`,
};
});
// After: Angular component
import { Component, Input, Output, EventEmitter } from "@angular/core";
@Component({
selector: "app-user-card",
template: `
<div class="card">
<h3>{{ user.name }}</h3>
<button (click)="delete.emit()">Delete</button>
</div>
`,
})
export class UserCardComponent {
@Input() user: any;
@Output() delete = new EventEmitter<void>();
}
// Usage: <app-user-card [user]="user" (delete)="handleDelete()"></app-user-card>
Service Migration
// Before: AngularJS service
angular.module("myApp").factory("UserService", function ($http) {
return {
getUser: function (id) {
return $http.get("/api/users/" + id);
},
saveUser: function (user) {
return $http.post("/api/users", user);
},
};
});
// After: Angular service
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs";
@Injectable({
providedIn: "root",
})
export class UserService {
constructor(private http: HttpClient) {}
getUser(id: number): Observable<any> {
return this.http.get(`/api/users/${id}`);
}
saveUser(user: any): Observable<any> {
return this.http.post("/api/users", user);
}
}
Dependency Injection Changes
Downgrading Angular → AngularJS
// Angular service
import { Injectable } from "@angular/core";
@Injectable({ providedIn: "root" })
export class NewService {
getData() {
return "data from Angular";
}
}
// Make available to AngularJS
import { downgradeInjectable } from "@angular/upgrade/static";
angular.module("myApp").factory("newService", downgradeInjectable(NewService));
// Use in AngularJS
angular.module("myApp").controller("OldController", function (newService) {
console.log(newService.getData());
});
Upgrading AngularJS → Angular
// AngularJS service
angular.module('myApp').factory('oldService', function() {
return {
getData: function() {
return 'data from AngularJS';
}
};
});
// Make available to Angular
import { InjectionToken } from '@angular/core';
export const OLD_SERVICE = new InjectionToken<any>('oldService');
@NgModule({
providers: [
{
provide: OLD_SERVICE,
useFactory: (i: any) => i.get('oldService'),
deps: ['$injector']
}
]
})
// Use in Angular
@Component({...})
export class NewComponent {
constructor(@Inject(OLD_SERVICE) private oldService: any) {
console.log(this.oldService.getData());
}
}
Routing Migration
// Before: AngularJS routing
angular.module("myApp").config(function ($routeProvider) {
$routeProvider
.when("/users", {
template: "<user-list></user-list>",
})
.when("/users/:id", {
template: "<user-detail></user-detail>",
});
});
// After: Angular routing
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
const routes: Routes = [
{ path: "users", component: UserListComponent },
{ path: "users/:id", component: UserDetailComponent },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
Additional patterns and templates
More detailed templates and worked examples live in references/details.md. Read that file for the full pattern library.
Related skills
More from wshobson/agents and the wider catalog.

anti-reversing-techniques
Understand and analyze anti-reversing, obfuscation, and protection techniques in authorized security contexts.

api-design-principles
Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs.

architecture-decision-records
Write and maintain Architecture Decision Records (ADRs) to document significant technical decisions with context, rationale, and consequences.

architecture-patterns
Implement Clean Architecture, Hexagonal Architecture, and Domain-Driven Design for maintainable backend systems.

async-python-patterns
Master asyncio, concurrent programming, and async/await patterns for high-performance Python applications.

attack-tree-construction
Visualize attack scenarios and defense gaps with systematic threat path mapping.