How was Angular bootstrapped before Standalone APIs?
1. What is Angular Bootstrapping?
Bootstrapping is the process Angular uses to start the application.
When an Angular application loads, Angular needs to know:
- Which module is the root module
- Which component is the root component
- Which providers/services are available
- Where the root component should be rendered in
index.html
Before standalone APIs became the preferred approach, Angular applications were normally bootstrapped using an NgModule, usually AppModule.
The basic flow was:
index.html
↓
main.ts
↓
AppModule
↓
AppComponent
↓
Application starts
2. Traditional NgModule-Based Bootstrapping
A typical older Angular application contained:
src/
│
├── main.ts
├── index.html
│
└── app/
├── app.module.ts
├── app.component.ts
└── app.component.html
The important difference is:
Before standalone Angular,
main.tsbootstrappedAppModule, andAppModulebootstrappedAppComponent.
3. Full Simple Sample Program
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Angular App</title>
<base href="/">
</head>
<body>
<app-root></app-root>
</body>
</html>
The browser initially sees:
<app-root></app-root>
Angular later creates the root component and renders it here.
app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent {
title = 'My Angular Application';
}
Notice that older Angular components did not normally use:
standalone: true
Instead, the component belonged to an NgModule.
app.component.html
<h1>{{ title }}</h1>
<p>Angular application started successfully.</p>
4. app.module.ts
This was the central file in traditional Angular applications.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [
AppComponent
]
})
export class AppModule { }
The @NgModule() metadata tells Angular how the application is organized.
declarations
declarations: [
AppComponent
]
Components, directives and pipes belonging to the module were declared here.
For example:
declarations: [
AppComponent,
HomeComponent,
ProductComponent
]
imports
imports: [
BrowserModule
]
Other Angular modules required by the application were imported here.
For example:
imports: [
BrowserModule,
FormsModule,
HttpClientModule,
AppRoutingModule
]
providers
Services or other dependency-injection providers could be registered here.
providers: [
ProductService
]
Although services commonly used:
@Injectable({
providedIn: 'root'
})
bootstrap
This was especially important:
bootstrap: [
AppComponent
]
It tells Angular:
AppComponent is the root component that should be created when this module starts.
5. main.ts
The application was started from main.ts.
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
This is the key traditional bootstrapping code:
platformBrowserDynamic()
.bootstrapModule(AppModule);
Angular bootstraps the module, not the component directly.
6. Complete Bootstrapping Flow
Suppose the browser loads:
<app-root></app-root>
The startup process is approximately:
Browser loads index.html
↓
main.ts executes
↓
platformBrowserDynamic()
↓
bootstrapModule(AppModule)
↓
Angular reads @NgModule
↓
AppModule bootstrap: [AppComponent]
↓
Angular creates AppComponent
↓
Angular finds selector:
app-root
↓
Finds <app-root> in index.html
↓
Renders AppComponent
↓
Application starts
So there are effectively two bootstrapping steps:
main.ts
↓
AppModule
↓
AppComponent
7. What does platformBrowserDynamic() mean?
Consider:
platformBrowserDynamic()
.bootstrapModule(AppModule);
platformBrowserDynamic()
It creates an Angular browser platform capable of running the Angular application.
bootstrapModule(AppModule)
It tells Angular:
Start the application using
AppModuleas the root NgModule.
Angular then examines:
@NgModule({
bootstrap: [AppComponent]
})
and determines that:
AppComponent
is the root component.
8. Before Standalone vs Standalone Angular
This is the most important comparison.
Before Standalone
main.ts
platformBrowserDynamic()
.bootstrapModule(AppModule);
app.module.ts
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
bootstrap: [
AppComponent
]
})
export class AppModule { }
Flow:
main.ts
↓
AppModule
↓
AppComponent
9. Modern Standalone Bootstrapping
Standalone Angular removes the requirement for a root AppModule.
A modern application commonly uses:
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
bootstrapApplication(App)
.catch(err => console.error(err));
Now the flow becomes:
main.ts
↓
bootstrapApplication(App)
↓
App
There is no mandatory:
AppModule
in between.
10. Modern Example with app.config.ts
A modern Angular application may have:
src/
│
├── main.ts
│
└── app/
├── app.ts
├── app.html
├── app.config.ts
└── app.routes.ts
main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { App } from './app/app';
import { appConfig } from './app/app.config';
bootstrapApplication(App, appConfig)
.catch(err => console.error(err));
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()
]
};
app.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>Welcome to Angular</h1>
`
})
export class App {
}
Now Angular directly bootstraps:
bootstrapApplication(App, appConfig);
11. Side-by-Side Comparison
| Traditional NgModule | Standalone |
|---|---|
AppModule required |
Root AppModule not required |
bootstrapModule() |
bootstrapApplication() |
platformBrowserDynamic() |
bootstrapApplication() |
Components declared in declarations |
Components can be standalone |
Modules imported into imports |
Dependencies imported by standalone components or configured with providers |
Root component specified by AppModule |
Root component passed directly |
AppModule → AppComponent |
Directly bootstrap root component |
The key code difference is:
Old
platformBrowserDynamic()
.bootstrapModule(AppModule);
Modern
bootstrapApplication(App, appConfig);
12. What Happened to AppModule?
Before standalone APIs:
main.ts
↓
AppModule
↓
AppComponent
With standalone APIs:
main.ts
↓
App
Configuration that traditionally lived in AppModule can now be expressed using standalone components and provider APIs such as:
provideRouter(routes)
provideHttpClient()
and application-level configuration:
ApplicationConfig
13. Easy Way to Remember
Think of the old architecture as:
main.ts
↓
Start Module
↓
Module starts Component
bootstrapModule(AppModule)
Modern standalone Angular:
main.ts
↓
Start Component
bootstrapApplication(App)
That is the fundamental change.
Key Points
- Traditional Angular applications were organized primarily around NgModules.
AppModulewas normally the application's root module.main.tsbootstrappedAppModule.AppModuleidentified the root component through:
bootstrap: [AppComponent]
- The traditional startup API was:
platformBrowserDynamic()
.bootstrapModule(AppModule);
- Components were normally registered under:
declarations: []
- Standalone Angular removes the requirement for a root NgModule.
- Modern applications can directly bootstrap a standalone root component:
bootstrapApplication(App, appConfig);
Interview memory line
Before standalone APIs, Angular typically bootstrapped the root
AppModuleusingplatformBrowserDynamic().bootstrapModule(AppModule). TheAppModulethen identified the root component through itsbootstraparray. With standalone APIs, Angular can directly bootstrap a standalone root component usingbootstrapApplication().
Interview Questions and Answers
1. How was Angular bootstrapped before standalone APIs?
Before standalone APIs, Angular normally used an NgModule-based bootstrap process. main.ts called:
platformBrowserDynamic()
.bootstrapModule(AppModule);
AppModule then specified the root component using:
bootstrap: [AppComponent]
2. What was the root module normally called?
Usually:
AppModule
defined in:
app.module.ts
3. What was the purpose of bootstrapModule()?
It started Angular using a root NgModule.
bootstrapModule(AppModule)
4. How did Angular know which component to start?
Through the root module's bootstrap array:
@NgModule({
bootstrap: [AppComponent]
})
export class AppModule {}
5. Where was AppComponent registered?
Usually in both the declarations and bootstrap metadata:
@NgModule({
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule {}
6. What is the modern replacement?
Standalone Angular commonly uses:
bootstrapApplication(App, appConfig);
instead of:
platformBrowserDynamic()
.bootstrapModule(AppModule);
7. Is AppModule mandatory in modern Angular?
No. Standalone Angular applications can operate without a root AppModule.
8. What is the main difference in one sentence?
Old Angular bootstrapped a module, which bootstrapped the root component; standalone Angular can bootstrap the root component directly.