Angular Labs
COOKIES
architecture / Prefer Standalone over NgModules

Prefer Standalone over NgModules

Use standalone components over NgModules for better modularity and simpler application architecture

Official Angular Style Guide

API Reference

@Component with Standalone

The standalone property makes a component self-contained and eliminates the need for NgModules.

Component Configuration

@Component({
selector: "app-example",
standalone: true, // Enables standalone mode
imports: [CommonModule, FormsModule], // Direct imports
providers: [ExampleService], // Component-level providers
template: `...`,
})
export class ExampleComponent {}

Properties

standalone: boolean

Marks the component as standalone, allowing it to manage its own dependencies.

@Component({
standalone: true, // Required for standalone components
// ...
})

imports: (Type | ReadonlyArray<Type>)[]

Declares dependencies directly in the component instead of through NgModules.

@Component({
imports: [
CommonModule, // Angular common directives and pipes
FormsModule, // Template-driven forms
ReactiveFormsModule, // Reactive forms
CustomComponent, // Other standalone components
CustomDirective, // Standalone directives
CustomPipe // Standalone pipes
]
})

providers: Provider[]

Provides services at the component level instead of module level.

@Component({
providers: [
ExampleService,
{ provide: API_URL, useValue: 'https://api.example.com' },
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
]
})

Bootstrap Functions

bootstrapApplication()

Bootstraps standalone applications without NgModules.

import { bootstrapApplication } from "@angular/platform-browser";
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
provideHttpClient(),
provideAnimations(),
// Custom providers
],
});

Provider Functions

Angular provides dedicated functions for common providers:

// Routing
provideRouter(routes, withEnabledBlockingInitialNavigation());
// HTTP Client
provideHttpClient(withInterceptors([authInterceptor]));
// Animations
provideAnimations();
// Service Worker
provideServiceWorker("ngsw-worker.js");

Lazy Loading with Standalone

loadComponent

Load standalone components lazily in routes.

const routes: Routes = [
{
path: "feature",
loadComponent: () => import("./feature/feature.component").then((m) => m.FeatureComponent),
},
];

loadChildren with Standalone Routes

Load child routes with standalone components.

const routes: Routes = [
{
path: "admin",
loadChildren: () => import("./admin/admin.routes").then((m) => m.ADMIN_ROUTES),
},
];
// admin.routes.ts
export const ADMIN_ROUTES: Routes = [
{ path: "", component: AdminDashboardComponent },
{ path: "users", component: AdminUsersComponent },
];

Migration from NgModules

Step-by-step Migration

  1. Enable standalone on components:
@Component({
standalone: true,
imports: [/* dependencies */]
})
  1. Update routing:
// From
{ path: 'feature', loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule) }
// To
{ path: 'feature', loadComponent: () => import('./feature/feature.component').then(m => m.FeatureComponent) }
  1. Update bootstrap:
// From
platformBrowserDynamic().bootstrapModule(AppModule)
// To
bootstrapApplication(AppComponent, { providers: [...] })

Performance Benefits

  • Smaller bundle sizes through better tree-shaking
  • Faster compilation with simplified dependency resolution
  • Improved lazy loading with component-level code splitting
  • Reduced runtime overhead from NgModule instantiation

Angular CLI Support

Generate standalone components by default:

Terminal window
ng generate component my-component --standalone
ng generate directive my-directive --standalone
ng generate pipe my-pipe --standalone

Set standalone as default in angular.json:

{
"schematics": {
"@schematics/angular:component": {
"standalone": true
}
}
}