Angular Interview Knowledge Hub

Study 88 original Angular interview questions across 18 connected topic areas. Rehearse the direct answer, inspect the runtime mechanism, compare alternatives, and practice the production judgment expected at senior and Staff level.

88 questions · 18 topic areas · 39 senior or Staff · 12 layered deep dives · updated

What should I study for an Angular interview?

Start with components, templates, binding, and dependency injection. Then learn routing, forms, and RxJS before going under the hood with Signals, change detection, rendering, and performance. Senior Angular interviews add state ownership, SSR and hydration trade-offs, production debugging, modernization, and architecture across teams—not obscure syntax trivia.

Answer for modern Angular. Recognize the legacy path.

This hub is reviewed against Angular 22.1. Current defaults are labeled explicitly; NgModules, Zone.js, decorator inputs, webpack builders, Jasmine, and Karma remain where interviewers may encounter long-lived applications.

Check the official release policy
  • Standalone-first application structure and lazy route boundaries
  • Signals for synchronous Angular state; RxJS for streams over time
  • Zoneless change detection by default in Angular 21 and newer
  • Incremental hydration in new server-rendered Angular applications
  • Vitest in new Angular CLI projects; Karma remains supported
  • The application builder with esbuild and Vite-powered development

The expected answer changes with the role

Seniority is not more API trivia. The signal moves from correct framework use, through runtime reasoning, to operating and evolving systems across teams.

Fundamentals

Explain components, templates, binding, services, directives, pipes, and lifecycle timing without relying on memorized slogans.

Study this level

Intermediate

Build typed forms, lazy routes, cancellable HTTP flows, reusable component APIs, and deliberate loading and error states.

Study this level

Advanced

Trace Signals, RxJS, dependency injection, OnPush, rendering, hydration, and performance through the runtime.

Study this level

Senior

Diagnose production symptoms with evidence and defend state, security, testing, delivery, and modernization trade-offs.

Study this level

Staff / Principal

Shape boundaries across teams, platforms, design systems, deployments, and migrations while preserving autonomy and reversibility.

Study this level

Angular concepts are a connected runtime

Interviewers rarely stop at one API. Use these paths to anticipate the mechanism and production follow-up that usually comes next.

Start anywhere. Each sequence moves from a visible Angular feature to the underlying ownership, scheduling, or delivery decision.

Async application flow

Model events over time, navigation, HTTP cancellation, validation, and state ownership together.

  1. RxJS
  2. Routing
  3. Forms
  4. State

Learn Angular in dependency order

The sequence moves from authoring views to operating systems. Jump to a known gap, or follow the path so that Signals and change detection build on a clear component and state-ownership model.

  1. Foundation

    Learn the component and composition model before adding application-wide state or runtime optimization.

    1. 1FoundationComponents, templates & bindingExplain bootstrap, binding, communication, directives, pipes, and lifecycle timing precisely.
    2. 2CompositionComponent APIs & dependency injectionDefend component contracts, content projection, provider scope, and service lifetimes.
  2. Application engineering

    Build navigable, validated, asynchronous workflows with explicit ownership.

    1. 3ApplicationRouting, forms & async dataBuild cancellable flows, typed forms, lazy routes, and deliberate loading/error states.
    2. 4ReactivitySignals, RxJS & state ownershipChoose Signals, RxJS, URL, local, server, or shared state from ownership and time semantics.
  3. Runtime understanding

    Trace notification, change detection, rendering, and browser work as one system.

    1. 5RuntimeChange detection & renderingExplain OnPush, zoneless scheduling, render hooks, hydration, and expensive rendering evidence.
  4. Production engineering

    Choose delivery strategies and build performance, testing, and security evidence.

    1. 6DeliveryPerformance, SSR & hydrationInvestigate bundles, lists, waterfalls, CWV, SSR boundaries, and hydration mismatches.
    2. 7QualityTesting & securityChoose resilient tests and explain XSS, sanitization, CSP, CSRF, and route-guard limits.
  5. Engineering judgment

    Design for teams and evolution, then diagnose production symptoms without magic fixes.

    1. 8JudgmentLarge-scale Angular architectureReason about design systems, monorepos, micro-frontends, observability, and organizational cost.
    2. 9EvolutionModernization & production debuggingPlan reversible migrations and move from symptom to hypothesis, mitigation, and verification.

Debug the Angular application

Senior scenarios do not have magic fixes. Protect users, separate symptoms from causes, collect evidence across Angular and the browser, and verify the mitigation under the same conditions.

  1. 01Reproduce
  2. 02Gather evidence
  3. 03Form a hypothesis
  4. 04Mitigate safely
  5. 05Verify the same path
  1. Hundreds of duplicate HTTP requestsNetwork initiators, subscription count, effect creation, retries, component and route lifecycles.Open investigation
  2. Memory rises after every navigationPost-GC heap floor, component instances, detached DOM, listeners, subscriptions, retainer paths.Open investigation
  3. Fresh response, stale UICache version, store transition, reference identity, Signal equality, route reuse, template consumer.Open investigation
  4. An unexpected component rerenderChecks versus DOM mutation, changing inputs, Signals, bound events, AsyncPipe, manual marks.Open investigation
  5. A lazy feature ships in the initial bundleChunk graph, static imports, barrels, providers, styles, queries, and @defer eligibility.Open investigation

Modernization is a delivery problem

Strong answers preserve behavior, sequence risk, use automated migrations, keep the application releasable, and prove each step before expanding scope.

Do not pitch a rewrite because an API is old. Explain dependency order, compatibility constraints, rollout slices, and the rollback path.

  1. 01
    Move from NgModules to standaloneOpen the question
  2. 02
    Introduce Signals without rewriting streamsOpen the question
  3. 03
    Modernize builders and test runnersOpen the question
  4. 04
    Plan a multi-version Angular upgradeOpen the question

Search the Angular question library

Search questions, direct answers, concepts, tags, or API names. Open the concise answer in place; cornerstone topics continue into a layered engineering explanation.

0 studied88 total
Next: What Angular owns

Showing 88 of 88 questions

Angular Fundamentals

Bootstrap, components, templates, binding, services, and the TypeScript/browser model beneath Angular.

Interview focus: Accurate mental models and data flow, not framework vocabulary recitation.

  • FundamentalsConceptModern Angular2 min

    What is Angular, and what does the framework own?

    Describe Angular as a compiled application framework with an integrated runtime and platform, not only a component library.

    frameworkcomponentscompiler
    30-second interview answer

    Angular is a TypeScript-first web application framework. It owns component rendering, template compilation, dependency injection, routing, forms, HTTP integration, build tooling, testing integration, and optional server rendering. That integrated platform reduces ecosystem assembly, but it also means architecture and upgrade choices should follow Angular's boundaries rather than treating it like a view-only library.

    Concise answer
  • IntermediateRenderingModern Angular2 min

    How does a modern Angular application bootstrap in the browser?

    Trace the entry module through provider creation, root component instantiation, template rendering, and event wiring.

    bootstrapApplicationApplicationConfigcompiler
    30-second interview answer

    The entry file calls bootstrapApplication with a standalone root component and application providers. Angular creates the environment injector, initializes providers, instantiates the root component, creates its view, evaluates bindings, and attaches the rendered view to the host element. Ahead-of-time compilation has already turned templates into efficient instructions; the runtime connects those instructions to dependency injection, reactivity, events, and change detection.

    Concise answer
  • FundamentalsConcept2 min

    How do interpolation, property binding, event binding, and two-way binding differ?

    Explain binding as directional data flow between component state, DOM properties, and events.

    interpolationproperty bindingevent binding
    30-second interview answer

    Interpolation renders a string representation into text or an attribute context; property binding assigns an expression result to a DOM, directive, or component property; event binding sends an event back to component code. Two-way binding is syntax that combines an input and a corresponding change output. The important model is direction: state flows down through properties, and user intent flows up through events.

    Concise answer
  • IntermediateArchitecture2 min

    How should Angular components communicate?

    Choose inputs/outputs, shared ownership, URL state, or a service based on relationship and lifetime.

    inputsoutputsservices
    30-second interview answer

    Use inputs for parent-owned data and outputs for child events. Lift state to the nearest common owner when siblings coordinate; use a scoped service when the state or workflow outlives one component tree; use the URL for navigable state. Avoid a global event bus as the default because it hides ownership and makes event order and cleanup difficult to reason about.

    Concise answer
  • FundamentalsConcept2 min

    What does TypeScript contribute to Angular?

    Connect class and API types to template checking, refactoring, DI tokens, and compiled metadata.

    TypeScripttemplate type checkingdecorators
    30-second interview answer

    TypeScript gives Angular statically analyzable classes, generics, access modifiers, decorators, and tooling. Angular's compiler extends that value into templates with binding and expression type checks, but TypeScript types disappear at runtime, so interfaces cannot be DI tokens. Runtime behavior still depends on JavaScript values, Angular metadata, providers, and browser APIs.

    Concise answer

Components & Templates

Signal inputs, outputs, content projection, queries, dynamic views, and reusable component API design.

Interview focus: Ownership, composition, template boundaries, and maintainable public contracts.

  • FundamentalsConcept2 min

    What makes an Angular component a component?

    Explain how metadata, a class instance, a host element, and a compiled template form one view boundary.

    Componentselectortemplate
    30-second interview answer

    A component is a directive with a template. Its metadata defines the selector, template, styles, imports, change-detection strategy, and host behavior; the class owns instance state and methods; Angular creates a host view and connects bindings to that instance. A good component also has a coherent responsibility and a deliberately small public API—not merely a @Component decorator.

    Concise answer
  • IntermediateCodingModern Angular2 min

    How do input(), output(), and model() shape modern component APIs?

    Use signal inputs for reactive reads, outputs for events, and model only for genuine two-way component state.

    inputoutputmodel
    30-second interview answer

    input() declares a readonly Signal that Angular updates from the parent; output() declares a typed event channel; model() declares a writable signal exposed as an input plus a Change output for two-way binding. Prefer explicit input and output flows. Use model when the child is a true editor of a parent-owned value, not to hide ordinary state changes behind two-way syntax.

    Concise answer
  • IntermediateArchitecture2 min

    How does content projection with ng-content work?

    Separate consumer-owned content from component-owned layout and understand projection-slot selection.

    ng-contentprojection slotscomponent composition
    30-second interview answer

    Content projection lets a component place markup supplied by its consumer into predefined ng-content slots. Angular determines the slot from selectors when it creates the view; the projected nodes remain conceptually owned by the declaring view even though they render inside the child. Use projection for layout and composition, but keep slot contracts small and avoid selectors that couple consumers to internal markup.

    Concise answer
  • IntermediateRendering2 min

    What is the difference between ViewChild and ContentChild?

    Distinguish a component's own view from content projected by its consumer and respect query timing.

    ViewChildContentChildqueries
    30-second interview answer

    A view query reads elements, directives, or components created by the component's own template; a content query reads projected content supplied between the component's tags. Their results become available at different lifecycle boundaries because Angular initializes content before the component's view. Query only what the component must coordinate—exposing data through an input or output is often less coupled.

    Concise answer
  • SeniorArchitecture2 min

    When should you create components or embedded views dynamically?

    Choose dynamic views for runtime composition boundaries while preserving injection, lifecycle, and cleanup ownership.

    ViewContainerRefTemplateRefcreateComponent
    30-second interview answer

    Use TemplateRef plus ViewContainerRef when a reusable template fragment should produce embedded views, and createComponent when the runtime must instantiate a real component type. Suitable cases include overlays, configurable dashboards, plugin surfaces, and schema-driven UI. The owner must also control injector scope, inputs, event subscriptions, placement, destruction, focus, and accessibility; dynamic creation is not a shortcut around normal composition.

    Concise answer

Signals & Angular Reactivity

Writable and derived state, dependency tracking, effects, linked state, resources, and RxJS interop.

Interview focus: Derive state cleanly and choose reactivity from semantics rather than fashion.

  • AdvancedConceptModern Angular8 min

    How do Angular Signals work?

    Explain synchronous reads, tracked dependencies, invalidation, lazy derivation, and template notification.

    signalcomputeddependency tracking
    30-second interview answer

    A Signal is a synchronous getter backed by a reactive producer. While a computed value or template executes, Angular records which Signals were read; when one changes, Angular invalidates dependent computed values and marks affected views for a future render. Dependencies are dynamic and follow the branch actually read. Signals notify consumers—they do not deep-observe arbitrary object mutation.

  • AdvancedArchitectureModern Angular2 min

    Why should computed() usually be preferred over effect() for derived state?

    Keep derivation declarative and reserve effects for synchronization with non-reactive systems.

    computedeffectderived state
    30-second interview answer

    computed expresses a value as a pure function of other Signals, caches it, and preserves one source of truth. An effect runs side-effecting code when dependencies change, so using it to copy one Signal into another creates scheduling, feedback-loop, and synchronization risks. Use effects at imperative boundaries such as logging, storage, a canvas, or a third-party API—and keep them small and cleanup-aware.

    Concise answer
  • SeniorArchitectureModern Angular8 min

    Signals vs RxJS: when should you use each?

    Choose Signals for synchronous state graphs and RxJS for asynchronous event streams, then bridge deliberately.

    SignalsRxJSObservable
    30-second interview answer

    Signals model a current synchronous value and derived state with fine-grained dependency tracking. RxJS models events over time and has strong operators for cancellation, concurrency, buffering, retries, and combining asynchronous sources. Use Signals for local/view state and synchronous derivation; keep RxJS where time and stream semantics are the problem. A healthy Angular application can use both without mirroring every value in both systems.

  • AdvancedRenderingModern Angular2 min

    How do Signals interact with OnPush components?

    Connect a Signal read in a template to view dependency tracking and dirty marking.

    SignalsOnPushtemplates
    30-second interview answer

    When an OnPush template reads a Signal, Angular records the view as a consumer. Updating that Signal marks the dependent view so it is eligible for refresh on the next scheduled change-detection pass. OnPush still matters because it lets Angular skip clean subtrees; Signals improve the precision of notifications but do not make expensive templates or giant DOM trees free.

    Concise answer
  • AdvancedCodingModern Angular2 min

    When are linkedSignal() and resource() useful?

    Model writable state that resets with a source and read-oriented async state without misusing effects.

    linkedSignalresourceasync state
    30-second interview answer

    linkedSignal creates writable state whose default value follows reactive source state—for example, a selection that resets when the available options change. resource models async read state with a request, loader, status, value, error, cancellation, and reload semantics. They reduce synchronization effects, but ownership still matters: mutations and complex event workflows often belong in explicit services or RxJS pipelines.

    Concise answer
  • IntermediateRxJSModern Angular2 min

    How should toSignal() and toObservable() be used?

    Bridge at ownership boundaries while accounting for initial values, subscription lifetime, and asynchronous emissions.

    toSignaltoObservableinterop
    30-second interview answer

    toSignal subscribes to an Observable and exposes its latest value as a Signal; define an initial value or require a synchronous first emission when necessary, and create it in a stable owner rather than per template evaluation. toObservable exposes Signal changes as an Observable for stream composition. Convert at a boundary, not repeatedly throughout the graph, and keep error and completion semantics visible.

    Concise answer

Change Detection

Dirty marking, tree traversal, OnPush, zoneless scheduling, manual APIs, and rendering cost.

Interview focus: Trace the notification, scheduled work, checked views, and resulting DOM update.

  • AdvancedRenderingModern Angular10 min

    How does Angular change detection actually work?

    Separate what marks a view, what schedules work, which views are traversed, and which DOM bindings change.

    change detectionviewsdirty marking
    30-second interview answer

    Angular renders through a tree of views. Framework notifications—such as a bound event, a new input, a template Signal update, or markForCheck—make relevant views eligible for refresh and schedule work. During change detection Angular traverses the required part of the view tree, reevaluates template bindings, compares results with stored values, and updates only changed DOM bindings. The scheduling source and the traversal strategy are separate concerns.

  • AdvancedRendering2 min

    What changes with OnPush change detection?

    Explain OnPush as eligibility and subtree-skipping behavior, not immutable-state magic.

    OnPushCheckAlwaysimmutable state
    30-second interview answer

    Default-strategy views are checked during ordinary application passes. An OnPush subtree can be skipped while it is clean and becomes eligible when it receives a changed input reference, handles a bound event, reads a Signal that changes, is explicitly marked, or is otherwise affected through Angular's view rules. Immutability makes input changes easy to detect, but Angular does not enforce immutable objects.

  • SeniorRenderingModern Angular2 min

    How does zoneless Angular schedule change detection?

    Replace global async monkey-patching with explicit framework notifications from Signals, inputs, events, and view APIs.

    zonelessZone.jsnotifications
    30-second interview answer

    In current Angular, zoneless is the default. Angular schedules rendering from notifications it owns: template-read Signal updates, bound listeners, setInput, markForCheck, view attachment/removal, and related view operations. Zone.js-based applications instead use patched async activity as a broad scheduling signal. Zoneless reduces that global coupling, but application and library code must notify Angular through supported reactive or view APIs.

    Legacy context: Zone.js-based applications remain common. Angular 21+ can opt back into zone-based scheduling with provideZoneChangeDetection.

    Concise answer
  • SeniorPerformance2 min

    When should you use markForCheck(), detectChanges(), detach(), or reattach()?

    Use manual view control as an explicit optimization or integration boundary, not a first response to stale UI.

    ChangeDetectorRefmarkForCheckdetectChanges
    30-second interview answer

    markForCheck makes an OnPush view eligible for a future application pass. detectChanges synchronously checks the view and descendants now. detach removes a view from ordinary traversal until it is reattached or checked manually. These APIs are useful for specialized rendering loops and external integrations, but frequent manual calls can hide broken ownership or notifications; prove the need with profiling and test the lifecycle carefully.

    Concise answer
  • AdvancedDebugging2 min

    What causes ExpressionChangedAfterItHasBeenCheckedError?

    Find state that changes after Angular checked it in the same render turn instead of masking the symptom with a timer.

    ExpressionChangedAfterItHasBeenCheckedErrordev modelifecycle
    30-second interview answer

    In development mode Angular can verify that a binding did not change after it was already checked in the same render cycle. The error commonly exposes a child changing parent-visible state during view initialization, a getter with side effects, or DOM-derived state written too late. Fix the ownership or timing; setTimeout and unconditional detectChanges often silence the evidence while preserving a fragile feedback loop.

    Concise answer
  • Staff / PrincipalDebugging2 min

    A component keeps rerendering unexpectedly. How do you find the trigger?

    Instrument view checks and trace changing inputs, events, Signal writes, stream emissions, and manual marks before optimizing.

    Angular DevToolsprofilinginputs
    30-second interview answer

    First verify what 'rerender' means: component checks, DOM mutations, or component recreation. Use Angular DevTools and browser performance traces, log identity-changing inputs and route reuse, and inspect bound events, Signal writes, AsyncPipe emissions, effects, and ChangeDetectorRef calls. Form one hypothesis, reproduce it with a minimal interaction, remove the trigger, and confirm both fewer checks and improved user-visible cost.

    Concise answer

Dependency Injection

Provider records, injector hierarchy, tokens, factories, injection context, scope, and lifetime.

Interview focus: Resolution paths, instance ownership, test seams, and architectural consequences.

  • AdvancedArchitecture8 min

    How does Angular dependency injection work?

    Trace a token from an injection request through provider lookup, factory creation, caching, and hierarchy.

    injectorprovidertoken
    30-second interview answer

    Angular DI maps a runtime token to a provider record. When code requests the token in an injection context, Angular searches the relevant element and environment injector hierarchy, creates the value from its provider factory if needed, caches it according to that injector's lifetime, and returns it. Provider placement therefore controls availability, instance count, lazy loading, cleanup, and architectural coupling.

  • SeniorArchitecture2 min

    How does hierarchical DI affect service scope and lifetime?

    Place providers at root, route, or component boundaries based on sharing, isolation, bundle, and cleanup needs.

    hierarchical DIcomponent providersroute providers
    30-second interview answer

    A root provider is shared across the application environment; a route provider creates feature-scoped configuration and state; a component provider creates an instance for that component subtree. Resolution chooses the nearest matching provider, so lower providers shadow higher ones. Scope is a design decision: it controls sharing and isolation, but also memory, retained state, lazy-boundary behavior, and surprising duplicate instances.

    Concise answer
  • IntermediateCoding2 min

    When would you use useClass, useValue, useFactory, useExisting, or multi providers?

    Choose provider construction explicitly and know when aliasing differs from creating another instance.

    useClassuseValueuseFactory
    30-second interview answer

    useClass constructs a class for a token; useValue supplies an existing value; useFactory computes a value with dependencies; useExisting aliases one token to the exact same instance; multi collects contributions into an array. Prefer InjectionToken for non-class contracts. A common trap is using useClass when aliasing was intended, which creates a separate instance and splits state.

    Concise answer
  • AdvancedConceptModern Angular2 min

    What is an Angular injection context, and when can inject() be called?

    Understand why inject() works during framework-managed creation but not in arbitrary callbacks or methods.

    injectinjection contextrunInInjectionContext
    30-second interview answer

    inject() needs an active injection context so Angular knows which injector hierarchy to search. That context exists during class field initialization and constructors created by DI, provider factories, route loaders, guards, and functions run with runInInjectionContext. It does not automatically exist later in any method or async callback; capture the dependency during construction or explicitly establish the correct context.

    Concise answer
  • Staff / PrincipalDebugging2 min

    A service unexpectedly has multiple instances. How would you determine why?

    Map provider declarations and injector boundaries, then prove which injector created each instance.

    provider scopelazy routescomponent providers
    30-second interview answer

    Search every provider declaration, including providedIn, application config, route providers, component providers, imported legacy modules, and test overrides. Identify the injection site and walk its element/environment injector chain. Add temporary instance IDs or creation traces and inspect Angular DevTools. Fix the provider boundary—not the symptom—then verify sharing, cleanup, lazy loading, and tests across navigation.

    Concise answer

RxJS & Asynchronous Angular

Angular-focused streams: HTTP cancellation, flattening operators, sharing, cleanup, and Signal interop.

Interview focus: Time, cancellation, concurrency, ownership, error recovery, and duplicate work.

  • IntermediateRxJS2 min

    How do Observable, Subject, BehaviorSubject, and ReplaySubject differ in Angular code?

    Separate a lazy stream contract from multicast event sources with current-value or replay semantics.

    ObservableSubjectBehaviorSubject
    30-second interview answer

    An Observable is a subscription contract and may be cold or hot. A Subject is both observer and Observable and multicasts new events to current subscribers. BehaviorSubject additionally requires and synchronously exposes a current value; ReplaySubject replays a configured history. Use the narrowest semantics needed, expose Observable rather than the writable Subject, and avoid using Subjects as a hidden application-wide event bus.

    Concise answer
  • AdvancedRxJS9 min

    How do switchMap, mergeMap, concatMap, and exhaustMap differ?

    Choose the operator from cancellation, concurrency, ordering, and duplicate-submission requirements.

    switchMapmergeMapconcatMap
    30-second interview answer

    switchMap keeps only the newest inner stream and unsubscribes the previous one; mergeMap runs inners concurrently; concatMap queues them in order; exhaustMap ignores new sources while one inner is active. For typeahead use switchMap, independent saves may use bounded mergeMap, ordered writes may use concatMap, and double-submit prevention may use exhaustMap. The business rule chooses the operator.

  • IntermediateRxJS2 min

    Why are nested subscriptions often a problem?

    Compose dependent work so cancellation, errors, loading, and cleanup stay in one observable lifecycle.

    nested subscriptionscancellationcomposition
    30-second interview answer

    Nested subscribe calls create independent lifecycles, making cancellation, error propagation, loading state, ordering, and cleanup harder to coordinate. Use flattening operators for dependent async work and combination operators for independent sources. A subscribe is appropriate at a true side-effect boundary, but the data-flow graph should normally be expressed before that boundary.

    Concise answer
  • IntermediateRxJS2 min

    How does AsyncPipe manage subscriptions?

    Explain automatic subscription switching, cleanup, latest-value rendering, and view notification.

    AsyncPipesubscriptionOnPush
    30-second interview answer

    AsyncPipe subscribes to an Observable or Promise, returns the latest emitted value, and marks the view when a new value arrives. If the bound source identity changes it unsubscribes from the old source and subscribes to the new one; it also cleans up when the view is destroyed. Avoid creating a new cold Observable expression in the template on every check, because source replacement can repeat work.

    Concise answer
  • AdvancedRxJS2 min

    How do you prevent RxJS subscription leaks in Angular?

    Prefer framework-owned subscription lifetimes and recognize which streams complete naturally.

    takeUntilDestroyedDestroyRefAsyncPipe
    30-second interview answer

    Prefer AsyncPipe or toSignal for view consumption. For imperative subscriptions tied to an Angular owner, use takeUntilDestroyed with its DestroyRef. One-shot HttpClient streams complete, but router events, Subjects, intervals, DOM events, and long-lived stores do not. Cleanup is necessary but not sufficient: callbacks, effects, caches, and third-party listeners can retain the same component graph.

    Concise answer
  • SeniorDebugging2 min

    When can shareReplay cause unexpected behavior?

    Define cache lifetime, reset behavior, source completion, and stale-value policy rather than adding sharing blindly.

    shareReplaycacherefCount
    30-second interview answer

    shareReplay can keep a source subscription or replayed value alive longer than intended, hide stale data behind a service lifetime, or restart work when refCount drops and later rises. The behavior depends on source completion and configuration. State the desired cache owner, invalidation, error reset, and subscriber lifecycle first; sometimes an explicit cache or share with reset options is clearer.

    Concise answer
  • SeniorDebugging2 min

    An RxJS chain triggers multiple HTTP calls. What might cause it?

    Count subscriptions and reconstruct the source lifecycle before introducing a cache.

    HttpClientcold Observablesubscriptions
    30-second interview answer

    HttpClient Observables are cold, so each subscription starts a request. Look for multiple AsyncPipe uses, an imperative subscription plus a template subscription, repeated effect creation, nested subscriptions, retry/repeat, component recreation, and sharing that resets. Instrument subscription and network timing, prove the subscriber graph, then share or cache at the correct owner and verify invalidation—not just request count.

    Concise answer

Angular Routing

Standalone route configuration, lazy boundaries, guards, resolvers, providers, navigation, and preloading.

Interview focus: Loading strategy, URL state, failure behavior, and the distinction between UX and authorization.

  • IntermediateArchitectureModern Angular2 min

    How is a modern standalone Angular router configured?

    Compose route records and router features through application providers instead of a routing NgModule.

    provideRouterRoutesoutlet
    30-second interview answer

    Define typed route records and provide them with provideRouter at application bootstrap. Router features such as preloading, component-input binding, scrolling, and tracing are added as provider features. Routed components render through outlets, while child routes create nested activation trees. NgModule routing remains relevant in legacy applications, but new feature boundaries do not require a routing module.

    Concise answer
  • SeniorPerformance2 min

    How should Angular routes be lazy-loaded and preloaded?

    Place dynamic imports at user-journey boundaries and preload from probability, cost, and network conditions.

    loadComponentloadChildrenpreloading
    30-second interview answer

    Use loadComponent for a standalone routed component and loadChildren for a lazy route tree. Put boundaries around meaningful user journeys so the initial route avoids unrelated code without creating request waterfalls at every nested level. Preload only likely next paths under suitable network and device conditions. Verify output chunks and navigation timing because an eager import elsewhere can pull a lazy feature into the initial graph.

    Concise answer
  • AdvancedSecurity2 min

    What should guards and resolvers do—and not do?

    Use guards for navigation UX and resolvers for required route data while keeping authorization on the server.

    guardsresolversauthorization
    30-second interview answer

    Guards can redirect, prevent an unsuitable client navigation, or stop a route from matching; they are not a security boundary because users control browser code. Resolvers load data that must exist before activation, but overuse delays navigation and can hide loading UX. Backend authorization must validate every protected operation, and router failures should have explicit redirect or error behavior.

    Concise answer
  • AdvancedDebugging2 min

    How would you reason about the Angular Router navigation lifecycle?

    Trace URL recognition, redirects, guards, data resolution, lazy loading, activation, cancellation, and errors.

    router eventsrecognitionguards
    30-second interview answer

    A navigation is a cancelable transaction: parse and recognize the URL, apply redirects, lazy-load route config, run guards and resolvers, build the target router state, deactivate/activate components, and commit history and scrolling behavior. Observe Router events to locate delay or cancellation, but avoid coupling product logic to a fragile event sequence when route state or a guard can express the requirement directly.

    Concise answer

Angular Forms

Typed reactive forms, Signal Forms, template-driven forms, validation, custom controls, and large-form design.

Interview focus: State ownership, validation timing, reusable controls, accessibility, and scale.

  • IntermediateArchitectureModern Angular2 min

    When should you choose reactive, template-driven, or Signal Forms?

    Choose from workflow complexity, typing, dynamic structure, existing controls, and migration cost.

    reactive formstemplate-driven formsSignal Forms
    30-second interview answer

    Template-driven forms suit small forms where the template naturally owns the workflow. Typed reactive forms remain a mature choice for explicit control trees, dynamic forms, and a large ControlValueAccessor ecosystem. Signal Forms, stable in Angular 22, make a Signal model the source of truth with type-safe field trees and schema validation. Choose per form and ecosystem; do not rewrite stable enterprise forms only to adopt a newer API.

    Concise answer
  • IntermediateCoding2 min

    What do typed reactive forms improve?

    Keep control values, nullability, nested groups, and form access consistent at compile time.

    FormControlFormGroupNonNullableFormBuilder
    30-second interview answer

    Typed forms make the control tree and value shape visible to TypeScript, so setValue, patchValue, getRawValue, validators, and access patterns catch more mismatches. Nullability is deliberate because reset can produce null unless controls are non-nullable. Types do not validate runtime server data; domain parsing and validation still belong at trust boundaries.

    Concise answer
  • AdvancedCoding2 min

    How should synchronous, async, and cross-field validation be designed?

    Keep validators pure, place relationship rules at the shared owner, and treat server validation as authoritative.

    validatorsasync validatorscross-field
    30-second interview answer

    A synchronous validator should be a pure function of current control state. Place a cross-field rule on the smallest group that owns all involved values. Async validators should debounce or avoid unnecessary requests, cancel stale work, and return structured errors; do not duplicate every server rule in the client. Error presentation should account for touched/submitted state and remain accessible.

    Concise answer
  • AdvancedCoding2 min

    What does ControlValueAccessor do?

    Bridge an Angular forms control to a custom component without creating competing sources of truth.

    ControlValueAccessorcustom controlsforms
    30-second interview answer

    ControlValueAccessor adapts a custom UI control to Angular's existing forms APIs. Angular writes model values through writeValue; the control reports user changes and touch through registered callbacks; setDisabledState mirrors disabled status. Keep writeValue free of change emission, preserve accessibility and focus behavior, and test model-to-view and view-to-model directions independently.

    Concise answer
  • SeniorArchitecture2 min

    How would you architect a large dynamic Angular form?

    Separate domain schema, control construction, rendering, validation, drafts, and submission while containing update cost.

    dynamic formsFormArrayperformance
    30-second interview answer

    Start from a versioned domain schema rather than component conditionals. Partition the form into owned sections, create only relevant controls, use stable identity for repeated groups, centralize cross-section rules deliberately, and define draft and server-error semantics. Profile validation and rendering before adding manual change detection; virtualize or page very large repeated sections and test migrations between schema versions.

    Concise answer

Directives & Pipes

Reusable element behavior, structural view creation, host directives, and pure transformation boundaries.

Interview focus: Use the smallest abstraction and understand its DOM and change-detection cost.

  • IntermediateConcept2 min

    How do attribute and structural directives differ?

    Distinguish behavior on an existing host from reusable creation and removal of embedded views.

    attribute directivestructural directiveTemplateRef
    30-second interview answer

    An attribute directive attaches behavior, bindings, or host interaction to an existing element or component. A structural directive controls embedded views through TemplateRef and ViewContainerRef. For normal conditionals and loops, use modern @if, @for, and @switch; write a custom structural directive only when reusable view-creation behavior adds a real domain abstraction.

    Concise answer
  • AdvancedArchitectureModern Angular2 min

    When are host directives useful?

    Compose reusable host behavior into components without inheritance while controlling the exposed API.

    hostDirectivesdirective compositionreusable behavior
    30-second interview answer

    Host directives let a component or directive apply another directive to its host at compile time and optionally expose selected inputs and outputs. They are useful for focus behavior, menus, selection, accessibility, and shared interaction policies. Keep composition shallow and explicit; a large invisible stack of host behavior can make provider resolution, host bindings, and event ownership hard to trace.

    Concise answer
  • AdvancedPerformance2 min

    How do pure and impure pipes affect performance and correctness?

    Use reference-based pure transformation by default and understand why deep mutation can leave results stale.

    pure pipeimpure pipechange detection
    30-second interview answer

    A pure pipe runs when its input value or reference changes, so it is efficient for deterministic display transformation but will not notice deep mutation behind a stable object reference. An impure pipe can run on every relevant check and can become extremely expensive. Prefer immutable inputs, computed state, or explicit async boundaries; use an impure pipe only for a measured case with bounded work.

    Concise answer

Lifecycle & Rendering

Input timing, view/content initialization, render callbacks, cleanup, DOM access, and SSR boundaries.

Interview focus: Explain why timing matters and choose the lifecycle boundary that owns the work.

  • IntermediateRendering7 min

    What lifecycle sequence should an Angular candidate understand?

    Connect construction, input initialization, content/view checks, rendering, and destruction to ownership.

    ngOnChangesngOnInitngAfterViewInit
    30-second interview answer

    Angular constructs the class, sets initial inputs, calls ngOnChanges, then ngOnInit, followed by content initialization/check hooks and view initialization/check hooks. Render callbacks run after rendering work, and destruction callbacks release owned resources. The exact list matters less than choosing the boundary whose prerequisites are actually ready and avoiding repeated work in the checked hooks.

  • FundamentalsConcept2 min

    What belongs in the constructor versus ngOnInit?

    Keep language-level construction distinct from framework initialization after inputs are assigned.

    constructorngOnInitinputs
    30-second interview answer

    The constructor establishes class invariants and receives dependencies; Angular inputs are not ready there. ngOnInit runs after initial inputs are set and is suitable for initialization that depends on them. Prefer field initialization and derived Signals for simple state, and avoid starting work in both places without a clear owner because tests and inheritance become harder to reason about.

    Concise answer
  • AdvancedRenderingModern Angular2 min

    When should afterNextRender() or afterEveryRender() be used?

    Schedule DOM-dependent work after Angular rendering and keep browser-only behavior out of server execution.

    afterNextRenderafterEveryRenderDOM
    30-second interview answer

    afterNextRender schedules work after the next application render; afterEveryRender repeats after renders. They are appropriate for layout measurement or integration with imperative browser libraries when normal bindings cannot express the work. Register them in an injection context, separate write and read phases when possible, clean up owned resources, and remember render callbacks do not run during server rendering.

    Concise answer
  • SeniorDebugging2 min

    How should Angular resources be cleaned up?

    Tie subscriptions, observers, listeners, timers, and dynamically created views to the owner that created them.

    DestroyRefngOnDestroyevent listeners
    30-second interview answer

    The creator of a long-lived resource should own its teardown. Use framework-managed lifetimes where possible, takeUntilDestroyed for subscriptions, and DestroyRef.onDestroy or ngOnDestroy for listeners, observers, timers, workers, and third-party instances. Also inspect services and caches: destroying a component does not free objects still retained by a root service, detached DOM, or a library callback.

    Concise answer

State Management

Local, lifted, service, Signal, RxJS, URL, server, cache, and global state with explicit ownership.

Interview focus: Complexity, event flow, derivation, persistence, debugging, and library thresholds.

  • AdvancedArchitecture2 min

    How do you decide where Angular state should live?

    Place state from who owns it, who needs it, how long it lives, and which system is authoritative.

    local stateURL stateserver state
    30-second interview answer

    Keep ephemeral interaction state in the component, lift shared view state to the nearest common owner, use a scoped service for a feature workflow, put navigable state in the URL, and treat backend data as server state with an explicit cache policy. Persist only what must survive reloads. Avoid copying one value into several stores; derived state should be computed from one authoritative source.

    Concise answer
  • SeniorArchitecture8 min

    When does an Angular application need a global state-management library?

    Adopt a store for demonstrated coordination and observability needs, not because the application is large.

    NgRxglobal storeevents
    30-second interview answer

    A global store becomes valuable when many distant features coordinate durable state, transitions need explicit events and effects, reproducible debugging matters, or policy must be standardized across teams. Component Signals and scoped services are simpler for local workflows. Evaluate ownership, event volume, server-cache needs, testability, and team fluency; application size alone is not the threshold.

  • AdvancedCodingModern Angular2 min

    How would you design a small Signal-based feature store?

    Encapsulate writable state, expose readonly state and derivations, and make commands own transitions.

    Signalsservicecomputed
    30-second interview answer

    Provide the store at the feature lifetime, keep writable Signals private, expose readonly Signals and computed derivations, and offer intention-revealing commands for transitions. Keep async work and error policy explicit rather than hiding them inside arbitrary effects. This is enough for many features; add a formal store when event history, cross-feature coordination, tooling, or standardized effects justify it.

    Concise answer
  • SeniorArchitecture2 min

    How does server state differ from client state?

    Treat fetched data as a cached remote snapshot with freshness, invalidation, and concurrency semantics.

    server statecachestale data
    30-second interview answer

    Server state is owned remotely and the client holds a potentially stale snapshot; it needs request deduplication, freshness, invalidation, error, retry, and mutation reconciliation. Client state is authoritative in the browser, such as an open panel or unsaved draft. Conflating them produces stale caches and duplicated truth. Define keys, ownership, TTL or invalidation events, and optimistic rollback explicitly.

    Concise answer
  • Staff / PrincipalArchitecture2 min

    When should Angular application state be normalized?

    Normalize shared entities when identity and cross-view updates matter, not as a blanket rule for every response.

    normalized stateentitiesderived state
    30-second interview answer

    Normalize when the same entity appears in many collections, updates arrive independently, and one canonical record prevents inconsistent copies. Keep ordered IDs and derive view models with selectors or computed values. For route-local read models and small immutable responses, normalization can add indirection without value. The deciding forces are identity, update patterns, ownership, and debugging cost.

    Concise answer

Angular Performance

Bundles, lazy boundaries, @defer, lists, change detection, requests, rendering, profiling, and CWV.

Interview focus: Measure the constraint, redesign the expensive path, and verify user-visible improvement.

  • SeniorPerformance9 min

    How do you investigate an Angular performance problem?

    Start from a user-visible metric, segment the path, and correlate framework, browser, network, and bundle evidence.

    Angular DevToolsChrome DevToolsCWV
    30-second interview answer

    Define the failing user journey and metric—LCP, INP, navigation time, frame drops, memory, or bundle cost. Reproduce with representative data and device constraints, then use Angular DevTools, Chrome Performance/Memory/Network, source maps, and bundle analysis to locate time and retention. Change one proven constraint, compare the same workload, and verify the user metric rather than a proxy alone.

  • SeniorScenario2 min

    An Angular dashboard renders 10,000 rows and becomes sluggish. What do you do?

    Measure DOM, scripting, layout, and update frequency before reducing rendered work and stabilizing identity.

    virtual scrollingtrackDOM
    30-second interview answer

    Profile whether the cost is creation, change detection, layout, paint, or repeated updates. Usually the redesign is to avoid rendering 10,000 interactive rows: virtualize, page, aggregate, or progressively disclose. Use stable track identity, OnPush/Signals, cheap templates, and batched updates. Verify frame time, memory, accessibility, keyboard behavior, and the actual user task with production-scale data.

    Concise answer
  • Staff / PrincipalPerformance2 min

    How do you reduce a multi-megabyte Angular initial bundle?

    Use the build graph to remove, replace, or move code across real loading boundaries and enforce budgets.

    bundle analysislazy loadingCommonJS
    30-second interview answer

    Measure compressed and parsed cost by chunk, inspect source-map bundle output, and identify eager feature imports, heavy libraries, duplicated versions, locale/data payloads, CommonJS limits, and side-effectful packages. Create route and @defer boundaries, replace or narrowly import dependencies, and enforce budgets in CI. Verify cold-load LCP/INP and navigation waterfalls, not bundle bytes alone.

    Concise answer
  • AdvancedPerformanceModern Angular2 min

    When should you use @defer?

    Defer non-critical standalone dependencies at a meaningful visual boundary while designing every loading state.

    @defercode splittingplaceholder
    30-second interview answer

    @defer lets the compiler split eligible standalone dependencies and load them on idle, viewport, interaction, timer, immediate, or a condition. Use it for expensive, non-critical regions with stable placeholders and deliberate prefetching. Do not defer above-the-fold essentials merely to improve a bundle report; account for layout shift, request waterfalls, error states, SSR, and incremental hydration behavior.

    Concise answer
  • IntermediateRenderingModern Angular2 min

    Why does the track expression in @for matter?

    Preserve logical row identity so Angular can reuse DOM and component instances through reordering and updates.

    @fortrackDOM identity
    30-second interview answer

    The track expression maps each item to stable logical identity. Angular uses it to match old and new collections, reuse views, move DOM, preserve focus and component state, and create or destroy only real additions/removals. Track a unique domain key; index is safe only for truly static order, and returning a new object defeats stable matching.

    Concise answer
  • AdvancedPerformance2 min

    Why can methods and getters in Angular templates be expensive?

    Treat template expressions as repeatable render work and move expensive derivation to cached, explicit state.

    template methodscomputedpipes
    30-second interview answer

    Angular may evaluate template expressions whenever the view is checked, so a method or getter that filters, sorts, allocates, parses, or triggers side effects can repeat frequently. Cheap pure accessors are fine. Move substantial derivation into computed Signals, pure pipes, memoized selectors, or preprocessing at the data boundary, and verify with a profile rather than banning every method syntactically.

    Concise answer

SSR, Prerendering & Hydration

CSR, server rendering, prerendering, hybrid routes, transfer cache, hydration, and server/browser boundaries.

Interview focus: Choose per route from freshness, personalization, cacheability, interactivity, and operating cost.

  • SeniorArchitecture8 min

    When should an Angular route use CSR, SSR, or prerendering?

    Choose per route from freshness, personalization, crawlability, cacheability, latency, and operating cost.

    CSRSSRSSG
    30-second interview answer

    Use client rendering for authenticated, highly interactive surfaces where server HTML adds little. Use SSR when first-response content must be fresh or request-specific and early HTML improves the journey. Prerender stable, cacheable routes at build time. Modern Angular supports hybrid choices per route; include CDN caching, backend latency, hydration cost, failure modes, and operational capacity in the decision.

  • AdvancedRenderingModern Angular2 min

    What does Angular hydration do?

    Reuse server-rendered DOM and restore client behavior instead of destroying and recreating the page.

    hydrationSSRDOM reuse
    30-second interview answer

    Hydration matches the client view structure to server-rendered DOM, reuses those nodes, restores Angular listeners and state, and can replay early events. It improves continuity and avoids a destructive rerender, but requires valid, deterministic HTML and careful browser-only code. Hydration does not remove the cost of downloading and executing the client application.

    Concise answer
  • AdvancedPerformanceModern Angular2 min

    How does incremental hydration relate to @defer?

    Render deferred regions on the server while delaying their client code and hydration until an explicit boundary triggers.

    incremental hydration@deferevent replay
    30-second interview answer

    Incremental hydration lets the server render the main content of a @defer block while the browser leaves that subtree dehydrated until a hydrate trigger fires. Angular then loads its dependencies, hydrates the boundary, and replays captured events. It can reduce initial JavaScript without above-the-fold layout replacement, but nested boundaries, trigger choice, and interaction readiness must be designed and measured.

    Concise answer
  • SeniorDebugging2 min

    How do you investigate an Angular hydration mismatch?

    Compare server and client DOM inputs, then isolate nondeterminism, invalid markup, or pre-hydration mutation.

    hydration mismatchvalid HTMLbrowser APIs
    30-second interview answer

    Capture the server HTML and the DOM before Angular hydrates, then compare the failing subtree. Check invalid table/nesting markup, direct DOM manipulation, random/time/locale output, request-specific state not transferred, browser-only branches, whitespace configuration, and third-party scripts that mutate early. Fix determinism and ownership; use skip hydration only as a narrow temporary boundary.

    Concise answer
  • Staff / PrincipalScenario2 min

    An Angular route works during client navigation but crashes on refresh. What do you investigate?

    Follow the server-only execution path and check platform assumptions, request state, imports, and route rendering configuration.

    SSRwindowrequest state
    30-second interview answer

    A refresh executes the server render while client navigation may not. Inspect the server stack and route render mode, then find top-level or lifecycle access to window, document, storage, layout, and DOM libraries. Check request-specific authentication, environment configuration, absolute URLs, ESM compatibility, and transferred data. Add a server-render test for the route and verify both direct and client navigation.

    Concise answer

Testing Angular

Vitest, TestBed, components, HTTP, Router, Signals, RxJS, integration, and browser-level confidence.

Interview focus: Test behavior and contracts without coupling every assertion to framework internals.

  • SeniorTesting2 min

    What should a large Angular application test?

    Match test level to risk: pure domain logic, component behavior, boundary integrations, and critical browser journeys.

    unit testingintegrationE2E
    30-second interview answer

    Unit-test domain transformations and failure rules; component-test public inputs, outputs, accessibility, and rendered behavior; integration-test routing, forms, HTTP adapters, and state boundaries; browser-test a small set of critical journeys. Avoid tests that only restate Angular or assert private method calls and DOM structure with no product meaning. Optimize for fault detection and refactor confidence.

    Concise answer
  • IntermediateTestingModern Angular2 min

    What is the current Angular unit-testing setup?

    Distinguish the current CLI default from the installed base candidates will still maintain.

    VitestKarmaAngular CLI
    30-second interview answer

    New Angular CLI projects use Vitest with a DOM emulation environment by default, and ng test integrates the runner. Karma is still supported and common in mature applications. TestBed remains Angular's component and DI test utility regardless of runner. Use real-browser mode or E2E tests for layout and browser APIs that a simulated DOM cannot validate.

    Legacy context: Karma remains supported and is common in existing projects; migrate because it improves the workflow, not merely to follow a default.

    Concise answer
  • AdvancedTestingModern Angular2 min

    How should Signals and zoneless Angular change testing?

    Let production-like notifications schedule rendering and test visible outcomes instead of forcing every update manually.

    SignalszonelesswhenStable
    30-second interview answer

    Update state through the same input, event, or Signal API production uses, await fixture.whenStable when rendering is scheduled, and assert visible behavior. A blanket fixture.detectChanges can hide code that fails to notify Angular in zoneless production. Test computed values as pure derivations where useful, and test effects through the external boundary they synchronize—not their implementation details.

    Concise answer
  • SeniorTesting2 min

    How do you test Angular HTTP, Router, and form integrations without brittle mocks?

    Use Angular's boundary harnesses to exercise observable contracts and user behavior while keeping backend and browser scope controlled.

    HttpTestingControllerRouterTestingHarnessforms
    30-second interview answer

    Use the HTTP testing provider and controller to assert request shape and drive response/error timing; use RouterTestingHarness to navigate real route configuration and inspect activated UI; exercise forms through controls and user-facing behavior. Mock the external boundary, not every collaborator. Keep a smaller browser suite for focus, native validation, history, and cross-page behavior.

    Concise answer

Angular Security

XSS, sanitization, trusted values, CSP, CSRF, tokens, route guards, and backend trust boundaries.

Interview focus: Know which protections the framework supplies and which only the server can enforce.

  • AdvancedSecurity2 min

    How does Angular protect against XSS?

    Treat template values as untrusted by default, understand security contexts, and avoid bypassing sanitization.

    XSSsanitizationtemplates
    30-second interview answer

    Angular escapes interpolation and sanitizes untrusted values in security-sensitive binding contexts such as HTML and URLs. Templates themselves are trusted executable code and must never be assembled from user input. DomSanitizer bypass methods assert that a value is already safe—they do not sanitize it. Prefer structured rendering, server validation, CSP, and Trusted Types over bypasses.

    Concise answer
  • SeniorSecurity2 min

    Where should an Angular application store authentication tokens?

    Choose a session design from XSS, CSRF, refresh, domain, and backend constraints rather than one universal storage rule.

    tokenscookieslocalStorage
    30-second interview answer

    JavaScript-readable storage makes tokens available to any successful XSS. HttpOnly, Secure, SameSite cookies reduce token theft but require a CSRF strategy and careful domain/session design. Short-lived in-memory access tokens plus protected refresh mechanisms are another pattern. The backend must validate every token and authorization decision; Angular interceptors are convenience, not enforcement.

    Concise answer
  • FundamentalsSecurity2 min

    Why are Angular route guards not a security boundary?

    Keep navigation experience in the client and data authorization on trusted infrastructure.

    route guardsauthorizationbackend
    30-second interview answer

    Users can modify browser code, call APIs directly, and bypass a client route entirely. A guard improves navigation UX and can avoid rendering an inappropriate screen, but it cannot protect data or operations. The server must authenticate the caller and authorize every request against current policy, regardless of which Angular route was visible.

    Concise answer
  • Staff / PrincipalSecurity2 min

    How do CSP and third-party scripts affect Angular security?

    Reduce executable trust, constrain script sources, and treat vendor code as privileged code with lifecycle risk.

    CSPTrusted Typesthird-party scripts
    30-second interview answer

    A strong CSP and Trusted Types policy reduce the paths by which injected text becomes executable, but they require compatible build and runtime behavior. Every third-party script runs with page privileges and can affect performance, privacy, hydration, and token exposure. Inventory, pin, review, sandbox where possible, load only with justified consent, monitor changes, and keep a removal path.

    Concise answer

Angular Architecture

Feature boundaries, libraries, design systems, monorepos, micro-frontends, platforms, and multi-team evolution.

Interview focus: Optimize dependency direction, team autonomy, release safety, observability, and change cost.

  • Staff / PrincipalArchitecture9 min

    How would you structure Angular architecture for an organization with 20–30 frontend teams?

    Align domain and ownership boundaries, standardize high-leverage platform seams, and measure whether autonomy improves.

    team topologyplatformlibraries
    30-second interview answer

    Align deployable applications and libraries to business domains with named owners and enforced dependency direction. Standardize the paved road—Angular version, build, testing, observability, security, design-system primitives, and API clients—while letting teams own domain decisions. Use automated boundaries and compatibility tests, not review committees. Measure lead time, upgrade adoption, incidents, bundle budgets, and cross-team dependency wait time.

  • Staff / PrincipalArchitecture2 min

    When should a company build a shared Angular platform?

    Invest when repeated cross-team friction and risk justify a product team with adoption, compatibility, and support responsibilities.

    frontend platformpaved roaddeveloper experience
    30-second interview answer

    Build a platform when many teams repeatedly solve the same build, auth, observability, testing, deployment, accessibility, and upgrade problems and inconsistency creates measurable risk. Treat it as a product: paved-road defaults, escape hatches, versioned contracts, migrations, documentation, telemetry, and support. Do not centralize domain state or every component; platform success is reduced cognitive load and faster safe delivery, not control.

    Concise answer
  • Staff / PrincipalArchitecture2 min

    How would you evolve a shared Angular component library without breaking hundreds of consumers?

    Separate tokens, primitives, and product composites; version contracts and ship migrations with adoption evidence.

    design systemsemantic versioningmigrations
    30-second interview answer

    Define the supported public API, accessibility behavior, tokens, visual regression contract, and browser/Angular range. Prefer composable primitives over domain-specific mega-components. Deprecate with telemetry and time, ship schematics or codemods, test representative consumers, canary releases, and support parallel versions when necessary. A platform team owns migration ergonomics, not only package publication.

    Concise answer
  • Staff / PrincipalArchitecture2 min

    When are micro-frontends justified for Angular?

    Use independent deployment only when organizational autonomy exceeds the runtime, UX, and governance cost.

    micro-frontendsmodule federationdeployment
    30-second interview answer

    Micro-frontends are justified when domains need genuinely independent release and ownership boundaries that a modular monolith cannot provide. Costs include duplicate framework/runtime code, shared dependency negotiation, routing, authentication, cross-app state, design consistency, observability, accessibility, and failure isolation. Start with repository and module boundaries; adopt runtime composition only with measurable autonomy requirements and a platform that owns the seams.

    Concise answer
  • Staff / PrincipalPerformance2 min

    How would you define Angular performance budgets across dozens of applications?

    Set journey- and device-based user budgets, connect them to build limits, and provide ownership and exception policy.

    performance budgetsCWVCI
    30-second interview answer

    Define representative devices, networks, and critical journeys, then set field-oriented LCP, INP, CLS, error, and navigation targets plus build-time JavaScript/CSS/image budgets. Enforce regression checks in CI and monitor real-user percentiles by application and route. Assign owners, publish trend dashboards, and use time-bounded exceptions with remediation—not one universal byte limit detached from product context.

    Concise answer

Modernizing Legacy Angular

NgModule-to-standalone migration, Signals adoption, build/test evolution, and multi-version upgrades.

Interview focus: Sequence change by risk, automate migrations, preserve behavior, and keep rollbacks available.

  • SeniorArchitectureLegacy-relevant2 min

    How would you migrate a large NgModule-based application to standalone architecture?

    Use official migrations and feature-by-feature boundaries while preserving provider scope, routes, tests, and rollback.

    NgModulesstandalonemigration
    30-second interview answer

    Inventory module roles first: declarations, provider scope, routing, initialization, and library compatibility. Run Angular's standalone migrations in small steps, convert leaf components and lazy routes, move providers deliberately, and use importProvidersFrom as a temporary bridge. Keep builds and behavior tests green, compare bundles and DI lifetimes, and remove obsolete modules only after consumers have moved.

    Legacy context: NgModules remain valid and interview-relevant in maintained applications; standalone is the recommended direction for new Angular code.

    Concise answer
  • Staff / PrincipalArchitectureModern Angular2 min

    How would you introduce Signals into a mature RxJS-heavy Angular application?

    Adopt Signals at synchronous view-state boundaries without rewriting stream workflows or duplicating truth.

    SignalsRxJSmigration
    30-second interview answer

    Start with local UI state and pure derived view models where Signals remove manual Subjects and subscriptions. Keep RxJS for cancellation, concurrency, WebSockets, and multi-event workflows; bridge once at feature boundaries with toSignal or toObservable. Define ownership and migration conventions, add zoneless compatibility tests, measure bundle/runtime effects, and avoid mirroring every store selector into a second Signal store.

    Concise answer
  • Staff / PrincipalScenarioLegacy-relevant2 min

    How would you upgrade an Angular application across many major versions?

    Move one supported major at a time, automate framework migrations, reduce ecosystem blockers, and keep every step releasable.

    ng updatedependenciesmigration
    30-second interview answer

    Map Angular, TypeScript, Node, RxJS, builder, test-runner, and library compatibility first. Upgrade one major at a time with ng update, commit automated migrations separately, replace abandoned blockers, and run unit, integration, SSR, visual, performance, and production smoke tests at each step. Release intermediate states when possible, monitor canaries, and avoid combining framework, state, design-system, and domain rewrites into one change.

    Concise answer
  • SeniorArchitectureLegacy-relevant2 min

    What would you modernize first in an older Angular build and test stack?

    Remove unsupported and blocking infrastructure first, then migrate with measured build, test, SSR, and deployment parity.

    application builderesbuildVite
    30-second interview answer

    First reach a supported Angular/Node/TypeScript baseline and eliminate custom webpack assumptions or abandoned test utilities that block upgrades. Move to the stable application builder and its esbuild/Vite-based toolchain, then evaluate Vitest migration for test speed and maintenance. Preserve production output, SSR behavior, source maps, coverage meaning, and browser-level tests; tooling change is successful only if delivery gets faster without losing confidence.

    Concise answer

Angular Production & Debugging

Evidence-first diagnosis of duplicate work, memory growth, stale UI, bundle leaks, and long-running slowness.

Interview focus: Symptom → evidence → hypothesis → mitigation → verification, with user protection first.

  • SeniorDebugging9 min

    Memory increases every time users navigate between two Angular pages. How do you find the leak?

    Use repeatable navigation and heap evidence to find the retaining owner before changing cleanup code.

    memory leakheap snapshotdetached DOM
    30-second interview answer

    Automate a navigation loop, force comparable garbage-collection conditions, and verify the retained heap grows after components should be destroyed. Compare heap snapshots and dominator/retainer paths for component instances, detached DOM, subscriptions, listeners, timers, overlays, caches, and third-party objects. Fix the retaining owner, repeat the same loop, and verify both heap stabilization and correct feature behavior.

  • SeniorScenario2 min

    An Angular page suddenly makes hundreds of duplicate HTTP requests. How do you investigate?

    Correlate request initiators with component, subscription, effect, retry, and route lifecycles before adding caching.

    duplicate requestsHttpClienteffects
    30-second interview answer

    Protect the backend with rollback, flags, or rate limits if needed, then capture Network initiators and application traces. Count component creation, Observable subscriptions, Signal effect creation, AsyncPipe consumers, retry loops, router reactivation, and polling timers. Build the exact fan-out graph, remove or share at the owning boundary, define invalidation, and verify request cardinality across navigation and error paths.

    Concise answer
  • Staff / PrincipalScenario2 min

    A dashboard becomes slow after running for several hours. What evidence do you gather?

    Trend heap, DOM, listeners, task duration, stream frequency, caches, and network work over time to distinguish accumulation from load.

    long taskmemorysubscriptions
    30-second interview answer

    Record a controlled long-running session and trend heap after GC, DOM node count, listeners, timers, subscriptions, Signal/effect activity, cache sizes, network frequency, long tasks, and frame time. Compare idle and active periods and take heap/CPU profiles early and late. Find the accumulating owner or increasing work rate, mitigate safely, and verify a soak test under production-like data.

    Concise answer
  • SeniorDebugging2 min

    Users see stale Angular data even though the backend returns fresh responses. Where can staleness originate?

    Trace the value from network response through transport, caches, state transitions, identity, and template consumption.

    stale datacacheOnPush
    30-second interview answer

    Confirm the browser received the fresh payload, then trace HTTP/service-worker/CDN caches, shareReplay or resource lifetime, store selectors, optimistic state, mutation behind stable references, Signal equality, route reuse, and template pipes. Instrument version/timestamp at each boundary to locate where the value diverges. Fix ownership or invalidation and verify reload, navigation, offline, and concurrent-mutation paths.

    Concise answer
  • Staff / PrincipalPerformance2 min

    A lazy Angular feature appears in the initial bundle. How do you diagnose it?

    Use the module graph to find the eager reference or incompatible boundary that defeated dynamic loading.

    lazy loadingbundle grapheager import
    30-second interview answer

    Verify the chunk with source-map/bundle analysis, then trace every import of its entry component, route tree, shared barrel, provider, constant, stylesheet, and query. A static import anywhere reachable from the initial graph defeats the lazy boundary; @defer dependencies also must meet eligibility rules. Remove the eager edge, rebuild, and test both cold-load bytes and first navigation behavior.

    Concise answer

Cornerstone answers, built in interview layers

Rehearse the answer you can say aloud, then inspect the runtime, code, version boundary, trade-offs, diagnostic path, and production implications expected in a senior response.

SignalsAdvancedConcept8 min

How do Angular Signals work?

Back to library

30-second interview answer

A Signal is a synchronous getter backed by a reactive producer. While a computed value or template executes, Angular records which Signals were read; when one changes, Angular invalidates dependent computed values and marks affected views for a future render. Dependencies are dynamic and follow the branch actually read. Signals notify consumers—they do not deep-observe arbitrary object mutation.

Understand the mechanism

Signals form a graph of producers and consumers. Reading a Signal returns its current value synchronously. If that read happens while Angular is evaluating a computed value, an effect, or a template, the current consumer records a dependency on the producer. The dependency graph follows the code path actually executed, so a branch that stops reading a Signal also stops depending on it.

Writing a new value notifies dependents. A computed value becomes invalid and recomputes lazily when it is next needed; a template consumer is marked so Angular can refresh the affected view in a scheduled render. This is finer-grained notification than treating every asynchronous browser task as evidence that the whole application may have changed.

Signals compare values before notifying. Custom equality can reduce noisy updates, but deep equality may hide mutation and add CPU cost. A Signal does not make the object inside it immutable: mutate an array in place without set or update and Angular has no new value transition to observe. Prefer immutable updates and computed derivation; reserve effects for imperative boundaries.

Writable state, dynamic derivation, and a template consumer

Angular 22
import {CurrencyPipe} from '@angular/common';
import {ChangeDetectionStrategy, Component, computed, signal} from '@angular/core';

@Component({
  selector: 'app-order-summary',
  imports: [CurrencyPipe],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <button (click)="quantity.update(q => q + 1)">Add one</button>
    <p>{{ quantity() }} × {{ unitPrice() | currency }}</p>
    <strong>Total: {{ total() | currency }}</strong>
  `,
})
export class OrderSummary {
  readonly quantity = signal(1);
  readonly unitPrice = signal(24);
  readonly total = computed(() => this.quantity() * this.unitPrice());
}

Trade-offs to name

  • Signals optimize dependency notification, not expensive DOM or layout work.
  • Synchronous current-value semantics are excellent for view state but do not replace stream cancellation or backpressure.
  • Custom equality can save work but can also make change semantics surprising.

Why interviewers ask this

The question reveals whether a candidate understands modern Angular reactivity beyond the signal/getter syntax and can connect it to rendering and state design.

Common candidate mistakes

  • Saying Signals automatically deep-observe objects and arrays.
  • Using effect to copy every derived value into another writable Signal.
  • Claiming Signals update the DOM immediately rather than notifying and scheduling Angular rendering.

Interviewer follow-ups

  • How are dependencies removed when a computed branch changes?
  • How does a template Signal read affect an OnPush view?
  • When would a custom equality function be dangerous?
  • Where would RxJS remain the better abstraction?

Senior-level perspective

A senior design keeps writable state at clear ownership boundaries, exposes readonly views, and lets computed derivations replace synchronization code. Evaluate the whole graph: a precise notification that eventually renders 20,000 nodes is still expensive.

Key takeaways

  • Reads build a dynamic dependency graph.
  • Writes notify consumers; computed values derive lazily.
  • Signals observe value transitions, not hidden deep mutation.
SignalsSeniorArchitecture8 min

Signals vs RxJS: when should you use each?

Back to library

30-second interview answer

Signals model a current synchronous value and derived state with fine-grained dependency tracking. RxJS models events over time and has strong operators for cancellation, concurrency, buffering, retries, and combining asynchronous sources. Use Signals for local/view state and synchronous derivation; keep RxJS where time and stream semantics are the problem. A healthy Angular application can use both without mirroring every value in both systems.

Understand the mechanism

Signals and Observables overlap at the edges but model different questions. A Signal answers “what is the value now?” synchronously and gives Angular a dependency graph for derivation and rendering. An Observable answers “what events occur over time?” and can be lazy, multicast, finite, infinite, cancellable, buffered, retried, or concurrent.

Local selection, toggles, form-adjacent view state, and computed view models are natural Signal territory. Typeahead, router events, WebSockets, request orchestration, retry policy, and competing async operations are natural RxJS territory. The decision is not local versus global; it is current-value semantics versus temporal event semantics, plus ownership and tooling.

Bridge once at a stable boundary. toSignal subscribes immediately and needs a lifetime and an initial-value policy. toObservable turns Signal invalidations into Observable emissions for operator composition. Repeated conversions or mirrored stores create two sources of truth and obscure error, completion, and cancellation behavior.

Signals own view state; RxJS owns cancellable search

Angular 22
import {Component, computed, inject, signal} from '@angular/core';
import {toObservable, toSignal} from '@angular/core/rxjs-interop';
import {debounceTime, distinctUntilChanged, switchMap} from 'rxjs';

@Component({
  selector: 'app-user-search',
  template: `
    <input [value]="query()" (input)="query.set($any($event.target).value)" />
    @if (results(); as users) {
      <p>{{ resultLabel() }}</p>
    }
  `,
})
export class UserSearch {
  private readonly api = inject(UserApi);
  readonly query = signal('');

  readonly results = toSignal(
    toObservable(this.query).pipe(
      debounceTime(250),
      distinctUntilChanged(),
      switchMap(query => this.api.search(query)),
    ),
    {initialValue: []},
  );

  readonly resultLabel = computed(() => String(this.results().length) + ' results');
}

Trade-offs to name

  • Converting an Observable to a Signal needs an initial or synchronous-value contract.
  • Signals do not carry completion and error channels in the same way as Observables.
  • A single abstraction everywhere is simpler only until it fights the problem's time semantics.

Why interviewers ask this

Modern Angular roles expect candidates to adopt Signals without discarding the async composition strengths that make RxJS valuable.

Common candidate mistakes

  • Claiming Signals replace RxJS throughout Angular.
  • Using BehaviorSubject only because a current value is needed locally.
  • Converting back and forth at every service and component boundary.

Interviewer follow-ups

  • Who owns the subscription created by toSignal?
  • How would you represent loading and error state?
  • Would a WebSocket stream become a Signal?
  • How would you migrate an RxJS-heavy feature incrementally?

Senior-level perspective

At scale, publish an architectural rule based on semantics, not a technology quota. Teams should be able to explain the owner, lifetime, error path, and conversion point of every reactive flow.

Key takeaways

  • Signals model synchronous current state.
  • RxJS models events, time, cancellation, and concurrency.
  • Bridge once at a deliberate ownership boundary.
Change DetectionAdvancedRendering10 min

How does Angular change detection actually work?

Back to library

30-second interview answer

Angular renders through a tree of views. Framework notifications—such as a bound event, a new input, a template Signal update, or markForCheck—make relevant views eligible for refresh and schedule work. During change detection Angular traverses the required part of the view tree, reevaluates template bindings, compares results with stored values, and updates only changed DOM bindings. The scheduling source and the traversal strategy are separate concerns.

Understand the mechanism

Change detection is a rendering process over Angular views, not a background observer that detects arbitrary JavaScript mutation. First, Angular receives a notification that work may be needed. In a current zoneless application, notifications include a Signal read by a template changing, a bound event, a new component input, markForCheck, and view attachment or removal. Zone-based applications also schedule from patched asynchronous activity.

Next Angular traverses the views that must be considered. Default-strategy views participate in ordinary passes; clean OnPush subtrees can be skipped. A dirty descendant can still require traversal through ancestors to reach it. During a view refresh, generated template instructions reevaluate bindings and compare their results with previously stored values.

Only bindings whose values changed produce corresponding DOM or directive updates. That means component checks, binding evaluations, DOM mutation, layout, and paint are distinct costs. Signals improve notification precision and OnPush improves subtree skipping, but neither removes expensive expressions, unstable list identity, large DOM, layout thrashing, or repeated network emissions.

A notification path through an OnPush view

Angular 22 (zoneless default)
import {ChangeDetectionStrategy, Component, computed, signal} from '@angular/core';

@Component({
  selector: 'app-cart-count',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <button (click)="items.update(xs => [...xs, createItem()])">Add</button>
    <span>{{ count() }} items</span>
  `,
})
export class CartCount {
  readonly items = signal<Item[]>([]);
  readonly count = computed(() => this.items().length);
}

// Click listener notifies Angular.
// items.set/update invalidates count and marks this template consumer.
// Angular refreshes the eligible view and updates the text binding if changed.

Trade-offs to name

  • More granular notification reduces checks but does not guarantee a faster user interaction.
  • Manual detectChanges can reduce latency locally while creating hidden rendering ownership.
  • Zone.js offers broad compatibility; zoneless requires Angular-aware notifications.

Why interviewers ask this

Change detection joins Signals, OnPush, templates, browser rendering, and performance. Strong candidates separate the phases instead of repeating one trigger list.

Common candidate mistakes

  • Saying Angular rerenders every DOM node on each event.
  • Saying OnPush checks only when an input reference changes.
  • Treating Zone.js as the change detector rather than a scheduling signal in legacy configurations.
  • Assuming object mutation is automatically observable.

Interviewer follow-ups

  • What makes an OnPush view dirty?
  • How does zoneless scheduling differ from Zone.js?
  • What does detectChanges do synchronously?
  • Why can a checked component still produce no DOM work?

Senior-level perspective

Performance work should identify the dominant cost in a real interaction. Optimizing checks while layout, a 10,000-row DOM, or duplicate emissions dominate produces a technically true change with no user benefit.

Key takeaways

  • Notification, scheduling, traversal, and DOM updates are separate phases.
  • OnPush skips clean subtrees; Signals mark dependent views.
  • Profile DOM and browser cost as well as component checks.
Change DetectionAdvancedRendering2 min

What changes with OnPush change detection?

Back to library

30-second interview answer

Default-strategy views are checked during ordinary application passes. An OnPush subtree can be skipped while it is clean and becomes eligible when it receives a changed input reference, handles a bound event, reads a Signal that changes, is explicitly marked, or is otherwise affected through Angular's view rules. Immutability makes input changes easy to detect, but Angular does not enforce immutable objects.

Understand the mechanism

OnPush changes when a view subtree is eligible to be refreshed. It does not create a separate rendering engine and it does not freeze state. A clean OnPush subtree can be skipped during an application pass, which is valuable when a large part of the tree did not receive a relevant notification.

Relevant notifications include a new input value compared by Angular, a bound event handled in the subtree, a template Signal dependency changing, AsyncPipe marking the view for an emission, an explicit markForCheck, and view operations that require refresh. Events in a descendant also make Angular traverse the path needed to process that subtree.

Immutable updates make input changes and list identity predictable, which is why they pair well with OnPush. Deeply mutating an input behind the same reference can leave the child without an input-change notification. The fix is a clear ownership and update contract, not sprinkling detectChanges throughout the tree.

Immutable input ownership with an OnPush child

Angular 22
import {ChangeDetectionStrategy, Component, input, output} from '@angular/core';

@Component({
  selector: 'app-profile-card',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <h2>{{ profile().name }}</h2>
    <button (click)="promote.emit(profile().id)">Promote</button>
  `,
})
export class ProfileCard {
  readonly profile = input.required<Readonly<Profile>>();
  readonly promote = output<string>();
}

// Parent replaces the value instead of mutating profile.role in place:
profiles.update(xs => xs.map(p =>
  p.id === id ? {...p, role: 'lead'} : p
));

Trade-offs to name

  • OnPush improves skip opportunities but requires clear notification-compatible state flow.
  • Immutable copying has allocation cost; structural sharing and appropriate state granularity matter.
  • A giant dirty OnPush subtree can still do substantial work.

Why interviewers ask this

The answer exposes whether a candidate understands view eligibility, event propagation, Signals, and state ownership rather than repeating 'OnPush equals immutable inputs.'

Common candidate mistakes

  • Claiming OnPush components never check unless an @Input reference changes.
  • Mutating an input object and forcing a child check as the long-term design.
  • Assuming OnPush prevents component recreation caused by routing or structural views.

Interviewer follow-ups

  • What happens when an event originates in an OnPush descendant?
  • How does AsyncPipe notify the view?
  • How do Signals change the input-reference discussion?
  • When would detach be justified instead?

Senior-level perspective

Set a default strategy based on team conventions and measure. OnPush is most effective alongside stable component boundaries, explicit state ownership, and profiling that prevents mechanical adoption from becoming ceremony.

Key takeaways

  • OnPush controls subtree eligibility and skipping.
  • Several notifications—not only input changes—mark a view.
  • Clear immutable ownership makes updates predictable.
DIAdvancedArchitecture8 min

How does Angular dependency injection work?

Back to library

30-second interview answer

Angular DI maps a runtime token to a provider record. When code requests the token in an injection context, Angular searches the relevant element and environment injector hierarchy, creates the value from its provider factory if needed, caches it according to that injector's lifetime, and returns it. Provider placement therefore controls availability, instance count, lazy loading, cleanup, and architectural coupling.

Understand the mechanism

An injection request starts with a runtime token: usually a class or an InjectionToken. The current injection context identifies where resolution begins. Angular checks providers associated with the element and its ancestors, then the environment injector hierarchy created by the application, routes, and other environment boundaries.

A provider record explains how to produce the value: construct a class, return a value, call a factory, alias another token, or aggregate multi providers. The injector normally caches the result, so the injector that owns the provider also owns the instance lifetime. A component provider therefore creates per-subtree state, while a root provider is application-wide.

Resolution details affect bundle and architecture as well as convenience. Route providers can arrive with a lazy feature; component providers can isolate multiple instances; providedIn metadata supports tree-shakable availability. Circular dependencies often reveal confused ownership or bidirectional architecture and should usually be redesigned rather than hidden with late lookup.

Root contract with a route-scoped implementation

Angular 22
import {InjectionToken, inject} from '@angular/core';
import {Routes} from '@angular/router';

export interface AuditSink {
  record(event: AuditEvent): void;
}

export const AUDIT_SINK = new InjectionToken<AuditSink>('AUDIT_SINK');

export const routes: Routes = [{
  path: 'admin',
  providers: [
    {provide: AUDIT_SINK, useClass: AdminAuditSink},
  ],
  loadComponent: () => import('./admin-page'),
}];

export class AdminActions {
  private readonly audit = inject(AUDIT_SINK);
}

Trade-offs to name

  • Narrow scopes improve isolation but can create duplicate state and retain route resources.
  • Abstraction tokens improve substitution but too many tokens can obscure a simple dependency graph.
  • Factories enable configuration and can also hide expensive or failure-prone startup work.

Why interviewers ask this

DI questions test framework mechanics, service lifetime, lazy loading, testability, and whether a candidate can debug duplicate or missing providers.

Common candidate mistakes

  • Calling an interface an injection token even though TypeScript erases it at runtime.
  • Assuming providedIn root always means one instance across every platform or independently bootstrapped application.
  • Using useClass when useExisting was needed, creating another instance.

Interviewer follow-ups

  • Why did a component provider create duplicate state?
  • How do route providers interact with lazy loading?
  • When is inject() legal?
  • How would you break a circular dependency?

Senior-level perspective

Review providers as an ownership map. A shared mutable service at root is a global store whether or not the team calls it one, and a route-scoped service may outlive its components depending on route/injector reuse behavior.

Key takeaways

  • A runtime token resolves through an injector hierarchy.
  • Provider placement controls instance ownership and lifetime.
  • DI boundaries are architecture and loading boundaries.
RxJSAdvancedRxJS9 min

How do switchMap, mergeMap, concatMap, and exhaustMap differ?

Back to library

30-second interview answer

switchMap keeps only the newest inner stream and unsubscribes the previous one; mergeMap runs inners concurrently; concatMap queues them in order; exhaustMap ignores new sources while one inner is active. For typeahead use switchMap, independent saves may use bounded mergeMap, ordered writes may use concatMap, and double-submit prevention may use exhaustMap. The business rule chooses the operator.

Understand the mechanism

Each flattening operator maps a source value to an inner Observable. The difference is the admission and concurrency policy when another source value arrives before an existing inner completes. switchMap cancels the previous subscription, mergeMap admits concurrent work, concatMap queues work, and exhaustMap rejects new work until the active inner completes.

Cancellation means unsubscription, not guaranteed remote rollback. Angular HttpClient can abort an in-flight client request, but a server may already have committed a mutation. That is why switchMap fits discardable reads such as search, while ordered or idempotent mutation policy must reflect backend semantics.

Error placement matters. Catch inside the inner pipeline when one failed request should not kill future source events; catch outside when the entire workflow should end or recover as a unit. Completion also matters for concatMap and exhaustMap because a non-completing inner can block later work indefinitely.

Operator choice from four product rules

Angular 22 / RxJS 7
// Latest query wins: cancel stale reads.
query$.pipe(switchMap(q => http.get('/api/search', {params: {q}})));

// Uploads are independent: allow at most three concurrently.
files$.pipe(mergeMap(file => upload(file), 3));

// Writes must preserve order.
changes$.pipe(concatMap(change => save(change)));

// Ignore double-submit while checkout is running.
submit$.pipe(exhaustMap(() => checkout()));

Trade-offs to name

  • switchMap can discard a response the business needed to preserve.
  • mergeMap concurrency can saturate browser, backend, or memory without a bound.
  • concatMap preserves order by adding queue latency.
  • exhaustMap protects an active operation by intentionally ignoring later intent.

Why interviewers ask this

The four operators provide a compact test of cancellation, ordering, concurrency, product semantics, and error handling in real Angular HTTP flows.

Common candidate mistakes

  • Memorizing one use case without stating the concurrency policy.
  • Using switchMap for non-idempotent writes and assuming unsubscribe undoes server work.
  • Forgetting that an inner stream may never complete.

Interviewer follow-ups

  • Where would catchError go so the typeahead keeps working?
  • How would you bound mergeMap concurrency?
  • What happens if checkout never completes?
  • How would retries affect duplicate writes?

Senior-level perspective

Operator choice is part of the product's consistency model. Document whether user intent may be dropped, reordered, replayed, or run concurrently, and align it with backend idempotency and capacity.

Key takeaways

  • Choose from cancellation, concurrency, ordering, and admission.
  • Unsubscription is not transaction rollback.
  • Place error handling at the lifecycle that should survive.
LifecycleIntermediateRendering7 min

What lifecycle sequence should an Angular candidate understand?

Back to library

30-second interview answer

Angular constructs the class, sets initial inputs, calls ngOnChanges, then ngOnInit, followed by content initialization/check hooks and view initialization/check hooks. Render callbacks run after rendering work, and destruction callbacks release owned resources. The exact list matters less than choosing the boundary whose prerequisites are actually ready and avoiding repeated work in the checked hooks.

Understand the mechanism

Construction is a JavaScript/DI event; it is not an Angular input lifecycle. Angular creates the instance, assigns initial inputs, and reports them through ngOnChanges before ngOnInit. That makes ngOnInit the first lifecycle hook where all initial input values are available, although simple derivation is often clearer as computed state.

Projected content is initialized before the component's own view, which explains the content and view hook ordering and the availability of ContentChild versus ViewChild queries. The checked hooks may run many times and should not contain substantial work or state changes that create feedback into the same render.

Render callbacks such as afterNextRender are application rendering hooks suited to layout measurement and imperative DOM libraries; they do not run during server rendering. Destruction closes the ownership loop. Subscriptions, listeners, observers, timers, dynamic views, and library instances should be tied to DestroyRef or another explicit owner.

Input reaction, post-render DOM work, and cleanup

Angular 22
import {Component, DestroyRef, afterNextRender, inject, input} from '@angular/core';

@Component({
  selector: 'app-chart',
  template: '<canvas #canvas></canvas>',
})
export class ChartComponent {
  readonly series = input.required<readonly Point[]>();
  private readonly destroyRef = inject(DestroyRef);

  constructor() {
    afterNextRender(() => {
      const chart = createChart(/* resolved canvas */, this.series());
      this.destroyRef.onDestroy(() => chart.destroy());
    });
  }
}

Trade-offs to name

  • Lifecycle hooks are familiar but computed/input effects can express some relationships more directly.
  • Post-render measurement can cause layout work; separate DOM writes and reads.
  • Browser-only render callbacks require another path for server-rendered output.

Why interviewers ask this

Lifecycle timing reveals whether a candidate understands input ownership, projected versus view content, DOM readiness, SSR, and cleanup.

Common candidate mistakes

  • Using the constructor for input-dependent initialization.
  • Running expensive work in ngAfterViewChecked.
  • Changing parent-visible state in ngAfterViewInit and masking the resulting error with a timer.

Interviewer follow-ups

  • When is a ViewChild available?
  • Why do render callbacks not run on the server?
  • How would you react to later input changes?
  • What resources should DestroyRef own?

Senior-level perspective

Lifecycle bugs are often ownership bugs. Prefer APIs that make dependencies explicit and isolate imperative DOM integrations behind components with server fallbacks and deterministic teardown.

Key takeaways

  • Inputs, content, and view each have distinct readiness boundaries.
  • Checked hooks must stay cheap and stable.
  • Creation and cleanup should have the same owner.
StateSeniorArchitecture8 min

When does an Angular application need a global state-management library?

Back to library

30-second interview answer

A global store becomes valuable when many distant features coordinate durable state, transitions need explicit events and effects, reproducible debugging matters, or policy must be standardized across teams. Component Signals and scoped services are simpler for local workflows. Evaluate ownership, event volume, server-cache needs, testability, and team fluency; application size alone is not the threshold.

Understand the mechanism

State management starts with ownership, not a library. Component state is cheap to understand because its lifetime and consumers are local. A feature-scoped service can coordinate a workflow and expose readonly Signals or Observables. URL state supports navigation and sharing. A server-state cache solves different problems from a client event store.

A global library earns its cost when many features coordinate durable transitions, effects must be explicit, event history or devtools improve incident debugging, or multiple teams need the same state conventions. It also introduces action/reducer/effect ceremony, indirection, migration responsibility, and the risk that unrelated state accumulates in one global container.

Decide from forces: number and distance of consumers, write paths, event ordering, async effects, offline/optimistic behavior, auditability, persistence, and team skill. Adopt incrementally at a bounded domain. Do not use a global store as a cache for every HTTP response or as a replacement for component inputs.

A scoped store before a global store

Angular 22
import {Injectable, computed, signal} from '@angular/core';

@Injectable()
export class CheckoutStore {
  private readonly _items = signal<readonly CartItem[]>([]);
  readonly items = this._items.asReadonly();
  readonly total = computed(() =>
    this._items().reduce((sum, item) => sum + item.price * item.quantity, 0)
  );

  add(item: CartItem) {
    this._items.update(items => [...items, item]);
  }
}

// Provide at the checkout route so ownership and lifetime are explicit.

Trade-offs to name

  • Local stores minimize indirection but do not automatically provide event history or cross-feature policy.
  • Global stores improve standardization and tooling while increasing ceremony and coupling risk.
  • Server-state libraries and client event stores solve different consistency problems.

Why interviewers ask this

The question tests architecture judgment: candidates should discuss ownership and complexity rather than arguing for a favorite library.

Common candidate mistakes

  • Using application size as the only threshold.
  • Putting derived values and duplicate server responses into writable global state.
  • Making every component dispatch an action even when a local event is clearer.

Interviewer follow-ups

  • Where should server cache state live?
  • How would you debug a transition without a global store?
  • When would event history justify NgRx?
  • How would multiple teams share conventions without one global state object?

Senior-level perspective

A Staff decision includes organizational cost: conventions, onboarding, migrations, devtools, incident workflows, and whether the chosen pattern makes domain ownership more or less visible across teams.

Key takeaways

  • Ownership comes before library choice.
  • Global stores earn their cost through coordination and observability.
  • Adopt at a bounded domain and keep derived state derived.
PerformanceSeniorPerformance9 min

How do you investigate an Angular performance problem?

Back to library

30-second interview answer

Define the failing user journey and metric—LCP, INP, navigation time, frame drops, memory, or bundle cost. Reproduce with representative data and device constraints, then use Angular DevTools, Chrome Performance/Memory/Network, source maps, and bundle analysis to locate time and retention. Change one proven constraint, compare the same workload, and verify the user metric rather than a proxy alone.

Understand the mechanism

Performance begins with a user-visible failure and a repeatable journey. A slow first load, delayed click, janky list, growing heap, and slow route transition require different evidence. Capture the device, network, data size, cache state, route, and percentile so the result is comparable.

Split the path into network, JavaScript loading/parse, Angular work, browser rendering, and retained memory. Use bundle analysis for bytes and dependency graph, Angular DevTools for component checks and timing, Chrome Performance for main-thread tasks/layout/paint, Memory for retainers, and Network for waterfalls and duplicate requests.

Optimize the proven constraint. Move code to a lazy or @defer boundary, reduce rendered DOM, stabilize list identity, remove duplicate subscriptions, cache at an explicit owner, or redesign an expensive interaction. Verify the original metric with the same workload and add a budget or regression test that protects it.

A performance hypothesis written as an experiment

Angular 22
type PerformanceExperiment = {
  symptom: 'INP exceeds 300ms when filtering 10k rows';
  evidence: readonly [
    '180ms scripting in row templates',
    '95ms style/layout',
    '10,000 live row nodes'
  ];
  hypothesis: 'Rendered DOM and repeated row derivation dominate the interaction';
  mitigation: 'Virtualize rows and compute the filtered model once';
  verification: 'p75 INP < 200ms; same dataset/device; keyboard behavior preserved';
};

Trade-offs to name

  • Lazy loading shifts cost to navigation and can create waterfalls.
  • Caching removes work by accepting freshness and memory obligations.
  • Virtualization improves scale while adding focus, measurement, and accessibility complexity.

Why interviewers ask this

Senior candidates should connect Angular mechanisms to browser evidence and user metrics instead of listing optimization techniques.

Common candidate mistakes

  • Starting with OnPush before proving change detection is the dominant cost.
  • Measuring development mode and treating it as production behavior.
  • Reporting a smaller bundle without checking navigation or INP consequences.

Interviewer follow-ups

  • How would you diagnose a large initial bundle?
  • What evidence distinguishes a memory leak from a legitimate cache?
  • How would you profile change detection versus layout?
  • Which performance budget belongs in CI versus real-user monitoring?

Senior-level perspective

Build a performance operating model: representative journeys, field percentiles, budgets with owners, regression triage, and architecture reviews for changes that add persistent JavaScript, DOM, or third-party work.

Key takeaways

  • Define the user metric and reproduction before the tool.
  • Separate network, Angular, browser, and memory costs.
  • Verify the same journey and protect it with a budget.
SSR & HydrationSeniorArchitecture8 min

When should an Angular route use CSR, SSR, or prerendering?

Back to library

30-second interview answer

Use client rendering for authenticated, highly interactive surfaces where server HTML adds little. Use SSR when first-response content must be fresh or request-specific and early HTML improves the journey. Prerender stable, cacheable routes at build time. Modern Angular supports hybrid choices per route; include CDN caching, backend latency, hydration cost, failure modes, and operational capacity in the decision.

Understand the mechanism

Client-side rendering sends a lightweight shell and lets the browser produce the route. It keeps infrastructure simple for authenticated applications, but first content waits on JavaScript and data. Server rendering produces HTML per request, which can improve the first response and crawlability for fresh or personalized pages, while adding server capacity, caching, timeout, and request-isolation concerns.

Prerendering produces HTML at build time. It is excellent for stable routes that can be enumerated and cached globally, but content freshness is tied to rebuild and deployment. Modern Angular hybrid rendering allows different route patterns to choose client, server, or prerender behavior rather than forcing one strategy on the whole application.

Hydration is a separate client concern: it reuses server DOM and restores interaction. Incremental hydration can delay code and hydration for @defer boundaries. Rendering strategy should account for backend latency, personalization, CDN cache keys, authentication, client bundle cost, event readiness, and failure behavior—not SEO as a single yes/no switch.

Choose a render mode per route

Angular 22
import {RenderMode, ServerRoute} from '@angular/ssr';

export const serverRoutes: ServerRoute[] = [
  {path: 'docs/**', renderMode: RenderMode.Prerender},
  {path: 'catalog/:id', renderMode: RenderMode.Server},
  {path: 'account/**', renderMode: RenderMode.Client},
  {path: '**', renderMode: RenderMode.Prerender},
];

Trade-offs to name

  • SSR can improve early HTML while worsening TTFB if server dependencies are slow.
  • Prerendering scales reads well but makes build cardinality and freshness explicit costs.
  • Hydration adds client JavaScript and correctness constraints even when HTML arrived early.

Why interviewers ask this

The question tests whether a candidate can choose a delivery architecture from route and business constraints instead of saying SSR is always better.

Common candidate mistakes

  • Treating SSR, hydration, and prerendering as synonyms.
  • Using request-global mutable state and leaking one user's data into another render.
  • Ignoring CDN caching and backend latency in the SSR decision.

Interviewer follow-ups

  • How would authentication work on a server-rendered route?
  • What creates a hydration mismatch?
  • How do you avoid duplicate data requests?
  • When would incremental hydration help above the fold?

Senior-level perspective

Model rendering as a capacity and cache system. Establish request isolation, timeouts, fallbacks, CDN policy, observability, and a client-rendered escape path before using SSR for a large personalized surface.

Key takeaways

  • Choose rendering per route and user journey.
  • SSR freshness costs server work; prerender freshness costs rebuilds.
  • Hydration restores interaction and has its own constraints.
ArchitectureStaff / PrincipalArchitecture9 min

How would you structure Angular architecture for an organization with 20–30 frontend teams?

Back to library

30-second interview answer

Align deployable applications and libraries to business domains with named owners and enforced dependency direction. Standardize the paved road—Angular version, build, testing, observability, security, design-system primitives, and API clients—while letting teams own domain decisions. Use automated boundaries and compatibility tests, not review committees. Measure lead time, upgrade adoption, incidents, bundle budgets, and cross-team dependency wait time.

Understand the mechanism

Start from domain and team topology. Each business capability needs an owned boundary with a documented public API and explicit dependency direction. Repository layout is secondary: a monorepo can still have tangled ownership, and multiple repositories can still share a tightly coupled release train.

The platform layer should standardize repeated, high-risk work: supported Angular/TypeScript/Node versions, build and deployment, authentication integration, observability, security headers, testing defaults, accessibility checks, performance telemetry, API client conventions, and design-system primitives. Domain policy and user workflows remain with product teams.

Enforcement should be automated through dependency rules, package boundaries, contract tests, budgets, templates, and migrations. Governance by central review queues reduces autonomy and makes the platform a bottleneck. Measure lead time, change-failure rate, incident detection, upgrade duration, bundle/CWV trends, and cross-team dependency wait time to prove the architecture helps.

Dependency direction as an enforceable contract

Angular 22 / TypeScript
// Allowed direction:
// app shell -> domain feature -> domain model -> platform primitives
//
// Forbidden:
// platform -> product domain
// domain A internal -> domain B internal
// shared "utils" -> everything

export type DomainContract<TCommand, TEvent> = {
  execute(command: TCommand): Promise<void>;
  events(): AsyncIterable<TEvent>;
};

// Publish contracts; keep feature implementation private to its owner.

Trade-offs to name

  • More boundaries increase local ceremony and versioning responsibility.
  • A shared platform reduces duplication but can become a centralized release bottleneck.
  • Independent deployment improves autonomy while increasing runtime integration and governance cost.

Why interviewers ask this

Staff/Principal interviews test organizational architecture: the ability to create leverage and safe autonomy rather than design one application's folder tree.

Common candidate mistakes

  • Answering only with an Nx folder layout.
  • Centralizing every decision in a platform team.
  • Choosing micro-frontends before proving an independent deployment need.
  • Defining success as framework consistency rather than delivery and reliability outcomes.

Interviewer follow-ups

  • Which boundaries would the build enforce?
  • How would shared state cross independently deployed domains?
  • How does a design-system breaking change roll out?
  • Which metrics prove developer productivity improved?

Senior-level perspective

The architectural unit is the socio-technical system. A technically elegant boundary that forces five teams into one release queue is not modular in the dimension that matters.

Key takeaways

  • Align architecture to domains and named ownership.
  • Standardize the paved road, not every product decision.
  • Automate boundaries and measure delivery outcomes.
ProductionSeniorDebugging9 min

Memory increases every time users navigate between two Angular pages. How do you find the leak?

Back to library

30-second interview answer

Automate a navigation loop, force comparable garbage-collection conditions, and verify the retained heap grows after components should be destroyed. Compare heap snapshots and dominator/retainer paths for component instances, detached DOM, subscriptions, listeners, timers, overlays, caches, and third-party objects. Fix the retaining owner, repeat the same loop, and verify both heap stabilization and correct feature behavior.

Understand the mechanism

First prove retention. A high heap during work may be legitimate allocation that the collector later reclaims. Automate navigation between the two routes, pause at a consistent state, and compare heap after similar collection conditions. If destroyed component instances or their DOM keep accumulating, the retained graph is the evidence.

Use heap snapshot comparison and dominator/retainer paths to find the owning root. Common roots include a long-lived service Subject, an unremoved event listener, timer, ResizeObserver, overlay container, third-party widget registry, cached view, route reuse strategy, or a closure stored in a library. The subscription itself is not always the owner; follow the exact path.

Fix the lifetime at the creator. Use AsyncPipe, takeUntilDestroyed, DestroyRef cleanup, bounded caches, or correct third-party destruction as appropriate. Then rerun the same loop, verify the post-GC floor stabilizes, and check that the intended shared state still survives when it should.

Bind a browser listener and stream to the component lifetime

Angular 22
import {Component, DestroyRef, inject} from '@angular/core';
import {takeUntilDestroyed} from '@angular/core/rxjs-interop';

@Component({selector: 'app-live-chart', template: '<canvas />'})
export class LiveChart {
  private readonly destroyRef = inject(DestroyRef);

  constructor(feed: PriceFeed) {
    feed.prices
      .pipe(takeUntilDestroyed(this.destroyRef))
      .subscribe(price => this.render(price));

    const onResize = () => this.resize();
    window.addEventListener('resize', onResize);
    this.destroyRef.onDestroy(() =>
      window.removeEventListener('resize', onResize)
    );
  }
}

Investigation path

  1. 01Reproduce a fixed navigation loop with production-scale data.
  2. 02Confirm the post-GC retained heap, DOM nodes, or component count grows.
  3. 03Compare heap snapshots and follow dominator/retainer paths to a live root.
  4. 04Map that root to the resource creator and intended lifetime.
  5. 05Fix ownership, rerun the loop, and verify a stable heap floor plus correct behavior.

Trade-offs to name

  • A cache or route-reused view may intentionally retain memory; the question is whether the bound and policy are correct.
  • Aggressive teardown can destroy useful shared state or create repeated initialization work.
  • Heap snapshots are intrusive, so production diagnosis may begin with lower-overhead counters and sampled profiles.

Why interviewers ask this

The scenario distinguishes cleanup folklore from evidence-based memory diagnosis and tests understanding of Angular, browser, RxJS, router, and service lifetimes.

Common candidate mistakes

  • Calling any high heap usage a leak without showing retained growth.
  • Adding unsubscribe everywhere without identifying the retaining root.
  • Ignoring detached DOM, listeners, observers, overlays, and third-party registries.

Interviewer follow-ups

  • How do you distinguish a cache from a leak?
  • Why might a route provider remain alive after navigation?
  • What does a dominator tell you?
  • How would you investigate safely in production?

Senior-level perspective

Production readiness includes lightweight counters for component/view churn, cache size, DOM nodes, and long-lived subscriptions, plus a safe profiling playbook and soak tests for screens designed to run all day.

Key takeaways

  • Prove retained growth before naming a leak.
  • Follow the retaining path to the actual owner.
  • Verify the same loop stabilizes after the fix.

How this Angular hub is maintained

Questions cover durable mechanisms and the decisions engineers make with them. Level labels describe reasoning depth, not claims about any employer's interview frequency. Modern, evergreen, and legacy-relevant labels keep current practice distinct from migration knowledge.

  • Version-specific claims link to official Angular documentation.
  • Examples use TypeScript and modern standalone Angular unless legacy context is the subject.
  • Counts, categories, and depth metrics are calculated from the source catalog.
  • Production scenarios require evidence, mitigation, and verification—not magic configuration.

Continue with focused Angular guides

Use the library for interview rehearsal, then follow these existing guides for implementation detail and migration context.

Browse every Angular article

Connect Angular depth to the rest of the interview

Pair framework depth with JavaScript semantics, system design, architecture judgment, or a personalized preparation plan.

Build a prep roadmap