Skip to content

Fix: NestJS Nest can't resolve dependencies — Provider Not Found Error

FixDevs · (Updated: )

Part of:  JavaScript & TypeScript Errors

Quick Answer

How to fix NestJS dependency injection errors — module imports, provider exports, circular dependencies, dynamic modules, and the most common 'can't resolve dependencies' patterns.

The Problem

NestJS throws a dependency injection error at startup:

Nest can't resolve dependencies of the UsersService (?).
Please make sure that the argument UserRepository at index [0]
is available in the UsersModule context.

Potential solutions:
- Is UsersModule a valid NestJS module?
- If UserRepository is a provider, is it part of the current UsersModule?
- If UserRepository is exported from a separate @Module, is that module imported within UsersModule?

Or a service injected into a controller isn’t found:

Error: Nest can't resolve dependencies of the AuthController (?).
Please make sure that the argument UsersService at index [0]
is available in the AuthModule context.

Or a provider from another module isn’t accessible:

Error: Nest can't resolve dependencies of the EmailService (?).
The argument ConfigService at index [0] is not available in the EmailModule context.

Why This Happens

NestJS uses a module-scoped dependency injection system. Every provider (service, repository, etc.) must be:

  1. Declared in a module’s providers array — or provided by an imported module
  2. Exported if another module needs it — providers are private to the module by default
  3. Imported — the module that exports the provider must be listed in the importing module’s imports array

This design is intentional. Module scoping enforces encapsulation: a UsersModule explicitly decides which of its services external consumers can use. But it also means a single missing line in a @Module() decorator silently breaks injection. The error message includes the argument index (? at position 0, 1, etc.) to help you trace which constructor parameter can’t be resolved. Always read that index and cross-reference it with the constructor signature.

Common causes:

  • Missing providers declaration — the service isn’t listed in any module’s providers
  • Not exported — a service is in providers but not in exports, so other modules can’t inject it
  • Module not imported — the module that contains the service isn’t imported where needed
  • TypeORM/Prisma entitiesforFeature() must be called in the module that uses the repository
  • Circular dependency — Module A imports Module B which imports Module A
  • Case-sensitive import paths — works on macOS (case-insensitive filesystem) but breaks on Linux CI or Docker (case-sensitive filesystem)

Fix 1: Declare Providers Correctly

Every injectable class must be listed in a module’s providers array:

// users.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {
  findAll() { return []; }
}

// users.module.ts — CORRECT
import { Module } from '@nestjs/common';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';

@Module({
  controllers: [UsersController],
  providers: [UsersService],   // UsersService must be here
  exports: [UsersService],     // Export if other modules need it
})
export class UsersModule {}

The error message tells you exactly what’s wrong:

// Error: Nest can't resolve dependencies of the UsersService (?).
//                                                             ^^^
// The ? marks the index of the missing dependency in the constructor:

@Injectable()
export class UsersService {
  constructor(
    private readonly userRepo: UserRepository,  // index [0] = ?
  ) {}
}

// Fix: ensure UserRepository is provided in UsersModule
// OR imported from another module that exports it

Fix 2: Export and Import Providers Across Modules

To use a provider from Module B in Module A, Module B must export it and Module A must import Module B:

// shared/config/config.module.ts
@Module({
  providers: [ConfigService],
  exports: [ConfigService],   // ← Export it
})
export class ConfigModule {}

// feature/email/email.module.ts
import { ConfigModule } from '../shared/config/config.module';

@Module({
  imports: [ConfigModule],    // ← Import the module (not the service directly)
  providers: [EmailService],
})
export class EmailModule {}

// Now EmailService can inject ConfigService
@Injectable()
export class EmailService {
  constructor(private configService: ConfigService) {}   // Works!
}

Common mistake — importing the service directly instead of the module:

// WRONG — you import modules, not individual providers
@Module({
  imports: [ConfigService],   // Error: ConfigService is not a module
})
export class EmailModule {}

// CORRECT
@Module({
  imports: [ConfigModule],    // Import the MODULE that provides ConfigService
})
export class EmailModule {}

Fix 3: Make a Module Global

For cross-cutting services like ConfigService or LoggerService that every module needs, use @Global() to avoid importing the module everywhere:

// config/config.module.ts
import { Global, Module } from '@nestjs/common';
import { ConfigService } from './config.service';

@Global()   // ← Makes providers available everywhere without explicit import
@Module({
  providers: [ConfigService],
  exports: [ConfigService],
})
export class ConfigModule {}

// app.module.ts — import once at the root
@Module({
  imports: [
    ConfigModule,    // Import once — globally available to all modules
    UsersModule,
    OrdersModule,
    // ConfigModule NOT needed here — global handles it
  ],
})
export class AppModule {}

// users.module.ts — no need to import ConfigModule
@Module({
  providers: [UsersService],
})
export class UsersModule {}

// users.service.ts — ConfigService available even without importing ConfigModule
@Injectable()
export class UsersService {
  constructor(private config: ConfigService) {}   // Works because @Global()
}

Note: Use @Global() sparingly. Overusing it makes the dependency graph implicit and harder to understand.

Fix 4: Fix TypeORM Repository Injection

TypeORM repositories require forFeature() in the module that uses them:

// user.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  email: string;
}

// users.module.ts — CORRECT
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

@Module({
  imports: [
    TypeOrmModule.forFeature([User]),   // Register User entity in this module
  ],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

// users.service.ts — inject repository
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,   // Works with forFeature
  ) {}
}

Forgot forFeature() — classic error:

Nest can't resolve dependencies of the UsersService (?).
Please make sure that the argument UserRepository at index [0]
is available in the UsersModule context.

This error specifically means TypeOrmModule.forFeature([User]) is missing from UsersModule.imports.

Fix 5: Fix Circular Module Dependencies

When Module A imports Module B and Module B imports Module A, use forwardRef():

// users/users.module.ts
import { forwardRef, Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module';

@Module({
  imports: [
    forwardRef(() => AuthModule),   // Break the circular reference
  ],
  providers: [UsersService],
  exports: [UsersService],
})
export class UsersModule {}

// auth/auth.module.ts
import { forwardRef, Module } from '@nestjs/common';
import { UsersModule } from '../users/users.module';

@Module({
  imports: [
    forwardRef(() => UsersModule),   // Break the circular reference
  ],
  providers: [AuthService],
  exports: [AuthService],
})
export class AuthModule {}

Inject services across circular-dependent modules:

@Injectable()
export class AuthService {
  constructor(
    @Inject(forwardRef(() => UsersService))
    private usersService: UsersService,   // Forward ref for service too
  ) {}
}

Pro Tip: Circular dependencies are often a sign that the module boundaries are wrong. Consider extracting shared functionality into a third SharedModule that both modules import.

Fix 6: Dynamic Modules — forRoot and forFeature

Dynamic modules (like ConfigModule.forRoot()) need special handling:

// config/config.module.ts
import { DynamicModule, Module } from '@nestjs/common';

@Module({})
export class ConfigModule {
  static forRoot(options: ConfigOptions): DynamicModule {
    return {
      module: ConfigModule,
      global: true,   // Make it global so you don't re-import everywhere
      providers: [
        {
          provide: 'CONFIG_OPTIONS',
          useValue: options,
        },
        ConfigService,
      ],
      exports: [ConfigService],
    };
  }
}

// app.module.ts
@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: '.env',
      isGlobal: true,
    }),
  ],
})
export class AppModule {}

Inject dynamic module tokens:

// Injecting a value token (not a class)
@Injectable()
export class ConfigService {
  constructor(
    @Inject('CONFIG_OPTIONS')
    private options: ConfigOptions,
  ) {}
}

Fix 7: Case Sensitivity and Filesystem Differences

This is one of the most frustrating NestJS issues because it only surfaces in CI or production. macOS uses a case-insensitive filesystem by default, while Linux (including Docker containers and most CI runners) uses a case-sensitive one. An import path mismatch that works on macOS silently fails on Linux.

// File on disk: src/users/Users.service.ts

// WRONG — works on macOS, fails on Linux
import { UsersService } from './users.service';   // lowercase 'u' in 'users'

// CORRECT — matches exact file case
import { UsersService } from './Users.service';    // uppercase 'U' matches file

Barrel file re-export ordering can also cause resolution failures. If index.ts barrel files re-export modules in a specific order, circular references between barrel exports can deadlock the module resolution:

// WRONG — if AuthModule and UsersModule import from each other's barrel file,
// the circular barrel reference causes one module to resolve as undefined
// src/auth/index.ts
export * from './auth.module';
export * from './auth.service';

// BETTER — import directly from the file, not the barrel
import { AuthService } from '../auth/auth.service';
// instead of: import { AuthService } from '../auth';

Monorepo path resolution (Nx, Turborepo) adds another layer. In Nx workspaces, tsconfig.base.json defines path mappings like @myapp/shared. If these paths don’t match the Nest module resolution, providers fail to resolve:

// tsconfig.base.json (Nx)
{
  "compilerOptions": {
    "paths": {
      "@myapp/shared": ["libs/shared/src/index.ts"],
      "@myapp/shared/*": ["libs/shared/src/*"]
    }
  }
}
// Ensure Nest can resolve the path at runtime, not just at compile time.
// Turborepo: the package must be listed in the consumer's package.json dependencies.
// Nx: use buildable libraries or ensure the path is mapped in both
// the root tsconfig AND the app-specific tsconfig.

Docker layer caching with node_modules can also break module resolution. If you copy node_modules from a cached layer but your package.json changed, NestJS packages may be out of sync:

# WRONG — stale node_modules from cache
COPY node_modules ./node_modules
COPY . .

# CORRECT — always install fresh after package.json change
COPY package*.json ./
RUN npm ci
COPY . .

Fix 8: Verify Module Structure

Use NestJS’s built-in debugging to inspect the module graph:

# Enable verbose module debug output
DEBUG=nestjs:* npm run start:dev

# Or add to main.ts
const app = await NestFactory.create(AppModule, { logger: ['error', 'warn', 'debug', 'log'] });

Systematically check the error message:

// Error: Nest can't resolve dependencies of the OrdersService (?, UserRepository).
//                                                              ^^
// First dependency (index 0) is missing
// The ? is at index 0 in the constructor:

@Injectable()
export class OrdersService {
  constructor(
    private emailService: EmailService,   // index 0 — MISSING (?)
    @InjectRepository(User)
    private userRepo: Repository<User>,   // index 1 — OK
  ) {}
}

// Fix: ensure EmailService is accessible in OrdersModule
// Option 1: Add EmailService to OrdersModule's providers
// Option 2: Import EmailModule (which exports EmailService) in OrdersModule

Checklist for fixing “can’t resolve dependencies”:

1. Is the service decorated with @Injectable()?
2. Is it listed in the module's `providers` array?
3. If it comes from another module:
   a. Is it in that module's `exports` array?
   b. Is that module imported in the current module's `imports` array?
4. For TypeORM: is TypeOrmModule.forFeature([Entity]) in the module's imports?
5. For circular deps: is forwardRef() used on both sides?
6. Do all import paths match the exact file casing on disk?
7. In a monorepo: are tsconfig paths mapped correctly for both compile and runtime?

Still Not Working?

Custom providers with tokens — when using @Inject('MY_TOKEN'), ensure the token string matches exactly (case-sensitive) and the provider is registered:

// Registration
@Module({
  providers: [
    { provide: 'DATABASE_URL', useValue: process.env.DATABASE_URL },
  ],
  exports: ['DATABASE_URL'],
})
export class DatabaseModule {}

// Injection — token must match exactly
constructor(@Inject('DATABASE_URL') private dbUrl: string) {}

useClass vs useValue vs useFactory — if your provider uses useFactory with inject, all injected dependencies must themselves be resolvable:

{
  provide: EmailService,
  useFactory: (config: ConfigService, logger: LoggerService) => {
    return new EmailService(config, logger);
  },
  inject: [ConfigService, LoggerService],  // Both must be resolvable in this module
}

Async providers — if a provider uses useFactory with async, it returns a Promise. Inject it with the token, not the class, and await happens automatically.

Nx/Turborepo build output directory mismatch — when running nest start in a monorepo, NestJS looks for compiled JS files in the dist directory. If the Nx or Turborepo build outputs to a different location (e.g., dist/apps/api or .next), module resolution fails at runtime even though TypeScript compilation succeeded. Verify the outDir in tsconfig.build.json matches where nest start expects compiled output.

SWC compiler with NestJS — if you switched from tsc to @swc/cli for faster builds, ensure emitDecoratorMetadata is enabled in .swcrc. SWC does not read tsconfig.json decorator settings by default. Without decorator metadata, Nest can’t resolve constructor parameter types and every injection fails with ?:

// .swcrc
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "decorators": true
    },
    "transform": {
      "decoratorMetadata": true
    }
  }
}

REQUEST and INQUIRER scope issues — if a provider is Scope.REQUEST, every provider that depends on it must also be request-scoped or injected via ModuleRef. Mixing Scope.DEFAULT (singleton) and Scope.REQUEST causes “can’t resolve dependencies” when the singleton tries to inject the request-scoped provider. Use @Inject(REQUEST) with Scope.REQUEST on the dependent service, or restructure to avoid request-scoped providers in singletons.

For related NestJS issues, see Fix: NestJS Circular Dependency, Fix: NestJS Guard Not Working, Fix: NestJS Validation Pipe Not Working, and Fix: TypeScript Path Alias Not Working.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles