Skip to main content

Standalone Components

What Are Standalone Components?

Standalone components (stable in Angular 15) allow you to build Angular applications without NgModules. They are self-contained units that declare their own dependencies.

Key Features

1. standalone: true Flag

import { Component } from "@angular/core";
import { CommonModule } from "@angular/common";

@Component({
selector: "app-user-profile",
standalone: true,
imports: [CommonModule], // Direct imports instead of NgModule
template: `<h1>{{ userName }}</h1>`,
})
export class UserProfileComponent {
userName = "John Doe";
}

2. Direct Imports

Components can import other standalone components, directives, pipes, or NgModules directly:

@Component({
standalone: true,
imports: [
CommonModule, // NgModule
MatButtonModule, // NgModule
UserCardComponent, // Standalone component
HighlightDirective, // Standalone directive
DateFormatPipe // Standalone pipe
],
// ...
})

3. Bootstrap Without NgModule

Old Way (NgModule):

// main.ts
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";

platformBrowserDynamic().bootstrapModule(AppModule);

New Way (Standalone):

// main.ts
import { bootstrapApplication } from "@angular/platform-browser";
import { AppComponent } from "./app/app.component";

bootstrapApplication(AppComponent);

Benefits

Tree-Shaking

  • Only import what you need
  • Smaller bundle sizes
  • Better code splitting

Simplified Architecture

  • No NgModule boilerplate
  • Clearer dependencies
  • Easier to understand component requirements

Better Developer Experience

  • Less configuration
  • Faster development
  • Reduced cognitive overhead

Improved Testing

// Simpler component testing
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { UserProfileComponent } from "./user-profile.component";

describe("UserProfileComponent", () => {
let component: UserProfileComponent;
let fixture: ComponentFixture<UserProfileComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [UserProfileComponent], // Just import the standalone component!
});
fixture = TestBed.createComponent(UserProfileComponent);
component = fixture.componentInstance;
});

it("should create", () => {
expect(component).toBeTruthy();
});
});

Common Patterns

Standalone Component with Services

import { Component, inject } from "@angular/core";
import { UserService } from "./user.service";

@Component({
selector: "app-user-list",
standalone: true,
template: `
@for (user of users; track user.id) {
<div>{{ user.name }}</div>
}
`,
})
export class UserListComponent {
private userService = inject(UserService);
users = this.userService.getUsers();
}

Providing Services in Standalone

import { Component } from "@angular/core";
import { provideHttpClient } from "@angular/common/http";

@Component({
standalone: true,
providers: [UserService], // Component-level providers
// ...
})
export class UserListComponent {}

Migration Strategy

Gradual Migration

You can mix NgModules and standalone components:

// Old NgModule importing standalone component
@NgModule({
imports: [
StandaloneUserCardComponent, // Import standalone in NgModule
],
declarations: [OldUserListComponent],
})
export class UserModule {}
// Standalone component importing NgModule
@Component({
standalone: true,
imports: [
UserModule, // Import NgModule in standalone
],
})
export class NewDashboardComponent {}

Interview Tips

Q: What problem do standalone components solve? A: They eliminate NgModule boilerplate, improve tree-shaking, simplify dependencies, and reduce bundle size while making the architecture more intuitive.

Q: Can you mix standalone and NgModule-based components? A: Yes! Angular 15+ supports both, allowing gradual migration.

Q: When should you use standalone components? A: For all new Angular 15+ projects. They're simpler, more maintainable, and will be the recommended approach going forward.