How to migrate AngularJS to Angular without downtime
The safe way to leave AngularJS is to run old and new code side by side and move one piece at a time. Here is how that works in practice.
The principle: the strangler fig
Instead of building a new app next to the old one and switching over on a single day, you grow the new code inside the existing app. Every screen that moves to modern Angular is released on its own. The AngularJS part shrinks until it's gone. Users keep using the product the whole time, and the team keeps shipping features.
Angular supports this directly through its upgrade tooling, which lets an Angular application host AngularJS modules, share services in both directions and route between the two.
Step 0: Assessment (1–2 weeks)
Before writing any migration code, build an inventory:
- Modules and screens, with a rough usage ranking. Unused screens are simply deleted.
- Routes (usually ui-router states) and deep links customers depend on.
- Services:
$httpwrappers, auth and session handling, shared state on$rootScope. - Directives and components, and how much logic lives in controllers versus templates.
- Third-party dependencies: AngularJS libraries, jQuery plugins, date and grid widgets. These are the usual blockers.
- Tests and build chain: what exists, what runs, which Node version everything needs.
From this you pick the pilot: a module that is valuable enough to matter and isolated enough to be low risk. Reports, settings and dashboards are typical first candidates. Login and the main list screen usually are not.
Step 1: Make the legacy code migration-ready
Migration is much easier when the AngularJS code already looks like modern code. Without changing behavior:
- Move to the component style introduced in AngularJS 1.5 (
.component()instead of controllers plus scope). - Replace
$scopewithcontrollerAswhere it's cheap. - Wrap direct jQuery DOM manipulation in dedicated directives so it can be swapped later.
- Put the code through a modern build (TypeScript, ES modules) so both frameworks can share one toolchain.
This step alone reduces the migration effort, because every component migrated later follows the same shape.
Step 2: Bootstrap the hybrid application
The Angular application starts first and bootstraps the AngularJS app inside it. Two things must be solved here, and they are the same in every migration:
- One session. Authentication, tokens and the current user live in one service, exposed to both frameworks. Users must never sign in twice or lose their session because a screen changed framework.
- Routing coexistence. The Angular router owns the new routes; the legacy router keeps the old ones. A wildcard route hands anything unknown to the legacy side, so every existing deep link keeps working.
At the end of this step nothing looks different to users. That's the point: the pilot is released with zero visible change and proves the plumbing works.
Step 3: Migrate services before screens
Services are the leaves of the dependency tree. Rewrite them in Angular first, then downgrade them so the legacy screens keep using them. This way the new screens and the old screens share the same data layer, and you never duplicate state during the migration.
Typical order: HTTP layer with interceptors, auth, configuration, then domain services.
Step 4: Move screens one at a time, behind flags
Each screen is rebuilt in Angular with the same layout and behavior. Same layout matters: a migration is not a redesign, and mixing both doubles the risk and the testing effort.
Release each screen behind a feature flag or a route switch. If something is wrong, flip it back within minutes. Once a screen has been stable in production for a while, delete the AngularJS version. Don't keep both.
Prioritize by risk and value: leaf screens first, the busiest screens once the patterns are proven, shared shell (navigation, layout) whenever it's convenient.
Step 5: Test what matters
- End-to-end tests for the critical flows (login, the main transaction, exports). Write them against the legacy app first; they are your parity check for every migrated screen.
- Unit tests as you migrate. Business rules that lived in AngularJS controllers become testable services and typed forms.
- Parity review for each screen: same fields, same validations, same edge cases.
Step 6: Remove AngularJS
When the last screen moves, delete the upgrade layer, the legacy router and every AngularJS dependency from package.json. Then remove the compatibility code you wrote in Step 2. The end state is a plain, modern Angular application.
Common pitfalls
- jQuery plugin widgets (grids, date pickers, rich editors). Wrap them if they must stay, replace them if a modern equivalent exists. Decide per widget during the assessment.
$rootScopeevents used as a global bus. Replace with typed services and observables before migrating the screens that depend on them.- Change detection differences. AngularJS's digest cycle and Angular's change detection are different; code that relied on "it updates eventually" needs explicit signals or observables.
- Two copies of the same state. If both frameworks keep their own user or settings state, you get bugs that are very hard to reproduce. Share the service instead.
- Bundle size during the hybrid phase. Both frameworks ship together for a while. Lazy-load the legacy bundle and measure.
- Styles leaking between old and new components. Scope the new styles and keep a shared design token layer.
What "no downtime" really requires
The framework does its part, but no downtime also depends on things outside the code: a deployment pipeline that can release a single screen, monitoring that tells you within minutes if errors rise, and feature flags that let you roll back without a redeploy. If these don't exist yet, set them up during the pilot. They pay off for every phase after it.
A realistic timeline
| Phase | Duration | Output |
|---|---|---|
| Assessment | 1–2 weeks | Inventory, pilot choice, plan with fixed price per phase |
| Pilot | 2–4 weeks | Hybrid bootstrap, shared session, first screen live |
| Phases | Per phase | Screens migrated in groups, each approved on its own |
| Cleanup | 1–2 weeks | AngularJS removed, upgrade layer deleted |
Total time depends on the number of screens and on how much third-party UI has to be replaced. The assessment is what turns that into a number you can plan with.
Planning a migration or a micro-frontend platform?
In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.
Message me on LinkedIn