Modules vs Standalone
Standalone Components (Modern - Default)
Standalone is the default and recommended approach for Angular 17+.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-user',
standalone: true,
imports: [CommonModule],
template: `<p>User component</p>`
})
export class UserComponent {}
Bootstrapping Standalone
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter } from '@angular/router';
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(),
provideRouter(routes),
UserService
]
});
Standalone App Component
import { Component } from '@angular/core';
import { RouterOutlet, RouterLink } from '@angular/router';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [
CommonModule,
RouterOutlet,
RouterLink,
UserListComponent
],
template: `
<nav>
<a routerLink="/">Home</a>
<a routerLink="/users">Users</a>
</nav>
<router-outlet></router-outlet>
`
})
export class AppComponent {}
Standalone Routes
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
loadComponent: () => import('./home/home.component')
.then(m => m.HomeComponent)
},
{
path: 'users',
loadComponent: () => import('./users/user-list.component')
.then(m => m.UserListComponent)
},
{
path: 'admin',
loadChildren: () => import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
}
];
Lazy Loading Standalone
// admin.routes.ts
import { Routes } from '@angular/router';
export const ADMIN_ROUTES: Routes = [
{
path: '',
loadComponent: () => import('./admin-dashboard.component')
.then(m => m.AdminDashboardComponent)
},
{
path: 'users',
loadComponent: () => import('./admin-users.component')
.then(m => m.AdminUsersComponent)
}
];
Mixing Modules and Standalone
// Import standalone component in NgModule
@NgModule({
imports: [
BrowserModule,
UserComponent // Standalone component
],
declarations: [AppComponent]
})
export class AppModule {}
// Import NgModule in standalone component
@Component({
standalone: true,
imports: [
CommonModule,
ReactiveFormsModule // NgModule
]
})
export class FormComponent {}
Providers in Standalone
// Component-level
@Component({
standalone: true,
providers: [UserService] // New instance per component
})
export class UserComponent {}
// Application-level
bootstrapApplication(AppComponent, {
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' },
UserService // Singleton
]
});
// Service-level
@Injectable({ providedIn: 'root' })
export class UserService {}
Common Imports
// Always import these when needed
import { CommonModule } from '@angular/common'; // *ngIf, *ngFor, pipes
import { FormsModule } from '@angular/forms'; // ngModel
import { ReactiveFormsModule } from '@angular/forms'; // Reactive forms
import { RouterModule } from '@angular/router'; // routerLink, router-outlet
import { HttpClientModule } from '@angular/common/http'; // Legacy
// Or
import { provideHttpClient } from '@angular/common/http'; // Standalone
Migration Tips
From NgModule to Standalone:
- Add
standalone: trueto@Component - Add
imports: []array - Import needed modules/components
- Remove from NgModule
declarations - Update routing to use
loadComponent
Example:
// Before
@Component({
selector: 'app-user'
})
@NgModule({
declarations: [UserComponent]
})
// After
@Component({
selector: 'app-user',
standalone: true,
imports: [CommonModule]
})
Benefits of Standalone
- Simpler - No NgModules needed
- Faster - Better tree-shaking
- Explicit - Clear dependencies
- Lazy loading - Component-level
- Less boilerplate
- Better DX - Easier to understand
NgModules (Legacy)
Only use NgModules for legacy applications or when maintaining existing code.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
declarations: [AppComponent, UserComponent],
imports: [BrowserModule],
providers: [UserService],
bootstrap: [AppComponent]
})
export class AppModule {}
When to Use Each
Use Standalone (Recommended)
- All new applications (Angular 17+)
- Component libraries
- Better tree-shaking and performance
- Simpler, more explicit dependencies
Use NgModules (Legacy only)
- Maintaining existing NgModule-based apps
- Gradual migration from old codebase
Best Practices
- Always use standalone for new Angular 17+ applications
- Use
bootstrapApplication()for app initialization - Use
provideHttpClient()instead ofHttpClientModule - Import only what you need in each component
- Use
loadComponentfor lazy loading - Keep
importsarray organized and minimal