§ Hiring Tips·7 min read·October 12, 2026

NestJS Interview Questions: 5 Answered, Basic to Advanced

O
Olibr TeamHiring Tips
NestJS Interview Questions: 5 Answered, Basic to Advanced

NestJS Interview Questions: 5 Answered, Basic to Advanced

A good set of nest js interview questions tests how a developer thinks about structure, not whether they can recite decorator names. The five questions below move from modules and dependency injection to the request lifecycle, circular dependencies, and dynamic modules. Juniors should master the first two. Mid-level developers should add the request lifecycle. Senior candidates are separated by the last two.

Most lists stop at one-line definitions. Interviewers get no signal on depth, and candidates memorize answers that fall apart at the first follow-up. Each question here comes with what it tests, a benchmark answer, and a follow-up that exposes real hands-on experience. The code samples are short and written in TypeScript.

We wrote this at Olibr, a recruiting platform used by recruiters and hiring teams across India and the US, because screening Node.js backend roles is a routine task for them. Use the answers as a scoring guide when you interview, or as a self-check when you prepare.

1. What are modules, controllers, and providers?

Level and what it tests

A dollhouse building with three enclosed rooms, a key on one door, and a rope linking two doors.

This is the beginner question that opens almost every NestJS interview. It shows whether the candidate understands how a Nest app is organized, which every later NestJS interview question builds on. Weak candidates define each term in isolation. Strong ones explain how the three connect.

A strong answer

A module groups related code. A controller maps incoming HTTP requests to handler methods. A provider is any class Nest can inject, usually a service that holds business logic. The @Module() decorator ties them together with four properties:

  • imports: other modules whose exported providers this module needs.
  • controllers: the controllers this module owns.
  • providers: the classes Nest instantiates and can inject inside this module.
  • exports: the providers other modules are allowed to use.

Every app has a root module, usually AppModule. Providers stay private to their module until that module exports them.

A provider is invisible outside its module until that module exports it.

Follow-up to ask next

Ask this: "A service works in one module but throws a dependency error in another. Why?" The cause is a missing exports entry or a missing imports entry. Candidates who have debugged this answer in seconds.

2. How does dependency injection work in NestJS?

Level and what it tests

A central container branching into four ways to supply providers: useClass, useValue, useFactory, and useExisting.

This is a core intermediate question. It checks whether the candidate understands what the framework does for them, not just how to type constructor(private service: X). It also reveals whether they have written tests, because mocking depends on DI.

A strong answer

Nest runs an inversion of control container. A class marked @Injectable() is registered as a provider in a module. When another class lists it in its constructor, Nest reads the emitted TypeScript type metadata, finds the matching provider, and injects it. Providers are singletons by default.

Custom providers cover cases where a class is not enough. The forms are useClass, useValue, useFactory, and useExisting, with a string or symbol token consumed through @Inject().

{
  provide: 'PAYMENTS_CLIENT',
  useFactory: (config: ConfigService) =>
    new PaymentsClient(config.get('PAYMENTS_KEY')),
  inject: [ConfigService],
}

Scopes matter too. Besides the default, a provider can be REQUEST scoped or TRANSIENT. Request scope bubbles up to every class that depends on it, and each request creates new instances.

Singleton is the default, so request-scoped providers are a deliberate cost, not a free option.

Follow-up to ask next

Ask when they would accept that cost. Per-request tenant context is a fair answer. Then ask how they would mock a provider in a Jest test. Look for Test.createTestingModule combined with overrideProvider(...).useValue(mock).

3. What is the request lifecycle in NestJS?

Level and what it tests

A paper envelope moving down a hallway past five doorways, each with a different tool hanging beside it.

This question separates developers who have shipped a NestJS API from those who followed a tutorial. A candidate who knows the order can place cross-cutting logic correctly, which is the point of every NestJS interview question on guards, pipes, and interceptors.

A strong answer

The order is fixed. Here is what each stage does:

Order Component Typical job
1 Middleware Logging, parsing, request tagging
2 Guards Allow or block the request (auth, roles)
3 Interceptors (before) Timing, caching, wrapping the handler
4 Pipes Validate and transform input
5 Controller handler Business logic via services
6 Interceptors (after) Map or transform the response
7 Exception filters Turn thrown errors into responses

Filters run whenever an exception is thrown at any earlier stage. Guards run before interceptors and pipes, so unauthorized requests never reach validation.

Guards decide whether the handler runs, pipes decide whether the input is valid, and neither replaces the other.

Follow-up to ask next

Ask: "Why check roles in a guard instead of middleware?" A strong answer says guards receive the ExecutionContext. That lets them read handler metadata, such as a @Roles() decorator, through Reflector. Middleware does not know which handler will run.

4. How do you resolve circular dependencies?

Level and what it tests

Here the interviewer moves into advanced territory. Circular dependencies appear in real codebases as they grow, so this question tests debugging skill and design judgment together. Many candidates only know the syntax fix.

A strong answer

A circular dependency exists when provider A needs B and B needs A. The same cycle can occur between modules. Nest cannot decide which to instantiate first and fails at startup. The framework's fix is forwardRef(), applied on both sides of the relationship.

@Module({ imports: [forwardRef(() => OrdersModule)] })
export class UsersModule {}

@Injectable()
export class UsersService {
  constructor(
    @Inject(forwardRef(() => OrdersService))
    private readonly orders: OrdersService,
  ) {}
}

The better answer is to remove the cycle. Extract the shared logic into a third provider or module that both sides depend on. Emitting an event instead of calling the other service directly also breaks the loop.

forwardRef is a patch. The better answer is to remove the cycle.

Follow-up to ask next

Ask: "Nest reports it can't resolve a dependency, shows a ? in the constructor list, and your design has no cycle. What do you check?" Strong candidates look for circular file imports, often through barrel files, which leave the injected type undefined at runtime.

5. What are dynamic modules and when do you use them?

Level and what it tests

This is a senior-level question. It tests whether the candidate can design reusable modules, the kind a platform team shares across services. Anyone can consume TypeOrmModule.forRoot(). Fewer can explain how it works.

A strong answer

A dynamic module is configured when it is imported. A static method returns a DynamicModule object containing the module, its providers, and its exports. Options usually arrive through a provider token.

@Module({})
export class MailModule {
  static register(options: MailOptions): DynamicModule {
    return {
      module: MailModule,
      providers: [{ provide: 'MAIL_OPTIONS', useValue: options }, MailService],
      exports: [MailService],
    };
  }
}

Naming conventions carry meaning. register configures the module for the importing module only. forRoot configures it once for the whole app. forFeature reuses that root configuration and adjusts it per module, as in TypeOrmModule.forFeature([User]). When options come from ConfigService, the async form forRootAsync with useFactory and inject is the right tool.

The method name is a contract: register is local, forRoot is global, forFeature is a per-module adjustment.

Follow-up to ask next

Ask how they would build a module that takes different credentials per environment. Listen for the async variant, injected config, and a restrained use of @Global(). Overusing global modules hides dependencies and weakens the structure Nest is meant to enforce.

Putting the questions to work

Modules and providers show whether a developer understands structure. Dependency injection and the request lifecycle show whether they have built and tested real APIs. Circular dependencies and dynamic modules show design judgment. Score answers on reasoning and the follow-up, not on recited definitions.

If you are hiring, you can start with a ready pool instead of a cold search. Browse vetted Node.js developers on Olibr, then use these five questions to screen the shortlist.

For engineers

Find work worth your time.

Live engineering roles across India and the US, matched to your stack. Build a profile recruiters actually discover.

Browse jobsHow it works

O
§ The author

Olibr Team

Reviewed by Raman Gupta, Founder, Olibr

Filed underHiring Tips
Reading time7 min · 1,338 words

PublishedOctober 12, 2026

CategoryHiring Tips
Enjoyed this piece?Share it with someone who would find it useful.
§ Stay in the loop

Don’t miss the next one.

We publish essays on engineering, hiring, and building teams. Subscribe and we’ll send them when they land.

Unsubscribe anytime · one letter, never more