Generated banner for Angular Migration
Generated logo for Angular Migration

Angular Migration

Seth HobsonCommunityCreated by Seth Hobson

  • Skill
  • Guidelines
  • Software development
  • MIT
  • No issues found

From the author

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.
— the description by Seth Hobson

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

This skill provides a structured approach for upgrading AngularJS (1.x) applications to modern Angular (2+). It covers various migration strategies, including Big Bang rewrites and incremental hybrid approaches using ngUpgrade. The documentation details the technical transformation of core concepts such as controllers, directives, services, dependency injection, and routing, while providing a phased roadmap for project execution.

What it does

  • Outlines strategies for Big Bang, incremental, and vertical slice migrations.
  • Provides configuration patterns for bootstrapping hybrid AngularJS/Angular applications.
  • Demonstrates code transformation from AngularJS controllers and directives to Angular components.
  • Explains how to migrate services and handle dependency injection across the hybrid boundary.
  • Details the transition from AngularJS routing to the Angular Router.
  • Offers a phased timeline for managing the migration process from setup to final cleanup.

When to use it

  • When planning to modernize a legacy AngularJS application.
  • When you need to run AngularJS and Angular side-by-side during a transition.
  • When converting specific features or components to modern Angular standards.
  • When updating dependency injection systems to match Angular best practices.

Advantages

  • Enables incremental modernization without requiring a complete application rewrite.
  • Provides clear side-by-side code comparisons for common AngularJS and Angular patterns.
  • Includes specific techniques for interoperability between the two frameworks.
  • Offers a structured, phased approach to minimize risk during large-scale migrations.

Usage examples

“How do I bootstrap a hybrid application with both AngularJS and Angular?”
The skill provides the main.ts and app.module.ts configuration patterns using UpgradeModule to initialize both frameworks simultaneously.
“Show me how to convert an AngularJS directive to an Angular component.”
The skill provides a direct comparison showing the transition from a directive definition object to an Angular component class with @Input and @Output decorators.
“How can I share a service between AngularJS and Angular?”
The skill explains how to use downgradeInjectable to expose Angular services to AngularJS, and how to use InjectionToken to expose AngularJS services to Angular.
“What is the recommended timeline for an Angular migration?”
The skill outlines a four-phase timeline covering setup, infrastructure, feature migration, and final cleanup.

Install

  1. Download the skill as a ZIP:

    https://autogineer.com/agent-skills/wshobson/angular-migration/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip angular-migration.zip -d .agents/skills

Documentation by Seth Hobson

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.

Files

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Seth Hobson
Publisher
Seth Hobson (Community)
Source
wshobson/agents · plugins/framework-migration/skills/angular-migration · commit 4bde316
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Seth Hobson or Seth Hobson.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download angular-migration.zip