Skip to content

Angular Standalone Components

Standalone components let you build an entire Angular application without ever writing an NgModule. This lesson covers how they work and how a fully standalone app is bootstrapped.

What Makes a Component Standalone?

A standalone component declares its own dependencies (other components, directives, pipes) directly through an imports array on its own @Component decorator, rather than relying on a surrounding NgModule to provide them.

Since Angular 17, standalone is the default when you generate a new component with the CLI, and the Angular team recommends it for all new projects going forward.

import { Component } from '@angular/core';
import { CurrencyPipe } from '@angular/common';

@Component({
  selector: 'app-price-tag',
  standalone: true,
  imports: [CurrencyPipe],
  template: '<span>{{ price | currency }}</span>',
})
export class PriceTagComponent {
  price = 19.99;
}

CurrencyPipe is imported directly on the component that needs it, no NgModule involved anywhere.

Bootstrapping a Fully Standalone App

// main.ts
bootstrapApplication(AppComponent, appConfig);

// app.config.ts
export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes), provideHttpClient()],
};
  • bootstrapApplication() replaces platformBrowserDynamic().bootstrapModule(AppModule).
  • ApplicationConfig replaces the root module's providers array for app-wide services.
  • provideRouter(), provideHttpClient(), and similar provideX() functions replace their XModule NgModule equivalents.
  • No root AppModule is needed at all in a fully standalone application.

Standalone Components Cheatsheet

NgModule concepts and their standalone equivalents.

NgModule Concept Standalone Equivalent
declarations: [Comp] Not needed, standalone components require no declaration
imports: [CommonModule] imports: [NgIf, NgFor] (or specific pipes/directives) on the component
RouterModule.forRoot(routes) provideRouter(routes) in app config
HttpClientModule provideHttpClient() in app config
platformBrowserDynamic().bootstrapModule(AppModule) bootstrapApplication(AppComponent, appConfig)
ng generate component (classic) ng generate component (standalone by default in modern CLI)

Importing Only What a Component Needs

Standalone components make dependencies explicit and local: a component only imports the specific directives, pipes, or other components its own template actually uses, rather than gaining access to everything a large shared module happens to export.

@Component({
  selector: 'app-user-list',
  standalone: true,
  imports: [NgFor, UserCardComponent, DatePipe],
  template: `
    @for (user of users; track user.id) {
      <app-user-card [user]="user" />
    }
  `,
})
export class UserListComponent {
  users: User[] = [];
}

Using the modern @for control flow, this component wouldn't even need NgFor imported at all.

Standalone Directives and Pipes

Directives and pipes can also be standalone (and are, by default, in modern Angular), meaning they're imported directly wherever they're used, exactly like standalone components.

@Directive({ selector: '[appHighlight]', standalone: true })
export class HighlightDirective {}

@Pipe({ name: 'truncate', standalone: true })
export class TruncatePipe implements PipeTransform { /* ... */ }

Using Standalone Components Inside NgModules

Standalone components can be gradually introduced into an existing NgModule-based codebase: an NgModule can import a standalone component, and a standalone component can, in turn, import an existing NgModule if it needs something that module exports.

@NgModule({
  declarations: [LegacyComponent],
  imports: [NewStandaloneWidgetComponent], // standalone component imported into an NgModule
})
export class LegacyFeatureModule {}

Common Mistakes

  • Forgetting to import a directive, pipe, or child component a standalone component's template actually uses.
  • Assuming standalone components can't coexist with NgModules; they interoperate in both directions.
  • Manually importing large NgModules into a standalone component when only a specific standalone piece is actually needed.
  • Using bootstrapModule alongside standalone components without a root AppModule, standalone apps should use bootstrapApplication.

Key Takeaways

  • Standalone components declare their own dependencies via an imports array, no NgModule required.
  • bootstrapApplication() and provideX() functions replace the root module and NgModule-based service registration.
  • Directives and pipes can also be standalone, imported directly wherever they're used.
  • Standalone components and NgModules interoperate, enabling gradual migration of existing codebases.

Pro Tip

When migrating an existing NgModule-based app, start by converting leaf components (ones with few dependents) to standalone first, working inward toward shared/core components, this minimizes the blast radius of each migration step.