angular/angular
Standalone components
Components, directives, and pipes that declare their own dependencies via imports: [...] instead of relying on an NgModule. Now the default for new code; the historical NgModule model is supported but no longer recommended.
What changed
Pre-standalone, every component was registered in an NgModule's declarations array. The module also declared providers (services), other modules to import, and exports for downstream modules to consume. Standalone components inverted the model: the component itself declares what it imports, and providers come from environment-level provideXxx functions.
// Standalone (current)
@Component({
selector: 'my-page',
imports: [CommonModule, RouterLink, MyChildComponent],
template: `...`,
})
export class MyPage {}
bootstrapApplication(AppRoot, {
providers: [
provideRouter(routes),
provideHttpClient(withFetch()),
provideAnimationsAsync(),
],
});// NgModule (legacy)
@NgModule({
declarations: [MyPage, MyChildComponent],
imports: [CommonModule, RouterModule.forRoot(routes)],
providers: [...],
bootstrap: [AppRoot],
})
export class AppModule {}
platformBrowserDynamic().bootstrapModule(AppModule);How the compiler implements standalone
ngtsc's ComponentDecoratorHandler (packages/compiler-cli/src/ngtsc/annotations/component) checks the component's standalone field (defaults to true in newer projects, was false historically). When standalone:
- The compiler treats the
importsarray as the component's compilation scope. - Each entry in
importsis statically evaluated by thepartial_evaluator. Acceptable forms: a directive class, another component class, a pipe class, or anNgModuleclass (whose exports flatten into the scope). - The flattened scope replaces what an
NgModule.declarations + importswould have provided. - The output
ɵcmpdefinition records the resolved scope so the runtime knows which directives to match against the template at runtime.
For DI, the runtime constructs an EnvironmentInjector chain at bootstrap; standalone components don't carry per-component environment providers (they use component-level providers: [...] for element-injector scoped providers).
provideXxx functions
Standalone-friendly libraries expose provide* factories that return EnvironmentProviders:
provideRouter(routes, …features)—@angular/router.provideHttpClient(…features)—@angular/common/http.provideAnimations()/provideAnimationsAsync()/provideNoopAnimations()— animations.provideClientHydration(…features)—@angular/corehydration.provideZonelessChangeDetection()— opt into zoneless mode.provideServerRendering()—@angular/platform-server.provideServiceWorker(filename, options)—@angular/service-worker.provideForms()(rare; reactive forms work without it in many cases).
The pattern: every feature that previously required XModule.forRoot(config) now has a provideX(config) function returning EnvironmentProviders.
Migrations
packages/core/schematics/migrations/standalone-migration/ — the canonical migration that:
- Marks every existing
@Component/@Directive/@Pipeasstandalone: true. - Generates
importsarrays from the matchingNgModule.declarations + imports. - Converts the bootstrap call from
platformBrowserDynamic().bootstrapModule(AppModule)tobootstrapApplication(AppRoot, {providers}). - Translates
XModule.forRoot(...)calls intoprovideX(...)calls where aprovide*equivalent exists.
The migration is the official way to move existing apps. New ng new projects start standalone by default.
Composition rules
- Standalone components can import:
- Other standalone components / directives / pipes.
NgModules (the module's exports flatten into the scope).- Arrays / functions returning the above (subject to static evaluation).
NgModules can declare and export standalone components as if they were declarations.- A standalone component cannot declare
providersat the environment level — those come frombootstrapApplication's providers orprovideXxxfeatures. - Element-injector providers (component-scoped DI) are still configured via
@Component({providers: [...]}).
Status
standalone: true is the default for ng new projects since v17. Documentation on angular.dev leads with the standalone API. The long-term plan is to deprecate and eventually remove @NgModule, but the timeline is intentionally gradual to give the ecosystem time to migrate. The tests in integration/ng-modules-importability/ make sure NgModules continue to work.
Where to start when modifying
- A new
provideXxxfeature: it lives in the package that owns the feature, returningEnvironmentProviders. Example:packages/router/src/provide_router.ts. - A change to standalone scope resolution: extend
packages/compiler-cli/src/ngtsc/scope/(and the matching runtime metadata inpackages/core/src/render3/definition.ts). - Migration improvements:
packages/core/schematics/migrations/standalone-migration/.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.