Skip to content
All essays
WebMarch 27, 202511 min

Angular Standalone Components

Master Angular standalone components. Learn to build modular applications without NgModule.

Ü
Ümit Uz
Mobile & Full Stack Developer

Standalone components eliminate the need for NgModules, making Angular applications simpler and more modular.

Creating Standalone Components

typescript
import { Component } from '@angular/core';

@Component({
  selector: 'app-header',
  template: `
    <header>
      <h1>{{ title }}</h1>
      <nav>
        <a routerLink="/">Home</a>
        <a routerLink="/about">About</a>
      </nav>
    </header>
  `,
  standalone: true
})
export class HeaderComponent {
  title = 'My App';
}

Importing Dependencies

typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-user-list',
  template: `
    <div *ngFor="let user of users">
      {{ user.name }}
    </div>
  `,
  standalone: true,
  imports: [
    CommonModule,
    RouterModule,
    FormsModule
  ]
})
export class UserListComponent {
  users = [...];
}

Standalone Services

typescript
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private http: HttpClient) {}

  getUsers() {
    return this.http.get<User[]>('/api/users');
  }
}

Bootstrapping Standalone Apps

typescript
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { provideRouter } from '@angular/router';
import { routes } from './app/app.routes';

bootstrapApplication(AppComponent, {
  providers: [
    provideRouter(routes),
    provideHttpClient()
  ]
});

Lazy Loading Standalone Components

typescript
export const routes: Routes = [
  {
    path: 'home',
    loadComponent: () =>
      import('./home/home.component')
        .then(m => m.HomeComponent)
  },
  {
    path: 'admin',
    loadComponent: () =>
      import('./admin/admin.component')
        .then(m => m.AdminComponent)
  }
];

Feature Modules with Routes

typescript
// app/admin/admin.routes.ts
import { Routes } from '@angular/router';

export const ADMIN_ROUTES: Routes = [
  {
    path: '',
    component: AdminComponent,
    children: [
      {
        path: 'users',
        loadComponent: () =>
          import('./users/users.component')
            .then(m => m.UsersComponent)
      },
      {
        path: 'settings',
        loadComponent: () =>
          import('./settings/settings.component')
            .then(m => m.SettingsComponent)
      }
    ]
  }
];
typescript
import { ADMIN_ROUTES } from './admin/admin.routes';

export const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () =>
      import('./admin/admin.routes')
        .then(m => m.ADMIN_ROUTES)
  }
];

Dependency Injection

typescript
@Component({
  selector: 'app-users',
  template: `...`,
  standalone: true,
  imports: [CommonModule],
  providers: [UserService] // Component-level providers
})
export class UsersComponent {
  constructor(private userService: UserService) {}
}

Pipes and Directives

typescript
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'truncate',
  standalone: true
})
export class TruncatePipe implements PipeTransform {
  transform(value: string, limit: number): string {
    return value.length > limit
      ? value.substring(0, limit) + '...'
      : value;
  }
}

Interceptors

typescript
import {
  HTTP_INTERCEPTORS,
  provideHttpClient,
  withInterceptorsFromDi
} from '@angular/common/http';

bootstrapApplication(AppComponent, {
  providers: [
    provideHttpClient(withInterceptorsFromDi()),
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ]
});

Testing Standalone Components

typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';

describe('UserListComponent', () => {
  let component: UserListComponent;
  let fixture: ComponentFixture<UserListComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [UserListComponent],
      providers: [UserService]
    }).compileComponents();

    fixture = TestBed.createComponent(UserListComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

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

Migration Strategy

Gradually migrate to standalone:

  1. 1Start new features as standalone
  2. 2Convert leaf components first
  3. 3Move up the component tree
  4. 4Remove NgModules last

Standalone components simplify Angular development while maintaining all the framework's powerful features.

Enjoyed this essay? Share it.

Related essays

Next essay
Angular Testing Guide