Angular Migration

Seamlessly migrate AngularJS apps to modern Angular with hybrid strategies

✨ The solution you've been looking for

Verified
Tested and verified by our team
25450 Stars

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 angularjs migration hybrid-apps component-conversion dependency-injection routing typescript
Repository

See It In Action

Interactive preview & real-world examples

Live Demo
Skill Demo Animation

AI Conversation Simulator

See how users interact with this skill

User Prompt

I have a large AngularJS 1.6 application with multiple controllers and services. Help me create a migration plan using the hybrid approach to gradually convert to Angular 17.

Skill Processing

Analyzing request...

Agent Response

Step-by-step migration plan with hybrid app setup, service conversion priorities, and incremental component migration strategy

Quick Start (3 Steps)

Get up and running in minutes

1

Install

claude-code skill install angular-migration

claude-code skill install angular-migration
2

Config

3

First Trigger

@angular-migration help

Commands

CommandDescriptionRequired Args
@angular-migration legacy-angularjs-app-modernizationTransform a large AngularJS (1.x) application to Angular using incremental hybrid modeNone
@angular-migration component-and-directive-conversionConvert AngularJS controllers and directives to modern Angular componentsNone
@angular-migration dependency-injection-updatesModernize AngularJS services and dependency injection for Angular compatibilityNone

Typical Use Cases

Legacy AngularJS App Modernization

Transform a large AngularJS (1.x) application to Angular using incremental hybrid mode

Component and Directive Conversion

Convert AngularJS controllers and directives to modern Angular components

Dependency Injection Updates

Modernize AngularJS services and dependency injection for Angular compatibility

Overview

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

 1// main.ts - Bootstrap hybrid app
 2import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
 3import { UpgradeModule } from "@angular/upgrade/static";
 4import { AppModule } from "./app/app.module";
 5
 6platformBrowserDynamic()
 7  .bootstrapModule(AppModule)
 8  .then((platformRef) => {
 9    const upgrade = platformRef.injector.get(UpgradeModule);
10    // Bootstrap AngularJS
11    upgrade.bootstrap(document.body, ["myAngularJSApp"], { strictDi: true });
12  });
 1// app.module.ts
 2import { NgModule } from "@angular/core";
 3import { BrowserModule } from "@angular/platform-browser";
 4import { UpgradeModule } from "@angular/upgrade/static";
 5
 6@NgModule({
 7  imports: [BrowserModule, UpgradeModule],
 8})
 9export class AppModule {
10  constructor(private upgrade: UpgradeModule) {}
11
12  ngDoBootstrap() {
13    // Bootstrapped manually in main.ts
14  }
15}

Component Migration

AngularJS Controller → Angular Component

 1// Before: AngularJS controller
 2angular
 3  .module("myApp")
 4  .controller("UserController", function ($scope, UserService) {
 5    $scope.user = {};
 6
 7    $scope.loadUser = function (id) {
 8      UserService.getUser(id).then(function (user) {
 9        $scope.user = user;
10      });
11    };
12
13    $scope.saveUser = function () {
14      UserService.saveUser($scope.user);
15    };
16  });
 1// After: Angular component
 2import { Component, OnInit } from "@angular/core";
 3import { UserService } from "./user.service";
 4
 5@Component({
 6  selector: "app-user",
 7  template: `
 8    <div>
 9      <h2>{{ user.name }}</h2>
10      <button (click)="saveUser()">Save</button>
11    </div>
12  `,
13})
14export class UserComponent implements OnInit {
15  user: any = {};
16
17  constructor(private userService: UserService) {}
18
19  ngOnInit() {
20    this.loadUser(1);
21  }
22
23  loadUser(id: number) {
24    this.userService.getUser(id).subscribe((user) => {
25      this.user = user;
26    });
27  }
28
29  saveUser() {
30    this.userService.saveUser(this.user);
31  }
32}

AngularJS Directive → Angular Component

 1// Before: AngularJS directive
 2angular.module("myApp").directive("userCard", function () {
 3  return {
 4    restrict: "E",
 5    scope: {
 6      user: "=",
 7      onDelete: "&",
 8    },
 9    template: `
10      <div class="card">
11        <h3>{{ user.name }}</h3>
12        <button ng-click="onDelete()">Delete</button>
13      </div>
14    `,
15  };
16});
 1// After: Angular component
 2import { Component, Input, Output, EventEmitter } from "@angular/core";
 3
 4@Component({
 5  selector: "app-user-card",
 6  template: `
 7    <div class="card">
 8      <h3>{{ user.name }}</h3>
 9      <button (click)="delete.emit()">Delete</button>
10    </div>
11  `,
12})
13export class UserCardComponent {
14  @Input() user: any;
15  @Output() delete = new EventEmitter<void>();
16}
17
18// Usage: <app-user-card [user]="user" (delete)="handleDelete()"></app-user-card>

Service Migration

 1// Before: AngularJS service
 2angular.module("myApp").factory("UserService", function ($http) {
 3  return {
 4    getUser: function (id) {
 5      return $http.get("/api/users/" + id);
 6    },
 7    saveUser: function (user) {
 8      return $http.post("/api/users", user);
 9    },
10  };
11});
 1// After: Angular service
 2import { Injectable } from "@angular/core";
 3import { HttpClient } from "@angular/common/http";
 4import { Observable } from "rxjs";
 5
 6@Injectable({
 7  providedIn: "root",
 8})
 9export class UserService {
10  constructor(private http: HttpClient) {}
11
12  getUser(id: number): Observable<any> {
13    return this.http.get(`/api/users/${id}`);
14  }
15
16  saveUser(user: any): Observable<any> {
17    return this.http.post("/api/users", user);
18  }
19}

Dependency Injection Changes

Downgrading Angular → AngularJS

 1// Angular service
 2import { Injectable } from "@angular/core";
 3
 4@Injectable({ providedIn: "root" })
 5export class NewService {
 6  getData() {
 7    return "data from Angular";
 8  }
 9}
10
11// Make available to AngularJS
12import { downgradeInjectable } from "@angular/upgrade/static";
13
14angular.module("myApp").factory("newService", downgradeInjectable(NewService));
15
16// Use in AngularJS
17angular.module("myApp").controller("OldController", function (newService) {
18  console.log(newService.getData());
19});

Upgrading AngularJS → Angular

 1// AngularJS service
 2angular.module('myApp').factory('oldService', function() {
 3  return {
 4    getData: function() {
 5      return 'data from AngularJS';
 6    }
 7  };
 8});
 9
10// Make available to Angular
11import { InjectionToken } from '@angular/core';
12
13export const OLD_SERVICE = new InjectionToken<any>('oldService');
14
15@NgModule({
16  providers: [
17    {
18      provide: OLD_SERVICE,
19      useFactory: (i: any) => i.get('oldService'),
20      deps: ['$injector']
21    }
22  ]
23})
24
25// Use in Angular
26@Component({...})
27export class NewComponent {
28  constructor(@Inject(OLD_SERVICE) private oldService: any) {
29    console.log(this.oldService.getData());
30  }
31}

Routing Migration

 1// Before: AngularJS routing
 2angular.module("myApp").config(function ($routeProvider) {
 3  $routeProvider
 4    .when("/users", {
 5      template: "<user-list></user-list>",
 6    })
 7    .when("/users/:id", {
 8      template: "<user-detail></user-detail>",
 9    });
10});
 1// After: Angular routing
 2import { NgModule } from "@angular/core";
 3import { RouterModule, Routes } from "@angular/router";
 4
 5const routes: Routes = [
 6  { path: "users", component: UserListComponent },
 7  { path: "users/:id", component: UserDetailComponent },
 8];
 9
10@NgModule({
11  imports: [RouterModule.forRoot(routes)],
12  exports: [RouterModule],
13})
14export class AppRoutingModule {}

Forms Migration

1<!-- Before: AngularJS -->
2<form name="userForm" ng-submit="saveUser()">
3  <input type="text" ng-model="user.name" required />
4  <input type="email" ng-model="user.email" required />
5  <button ng-disabled="userForm.$invalid">Save</button>
6</form>
 1// After: Angular (Template-driven)
 2@Component({
 3  template: `
 4    <form #userForm="ngForm" (ngSubmit)="saveUser()">
 5      <input type="text" [(ngModel)]="user.name" name="name" required>
 6      <input type="email" [(ngModel)]="user.email" name="email" required>
 7      <button [disabled]="userForm.invalid">Save</button>
 8    </form>
 9  `
10})
11
12// Or Reactive Forms (preferred)
13import { FormBuilder, FormGroup, Validators } from '@angular/forms';
14
15@Component({
16  template: `
17    <form [formGroup]="userForm" (ngSubmit)="saveUser()">
18      <input formControlName="name">
19      <input formControlName="email">
20      <button [disabled]="userForm.invalid">Save</button>
21    </form>
22  `
23})
24export class UserFormComponent {
25  userForm: FormGroup;
26
27  constructor(private fb: FormBuilder) {
28    this.userForm = this.fb.group({
29      name: ['', Validators.required],
30      email: ['', [Validators.required, Validators.email]]
31    });
32  }
33
34  saveUser() {
35    console.log(this.userForm.value);
36  }
37}

Migration Timeline

Phase 1: Setup (1-2 weeks)
- Install Angular CLI
- Set up hybrid app
- Configure build tools
- Set up testing

Phase 2: Infrastructure (2-4 weeks)
- Migrate services
- Migrate utilities
- Set up routing
- Migrate shared components

Phase 3: Feature Migration (varies)
- Migrate feature by feature
- Test thoroughly
- Deploy incrementally

Phase 4: Cleanup (1-2 weeks)
- Remove AngularJS code
- Remove ngUpgrade
- Optimize bundle
- Final testing

Resources

  • references/hybrid-mode.md: Hybrid app patterns
  • references/component-migration.md: Component conversion guide
  • references/dependency-injection.md: DI migration strategies
  • references/routing.md: Routing migration
  • assets/hybrid-bootstrap.ts: Hybrid app template
  • assets/migration-timeline.md: Project planning
  • scripts/analyze-angular-app.sh: App analysis script

Best Practices

  1. Start with Services: Migrate services first (easier)
  2. Incremental Approach: Feature-by-feature migration
  3. Test Continuously: Test at every step
  4. Use TypeScript: Migrate to TypeScript early
  5. Follow Style Guide: Angular style guide from day 1
  6. Optimize Later: Get it working, then optimize
  7. Document: Keep migration notes

Common Pitfalls

  • Not setting up hybrid app correctly
  • Migrating UI before logic
  • Ignoring change detection differences
  • Not handling scope properly
  • Mixing patterns (AngularJS + Angular)
  • Inadequate testing

What Users Are Saying

Real feedback from the community

Environment Matrix

Dependencies

Angular CLI 17+
Node.js 16+
@angular/upgrade package
TypeScript 5+

Framework Support

AngularJS 1.5+ ✓ (source) Angular 17+ ✓ (recommended target) Angular 15-16 ✓ (supported)

Context Window

Token Usage ~3K-8K tokens for complex migration scenarios

Security & Privacy

Information

Author
wshobson
Updated
2026-01-30
Category
frontend