NestJS Interview Questions

Real NestJS interview questions and answers covering DI, modules, guards, pipes, interceptors, and decorators.

A curated set of NestJS interview questions, ordered roughly from architecture to implementation detail — the kind you'll actually be asked in real screens and on-sites.

Architecture and comparisons

Q: How does NestJS compare to building the same API in plain Express? Express gives you routing and middleware and leaves everything else — project structure, dependency injection, validation, testing conventions — up to the team. NestJS is built on top of Express (or Fastify) but adds an opinionated, Angular-inspired structure: modules, controllers, and providers wired together by a built-in DI container, plus first-party packages for common concerns like config, ORMs, and validation. The tradeoff is a steeper learning curve and more boilerplate for very small services, in exchange for consistency and testability as an application and team grow.

Q: What does the @Module() decorator actually do, and what are its four properties for? @Module() groups a related set of controllers and providers and declares how the module relates to the rest of the app. controllers and providers register classes the module owns; imports pulls in other modules whose exported providers this one needs; exports decides which of this module's own providers are visible to modules that import it. Nest reads these decorators at startup to build the full dependency graph before the application starts serving requests.

Q: What's the difference between a Guard, a Pipe, and an Interceptor? A Guard decides whether a request is allowed to reach a route handler at all — typically authentication/authorization — and runs first. A Pipe transforms and validates the arguments that will be passed to the handler, such as parsing a route param or validating a request body against a DTO. An Interceptor wraps around the handler itself, able to run logic both before it executes and after it returns (useful for logging, timing, or reshaping the response), and can even short-circuit the handler entirely.

Q: How does constructor-based dependency injection work in Nest, under the hood? When a class needs a dependency, it declares it as a constructor parameter typed to the provider's class; Nest reads each parameter's type via reflect-metadata (populated by TypeScript's emitDecoratorMetadata compiler option) and uses it as the lookup key in its DI container. At startup, Nest walks the module graph, instantiates each provider it discovers — resolving its own dependencies first if it has any — and injects the resulting singleton instance wherever it's requested.

Q: Why does NestJS use the legacy experimentalDecorators syntax instead of the newer standard TypeScript decorators? NestJS predates the finalized TC39 decorators proposal and was built against TypeScript's original, non-standard decorator implementation, which pairs with the reflect-metadata package to expose a constructor parameter's type information at runtime — something Nest's DI container depends on directly. The modern standard decorators (stable since TypeScript 5.0) use a different underlying mechanism and don't provide that same runtime type metadata in the way Nest's DI needs, so a framework-level change would be required to use them instead.

Q: What's the difference between a singleton-scoped provider (the default) and a request-scoped one? A singleton provider is instantiated once for the lifetime of the application and reused for every request — the default, and the right choice for almost everything, since it avoids the cost of recreating objects per request. A request-scoped provider (@Injectable({ scope: Scope.REQUEST })) is instantiated fresh for every incoming request, useful when a provider needs to hold per-request state (like the current authenticated user), at the cost of losing the performance benefit of reuse and requiring every consumer up the dependency chain to also become request-scoped.

Testing and microservices

Q: How do you unit test a Nest service that depends on another provider? With Test.createTestingModule, registering the class under test alongside an override for its dependency — { provide: TheDependencyClass, useValue: fakeImplementation } — then resolving the class under test with module.get(...). This mirrors exactly how the real DI container would wire it up, but with a lightweight fake standing in for the real collaborator, keeping the test fast and isolated.

Q: What's the difference between a Nest unit test and an e2e test? A unit test fakes every collaborator of the class under test and never boots the wider application. An e2e test compiles the real module graph (Test.createTestingModule({ imports: [AppModule] })), creates a genuine running application instance, and issues real HTTP requests against it (typically via supertest) — exercising routing, guards, and pipes together, not just one class's internal logic.

Q: What's the difference between @MessagePattern and @EventPattern in a Nest microservice? @MessagePattern handles a message that expects a reply sent back to the caller — paired with ClientProxy.send() on the calling side, analogous to a normal request/response call. @EventPattern handles a fire-and-forget notification with no reply expected at all — paired with ClientProxy.emit().