Skip to content

Standalone Components ๐Ÿ—๏ธ

Standalone components are Angularโ€™s default and recommended approach for building modern applications! Since Angular 19, standalone is the default for all components, directives, and pipes โ€” you no longer need to set standalone: true explicitly. Think of them as independent LEGO blocks that donโ€™t need a big box (NgModule) to organize them.

Standalone components are Angular components that work independently without NgModules. They manage their own dependencies and can be imported directly where needed. Since Angular 19, all components are standalone by default โ€” no flag needed.

Why Standalone is Now the Standard:

  • ๐ŸŽฏ Default by Design - All new components are standalone automatically (since Angular 19)
  • ๐Ÿšซ No NgModules - Skip the module boilerplate entirely
  • ๐Ÿ“ฆ Direct Imports - Import exactly what you need, where you need it
  • ๐ŸŒณ Better Tree Shaking - Smaller bundles with unused code elimination
  • โšก Simpler Architecture - Less complexity, easier to understand
  • ๐Ÿ”„ Easy Migration - Can coexist with existing NgModule components
  • ๐Ÿš€ Angularโ€™s Direction - The standard for all Angular development
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-user-profile',
imports: [CommonModule, FormsModule], // Direct imports
template: `
<div class="profile">
<h1>{{ user.name }}</h1>
<input [(ngModel)]="user.email" placeholder="Email">
<button (click)="save()">Save</button>
</div>
`
})
export class UserProfileComponent {
user = { name: 'John Doe', email: 'john@example.com' };
save() {
console.log('Saving user:', this.user);
}
}
// Just import the component directly - no modules needed!
import { UserProfileComponent } from './user-profile.component';
@Component({
imports: [UserProfileComponent], // Direct import
template: `<app-user-profile></app-user-profile>`
})
export class AppComponent { }

New Angular projects generate standalone components by default โ€” no flags needed!

Terminal window
# Create a new Angular project (standalone by default)
ng new my-app
# Generate a new component (standalone by default since Angular 19)
ng generate component user-profile
# Creates: user-profile.component.ts โ€” standalone automatically

Generated component structure:

// Generated component โ€” standalone by default, no flag needed
@Component({
selector: 'app-user-profile',
imports: [CommonModule],
templateUrl: './user-profile.component.html',
styleUrl: './user-profile.component.css'
})
export class UserProfileComponent { }
@Component({
selector: 'app-counter',
template: `
<div>
<p>Count: {{ count }}</p>
<button (click)="increment()">+</button>
<button (click)="decrement()">-</button>
</div>
`
})
export class CounterComponent {
count = 0;
increment() { this.count++; }
decrement() { this.count--; }
}
@Injectable({ providedIn: 'root' })
export class UserService {
getUsers() {
return ['Alice', 'Bob', 'Charlie'];
}
}
@Component({
selector: 'app-user-list',
imports: [CommonModule],
template: `
<ul>
@for (user of users; track user) {
<li>{{ user }}</li>
}
</ul>
`
})
export class UserListComponent {
users = inject(UserService).getUsers();
}
@Component({
selector: 'app-user-card',
template: `
<div class="card">
<h3>{{ user.name }}</h3>
<p>{{ user.email }}</p>
</div>
`,
inputs: ['user']
})
export class UserCardComponent {
user!: { name: string; email: string };
}
@Component({
selector: 'app-dashboard',
imports: [CommonModule, UserCardComponent], // Import child component
template: `
<div class="dashboard">
<h2>User Dashboard</h2>
@for (user of users; track user.id) {
<app-user-card [user]="user"></app-user-card>
}
</div>
`
})
export class DashboardComponent {
users = [
{ id: 1, name: 'Alice', email: 'alice@example.com' },
{ id: 2, name: 'Bob', email: 'bob@example.com' }
];
}
routes.ts
export const routes: Routes = [
{
path: 'users',
loadComponent: () => import('./user-list.component').then(c => c.UserListComponent)
},
{
path: 'profile',
loadComponent: () => import('./user-profile.component').then(c => c.UserProfileComponent)
}
];
// main.ts
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes), // โœ… No RouterModule needed
provideHttpClient() // โœ… No HttpClientModule needed
]
});
// โœ… Good - Import specific modules
@Component({
imports: [CommonModule, FormsModule, RouterModule],
// ...
})
// โŒ Avoid - Don't create unnecessary modules
@NgModule({
imports: [CommonModule, FormsModule],
exports: [CommonModule, FormsModule]
})
export class SharedModule { } // Not needed with standalone!
// โœ… Good - Provide services directly
@Component({
providers: [UserService], // Component-level service
// ...
})
// โœ… Better - Use providedIn: 'root' for global services
@Injectable({ providedIn: 'root' })
export class UserService { }
// โœ… Good - Group imports logically
@Component({
imports: [
// Angular modules
CommonModule,
FormsModule,
RouterModule,
// Your components
UserCardComponent,
LoadingSpinnerComponent
],
// ...
})
  • Components are standalone by default โ€” no flag needed (Angular 19+)
  • Import necessary modules in the imports array
  • Import the component directly where needed
  • Use loadComponent for lazy loading
  • Provide services using providedIn: 'root' or component providers
  • For legacy NgModule projects, consider migrating with ng generate @angular/core:standalone
  1. Angular Signals - Modern reactivity with standalone components
  2. Computed Signals - Derived state in standalone apps
  3. Control Flow - New template syntax with standalone components

Remember: Standalone components are Angularโ€™s default architecture since Angular 19! All new components are standalone automatically โ€” no flag needed. If youโ€™re working with legacy NgModule projects, consider migrating with ng generate @angular/core:standalone to enjoy simpler, more modular code! ๐ŸŒŸ