Skip to content
← Field notes
Angular Standalone TypeScript

Angular Standalone Components: The Complete Guide

Everything you need to know about standalone components in Angular — from migration to best practices and lazy-loading strategies.


title: 'Angular Standalone Components: The Complete Guide' slug: standalone-components-guide summary: Everything you need to know about standalone components in Angular — from migration to best practices and lazy loading strategies. date: 2024-05-01 author: Alex Rivera category: typescript tags: [standalone, angular, typescript] status: published featured: false#

Angular Standalone Components: The Complete Guide#

Standalone components are the default in Angular 18. They eliminate the need for NgModules, reduce boilerplate, and make dependency management explicit at the component level. Whether you are starting a greenfield project or migrating an existing codebase, understanding standalone components is essential.

What Are Standalone Components?#

A standalone component declares its own dependencies directly in its @Component decorator rather than relying on a module to provide them.

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterLink } from '@angular/router';
import { ArticleCardComponent } from '../shared/article-card/article-card.component';

@Component({
  selector: 'app-article-list',
  standalone: true,
  imports: [CommonModule, RouterLink, ArticleCardComponent],
  template: `
    <ul>
      @for (article of articles(); track article.slug) {
        <li>
          <a [routerLink]="['/articles', article.slug]">{{ article.title }}</a>
        </li>
      }
    </ul>
  `,
})
export class ArticleListComponent {
  articles = signal<Article[]>([]);
}

The imports array is the key concept. It tells Angular exactly which directives, pipes, and components this template needs. There is no guessing about which module exports what.

Bootstrapping Without NgModules#

Angular 18 applications bootstrapped with bootstrapApplication do not use AppModule at all.

import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err));

Application-wide providers live in app.config.ts using ApplicationConfig:

import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient } from '@angular/common/http';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [provideRouter(routes), provideHttpClient()],
};

Lazy Loading Standalone Components#

Lazy loading works without route-level NgModules. Use loadComponent for individual components or loadChildren for route arrays.

import { Routes } from '@angular/router';

export const routes: Routes = [
  {
    path: 'articles',
    loadChildren: () => import('./features/articles/articles.routes').then(m => m.ARTICLES_ROUTES),
  },
  {
    path: 'about',
    loadComponent: () => import('./features/about/about.component').then(m => m.AboutComponent),
  },
];

The articles.routes.ts file is just an array of routes, not a module:

import { Routes } from '@angular/router';
import { ArticleListComponent } from './article-list/article-list.component';
import { ArticleDetailComponent } from './article-detail/article-detail.component';

export const ARTICLES_ROUTES: Routes = [
  { path: '', component: ArticleListComponent },
  { path: ':slug', component: ArticleDetailComponent },
];

Migrating from NgModules#

If you have an existing Angular application using NgModules, you can migrate incrementally. The Angular CLI provides a schematic to convert modules to standalone:

ng generate @angular/core:standalone

Follow the prompts to migrate components, directives, and pipes. The schematic updates imports, removes module declarations, and adjusts bootstrapping automatically.

For manual migration, follow this checklist for each component:

  1. Add standalone: true to the @Component decorator.
  2. Add an imports array with every directive, pipe, and component used in the template.
  3. Remove the component from its NgModule's declarations array.
  4. If the module is now empty, delete it.

Best Practices#

Keep imports minimal. Only import what the template actually uses. Excess imports bloat the bundle and create unnecessary coupling.

Use barrel exports for shared components. A shared/components/index.ts barrel simplifies importing multiple shared components:

import { ArticleCardComponent, TagListComponent } from '../shared/components';

Prefer loadComponent for single routes. It generates smaller chunks than loadChildren and keeps route configuration flat.

Do not mix standalone and module-based bootstrapping. While Angular supports both patterns in the same application, mixing them at the bootstrap level causes confusion. Choose one and migrate fully.

Standalone Directives and Pipes#

Directives and pipes can also be standalone:

@Directive({
  selector: '[appHighlight]',
  standalone: true,
})
export class HighlightDirective {
  // ...
}

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

Import them directly into component imports arrays just like standalone components.

Standalone components represent a fundamental simplification of Angular architecture. Less boilerplate, clearer dependencies, and easier lazy loading make them the right default for every new Angular project.

Next field note

Dockerizing Angular Apps with Nginx