Lazy geladen modules en feature toggles
Laad optionele featuremodules op aanvraag met LazyModuleLoader om de opstartkosten te verlagen.
Lazy geladen modules en feature toggles is een gratis Enterprise-backend-API's met NestJS-les op CoddyKit. Dit is les 3 van 4. Je kunt de volledige les hieronder gratis lezen en daarna in de browser praktisch oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject Enterprise-backend-API's met NestJS. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus Enterprise-backend-API's met NestJS bevat in totaal 4 lessen.
Waarom eager loading het opstarten vertraagt
Standaard instantieert NestJS tijdens het opstarten elke module in je graaf van imports. Voor een bedrijfs-API met tientallen optionele functies, zoals een PDF-exporteur, een betalingsgateway of een AI-score-engine, betekent dit dat je de volledige kosten van het instantiëren van providers en het opwarmen van verbindingen betaalt voordat de app zelfs maar een verzoek accepteert.
- Zware SDK's (Stripe, AWS, gRPC-clients) voeren hun constructors meteen uit.
- Modules die een bepaalde implementatie nooit gebruikt, worden toch geladen.
- De latentie bij een koude start groeit lineair met de modulegraaf.
De oplossing: geselecteerde functiemodules lui laden, pas wanneer ze voor het eerst worden aangeroepen.
De LazyModuleLoader
Nest levert een ingebouwde LazyModuleLoader (uit @nestjs/core). Je injecteert deze net als elke andere provider en roept vervolgens load() aan met een factory die de module retourneert. Nest registreert de providers van de module op aanvraag en slaat de resulterende verwijzing op voor volgende aanroepen.
Belangrijkste eigenschappen:
- Luie modules staan in geen enkele
imports-array. - Ze registreren geen controllers, resolvers of enhancers — alleen providers.
- De eerste
load()instantieert de module; latere aanroepen retourneren de opgeslagenModuleRef.
import { Injectable } from '@nestjs/common';
import { LazyModuleLoader } from '@nestjs/core';
@Injectable()
export class ReportsService {
constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}
async generate(): Promise<void> {
const { PdfModule } = await import('./pdf/pdf.module');
const moduleRef = await this.lazyModuleLoader.load(() => PdfModule);
// moduleRef now exposes PdfModule's providers
}
}Een provider uit de luie module ophalen
Het object dat load() retourneert, is een ModuleRef. Gebruik de methode get() om een concrete provider uit de zojuist geladen module op te halen. Omdat luie modules geïsoleerd zijn, vraag je een provider pas op nadat de module is geladen.
Gebruik voor providers met request-bereik of tijdelijk bereik moduleRef.resolve() in plaats van get().
async generate(): Promise<Buffer> {
const { PdfModule } = await import('./pdf/pdf.module');
const moduleRef = await this.lazyModuleLoader.load(() => PdfModule);
const pdfService = moduleRef.get(PdfService);
return pdfService.render({ title: 'Invoice' });
}Dynamische import() bespaart de bytes
De echte winst bij het opstarten ontstaat door LazyModuleLoader.load() te combineren met een dynamische import(). Een statische import bovenaan het bestand neemt de module — en de zware transitieve afhankelijkheden ervan — op in de bootstrapbundel. Een dynamische import() stelt de evaluatie van dat bestand uit totdat de aanroep wordt uitgevoerd.
- Statische
import { PdfModule }bovenaan het bestand = geladen bij het opstarten. await import('./pdf/pdf.module')binnen de methode = geladen bij het eerste gebruik.
Importeer het bestand van de luie module dus altijd dynamisch, nooit statisch.
Een luie featuremodule definiëren
De luie module zelf is een gewone @Module — er is niets bijzonders aan de decorator. Wat deze module lui maakt, is uitsluitend hoe deze wordt gebruikt (via LazyModuleLoader in plaats van een imports-array).
Houd de providers ervan zelfstandig, zodat het laden niet de hele app meesleept.
import { Module } from '@nestjs/common';
import { PdfService } from './pdf.service';
@Module({
providers: [PdfService],
exports: [PdfService],
})
export class PdfModule {}Caching maakt herhaald laden goedkoop
Nest houdt intern een register bij van al geladen luie modules, waarbij de sleutel het resultaat van de factory is. Als je load() dus herhaaldelijk aanroept met dezelfde moduleklasse, kost dat na de eerste treffer vrijwel niets — er vindt geen dubbele instantiatie plaats en er worden geen dubbele verbindingen gemaakt.
Je kunt load() daarom veilig rechtstreeks in een drukbezochte handler aanroepen zonder dit zelf te beveiligen; het framework voorkomt duplicaten. De eenmalige kosten worden gemaakt bij het eerste verzoek dat de feature nodig heeft.
Featuretoggles: het laden conditioneren
Featuretoggles en lui laden vormen een natuurlijke combinatie. In plaats van modules tijdens het compileren voorwaardelijk te registreren, controleer je tijdens runtime een vlag en laad je de module alleen met load() als de vlag is ingeschakeld. Een uitgeschakelde feature kost dan niets — zelfs de constructor wordt niet uitgevoerd.
- Een vlag uit de omgeving, een configuratieservice of een externe vlagprovider (LaunchDarkly, Unleash).
- Als de toggle is uitgeschakeld, stop je meteen voordat je importeert.
@Injectable()
export class ExportService {
constructor(
private readonly lazyModuleLoader: LazyModuleLoader,
private readonly flags: FeatureFlagService,
) {}
async export(payload: ExportDto) {
if (!this.flags.isEnabled('pdf-export')) {
throw new ForbiddenException('Feature disabled');
}
const { PdfModule } = await import('./pdf/pdf.module');
const ref = await this.lazyModuleLoader.load(() => PdfModule);
return ref.get(PdfService).render(payload);
}
}Een minimale vlagservice (zelfstandig)
Een controle van een featurevlag is gewoon een deterministische opzoekactie. Hier is een frameworkvrije versie die je afzonderlijk kunt begrijpen en testen — dezelfde logica die een Nest FeatureFlagService zou omhullen. De service leest een vlaggenkaart en gebruikt een standaardwaarde als de sleutel onbekend is.
class FeatureFlags {
constructor(private readonly flags: Record<string, boolean>) {}
isEnabled(key: string, fallback = false): boolean {
return this.flags[key] ?? fallback;
}
}
const flags = new FeatureFlags({ 'pdf-export': true, 'ai-scoring': false });
console.log(flags.isEnabled('pdf-export')); // true
console.log(flags.isEnabled('ai-scoring')); // false
console.log(flags.isEnabled('unknown', true)); // true (fallback)Controllers en enhancers worden genegeerd
Een belangrijke beperking: wanneer een module lui wordt geladen, registreert Nest alleen de providers. Het slaat bewust het volgende over:
controllers— er verschijnen geen nieuwe HTTP-routes.- Globale guards, interceptors, pipes en filters die in de module zijn gedeclareerd.
- GraphQL-resolvers.
Een luie module kan dus geen endpoints toevoegen. Stel de feature beschikbaar via een controller in een eager geladen module, die de aanroepen doorgeeft aan de lui geladen provider.
@Controller('reports')
export class ReportsController {
constructor(private readonly reports: ReportsService) {}
@Post('pdf')
async pdf(@Body() dto: ExportDto) {
// controller is eager; PdfModule is loaded lazily inside the service
return this.reports.generate(dto);
}
}Opwarmen of lui laden: kies per feature
Lui laden ruilt een eenmalige latentiepie in bij het eerste verzoek in voor sneller en lichter opstarten. Dat is de juiste keuze voor zelden gebruikte, dure features. Voor features op het kritieke pad voorkomt eager laden (of expliciet opwarmen via onApplicationBootstrap) dat de eerste gebruiker nadeel ondervindt.
Keuzehulp:
- Lui: zware SDK, gebruikt door <X% van de verzoeken, optioneel per implementatie.
- Eager: kerndomein, elk verzoek, gevoelig voor latentie.
- Lui + opwarmen: zwaar, maar kort na het opstarten voorspelbaar nodig.
@Injectable()
export class Warmer implements OnApplicationBootstrap {
constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}
async onApplicationBootstrap() {
if (process.env.PRELOAD_PDF === 'true') {
const { PdfModule } = await import('./pdf/pdf.module');
await this.lazyModuleLoader.load(() => PdfModule); // pay cost now, off the request path
}
}
}De winst meten
Meet voor en na de wijziging. Meet de tijd van het opstarten en de eerste luie load() om te bevestigen dat de afweging voor jouw werklast echt gunstig is.
- De opstarttijd hoort af te nemen met de cumulatieve kosten van constructors en verbindingen van de uitgestelde modules.
- De latentie van de eerste aanroep van de luie feature draagt die kosten één keer.
- Let op P99 van het eerste verzoek na een implementatie — daar worden de uitgestelde kosten zichtbaar.
Als de luie feature bijna bij elk verzoek wordt gebruikt, zullen de cijfers aangeven dat je deze weer eager moet laden.
const t0 = performance.now();
const { PdfModule } = await import('./pdf/pdf.module');
const ref = await this.lazyModuleLoader.load(() => PdfModule);
this.logger.log(`Lazy PdfModule ready in ${Math.round(performance.now() - t0)}ms`);Snelle controle
Je laadt PdfModule lui via LazyModuleLoader. PdfModule declareert een controller met een @Post('pdf')-route. Na het laden retourneert de route 404. Wat is de juiste verklaring en oplossing?
Samenvatting
Je hebt geleerd hoe je de opstartkosten van NestJS verlaagt met modules die op aanvraag worden geladen:
LazyModuleLoader.load(() => SomeModule)instantieert de providers van een module bij het eerste gebruik en slaat het resultaat op.- Combineer dit met een dynamische
import(), zodat het bestand van de module (en zware afhankelijkheden) nooit tijdens het opstarten wordt geëvalueerd. - Haal providers op via
moduleRef.get()(ofresolve()voor providers met een bereik). - Featuretoggles bepalen of de module wordt geladen: een uitgeschakelde feature kost niets, zelfs geen constructor.
- Luie modules registreren geen controllers, resolvers of enhancers — geef de aanroepen door vanuit een eager geladen controller.
- Kies lui laden voor zware, zelden gebruikte, optionele features; kies eager laden (of lui laden + opwarmen) voor code op het kritieke pad. Meet de opstarttijd en de latentie van de eerste aanroep om de afweging te bevestigen.
Leer TypeScript met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 20
- Lessen
- 76
Veelgestelde vragen
Is de les “Lazy geladen modules en feature toggles” gratis?
Ja — de volledige tekst van “Lazy geladen modules en feature toggles” kun je hier gratis op het web lezen. Als je interactief wilt oefenen met een ingebouwde code-editor en een AI-begeleider die 24/7 beschikbaar is, en de rest van de cursus Enterprise-backend-API's met NestJS wilt ontgrendelen, kun je upgraden naar CoddyKit PRO. De cursus Enterprise-backend-API's met NestJS bevat in totaal 4 lessen.
Wat leer ik in “Lazy geladen modules en feature toggles”?
Laad optionele featuremodules op aanvraag met LazyModuleLoader om de opstartkosten te verlagen. Je oefent met Enterprise-backend-API's met NestJS door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met Enterprise-backend-API's met NestJS te beginnen?
Ervaring vooraf is niet nodig. Enterprise-backend-API's met NestJS op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 3 van 4.
Hoe lang duurt de les “Lazy geladen modules en feature toggles”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over Enterprise-backend-API's met NestJS?
Ja. Elke les over Enterprise-backend-API's met NestJS bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Ports en adapters voor domeinisolatie
- Dynamische providerregistratie met DiscoveryService
- Lazy geladen modules en feature toggles
- Uitbreidingspunten met de Module Reference API