Skip to the solution
MediumFrontend9 min read

How do you bootstrap a standalone Angular application?

405 views

The problem

Question presented to candidate: "You run ng new on a current Angular version. Walk me through how the app starts: which files are involved, what goes where, and how you would add HTTP, a config file loaded at startup and an existing NgModule library."

What a strong answer should cover:

  • main.ts calls bootstrapApplication(App, appConfig) from @angular/platform-browser; there is no root NgModule.
  • app.config.ts exports an ApplicationConfig whose providers hold app-wide setup: provideRouter(routes), provideHttpClient(...), provideBrowserGlobalErrorListeners().
  • The root component must be standalone and its selector must match a tag in index.html.
  • Startup work goes in provideAppInitializer(() => ...) (the APP_INITIALIZER token is deprecated); bootstrap waits for a returned Promise.
  • NgModule-based libraries plug in with importProvidersFrom(SomeModule).
  • Typical failures: selector not in the page (NG05104), non-standalone root (NG0907), a rejected initializer (bootstrap rejects, nothing renders).

Clarifying questions expected:

  • "Browser only, or does the app also render on the server?"
  • "Is this a new project, or an existing NgModule app we are converting?"

Code / implementation expected: Yes β€” an appConfig with router, a value provider and an async app initializer, and the root component reading what the initializer loaded.

  • bootstrap
  • standalone

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

9 min read Β· 9 sections

Read the code

AngularappConfig with the router, a token, and an async app initializer that runs before the first render
// In a real project this is three files: main.ts, app.config.ts and app.ts.
// main.ts would be:  bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
import {
  ApplicationConfig, Component, InjectionToken, inject, provideAppInitializer,
  provideBrowserGlobalErrorListeners, signal,
} from "@angular/core";
import { provideRouter } from "@angular/router";

// app.config.ts: everything an NgModule used to provide now goes here.
export const FEATURE_FLAGS = new InjectionToken<{ beta: boolean }>("FEATURE_FLAGS", {
  factory: () => ({ beta: false }),
});

export class RuntimeConfig {
  apiUrl = "(not loaded)";
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideBrowserGlobalErrorListeners(),
    provideRouter([]),
    RuntimeConfig,
    { provide: FEATURE_FLAGS, useValue: { beta: true } },
    // Runs before the root component is created; bootstrap waits for the promise.
    provideAppInitializer(async () => {
      const config = inject(RuntimeConfig);
      await new Promise((r) => setTimeout(r, 20)); // stands in for fetch("/config.json")
      config.apiUrl = "https://api.example.com";
    }),
  ],
};

// app.ts: the root component. Its selector must match a tag in index.html.
@Component({
  selector: "app-root",
  template: `<p>API: {{ api }}</p> <p>beta: {{ flags.beta }}</p> <p>clicks: {{ clicks() }}</p>
    <button (click)="clicks.set(clicks() + 1)">+1</button>`,
})
export class AppComponent {
  api = inject(RuntimeConfig).apiUrl; // already set: initializers finished first
  flags = inject(FEATURE_FLAGS);
  clicks = signal(0);
}

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 63 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

What is provideHttpClient(withInterceptors([...])) and how does it replace legacy HTTP interceptor providing?

Continue