NestJS Mimarisi: Provider Nedir? Ne Sağlar? (11. Bölüm)

Posted on Jul 31, 2025

NestJS’te Her Şey Bir Provider’dır

NestJS’te controller, service, guard, pipe, hatta resolver… Bunların hepsi özünde birer provider’dır.

Provider = Nest container’ına tanıtılan ve başka yerlerden inject edilebilen bir “şey”dir.

Sen bir service yazarsın, onu @Injectable() yaparsın - bu, Nest’e şunu demektir:

“Bunu bir yerde kullanmak isteyeceğim, lütfen enjekte edilebilir hale getir.”

En Temel Kullanım: Servis Olarak Provider

@Injectable()
export class UserService {
  findAll() {
    return ['Ali', 'Ayşe'];
  }
}

Bu sınıf bir provider olur. Bir yerde kullanmak için constructor’a inject edersin:

@Controller('users')
export class UserController {
  constructor(private userService: UserService) {}

  @Get()
  getUsers() {
    return this.userService.findAll();
  }
}

Nest bu yapıyı tanır ve UserService‘i otomatik olarak örnekler (instantiate eder).

Provider Tanımlamanın 4 Yolu

Nest sana provider tanımlamak için birkaç farklı yol sunar. Her biri özel durumlar için vardır.

1. Class Provider (En yaygın)

providers: [UserService]

Bu, şu anlama gelir:

UserService adında bir sınıfı instance olarak oluştur ve her yerde aynı nesneyi kullan.

2. Value Provider

Statik bir veri ya da config objesi vermek istiyorsan:

{
  provide: 'APP_CONFIG',
  useValue: { port: 3000, env: 'dev' },
}

Ve kullanırken:

constructor(@Inject('APP_CONFIG') config) {}

3. Factory Provider

Bağımlılıklara göre dinamik üretim gerekiyorsa:

{
  provide: 'UUID',
  useFactory: () => randomUUID(),
}

4. Existing Provider

Mevcut bir provider’ı başka bir isimle kullanmak istersen:

{
  provide: 'IUserService',
  useExisting: UserService,
}

NestJS Container ve Bağımlılık Çözümleme

Nest uygulaması başlarken tüm provider’ları memory’ye alır. Bu yapıya IoC Container denir. (Inversion of Control)

UserController depends on UserService
UserService depends on DatabaseService

Nest bu bağımlılıkları constructor üzerinden çözer. Ve enjekte edilecek her şeyi @Injectable() olarak tanıman gerekir.

Manual @Inject() Kullanımı

Normalde Nest tipi baz alarak provider’ı bulur. Ama bazı özel durumlarda string token kullanman gerekebilir:

constructor(@Inject('UUID') uuid: string) {}

Bu durum genelde useValue veya useFactory kullanıldığında gerekir.

Global Provider Nedir?

Bir provider’ı her modülde tek tek tanıtmak yerine global yapabilirsin:

@Module({
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ],
})
export class AppModule {}

APP_ ile başlayan token’lar global tanımlamalarda kullanılır. @nestjs/core içinde gelir.

Provider vs Service

Bazen “provider” ve “service” karıştırılır. Açık net fark şu:

TerimAçıklama
ServiceYazdığın sınıf
ProviderNest’e tanıttığın şey (bir service olabilir, ama sadece bu değildir)

Yani her service bir provider olabilir ama her provider service değildir. Pipe, Guard, Interceptor… hepsi provider’dır.

Provider Kullanmadan da İş Görür mü?

Evet. Ama ne kaybedersin?

  • Test edilebilirlik (mock zorlaşır)
  • Reusability (servisi tekrar kullanamazsın)
  • Configurability (dinamik bağımlılıklar tanımlayamazsın)

Kafaya Takılan: @Injectable() Olmadan Çalışır mı?

Eğer o sınıf DI yoluyla bir yere enjekte edilmeyecekse evet, çalışır. Ama constructor injection kullanacaksan @Injectable() zorunludur. Aksi takdirde Nest hata fırlatır:

Nest can’t resolve dependencies of the …

Özet

  • Provider = Enjekte edilebilir her türlü yapı
  • @Injectable() -> Nest’e bu sınıfı provider olarak tanıtır
  • Class, value, factory, existing provider türleri vardır
  • Nest tüm provider’ları IoC container içinde yönetir
  • Servis, pipe, guard, interceptor… hepsi birer provider’dır
  • Sağlam bir DI mimarisi için provider sistemi kaçınılmazdır