CPCODELAB
Angular

Standalone Components vs NgModules

10 min read

The Evolution: NgModules to Standalone

Historically, Angular organized code using NgModules — classes decorated with @NgModule that declared components, imported other modules, and exported things for use elsewhere. While powerful, NgModules added boilerplate and made dependencies less obvious.

Standalone components (stable since Angular 15) declare their own dependencies directly via the imports array in @Component. There is no need for a surrounding NgModule. This makes each component self-contained, easier to understand, and simpler to test.

ts
// OLD: NgModule approach
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { UserCardComponent } from './user-card.component';

@NgModule({
  declarations: [UserCardComponent],
  imports: [CommonModule, FormsModule],
  exports: [UserCardComponent]
})
export class UserModule {}

// NEW: Standalone approach
import { Component } from '@angular/core';
import { NgClass } from '@angular/common';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-user-card',
  standalone: true,
  imports: [NgClass, FormsModule],   // Self-contained!
  template: `<div [ngClass]="cardClass">{{ user }}</div>`
})
export class UserCardComponent {
  user = 'Jane';
  cardClass = 'card';
}

Migrating from NgModules

The Angular CLI provides a schematic to migrate existing NgModule-based apps: ng generate @angular/core:standalone. It converts declarations to standalone components and cleans up module boilerplate automatically. You can migrate incrementally — standalone and NgModule-based code can coexist in the same project.

All new Angular projects should use standalone components by default. NgModules are still fully supported but are no longer the recommended pattern. Understanding NgModules remains important for working with existing codebases.

Ready to test yourself?
Practice Angular— quiz & coding exercises