Skip to content

Standalone Components

If you have read older Angular tutorials, you have seen NgModule — a class decorated with @NgModule that declares which components, directives, and pipes are available together. Every component had to be declared in a module. Modules declared which other modules they imported. The whole system was powerful but verbose.

Angular 14 introduced standalone components, and Angular 17 made them the default. This course uses standalone components exclusively. There are no NgModules anywhere in CinemaVault.

A standalone component declares its own dependencies directly in the @Component decorator using the imports array. Instead of relying on a module to make other components and directives available, the component lists exactly what it needs:

import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterLink } from '@angular/router';
import { Movie } from '../../models/movie.model';
@Component({
selector: 'app-movie-card',
standalone: true, // ← this is the key option
imports: [CommonModule, RouterLink], // ← declare dependencies here
templateUrl: './movie-card.html',
styleUrl: './movie-card.css'
})
export class MovieCard {
@Input({ required: true }) movie!: Movie;
}

The imports array lists anything the template uses that is not a standard HTML element: other components, Angular directives like NgIf/NgFor (or the newer @if/@for control flow), pipes, and router directives.

Clarity: Each component explicitly declares what it depends on. Reading the imports array tells you exactly what the template can use.

Simplicity: There are no NgModule files to maintain. No declarations arrays. No forRoot() / forChild() patterns. Components are self-contained.

Lazy loading: Standalone components are easier to lazy-load at the route level because they do not need to be bundled with a module.

Tree-shaking: Bundlers can more easily remove unused code when dependencies are explicit at the component level.

When you run ng generate component, the generated component has standalone: true automatically. You do not need to add it. The CLI also no longer creates NgModule files by default.

If you work on an older codebase, you may still encounter NgModules. The concepts are the same — components, templates, inputs, outputs — but the wiring is different.

bootstrapApplication (in main.ts) is the standalone equivalent of bootstrapping via an AppModule. It accepts the root component and a configuration object:

main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { App } from './app/app';
bootstrapApplication(App, appConfig);

Providers that used to go in AppModule.imports now go in appConfig.providers:

app.config.ts
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()
]
};
  1. Run ng generate component components/movie-badge in your practice project.
  2. Confirm the generated file has standalone: true in the @Component decorator.
  3. In MovieBadge, add an @Input() label = 'New' property and display it in the template.
  4. Use MovieBadge inside MovieCard by adding it to MovieCard’s imports array and using <app-movie-badge /> in the template.
  5. Confirm the app builds without errors.
  • Angular 17+ uses standalone components by default — no NgModules needed.
  • standalone: true in @Component declares the component as self-contained.
  • The imports array in @Component lists other components, directives, and pipes the template uses.
  • bootstrapApplication in main.ts starts a standalone Angular app.
  • Providers like the router and HttpClient go in appConfig.providers in app.config.ts.