AngularJS has long since reached end-of-life: no security patches, no dependency updates, and a steadily shrinking pool of developers who know it. Continuing to keep an AngularJS application in production means accumulating security risk, technical debt, and hiring cost. This guide covers the entire journey to modern Angular: legacy code audit, choosing between big bang and incremental strangler pattern migration, hybrid bootstrap with ngUpgrade, direct concept mapping (controller, directive, $http, routing, authentication), testing, performance, and a 30/60/90 day operational plan with measurable KPIs.
Why migrate from AngularJS to Angular
The jump from AngularJS to Angular is not a simple version upgrade: it is a paradigm shift, from a framework based on pervasive two-way data binding and $scope to a components model with typed Dependency Injection, change Optimized detection and AOT compilation. The benefits are measurable — smaller bundles thanks to tree-shaking, end-to-end TypeScript, an actively maintained ecosystem — but must be balanced against the real risk of a poorly planned migration: functional regressions, team stalled for months, frozen feature releases.
Benefits and risks at a glance
| Benefits of migration | Risks to manage |
|---|---|
| Superior performance (change detection, AOT, tree-shaking) | Functional regressions on untested legacy features |
| End-to-end TypeScript, fewer bugs at runtime | High initial cost without immediate value release |
| Ecosystem maintained, security updated | Team learning new paradigm under pressure |
| Easier to find developers on the market | Temporary hybrid code more complex to debug |
Initial evaluation: AngularJS code audit
Before writing a line of Angular, you need to precisely map out what you are migrating. A superficial audit is the most common cause of bad estimates and migrations that get stuck midway. The audit must answer three questions: how large the code is, how internally coupled it is, and what external dependencies are involved.
Operational audit checklist
- Module Inventory: Lists each AngularJS module (
angular.module(...)) and its declared dependencies. - Controller/directive/service count: Use
grep -rn "\.controller(\|\.directive(\|\.factory(\|\.service(" src/) for a quick and objective count. - Map of shared $scopes - Identify the use of
$rootScopeby global state — almost always the sweet spot to migrate to Angular services. - AngularJS-specific dependencies:
angular-ui-router,angular-translate,restangularhave no direct equivalent and they must be replaced, not translated line by line. - Existing test coverage: Without testing, every refactor is a leap in the dark; measure current coverage before starting.
- Classification by criticality: divide the features into "core business" (high risk, migrate last, with more tests) and "peripheral" (good starting point).
Migration strategy: big bang vs incremental (strangler pattern)
There are two main approaches. The big bang rewrites the entire application in Angular before releasing anything: risky on large applications, but easier to reason about on small projects. The strangler pattern (incremental) allows AngularJS and Angular to coexist in the same application via ngUpgrade, migrating one feature at a time and releasing continuously: slower in the short term, but drastically reduces risk and allows the business to continue to receive value during the migration.
How to choose the right approach
| Criterion | Big bang | Strangler pattern (incremental) |
|---|---|---|
| Application Size | Small/medium (< 50 components) | Large, enterprise |
| Business risk tolerance | High (release can be blocked) | Low (continuity required) |
| Team available | Dedicated full-time to migration | Split between new features and migration |
| Existing test coverage | Not critical | Strongly recommended |
For most real-world enterprise applications, the strangler pattern is the correct choice: it allows you to validate each module migrated into production before proceeding with the next one.
Development environment setup
Before starting the refactor you need the right tools installed and configured correctly, including the @angular/upgrade package which enables interoperability between the two frameworks.
Necessary tools checklist
# Verifica versioni installate
node -v # Node 20.x LTS o superiore
npm -v
# Installa Angular CLI globalmente
npm install -g @angular/cli
# Crea il progetto Angular che ospiterà il bootstrap ibrido
ng new my-app --routing --style=scss
cd my-app
# Installa il modulo di interoperabilità con AngularJS
npm install @angular/upgrade
# Installa AngularJS stesso come dipendenza (per il periodo ibrido)
npm install angular@1.8.3
Refactor and concept mapping: from AngularJS to Angular
The most delicate part of the migration is correctly translating the architectural concepts. Each AngularJS construct has a conceptually close Angular equivalent, but with different semantics and lifecycle.
Concept mapping table
| AngularJS | Modern Angular |
|---|---|
$scope | Component class properties (this) |
$rootScope for global state | Service @Injectable({ providedIn: 'root' }) with BehaviorSubject or signal |
.controller() | Component class with @Component() |
.directive() | Component or Directive (@Directive()) depending on whether it has a template |
.factory() / .service() | Class with @Injectable(), injected via constructor |
$http | HttpClient (RxJS Observable instead of promise) |
$route / ui-router | RouterModule with standalone route or lazy-loaded |
Binding =, @, & | @Input(), @Output() with EventEmitter |
Snippet 1–2: Controller → Component
// AngularJS — controller
angular.module('app').controller('UserListController', function($scope, UserService) {
$scope.users = [];
$scope.loading = false;
$scope.loadUsers = function() {
$scope.loading = true;
UserService.getAll().then(function(res) {
$scope.users = res.data;
$scope.loading = false;
});
};
$scope.loadUsers();
});
// Angular — component equivalente
@Component({
selector: 'app-user-list',
standalone: true,
templateUrl: './user-list.component.html',
})
export class UserListComponent implements OnInit {
users: User[] = [];
loading = false;
constructor(private userService: UserService) {}
ngOnInit(): void {
this.loadUsers();
}
loadUsers(): void {
this.loading = true;
this.userService.getAll().subscribe((users) => {
this.users = users;
this.loading = false;
});
}
}
Snippet 3–4: Complex Directive → Component
// AngularJS — directive con isolate scope
angular.module('app').directive('userCard', function() {
return {
restrict: 'E',
scope: { user: '=', onSelect: '&' },
template: '<div class="card" ng-click="onSelect({user: user})">{{user.name}}</div>',
};
});
// Angular — component con Input/Output
@Component({
selector: 'app-user-card',
standalone: true,
template: `<div class="card" (click)="select.emit(user)">{{ user.name }}</div>`,
})
export class UserCardComponent {
@Input({ required: true }) user!: User;
@Output() select = new EventEmitter<User>();
}
Snippet 5–6: Service AngularJS → Service Angular with DI
// AngularJS — factory
angular.module('app').factory('UserService', function($http) {
return {
getAll: function() {
return $http.get('/api/users');
},
};
});
// Angular — servizio con HttpClient e DI
@Injectable({ providedIn: 'root' })
export class UserService {
constructor(private http: HttpClient) {}
getAll(): Observable<User[]> {
return this.http.get<User[]>('/api/users');
}
}
Snippet 7–8: Routing and HTTP calls
// AngularJS — ui-router
$stateProvider.state('users.detail', {
url: '/users/:id',
template: '<user-detail user-id="$resolve.userId"></user-detail>',
resolve: {
userId: ['$stateParams', function($stateParams) { return $stateParams.id; }],
},
});
// Angular — Router standalone con lazy loading
export const routes: Routes = [
{
path: 'users/:id',
loadComponent: () =>
import('./user-detail/user-detail.component').then((m) => m.UserDetailComponent),
},
];
// Nel component: lettura del parametro via ActivatedRoute
export class UserDetailComponent implements OnInit {
userId = signal<string | null>(null);
constructor(private route: ActivatedRoute) {}
ngOnInit(): void {
this.userId.set(this.route.snapshot.paramMap.get('id'));
}
}
Authentication and state management
The authentication flow needs to be rethought, not just translated. In AngularJS it is common to handle the token at $rootScope with an interceptor at $http; in Angular the correct pattern is a centralized AuthService with reactive state (BehaviorSubject or signal) and a functional HttpInterceptorFn.
Authentication flow migration
// auth.service.ts
@Injectable({ providedIn: 'root' })
export class AuthService {
private tokenSignal = signal<string | null>(localStorage.getItem('access_token'));
readonly isAuthenticated = computed(() => !!this.tokenSignal());
constructor(private http: HttpClient) {}
login(credentials: LoginPayload): Observable<AuthTokens> {
return this.http.post<AuthTokens>('/api/auth/login', credentials).pipe(
tap((tokens) => this.setTokens(tokens)),
);
}
refresh(): Observable<AuthTokens> {
return this.http.post<AuthTokens>('/api/auth/refresh', {}).pipe(
tap((tokens) => this.setTokens(tokens)),
);
}
private setTokens(tokens: AuthTokens): void {
localStorage.setItem('access_token', tokens.accessToken);
this.tokenSignal.set(tokens.accessToken);
}
}
// auth.interceptor.ts — funzione, non più basata su $http config
export const authInterceptor: HttpInterceptorFn = (req, next) => {
const token = localStorage.getItem('access_token');
const cloned = token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req;
return next(cloned);
};
For broader state management (not just auth), on complex enterprise applications it is better to evaluate NgRx, which offers a predictable centralized store; for most cases, though, services with BehaviorSubject or signal are sufficient and much easier to maintain than introducing an entire Redux-like pattern.
Progressive integration with ngUpgrade
ngUpgrade is the official package that allows an AngularJS and an Angular application to run on the same page, at the same time, sharing services and communicating between components. It is the technical heart of the strangler pattern.
Hybrid bootstrap: practical example
// main.ts — bootstrap ibrido con downgradeModule
import { setUpLocationSync } from '@angular/upgrade/static';
import { UpgradeModule } from '@angular/upgrade/static';
@NgModule({
imports: [BrowserModule, UpgradeModule, AppRoutingModule],
declarations: [UserCardComponent],
})
export class AppModule {
constructor(private upgrade: UpgradeModule) {}
ngDoBootstrap(): void {
this.upgrade.bootstrap(document.body, ['legacyApp']);
setUpLocationSync(this.upgrade);
}
}
// Espone il component Angular come directive AngularJS,
// utilizzabile nei template AngularJS esistenti senza riscriverli
angular
.module('legacyApp')
.directive('appUserCard', downgradeComponent({ component: UserCardComponent }));
// Espone un servizio AngularJS ad Angular, per riuso durante la transizione
angular.module('legacyApp').factory('legacyUserService', downgradeInjectable(UserService));
With this setup, an existing AngularJS template can use without modification, while new Angular components can inject legacy AngularJS services via upgradeInjectable, until those are migrated too.
Testing during migration
Hybrid code is by nature more fragile to test: two frameworks, two digest/change detection cycles, two different test runners coexist for months. The correct strategy is to keep Karma/Jasmine on the AngularJS code not yet migrated, introduce Jest for each new Angular component (faster, better watch mode), and gradually replace Protractor with (deprecated) Cypress for E2E, which does not depend on the underlying framework and tests the application as the user sees it.
Checklist testing
- Do not remove existing AngularJS tests until the corresponding module is fully migrated.
- Each new Angular component requires unit tests before it is linked via
ngUpgrade, not after. - Cypress E2Es must cover critical flows end-to-end, traversing both AngularJS and Angular pages during the hybrid period.
- Monitor overall coverage every sprint: it should never fall below the pre-migration level.
Performance and bundle optimization
During the hybrid period the bundle inevitably grows, because it contains both AngularJS and Angular. It is critical to monitor this growth and plan to remove AngularJS as soon as the last module is migrated.
Performance checklist
- Lazy loading aggressive on each Angular route with
loadComponent/loadChildren, so as not to load all the new code early. - AOT compilation always active in production (
ng builduses it by default from the modern CLI). - Bundle analyzer run at each migration milestone, to verify that AngularJS is actually removed at the end of the journey and does not remain "dead" in the bundle.
- Differential loading: Angular CLI automatically generates differentiated bundles for modern/legacy browsers when needed.
- Remove
angular(1.x) frompackage.jsonand from every import as soon as the last AngularJS module has been migrated - this is the step most often forgotten.
Deploy, CI/CD and rollback strategy
Each migrated module must be released behind a feature flag, so as to be able to instantly return to the AngularJS version in case of critical regression, without a complete deployment rollback.
Feature flags and rollback: example
// Semplice feature flag basato su configurazione remota
if (this.featureFlags.isEnabled('new-user-list-angular')) {
this.router.navigate(['/users']); // route Angular
} else {
window.location.href = '/legacy/users'; // route AngularJS esistente
}
The CI/CD pipeline must perform, for each pull request: production build, Jest/Karma suite, Cypress suite on critical flows, and an automatic bundle size check with maximum threshold — an abnormal bundle increase is often the first sign of a forgotten AngularJS dependency.
5 practical mini-guides ready to publish
Mini-guide 1 — Convert an AngularJS controller to an Angular component
H1: From AngularJS controller to Angular component: step by step guide
Intro: The controller is the first brick to migrate in each module: the conversion into a component always follows the same repeatable pattern.
Snippet (40-60 words): An AngularJS controller with $scope becomes an Angular component class: the properties on $scope become properties of the class, the methods remain methods, and the initialization that happened at the end controller moves to ngOnInit(). Dependencies injected via function parameters become typed constructor parameters.
Structure: H2 "Identify the scope of the controller" → H3 "List properties and methods"; H2 "Create component class" → H3 "Move initialization logic"; H2 "Update the template".
Short FAQ: "Do you need to migrate the template together with the controller?" → "Yes, always together: binding syntax changes (ng-click → (click))." · "Can I leave $scope temporarily?" → "No, it doesn't exist in Angular: it must be removed contextually."
Mini-guide 2 — Migrate a complex directive into an Angular component
H1: Migrate an AngularJS directive with isolated scope to Angular component
Intro: The directives with isolated scope and binding =/@/& are the most common case and map almost 1:1 on Input/Output.
Snippet (40-60 words): A binding = (two-way) becomes a @Input() combined, if necessary, with @Output() to notify the parent; a & binding (function) directly becomes a @Output() with EventEmitter. The inline template of the directive becomes the template/templateUrl of the new Angular component.
Structure: H2 "Analyze directive bindings" → H3 "Map =, @, & to Input/Output"; H2 "Create component" → H3 "Handle restrict: 'E' vs 'A'"; H2 "Update usages in templates".
Short FAQ: "What happens to restrict: 'A' (attribute directive)?" → "Become a @Directive() Angular without template." · "Are two-way bindings still supported?" → "Yes, via convention [(value)] with coupled Input+Output."
Mini-guide 3 — Integrating ngUpgrade for a hybrid bootstrap
H1: AngularJS + Angular hybrid bootstrap with ngUpgrade
Intro: The hybrid bootstrap is the enabling step for the entire incremental strategy: without it, every migration is forcibly big bang.
Snippet (40-60 words): UpgradeModule.bootstrap() starts both frameworks on the same page; downgradeComponent makes an Angular component usable in AngularJS templates, upgradeComponent does the opposite. downgradeInjectable/upgradeInjectable share services between the two worlds, allowing immediate reuse without duplicating logic.
Structure: H2 "Install @angular/upgrade" → H3 "Configure ngDoBootstrap"; H2 "Expose Angular components to AngularJS" → H3 "downgradeComponent in practice"; H2 "Share services between the two frameworks".
Short FAQ: "is ngUpgrade slowing down the application?" → "A little, for double change detection: it's a temporary cost, not a permanent one." · "How long can the hybrid phase last?" → "A few weeks to many months, depending on the size of the app."
Mini-guide 4 — Migrate routing from ui-router to Angular Router
H1: From ui-router to Angular Router: Routing Migration Guide
Intro: Routing is often the last piece to be migrated, because it affects the entire navigation structure of the application.
Snippet (40-60 words): Each state of ui-router becomes a Route Angular: url becomes path, template/controller become component (or loadComponent for lazy loading), and the resolve become resolve Angular service-based with Resolve or simply read into the component via ActivatedRoute.
Structure: H2 "Map existing states" → H3 "url → path, resolve → Resolve"; H2 "Configure routes with lazy loading" → H3 "loadComponent vs loadChildren"; H2 "Manage co-existence with setUpLocationSync".
Short FAQ: "Can the two routers coexist?" → "Yes, temporarily, with setUpLocationSync to sync the URL." · "What do I use instead of ui-router nested states?" → "Angular routes nested with child routes and ."
Mini-guide 5 — Implement JWT authentication and refresh token during migration
H1: JWT authentication with refresh token during AngularJS migration → Angular
Intro: The authentication flow must work identically in both still AngularJS and already Angular pages, sharing the same token.
Snippet (40-60 words): Centralizes the token in localStorage (or httpOnly cookie, preferable for security), read by both the $http AngularJS interceptor and from HttpInterceptorFn Angular. An AuthService Angular exposed to AngularJS via downgradeInjectable avoids duplicating login/refresh logic in the two frameworks during the hybrid period.
Structure: H2 "Centralize token management" → H3 "localStorage vs httpOnly cookies"; H2 "Share the AuthService between the two frameworks" → H3 "downgradeInjectable in practice"; H2 "Manage automatic refresh on 401".
Short FAQ: "Do I need to duplicate the login in both frameworks?" → "No, a single Angular AuthService shared via downgradeInjectable is enough." · "How do I handle logging out on an expired token?" → "Intercept 401s in both interceptors and redirect to centralized login."
Case study: Migration of an enterprise application
A typical case: AngularJS management application with 340 controllers, 85 custom directives and 6 years of incremental development. With a strangler pattern approach on teams of 4 developers, the migration lasted 9 months, with continuous weekly releases throughout the entire period. Results measured at the end of the project: initial bundle reduced by 38% (from 2.4MB to 1.5MB gzip) after completely removing AngularJS, loading time (Time to Interactive) improved by 44%, test coverage went from 22% to 68% thanks to the new tests introduced at the same time as each migrated component. Estimated effort: approximately 1,400 person/hours total, of which 60% concentrated on the core business modules migrated in the second half of the project.
Frequently Asked Questions
How long does a migration from AngularJS to Angular take?
Varies from a few weeks for small applications to over a year for large enterprise applications; the strangler pattern allows you to distribute effort over multiple sprints without blocking releases.
Do I have to use ngUpgrade?
No, only if you choose the incremental approach. With the big bang there is no need, because there is no period of coexistence between the two frameworks.
Is NgRx mandatory after migration?
No: For most applications, services with BehaviorSubject or signal are sufficient; NgRx is only suitable for very complex state shared between many features.
Can I migrate only some pages and leave the others in AngularJS long term?
Technically yes with ngUpgrade, but it is not recommended as a permanent state: it increases maintenance complexity and the bundle remains heavier than necessary.
How do I handle AngularJS-specific third-party libraries?
They must be replaced with the Angular equivalent or a framework-agnostic library; there is no machine translation for libraries like restangular or angular-translate.
Is Protractor still usable for E2E testing?
It is deprecated by the Angular team: for new projects or migrations we recommend Cypress, which does not depend on the framework and tests the app as a real user would do.
What is the difference between downgradeComponent and upgradeComponent?
downgradeComponent makes an Angular component usable in an AngularJS template; upgradeComponent does the reverse operation, to temporarily reuse AngularJS components in Angular.
When is it better to choose the big bang instead of the strangler pattern?
On small to medium applications, with a dedicated full-time team and business risk tolerance, where temporarily blocking releases is acceptable.
How do I prevent the bundle from growing too much during the hybrid phase?
Monitor the bundle size at each milestone with a bundle analyzer and explicitly schedule the removal of AngularJS as soon as the last module is migrated.
Do you need to rewrite all tests during migration?
No: Existing AngularJS tests remain valid until the corresponding module is migrated; new Jest/Cypress tests are progressively added for Angular code.
6 quick replies for featured snippets and AI assistants
What is ngUpgrade?
ngUpgrade is the official Angular package (@angular/upgrade) that allows an AngularJS application and an Angular application to run simultaneously on the same page, sharing components and services. It is the key tool to migrate incrementally without blocking releases, via downgradeComponent and upgradeComponent.
What is the strangler pattern applied to the frontend?
The strangler pattern is an incremental migration strategy in which the new application (Angular) progressively "wraps" the legacy one (AngularJS), replacing one module at a time until the old code is completely removed. Reduces risk compared to a complete rewrite (big bang).
What is the main difference between $scope and Angular components?
$scope in AngularJS is a shared and mutable object that connects controllers and templates with pervasive two-way binding. In Angular, state lives as typed properties of the component class, with explicit binding ([value], (event)) and isolated change detection per component, more predictable and performant.
How do you replace $http in Angular?
With HttpClient, injected via Dependency Injection into services. The main difference is that HttpClient returns RxJS's Observable instead of promise, enabling operators like retry, debounceTime and switchMap to handle complex requests.
How do you handle authentication during the hybrid period?
Centralizing tokens and login logic into a single AuthService Angular, also exposed to AngularJS via downgradeInjectable. This way both AngularJS and Angular pages share the same authentication state without duplicating code.
How much does an AngularJS → Angular migration cost in terms of effort?
Depends on size: small applications require a few weeks, enterprise applications with hundreds of controllers can require 1,000+ person-hours spread over 6-12 months with an incremental approach, keeping new feature releases active along the way.
Common Mistakes to Avoid
- Migrate without prior audit: starting to write Angular components without having mapped dependencies and critical issues leads to wrong estimates and blocks halfway.
- Choosing the big bang on an application that's too big: blocks releases for months and drastically increases the risk of regressions not discovered in time.
- Forgetting to remove AngularJS at the end of migration: the bundle remains bloated for months because no one removed the
angulardependency onpackage.json. - Do not centralize shared state (auth, current user): Duplicating logic between the two frameworks during the hybrid phase generates hard-to-diagnose synchronization bugs.
- Neglecting E2E testing during the hybrid period: it is precisely at this stage that the risk of regression is highest, not after.
- Translate 1:1 directives without rethinking the architecture: some AngularJS directives hide more responsibilities that in Angular should be separated into distinct components.
- Underestimate the team's learning curve: decorator, typed DI and RxJS require dedicated training, not just "learning by doing" under deadline pressure.
- Do not monitor bundle size during migration: Without automatic checking in CI, an anomalous increase goes unnoticed until released to production.
Operational checklist and 30/60/90 day plan
| Phase | Objective | Reference KPI |
|---|---|---|
| Days 1-30 | Full audit, strategy choice, environment setup and hybrid bootstrap with ngUpgrade | Hybrid bootstrap working in staging, complete module inventory |
| Days 31-60 | Migration of the first 3-5 peripheral modules (low criticality), introduction of Jest/Cypress tests | Coverage test not lower than the level pre-migration |
| Days 61-90 | Migration of central authentication and routing, first core business module migrated | 0 critical regressions in production, bundle monitored at each release |
Recurring activities: every day monitor any errors in production on modules already migrated; every week perform an audit of the bundle size and coverage test; every month review the migration roadmap with the team and update the criticality rating of the remaining modules.
Useful tools and resources
- Angular CLI
- ngUpgrade (@angular/upgrade)
- TypeScript
- ESLint
- Prettier
- Cypress
- Lighthouse
- Bundle Analyzer (source-map-explorer or webpack-bundle-analyzer)
Structured data and technical SEO
For a technical article of this type, Article and FAQPage structured data help both your ranking on Google and the likelihood of being cited by conversational assistants who analyze the page.
Example JSON-LD Article
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Migrazione da AngularJS a Angular: guida completa, strategia e best practice",
"description": "Guida pratica alla migrazione da AngularJS ad Angular: strategia, ngUpgrade, routing, auth, testing, checklist 30/60/90 giorni.",
"author": { "@type": "Organization", "name": "Nome Azienda" },
"datePublished": "2026-08-07",
"dateModified": "2026-08-07",
"mainEntityOfPage": "https://www.esempio.it/blog/migrazione-angularjs-angular"
}
Recommended Open Graph Tags
| Tag | Recommended value |
|---|---|
| og:title | AngularJS Migration → Angular: Complete Guide |
| og:description | Strategy, ngUpgrade, concept mapping and operational checklist to migrate without stopping releases. |
| og:image | Dedicated image 1200x630px, not the company logo |
| Recommended URL | /migration-angularjs-angular |
How to check
- Mobile test: verify the rendering and performance of the hybrid application on a real device, not just in emulation.
- Schema Check: Validate the JSON-LD Article/FAQPage with Google's Structured Data Testing Tool.
- Check bundle size: compare the size of the bundle before/after each milestone with a bundle analyzer, to intercept anomalous growth.
- ngUpgrade integration test: Verify that components and services shared between AngularJS and Angular work correctly in both directions (downgrade and upgrade).
- Verify test coverage: Overall coverage must never fall below the pre-migration level during the entire journey.
- Lighthouse performance audit: Perform a Lighthouse audit at each milestone, comparing Time to Interactive and Largest Contentful Paint to the AngularJS baseline.
Conclusion: where to start
Migrating from AngularJS to Angular is not an improvised project: it requires an honest audit of existing code, a strategy chosen based on size and risk tolerance, and tools like ngUpgrade that make an incremental transition possible without blocking the business. Start with audit, choose the strangler pattern if the application is large, and migrate a low-criticality peripheral module as a first concrete step. If you prefer a direct comparison on your specific case, request a migration audit or download the operational checklist of this guide to immediately start applying it to your project.