As of version 15.2.0, Angular offers a schematic to help project authors convert existing projects to the new standalone APIs. The schematic aims to transform as much code as possible automatically, but it may require some manual fixes by the project author. Run the schematic with the following command:
ng generate @angular/core:standalone
Before using the schematic, please ensure that the project:
Option | Details |
---|---|
mode | The transformation to perform. See Migration modes below for details on the available options. |
path | The path to migrate, relative to the project root. You can use this option to migrate sections of your project incrementally. |
The migration process is composed of three steps. You'll have to run it multiple times and check manually that the project builds and behaves as expected.
While the schematic can automatically update most code, some edge cases require developer intervention. You should plan to apply manual fixes after each step of the migration. Additionally, the new code generated by the schematic may not match your code's formatting rules.
Run the migration in the order listed below, verifying that your code builds and runs between each step:
ng g @angular/core:standalone
and select "Convert all components, directives and pipes to standalone"ng g @angular/core:standalone
and select "Remove unnecessary NgModule classes"ng g @angular/core:standalone
and select "Bootstrap the project using standalone APIs"Congratulations, your application has been converted to standalone 🎉. These are some optional follow-up steps you may want to take now:
NgModule
declarations: since the "Remove unnecessary NgModules" step cannot remove all modules automatically, you may have to remove the remaining declarations manually.--fix
flag that may resolve so warnings automatically.The migration has the following modes:
In this mode, the migration converts all components, directives and pipes to standalone by setting standalone: true
and adding dependencies to their imports
array.
The schematic ignores NgModules which bootstrap a component during this step because they are likely root modules used by bootstrapModule
rather than the standalone-compatible bootstrapApplication
. The schematic converts these declarations automatically as a part of the "Switch to standalone bootstrapping API" step.
Before:
// shared.module.ts @NgModule({ imports: [CommonModule], declarations: [GreeterComponent], exports: [GreeterComponent] }) export class SharedModule {}
// greeter.component.ts @Component({ selector: 'greeter', template: '<div *ngIf="showGreeting">Hello</div>', }) export class GreeterComponent { showGreeting = true; }
After:
// shared.module.ts @NgModule({ imports: [CommonModule, GreeterComponent], exports: [GreeterComponent] }) export class SharedModule {}
// greeter.component.ts @Component({ selector: 'greeter', template: '<div *ngIf="showGreeting">Hello</div>', standalone: true, imports: [NgIf] }) export class GreeterComponent { showGreeting = true; }
After converting all declarations to standalone, many NgModules can be safely removed. This step deletes such module declarations and as many corresponding references as possible. If the migration cannot delete a reference automatically, it leaves the following TODO comment so that you can delete the NgModule manually:
/* TODO(standalone-migration): clean up removed NgModule reference manually */
The migration considers a module safe to remove if that module:
declarations
.providers
.bootstrap
components.imports
that reference a ModuleWithProviders
symbol or a module that can't be removed.Before:
// importer.module.ts @NgModule({ imports: [FooComponent, BarPipe], exports: [FooComponent, BarPipe] }) export class ImporterModule {}
After:
// importer.module.ts // Does not exist!
This step converts any usages of bootstrapModule
to the new, standalone-based bootstrapApplication
. It also switches the root component to standalone: true
and deletes the root NgModule. If the root module has any providers
or imports
, the migration attempts to copy as much of this configuration as possible into the new bootstrap call.
Before:
// ./app/app.module.ts import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule {}
// ./app/app.component.ts @Component({ selector: 'app', template: 'hello' }) export class AppComponent {}
// ./main.ts import { platformBrowser } from '@angular/platform-browser'; import { AppModule } from './app/app.module'; platformBrowser().bootstrapModule(AppModule).catch(e => console.error(e));
After:
// ./app/app.module.ts // Does not exist!
// ./app/app.component.ts @Component({ selector: 'app', template: 'hello', standalone: true }) export class AppComponent {}
// ./main.ts import { bootstrapApplication } from '@angular/platform-browser'; import { AppComponent } from './app/app.component'; bootstrapApplication(AppComponent).catch(e => console.error(e));
Some common problems that may prevent the schematic from working correctly include:
tsconfig.json
files. The schematic excludes any files not captured by a tsconfig.Due to the size and complexity of the migration, there are some cases that the schematic cannot handle:
imports
added to components in unit tests might not be entirely correct.customConfigureTestModule
function that wraps TestBed.configureTestingModule
, components it declares may not be recognized.
© 2010–2023 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://angular.io/guide/standalone-migration