Skip to content
Angular interview 4 min read

Performance & Advanced Questions

Senior Angular interviews move past syntax and into systems thinking: how do you keep a large app fast, how does server-side rendering and hydration actually work, and how do you split a monolith into independently deployable pieces? These questions reward candidates who understand why Angular behaves the way it does and can reason about trade-offs under real-world constraints. The answers below use modern Angular 17–19 idioms — standalone components, signals, deferrable views, and the new SSR pipeline.

How do you optimize change detection in a large app?

The single biggest lever is OnPush change detection combined with immutable inputs and signals. Under OnPush, a component is only checked when one of its @Input references changes, an event fires inside it, an async pipe emits, or a signal it reads changes. This prunes huge swaths of the component tree from every check.

Signals make this even cleaner because reading a signal in a template registers a fine-grained dependency — when the signal changes, Angular marks only the components that consumed it.

import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';

@Component({
  selector: 'app-cart',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <p>Items: {{ count() }}</p>
    <p>Total: {{ total() | currency }}</p>
    <button (click)="add()">Add</button>
  `,
})
export class CartComponent {
  private items = signal<number[]>([]);
  count = computed(() => this.items().length);
  total = computed(() => this.items().reduce((a, b) => a + b, 0));

  add() {
    this.items.update((list) => [...list, 9.99]);
  }
}

Other high-impact techniques: always use track in @for to avoid re-rendering unchanged rows, run hot non-UI work in runOutsideAngular to skip change detection entirely, and use trackBy-style stable identities for lists.

Zoneless change detection (provideExperimentalZonelessChangeDetection()) removes Zone.js entirely and relies on signals and explicit notifications. It is the direction Angular is heading and a strong talking point.

What is hydration and why does it matter?

Server-side rendering (SSR) sends fully rendered HTML so the user sees content fast and search engines index it. Without hydration, Angular would throw that server HTML away and re-render from scratch on the client, causing a visible flicker and wasted work. Non-destructive hydration (provideClientHydration()) instead reuses the existing DOM, attaching event listeners and state on top of it.

import { bootstrapApplication } from '@angular/platform-browser';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, {
  providers: [provideClientHydration(withEventReplay())],
});

withEventReplay() captures clicks that happen before JavaScript loads and replays them once the app is interactive, so early taps are not lost. Angular 19 also adds incremental hydration, letting you hydrate @defer blocks on demand rather than all at once.

How do deferrable views improve performance?

@defer lazily loads a block of template — and its dependencies — only when a trigger fires. This shrinks the initial bundle and time-to-interactive without manual lazy-loading boilerplate.

@defer (on viewport) {
  <app-heavy-chart [data]="metrics()" />
} @placeholder {
  <div class="skeleton">Loading chart…</div>
} @loading (minimum 200ms) {
  <app-spinner />
} @error {
  <p>Failed to load chart.</p>
}

Triggers include on idle, on viewport, on interaction, on hover, on timer(2s), and when condition(). Use prefetch to fetch the bundle early while still deferring rendering.

TriggerFires when
on idleBrowser is idle (default)
on viewportBlock scrolls into view
on interactionUser clicks/keys the placeholder
on hoverPointer hovers the placeholder
when exprSignal/expression becomes truthy

What are micro frontends and how does Angular support them?

Micro frontends split a large app into independently developed and deployed pieces, each owned by a different team. The dominant approach in Angular is Module Federation (via @angular-architects/module-federation on top of webpack, or native federation for esbuild). A shell app loads remote apps at runtime.

// Shell route that loads a remote at runtime
import { loadRemoteModule } from '@angular-architects/native-federation';

export const routes = [
  {
    path: 'checkout',
    loadComponent: () =>
      loadRemoteModule('checkout', './Checkout').then((m) => m.CheckoutComponent),
  },
];

The trade-off is real: federation buys independent deploys and team autonomy but adds version-skew risk, shared-dependency negotiation, and operational complexity. Mention that for many apps, a well-structured Nx monorepo with library boundaries delivers most of the modularity benefits without the runtime cost.

How do you architect a large Angular application?

Discuss boundaries and ownership. A common pattern is feature-based folders with a clear separation between smart (container) and presentational components, a shared UI library, and a core layer for app-wide singletons. Lazy-load each feature route so the bundle scales with what the user actually visits.

export const routes = [
  { path: 'orders', loadChildren: () => import('./orders/routes') },
  { path: 'admin', loadChildren: () => import('./admin/routes') },
];

Enforce dependency direction with Nx tags or ESLint boundary rules so feature code cannot import another feature directly, only shared libraries. Use inject() with providedIn: 'root' services for tree-shakable singletons, and prefer signals for component state to keep change detection predictable.

Best practices

  • Default to OnPush (or zoneless) and drive UI with signals so Angular checks only what changed.
  • Always provide track in @for and stable keys to prevent needless DOM churn.
  • Enable SSR with provideClientHydration(withEventReplay()) for fast first paint and resilient early interactions.
  • Reach for @defer to lazy-load heavy, below-the-fold, or interaction-gated UI.
  • Treat micro frontends as a team-scaling tool, not a default — prefer a monorepo with enforced boundaries until autonomy demands more.
  • Lazy-load routes and run expensive non-UI work outside Angular to keep change detection cheap.
Last updated June 14, 2026
Was this helpful?