100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
TypeScript

Standalone Components and Bootstrapping

Understand how standalone components eliminate the need for NgModules, and how modern Angular applications bootstrap directly from a root component and providers array.

Testing & DeploymentIntermediate9 min readJul 9, 2026
Analogies

Standalone Components and Bootstrapping

Since Angular 14 introduced them and Angular 17+ made them the default, standalone components let a component declare its own dependencies—other components, directives, and pipes—directly in an imports array on the @Component decorator, without needing to belong to an NgModule. This removes an entire layer of ceremony that historically confused newcomers: no more deciding which NgModule a component belongs to, no more declarations arrays, and no more forgetting to export a component so another module can use it. A standalone component is self-contained and can be imported wherever it's needed, much like importing a component in React or Vue.

🏏

Cricket analogy: It's like a franchise player who brings their own kit and support staff to any tournament they join, rather than needing to be permanently registered with one specific league body, just as a standalone component declares its own imports without belonging to an NgModule.

Bootstrapping Without a Root Module

Traditional Angular applications bootstrapped via platformBrowserDynamic().bootstrapModule(AppModule), where AppModule declared the root component and imported feature modules. Standalone applications instead call bootstrapApplication(AppComponent, appConfig) from @angular/platform-browser, passing the root standalone component directly along with an ApplicationConfig object that supplies application-wide providers—router configuration, HTTP client setup, and any global services.

🏏

Cricket analogy: The old bootstrapModule approach is like a board selecting the whole squad through one central selection committee meeting, while bootstrapApplication(AppComponent, appConfig) is like directly naming the captain and handing them a settings sheet covering fielding rules and umpiring setup.

typescript
// main.ts
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));

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { routes } from './app.routes';
import { authInterceptor } from './auth.interceptor';

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

// app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet],
  template: `<router-outlet />`,
})
export class AppComponent {}

The provideX() Pattern

Standalone bootstrapping favors function-based provider configuration—provideRouter(), provideHttpClient(), provideAnimations(), provideStore() in NgRx—over NgModule imports. Each provideX() function returns an array of providers configured for a specific concern, composable via the providers array in ApplicationConfig. This tree-shakable, functional style means unused features (like HTTP interceptors you never opt into) don't bloat the bundle, and it mirrors patterns familiar from other modern frameworks' composable setup functions.

🏏

Cricket analogy: provideRouter() and provideHttpClient() are like a franchise separately hiring a fielding coach and a data analyst as needed, rather than being forced to take a whole bundled support-staff package, keeping the payroll (bundle size) lean by only paying for roles actually used.

Since Angular 19, standalone: true is the implicit default for components generated by the CLI—you no longer need to write it explicitly. NgModules still exist and remain fully supported for legacy codebases, but new Angular projects and the official style guide now steer entirely toward standalone components as the default mental model.

A standalone component must explicitly import everything it uses in its template—including CommonModule directives like NgIf/NgFor if you're not using the newer @if/@for control-flow syntax. Forgetting to add a used component or directive to the imports array produces a template error at compile time (or a silently unrendered element in some cases), unlike NgModule-declared components which inherited the whole module's declarations implicitly.

  • Standalone components declare their own dependencies via an imports array on @Component, removing the need for NgModules.
  • bootstrapApplication(AppComponent, appConfig) replaces bootstrapModule(AppModule) as the entry point for standalone apps.
  • ApplicationConfig's providers array configures app-wide services using composable provideX() functions like provideRouter() and provideHttpClient().
  • Since Angular 19, standalone: true is the implicit default and no longer needs to be written explicitly.
  • Each standalone component must explicitly import everything its template references — there is no implicit inheritance from a shared module.
  • NgModules remain supported for legacy code but are no longer the recommended default architecture.

Practice what you learned

Was this page helpful?

Topics covered

#TypeScript#AngularStudyNotes#WebDevelopment#StandaloneComponentsAndBootstrapping#Standalone#Components#Bootstrapping#Without#StudyNotes#SkillVeris