Skip to the solution
MediumFrontend10 min read

Standalone bootstrapApplication — how does Angular bootstrap without NgModules in 2025?

740 views

The problem

Question presented to candidate: "With no AppModule, something still has to create the injector, run initializers and render the root component. Explain what bootstrapApplication actually does, in order, and how that differs from the old bootstrapModule path."

What a strong answer should cover:

  • A platform injector is created (or reused) once per page; an environment (application) injector is created from the ApplicationConfig providers, with the platform injector as parent.
  • Angular prepends its own providers: browser essentials and the zoneless change detection setup, so a bare bootstrap uses NoopNgZone.
  • Order: environment initializers run while the injector is set up, then app initializers (awaited), then the root component is created, change detection runs once, then bootstrap listeners fire.
  • ApplicationRef.bootstrap(Root) creates the root ComponentRef in the host element and the bootstrap Promise resolves with the ApplicationRef.
  • Differences from bootstrapModule: no NgModule class or module injector; providers come from a plain array. In v22 both paths are zoneless by default.
  • Version context: standalone APIs previewed in v14 and stable in v15; standalone by default in v19; zoneless by default in v21.

Clarifying questions expected:

  • "Do you want the browser path only, or also how SSR passes a platform in?"
  • "Should I cover change detection after bootstrap, or stop at the first render?"

Code / implementation expected: Optional — an instrumented appConfig that logs each bootstrap phase.

  • standalone
  • bootstrap
  • angular-17

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

10 min read · 10 sections

Read the code

AngularInstrumented appConfig that logs every phase of bootstrapApplication
import {
  APP_BOOTSTRAP_LISTENER, ApplicationConfig, ApplicationRef, Component, ComponentRef, Injectable,
  NgZone, afterNextRender, inject, provideAppInitializer, provideEnvironmentInitializer,
} from "@angular/core";

// Every step of bootstrapApplication() writes here, so the order is visible.
export const steps: string[] = [];
const log = (s: string) => steps.push(`${steps.length + 1}. ${s}`);

@Injectable({ providedIn: "root" })
export class Session {
  constructor() { log("Session service created (first inject)"); }
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideEnvironmentInitializer(() => log("environment initializer (sync, while the injector is set up)")),
    provideAppInitializer(() => {
      log("app initializer starts");
      inject(Session);
      return new Promise<void>((done) => setTimeout(() => { log("app initializer resolves"); done(); }, 20));
    }),
    {
      provide: APP_BOOTSTRAP_LISTENER, multi: true,
      useValue: (ref: ComponentRef<unknown>) => log(`bootstrap listener: root <${ref.location.nativeElement.localName}> attached`),
    },
  ],
};

@Component({ selector: "app-root", template: `<p>{{ zone }}</p>` })
export class AppComponent {
  zone = inject(NgZone).constructor.name; // which zone did a bare bootstrap pick?
  steps = steps;
  constructor() {
    log("root component constructor");
    afterNextRender(() => log("afterNextRender: first render is in the DOM"));
  }
  ngOnInit() { log("root ngOnInit (first change detection)"); }
}

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 37 of 121 in Angular

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Angular questions
Up nextMedium

How do toSignal() and toObservable() bridge Signals and RxJS?

Continue