NestJSDIRequest pipeline

NestJS Interview Questions

NestJS interviews concentrate on two structures: the dependency injection container and the request pipeline. Nearly every question is about one of them — what scope a provider has and what that means under concurrency, or which of guards, interceptors, pipes and filters runs when and what each is actually for.

The failure that shows up most is a candidate comfortable with the decorators and unclear on the semantics behind them. Providers are singletons by default, so a service holding per-request state is shared across concurrent requests — a data race that no single-user test will reveal. It is the NestJS equivalent of the Spring singleton bug and it is asked for the same reason.

Written and reviewed by Sahil Srivastav

What the bar actually is

You should know the default provider scope is singleton, what request scope costs — the provider and its dependency subtree are instantiated per request — and that request-scoped providers bubble: anything depending on one becomes request-scoped too. That cascade is the detail candidates miss and interviewers probe.

On the pipeline you are expected to place responsibilities correctly: guards for authorisation decisions, pipes for validation and transformation of inputs, interceptors for cross-cutting concerns wrapping the handler, exception filters for shaping errors. Putting authorisation in an interceptor or validation in the controller body is the kind of structural mistake that gets flagged.

How the rounds are structured

Machine coding with NestJS

Modules, controllers, providers for a small feature. Structure and where responsibilities sit are scored alongside working endpoints.

Dependency injection and scope

Provider scope, custom providers, circular dependencies, and what request scope costs. The core NestJS round.

Request pipeline ordering

Guards, interceptors, pipes and filters: execution order and what belongs in each. Frequently asked as a debugging scenario.

Persistence and transactions

TypeORM or Prisma: where a transaction boundary lives when the work spans services, and how it is propagated.

What this interview bar tests

Singleton by default

Providers are shared across all requests. Per-request mutable state on a service is a race that passes every single-user test and corrupts under concurrency.

Request scope cascades

Making one provider request-scoped forces everything that depends on it to be instantiated per request too. The performance consequence surprises people.

Pipeline responsibilities

Guards decide access, pipes validate and transform input, interceptors wrap the handler, filters shape errors. Misplacing these is a structural smell reviewers notice.

Transactions across services

A boundary spanning two service methods needs the transaction or manager passed explicitly. Relying on ambient context is where silent partial writes come from.

A preparation plan that works

  1. 1Give a singleton provider a mutable field, hit it with concurrent requests, and watch the state cross between them. One demonstration makes the scope answer permanent.
  2. 2Build a feature using guards, a validation pipe, an interceptor and an exception filter, then log the order they execute. Having observed it beats having memorised it.
  3. 3Write a transaction spanning two service methods and make the second one fail. Confirm whether the first rolled back — then fix it by passing the transaction explicitly.
  4. 4Create a circular dependency on purpose, read the error, and resolve it with `forwardRef`. It comes up often and the error message is initially opaque.

Questions you should expect

What scope are providers by default, and why does it matter?

Singleton — one instance shared across every request for the application lifetime. It matters because any mutable instance state is shared concurrently, so storing the current user or a request id on a service is a data race. State should be passed as parameters, or held in a request-scoped provider if it genuinely must live somewhere.

What does making a provider request-scoped cost?

Instantiation per request for that provider and for everything in its dependency subtree, because request scope bubbles up to consumers. A single request-scoped provider deep in a widely-used chain can make a surprising amount of your application per-request, which is why it should be a deliberate decision rather than a convenience.

Guard, pipe or interceptor for this?

Guard for an access decision — can this caller do this at all. Pipe for validating and transforming the incoming payload. Interceptor for cross-cutting behaviour around the handler such as logging, caching or response mapping. Exception filter for turning a thrown error into a response shape. Authorisation in an interceptor runs too late to be the access control you wanted.

A transaction spans two service methods. How do you handle it?

Pass the transactional manager or client explicitly through the call, or run both inside a single transaction callback at the orchestrating layer. What does not work is each method opening its own transaction and assuming they compose — the second failing then leaves the first committed, which is a silent partial write.

What gets candidates rejected

  • Storing per-request state on a singleton provider
  • Making providers request-scoped without understanding that the scope cascades
  • Authorisation logic in an interceptor rather than a guard
  • Validation in the controller body instead of a pipe
  • Each service method opening its own transaction and assuming they compose
  • Resolving circular dependencies by restructuring around the error rather than understanding it
  • Knowing the decorators without being able to explain the semantics they configure

What to practise, in order

Webhook event idempotency and ordering

At-least-once delivery handled at the endpoint, with duplicates and reordering driven by the test suite.

Database connection pool exhaustion

Connection lifecycle failures that a bigger pool cannot fix, with tests asserting the invariant.

Wallet transaction and refund system

A transaction boundary spanning multiple operations, where a repeated refund must not apply twice.

Subscription billing and proration engine

Business rules complex enough that structure matters, and an extension the interviewer will add.

Practise in a real repository

Gronex ships broken backend repositories with failing test suites that encode the production invariant. You read the evidence, find the defect, and make the tests pass — which is what the round actually measures, rather than whether you can recite a definition.

FAQ

Is NestJS knowledge transferable from Spring?

Substantially — modules, DI and the interceptor pipeline are deliberately similar, and the singleton-state bug is identical in both. The differences that matter are the single-threaded event loop underneath, which changes how blocking work behaves, and explicit transaction propagation rather than proxy-based ambient transactions.

TypeORM or Prisma in interviews?

Either, and you should know your chosen one's failure modes: lazy relation behaviour and N+1 queries for TypeORM, transaction and connection handling for Prisma. Interviewers probe query counts and transaction boundaries regardless of which you name.

How much does the event loop matter in a NestJS round?

More than candidates expect, because NestJS runs on Node. A blocking operation inside a handler stalls every concurrent request on that instance, and NestJS does nothing to protect you from it. Expect at least one question that is really a Node question.

Are microservice features asked about?

If the role uses them. The useful depth is about delivery semantics and failure handling — what happens to an in-flight message on restart — rather than transport configuration.

Related

Other preparation tracks