Skip to content

Full Stack Angular Engineer Interview Questions & Answers

40 questions for Full Stack Angular Engineer interviews — 4 easy, 31 medium, 5 hard.

About the Full Stack Angular Engineer role

A Full Stack Angular Engineer with a few years of experience owns modules end to end. You design shared TypeScript models, plan API contracts with the frontend structure, choose state management approaches, write unit and integration tests and manage deployments. You review code, guide juniors and work directly with business analysts or clients to clarify requirements and deliver features on schedule.

Module ownership State management API contracts Testing CI/CD
Solved for this roleStart practicing
3 QUESTIONS FREESign up to unlock the full question bank and track your progress.Unlock every question and answer, then continue practising company-wise and package-wise.
3 questions free Unlock the rest in seconds
01

How should HTTP errors be handled in an Angular application?

Save to ▾
Show answer
Handle them at two levels. A global error interceptor catches HttpErrorResponse, redirects to login on 401, shows a toast for 500 errors and logs details. Component or service code uses catchError to provide fallbacks or show specific messages, such as field errors from a 422 response. Use retry with a delay for transient network failures, and never leave errors unhandled so the UI shows a blank state.
02

What is the inject() function and how does it compare to constructor injection?

Save to ▾
Show answer
inject() retrieves a dependency inside an injection context, such as a field initialiser, constructor, factory or functional guard. It removes long constructor parameter lists, works in plain functions like functional guards, interceptors and resolvers, and makes inheritance simpler because subclasses do not need to pass dependencies to super. Constructor injection still works, but modern Angular code and CLI templates favour inject().
03

Implement a type-ahead search box that calls the API only after the user pauses typing and ignores outdated results. Which RxJS approach would you use?

Save to ▾
Show answer
Take the input stream from a FormControl's valueChanges or toObservable of a signal, then pipe debounceTime(300) to wait for a pause, map to trimmed text, filter out terms shorter than two characters, distinctUntilChanged to skip repeats, and switchMap to call the API, which cancels any in-flight request when a new term arrives. Add catchError inside switchMap so one failed request does not kill the stream.
04

How does Angular protect against cross-site scripting?

Save to ▾
Show answer
Angular treats all values as untrusted by default and sanitises them before inserting into the DOM: interpolation escapes HTML, and binding to innerHTML, styles or URLs is sanitised to strip dangerous content. Bypass methods in DomSanitizer, like bypassSecurityTrustHtml, should be used only for trusted content. Avoid direct DOM manipulation through ElementRef with user data, and add a Content Security Policy for defence in depth.
05

Write a functional HTTP interceptor that adds a JWT and handles 401 errors.

Save to ▾
Show answer
Register with provideHttpClient(withInterceptors([authInterceptor])). export const authInterceptor: HttpInterceptorFn = (req, next) => { const auth = inject(AuthService); const router = inject(Router); const token = auth.token(); const authReq = token ? req.clone({ setHeaders: { Authorization: `Bearer ${token}` } }) : req; return next(authReq).pipe( catchError((err: HttpErrorResponse) => { if (err.status === 401) { auth.logout(); router.navigate(['/login']); } return throwError(() => err); }) ); };
06

A dashboard needs data from three independent APIs before it can render. How would you load them?

Save to ▾
Show answer
Use forkJoin to run all three requests in parallel and emit once when all complete, giving an object or array of results. Handle errors per request with catchError returning a fallback value, so one failed widget does not block the whole dashboard. If any source emits repeatedly, use combineLatest instead. With signals, you could use three httpResource instances and a computed for the combined loading state.
07

Create a text index and run a relevance-sorted search in MongoDB.

Save to ▾
Show answer
Text search with scores: db.articles.createIndex({ title: 'text', body: 'text' }, { weights: { title: 5, body: 1 } }) db.articles.find( { $text: { $search: 'angular signals' } }, { score: { $meta: 'textScore' }, title: 1 } ).sort({ score: { $meta: 'textScore' } }).limit(10) Weights make title matches rank higher. A collection can have only one text index, so include all searchable fields in it.
08

What is the role of a controller-service-repository structure in an Express API?

Save to ▾
Show answer
Controllers handle HTTP: they read request data, call services and format responses with status codes. Services contain business rules, such as checking stock before creating an order, and are independent of Express. Repositories or models encapsulate database access through Mongoose. This separation makes code easier to test, lets you reuse services in jobs or other transports, and stops route files from turning into large unmaintainable blocks.
09

Write a functional auth guard that redirects unauthenticated users to the login page.

Save to ▾
Show answer
Return a UrlTree to redirect. import { inject } from '@angular/core'; import { CanActivateFn, Router } from '@angular/router'; import { AuthService } from './auth.service'; export const authGuard: CanActivateFn = (route, state) => { const auth = inject(AuthService); const router = inject(Router); return auth.isLoggedIn() ? true : router.createUrlTree(['/login'], { queryParams: { returnUrl: state.url } }); }; // { path: 'orders', canActivate: [authGuard], loadComponent: ... }
10

What is the difference between a cold and a hot Observable?

Save to ▾
Show answer
A cold Observable starts producing values when each subscriber subscribes, and every subscriber gets its own independent execution; an HttpClient call is cold, so two subscriptions send two requests. A hot Observable produces values regardless of subscribers, and subscribers share the same stream, like mouse events or a websocket. You can make a cold Observable shared with operators like share or shareReplay.
11

Explain the difference between switchMap, mergeMap, concatMap and exhaustMap.

Save to ▾
Show answer
All map each source value to an inner Observable but differ in concurrency. switchMap cancels the previous inner Observable, ideal for search. mergeMap runs all inner Observables in parallel, good for independent uploads. concatMap queues them and runs one at a time in order, good for sequential saves. exhaustMap ignores new values while one is active, ideal for preventing duplicate login or submit clicks.
12

Tell me about a data modelling decision you made and how it worked out.

Save to ▾
Show answer
Situation: in a learning portal, I first embedded all quiz attempts inside each user document. Task: attempts grew quickly and user loads became slow. Action: I moved attempts to their own collection with an index on userId and quizId, kept a small summary of best scores on the user, and wrote a migration script. Result: profile pages became much faster and reporting queries became simpler.
13

How does lazy loading work with the Angular router?

Save to ▾
Show answer
Lazy loading defers downloading a feature's code until the user navigates to it. Use loadComponent: () => import('./admin/admin.component').then(m => m.AdminComponent) for a single component, or loadChildren to load a file of child routes. The CLI builds a separate chunk for each lazy route. You can add preloading strategies like withPreloading(PreloadAllModules) to fetch lazy chunks in the background after startup.
14

Test an Angular service's HTTP call with HttpTestingController.

Save to ▾
Show answer
Capture and flush the request. describe('ProductService', () => { let service: ProductService; let httpMock: HttpTestingController; beforeEach(() => { TestBed.configureTestingModule({ providers: [provideHttpClient(), provideHttpClientTesting()] }); service = TestBed.inject(ProductService); httpMock = TestBed.inject(HttpTestingController); }); it('fetches products', () => { service.getAll().subscribe((p) => expect(p.length).toBe(1)); const req = httpMock.expectOne('/api/products'); expect(req.request.method).toBe('GET'); req.flush([{ _id: '1', name: 'Pen' }]); httpMock.verify(); }); });
15

Write an injectable service that fetches and caches a list of categories.

Save to ▾
Show answer
Cache the Observable with shareReplay so the API is called once. import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable, shareReplay } from 'rxjs'; export interface Category { _id: string; name: string } @Injectable({ providedIn: 'root' }) export class CategoryService { private http = inject(HttpClient); private categories$?: Observable<Category[]>; getAll(): Observable<Category[]> { this.categories$ ??= this.http.get<Category[]>('/api/categories') .pipe(shareReplay({ bufferSize: 1, refCount: false })); return this.categories$; } }
16

What is the difference between signal, computed and effect?

Save to ▾
Show answer
signal() creates writable state. computed() derives a read-only value from other signals, is lazily evaluated and memoised, and recalculates only when its dependencies change, for example a cart total from cart items. effect() runs side effects whenever signals it reads change, such as logging or syncing to local storage. Use computed for derived data and keep effects for non-UI side effects, not for setting other state.
17

Write a cart service using signals with computed totals.

Save to ▾
Show answer
Expose read-only state and mutation methods. @Injectable({ providedIn: 'root' }) export class CartService { private items = signal<CartItem[]>([]); readonly cart = this.items.asReadonly(); readonly count = computed(() => this.items().reduce((n, i) => n + i.qty, 0)); readonly total = computed(() => this.items().reduce((s, i) => s + i.qty * i.price, 0)); add(product: Product) { this.items.update((list) => { const found = list.find((i) => i.id === product.id); return found ? list.map((i) => (i.id === product.id ? { ...i, qty: i.qty + 1 } : i)) : [...list, { ...product, qty: 1 }]; }); } remove(id: string) { this.items.update((l) => l.filter((i) => i.id !== id)); } }
18

How do containers and orchestration fit into deploying a MEAN stack?

Save to ▾
Show answer
Docker packages the Express API and an Nginx image serving the Angular build into portable images with all dependencies. docker compose runs them with MongoDB locally. In production, services like AWS ECS, Azure Container Apps or Kubernetes run multiple replicas, perform rolling updates, restart failed containers and scale on load. Images are built and pushed to a registry by the CI pipeline, tagged by commit.
19

Describe how you handled a situation where requirements changed late in a sprint.

Save to ▾
Show answer
Situation: two days before release, the client asked to add role-based access to a reporting page. Task: deliver without breaking the release. Action: I clarified the minimum needed with the product owner, implemented a canMatch guard and hid admin actions, and coordinated with the backend developer for API checks, while moving extra filters to the next sprint. Result: we released on time and the client approved the change.
20

How do you design an API endpoint that returns a dashboard summary quickly when the underlying data is large?

Save to ▾
Show answer
Avoid heavy aggregation on every request. Precompute summaries with scheduled jobs or on write events and store them in a summary collection, cache the response in Redis with a short TTL, and return only the fields the dashboard needs. Use indexes for any live queries, add pagination for detail lists, and expose a separate endpoint for drill-down data so the first load stays fast.
21

How do you test an Angular service that makes HTTP calls?

Save to ▾
Show answer
Provide provideHttpClient() and provideHttpClientTesting() in TestBed, then inject the service and HttpTestingController. Call the service method and subscribe, use httpMock.expectOne('/api/products') to capture the request, assert its method and body, and flush a fake response. Finally call httpMock.verify() to ensure no unexpected requests remain. This tests the service logic without a real backend.
22

Write a role-based canMatch guard that only matches admin users.

Save to ▾
Show answer
Guard factories keep it reusable. import { inject } from '@angular/core'; import { CanMatchFn, Router } from '@angular/router'; export const roleGuard = (role: string): CanMatchFn => () => { const auth = inject(AuthService); const router = inject(Router); return auth.user()?.role === role ? true : router.createUrlTree(['/forbidden']); }; export const routes = [ { path: 'admin', canMatch: [roleGuard('admin')], loadChildren: () => import('./admin/admin.routes').then(m => m.ADMIN_ROUTES) } ];
23

A penetration test report says your API returns other users' invoices when the invoice id is changed. How do you fix it?

Save to ▾
Show answer
This is broken object-level authorization, the top API risk in the OWASP list. Fix every query to scope by the authenticated user, for example Invoice.findOne({ _id: id, userId: req.user.id }), and return 404 when not found. Centralise ownership checks in services or middleware, add tests that try cross-user access, and review similar endpoints. Avoid relying on unguessable ids as protection.
24

What is hierarchical dependency injection in Angular?

Save to ▾
Show answer
Angular has a tree of injectors that mirrors the application. Environment injectors come from the root and lazy routes, and element injectors come from components and directives. When a dependency is requested, Angular searches upward from the requesting element to the root. Providing a service at component level creates an isolated instance for that subtree. Modifiers like optional, self, skipSelf and host control this lookup.
25

Explain dependency injection in Angular.

Save to ▾
Show answer
Dependency injection means a class asks for what it needs instead of creating it. Angular's injector creates instances based on providers and supplies them when a component or service requests them, either through constructor parameters or the inject() function. This decouples code, enables singletons, and lets tests or different environments swap implementations, for example providing a mock AuthService in unit tests.
26

Write an Nginx server block that serves Angular and proxies /api to Node.

Save to ▾
Show answer
One domain, no CORS needed. server { listen 80; server_name shop.example.com; root /usr/share/nginx/html; location /api/ { proxy_pass http://api:3000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location / { try_files $uri $uri/ /index.html; } location ~* \.(js|css|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } } Angular hashed file names make long caching safe.
27

Admin routes are protected by a guard, but the admin feature code is still downloaded by every user. How do you fix this?

Save to ▾
Show answer
canActivate does not stop the route from matching, so its lazy chunk can still be downloaded, for example by a preloading strategy. Use a canMatch guard on the lazy admin route instead, so the route definition does not match for non-admin users and its code is never loaded; they fall through to another route or a not-authorised page. Keep the real security on the API, since frontend code is always visible.
28

Your API needs to send welcome emails and SMS after signup, but this makes signup slow. What would you change?

Save to ▾
Show answer
Do not make the user wait for third-party providers. After saving the user, publish an event or add jobs to a queue and return the response immediately. Workers send the email and SMS with retries and backoff, and failures are logged without affecting signup. An EventEmitter is enough for a quick in-process version, but a persistent queue survives restarts and scales across instances.
29

How do real-time features work in a MEAN application?

Save to ▾
Show answer
Use WebSockets, commonly through Socket.IO on the Express server and its client library in an Angular service that exposes events as Observables or signals. The server emits events, such as new chat messages or order status changes, to rooms of interested users. For scaling across instances, add a Redis adapter. Server-sent events are a simpler option for one-way updates like notifications or live dashboards.
30

Write a multi-stage Dockerfile that builds Angular and serves it with Nginx.

Save to ▾
Show answer
Build in Node, ship only static files. FROM node:22-alpine AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npx ng build --configuration production FROM nginx:alpine COPY nginx.conf /etc/nginx/conf.d/default.conf COPY --from=build /app/dist/shop/browser /usr/share/nginx/html EXPOSE 80 The final image contains no Node.js or source code. nginx.conf should include try_files $uri /index.html for Angular routes.
31

How do you serve an Angular build and an Express API from the same Node server?

Save to ▾
Show answer
Build Angular with ng build, which outputs static files to dist/project/browser. In Express, register API routes under /api first, then serve the static files with express.static, and finally add a catch-all GET route that returns index.html so Angular routing works on refresh. In larger deployments, Nginx or a CDN usually serves the Angular files while Express handles only the API.
32

Describe a time you helped a teammate who was struggling with RxJS.

Save to ▾
Show answer
Situation: a new teammate kept writing nested subscribes and could not follow our streams. Task: help him become productive quickly. Action: I drew marble diagrams for map, switchMap and combineLatest, paired with him to refactor one of his components, and shared a short list of the operators we use most with examples. Result: within two weeks his pull requests used flattening operators correctly and he started reviewing others.
33

Your app must call different API base URLs for development, staging and production. How do you configure this in Angular?

Save to ▾
Show answer
Use environment files such as environment.ts and environment.prod.ts with fileReplacements in angular.json build configurations, or load a config.json at startup with provideAppInitializer so one build works in every environment. Expose the URL through an InjectionToken and inject it in services or an interceptor. Never put secrets in these files, because everything in the Angular bundle is public.
34

How is routing configured in a standalone Angular application?

Save to ▾
Show answer
You define a Routes array mapping paths to components, with redirectTo, child routes and a wildcard ** route for 404 pages, and register it with provideRouter(routes) in app.config.ts. The root template contains <router-outlet />, links use routerLink and routerLinkActive, and code navigates with Router.navigate. Features such as withComponentInputBinding let route parameters bind directly to component inputs.
35

What is a route resolver and when would you use one?

Save to ▾
Show answer
A resolver fetches data before a route activates, so the component receives ready data instead of showing an empty state first. A functional resolver, ResolveFn<Product>, uses inject() to call a service and returns an Observable or Promise. The data is available through ActivatedRoute or bound inputs. Use it for detail pages that are useless without data, but avoid it for slow calls, because navigation waits.
36

Configure an Angular dev server proxy to forward API calls to Express.

Save to ▾
Show answer
proxy.conf.json in the Angular project: { "/api": { "target": "http://localhost:3000", "secure": false, "changeOrigin": true, "logLevel": "debug" } } angular.json, under serve options: "proxyConfig": "proxy.conf.json" Then call relative URLs in services, such as this.http.get('/api/products'), and run ng serve. The browser talks only to the dev server, so no CORS setup is needed locally.
37

An npm audit shows several high-severity vulnerabilities in the Express project. How do you handle it?

Save to ▾
Show answer
Read each advisory to see whether the vulnerable code path is actually used in production or only in dev tooling. Run npm audit fix for safe updates, upgrade direct dependencies that pull vulnerable transitive packages, and use overrides in package.json if a fix is not yet released upstream. Test thoroughly after upgrading, enable Dependabot or Renovate for continuous updates and track any accepted risks.
38

Write a type-ahead search using a reactive FormControl and RxJS operators.

Save to ▾
Show answer
switchMap cancels stale requests. export class SearchComponent { private api = inject(ProductService); search = new FormControl('', { nonNullable: true }); results = toSignal( this.search.valueChanges.pipe( debounceTime(300), map((t) => t.trim()), distinctUntilChanged(), filter((t) => t.length >= 2), switchMap((t) => this.api.search(t).pipe(catchError(() => of([])))) ), { initialValue: [] } ); } // template: <input [formControl]='search'> @for (p of results(); track p._id) {...}
39

Serve the built Angular app and the API from one Express server.

Save to ▾
Show answer
API first, static files next, fallback last. import express from 'express'; import path from 'node:path'; const app = express(); app.use(express.json()); app.use('/api', apiRouter); const dist = path.join(process.cwd(), 'dist/shop/browser'); app.use(express.static(dist, { maxAge: '1y', index: false })); app.get('/*splat', (req, res) => { res.sendFile(path.join(dist, 'index.html')); }); app.listen(process.env.PORT || 3000); The named wildcard follows Express 5 path syntax.
40

Tell me about a time you fixed a difficult asynchronous bug.

Save to ▾
Show answer
Situation: users sometimes saw another customer's details after quickly switching between records. Task: find the cause in a busy sprint. Action: I reproduced it with network throttling and found nested subscribes, where slow responses for an earlier id arrived last. I replaced them with switchMap so stale requests were cancelled, and added a test with delayed responses. Result: the bug disappeared and we added a review rule against nested subscribes.

Frequently asked questions

What does a Full Stack Angular Engineer do?

A Full Stack Angular Engineer with a few years of experience owns modules end to end. You design shared TypeScript models, plan API contracts with the frontend structure, choose state management approaches, write unit and integration tests and manage deployments. You review code, guide juniors and work directly with business analysts or clients to clarify requirements and deliver features on schedule.

Which skills are tested in a Full Stack Angular Engineer interview?

Expect questions on Module ownership, State management, API contracts, Testing, CI/CD. Most rounds also ask you to explain a project and solve one practical problem live.

How do I prepare for a Full Stack Angular Engineer interview?

Revise RxJS, Signals and State Management, Services, Dependency Injection and Routing, Node.js and Express APIs, Security, Testing and Deployment first using the topic sheets, practise the questions on this page aloud, then do one full mock interview to practise timing.