NestJS Core Module Source Code
Module System Source Code Implementation
Module Class Core Implementation:
// packages/core/src/module.ts
export class Module {
constructor(
public readonly metatype: Type<any>,
public readonly scope: Scope[],
public readonly providers: Provider[],
public readonly controllers: Type<any>[],
public readonly imports: ModuleWithProviders[],
public readonly exports: Provider[]
) {}
// Resolve module dependency graph
static async create(
metatype: Type<any>,
container: NestContainer,
scope: Scope[]
): Promise<Module> {
const { providers, controllers, imports, exports } = await this.reflectMetadata(metatype)
const moduleRef = new Module(metatype, scope, providers, controllers, imports, exports)
// Register module to container
container.addModule(moduleRef)
// Recursively load imported modules
await this.loadImports(moduleRef, container)
return moduleRef
}
// Reflect module metadata
private static async reflectMetadata(metatype: Type<any>): Promise<{
providers: Provider[]
controllers: Type<any>[]
imports: ModuleWithProviders[]
exports: Provider[]
}> {
// Use reflection API to get decorator metadata
const providers = Reflect.getMetadata(PROVIDERS, metatype) || []
const controllers = Reflect.getMetadata(CONTROLLERS, metatype) || []
const imports = Reflect.getMetadata(IMPORTS, metatype) || []
const exports = Reflect.getMetadata(EXPORTS, metatype) || []
return { providers, controllers, imports, exports }
}
}Dependency Graph Construction Process:
// packages/core/src/module/container.ts
export class NestContainer {
private modules = new Map<string, Module>()
private moduleGraph = new Map<string, Set<string>>()
// Add module and build dependency graph
addModule(module: Module, scope?: Scope[]) {
const moduleName = this.getModuleName(module.metatype)
// Register module
this.modules.set(moduleName, module)
// Build dependency graph
this.moduleGraph.set(moduleName, new Set())
module.imports.forEach(imported => {
const importedName = this.getModuleName(imported.module.metatype)
this.moduleGraph.get(moduleName)?.add(importedName)
})
}
// Load modules in topological order
async loadModules() {
const sortedModules = this.topologicalSort()
for (const moduleName of sortedModules) {
const module = this.modules.get(moduleName)
await this.initializeModule(module)
}
}
// Topological sort algorithm implementation
private topologicalSort(): string[] {
// Kahn's algorithm for dependency graph sorting
const inDegree = new Map<string, number>()
const queue: string[] = []
const result: string[] = []
// Initialize in-degree
this.moduleGraph.forEach((deps, moduleName) => {
inDegree.set(moduleName, 0)
})
// Calculate in-degree
this.moduleGraph.forEach((deps, moduleName) => {
deps.forEach(dep => {
inDegree.set(dep, (inDegree.get(dep) || 0) + 1)
})
})
// Enqueue nodes with in-degree 0
this.moduleGraph.forEach((_, moduleName) => {
if (inDegree.get(moduleName) === 0) {
queue.push(moduleName)
}
})
// Perform topological sort
while (queue.length) {
const moduleName = queue.shift()!
result.push(moduleName)
this.moduleGraph.get(moduleName)?.forEach(dep => {
inDegree.set(dep, inDegree.get(dep)! - 1)
if (inDegree.get(dep) === 0) {
queue.push(dep)
}
})
}
return result
}
}Dependency Injection Container Source Code Implementation
Injector Core Implementation:
// packages/core/src/di/injector.ts
export class Injector {
async resolve<T>(provider: Provider, contextId = STATIC_CONTEXT): Promise<T> {
// 1. Handle different types of Provider
if (isValueProvider(provider)) {
return provider.useValue
} else if (isFactoryProvider(provider)) {
return this.resolveFactoryProvider(provider, contextId)
} else if (isClassProvider(provider)) {
return this.resolveClassProvider(provider, contextId)
}
}
// Resolve class Provider
private async resolveClassProvider(
provider: ClassProvider,
contextId: ContextId
): Promise<any> {
// 1. Get or create instance
const instanceWrapper = this.getInstanceWrapper(provider.provide)
if (!instanceWrapper.isResolved) {
// 2. Resolve constructor dependencies
const dependencies = this.reflectConstructorParams(provider.provide)
const resolvedDependencies = await this.resolveDependencies(dependencies, contextId)
// 3. Instantiate class
instanceWrapper.instance = new provider.provide(...resolvedDependencies)
instanceWrapper.isResolved = true
}
return instanceWrapper.instance
}
// Reflect constructor parameters
private reflectConstructorParams(provider: Type<any>): any[] {
const paramTypes = Reflect.getMetadata(PARAMTYPES_METADATA, provider) || []
const paramInjections = Reflect.getMetadata(INJECT_METADATA, provider) || []
return paramTypes.map((type, index) => {
return paramInjections[index] || type
})
}
}Provider Resolution Process:
// packages/core/src/di/provider.ts
export function isValueProvider(provider: any): provider is ValueProvider {
return provider && !!provider.useValue
}
export function isFactoryProvider(provider: any): provider is FactoryProvider {
return provider && !!provider.useFactory
}
export function isClassProvider(provider: any): provider is ClassProvider {
return provider && !!provider.useClass
}
// Provider type definition
export type Provider =
| ValueProvider
| FactoryProvider
| ClassProvider
| ExistingProvider
| any[]Controller Source Code Analysis
Route Registration Process:
// packages/core/src/router/router-explorer.ts
export class RouterExplorer {
explore(controller: Type<any>, module: Module) {
// 1. Get controller metadata
const routes = this.reflectRoutes(controller)
// 2. Create handler for each route method
routes.forEach(route => {
const handler = this.createHandler(controller, route)
// 3. Register route to Express/Koa
this.registerRoute(module, controller, route, handler)
})
}
// Reflect route metadata
private reflectRoutes(controller: Type<any>): RouteMetadata[] {
const prototype = Object.getPrototypeOf(controller.prototype)
const methods = Object.getOwnPropertyNames(prototype)
return methods
.filter(method => this.isRouteMethod(prototype[method]))
.map(method => ({
method: prototype[method],
path: Reflect.getMetadata(PATH_METADATA, controller.prototype, method),
methodMetadata: Reflect.getMetadata(METHOD_METADATA, controller.prototype, method)
}))
}
// Create request handler
private createHandler(controller: Type<any>, route: RouteMetadata) {
return async (req: Request, res: Response, next: NextFunction) => {
// 1. Resolve dependency injection
const instance = this.getInstance(controller)
// 2. Call controller method
const result = await instance[route.method.name](req, res, next)
// 3. Handle response
if (result instanceof Observable) {
result.subscribe(data => res.send(data))
} else {
res.send(result)
}
}
}
}Request Processing Flow:
// packages/core/src/router/router-execution-context.ts
export class RouterExecutionContext {
create(
instance: Controller,
callback: Function,
metadataKey: string
): (...args: any[]) => any {
return async (req: Request, res: Response, next: NextFunction) => {
// 1. Resolve method parameters
const args = this.reflectArgs(instance, callback, req, res, next)
// 2. Execute method
const result = await callback.apply(instance, args)
// 3. Handle return value
if (result instanceof Observable) {
return result.pipe(
map(data => res.send(data)),
catchError(err => next(err))
)
}
return result
}
}
// Reflect method parameters
private reflectArgs(
instance: Controller,
callback: Function,
req: Request,
res: Response,
next: NextFunction
): any[] {
const paramTypes = Reflect.getMetadata(PARAMTYPES_METADATA, instance, callback.name)
const paramInjections = Reflect.getMetadata(INJECT_METADATA, instance, callback.name) || []
return paramTypes.map((type, index) => {
if (paramInjections[index]) {
return this.resolveParam(paramInjections[index], req, res, next)
}
switch (index) {
case 0: return req
case 1: return res
case 2: return next
default: return undefined
}
})
}
}Middleware Source Code Implementation
MiddlewareConsumer Implementation:
// packages/core/src/middleware/middleware-consumer.ts
export class MiddlewareConsumer {
private middleware: MiddlewareMetadata[] = []
apply(middleware: Middleware): this {
this.middleware.push({
middleware,
path: undefined,
method: undefined
})
return this
}
forRoutes(routes: any[]): this {
this.middleware.forEach(meta => {
meta.path = this.reflectRoutes(routes)
})
return this
}
// Build middleware execution chain
build(container: NestContainer): MiddlewareBuilder {
return new MiddlewareBuilder(this.middleware, container)
}
}
// Middleware execution order control
export class MiddlewareBuilder {
constructor(
private middleware: MiddlewareMetadata[],
private container: NestContainer
) {}
build(): (req: Request, res: Response, next: NextFunction) => void {
return async (req, res, next) => {
// 1. Execute middleware in order
for (const meta of this.middleware) {
const instance = this.container.getInstance(meta.middleware)
await instance.use(req, res, next)
}
// 2. Execute next middleware or route handler
next()
}
}
}Exception Filter Source Code Implementation
ExceptionFilterFactory Implementation:
// packages/core/src/filters/exception-filters.ts
export class ExceptionFiltersContext {
create(
instance: Controller,
callback: Function,
module: string
): ExceptionFilter[] {
// 1. Get exception filters on method
const methodFilters = this.reflectMethodExceptionFilters(instance, callback)
// 2. Get exception filters on class
const classFilters = this.reflectClassExceptionFilters(instance)
// 3. Merge filters and create instances
return [...classFilters, ...methodFilters].map(filter => {
return this.container.getInstance(filter)
})
}
// Handle exception
handle(exception: any, filters: ExceptionFilter[], response: Response) {
// 1. Execute filters in order
for (const filter of filters) {
if (filter.catch(exception, response)) {
break // Stop propagation if filter handles exception
}
}
}
}
// Built-in exception filter
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp()
const response = ctx.getResponse<Response>()
const request = ctx.getRequest<Request>()
const status = exception.getStatus()
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url
})
}
}NestJS Compilation and Startup Source Code
Application Startup Process Source Code Analysis
NestFactory.create Implementation:
// packages/core/src/nest-factory.ts
export class NestFactoryStatic {
static async create<T extends INestApplication>(
module: Type<any>,
options?: NestApplicationOptions
): Promise<T> {
// 1. Create application container
const container = new NestContainer()
// 2. Load root module
const rootModule = await this.loadRootModule(module, container, options)
// 3. Resolve module dependency graph
await container.loadModules()
// 4. Initialize modules
await this.initializeModules(container, options)
// 5. Create application instance
const applicationRef = this.createApplicationRef(rootModule, options)
// 6. Set up exception filters
this.setupExceptionFilters(applicationRef, container)
return applicationRef as T
}
// Load root module
private static async loadRootModule(
module: Type<any>,
container: NestContainer,
options?: NestApplicationOptions
): Promise<Module> {
// 1. Reflect module metadata
const { providers, controllers, imports } = await Module.reflectMetadata(module)
// 2. Create module instance
const rootModule = new Module(
module,
options?.scope || [],
providers,
controllers,
imports,
[]
)
// 3. Register to container
container.addModule(rootModule)
return rootModule
}
}Module Loading and Initialization
Module Loading Process:
// packages/core/src/core/modules-loader.ts
export class ModulesLoader {
async loadModules(container: NestContainer) {
// 1. Get all registered modules
const modules = Array.from(container.getModules().values())
// 2. Topologically sort modules
const sortedModules = this.topologicalSort(modules)
// 3. Load modules in order
for (const module of sortedModules) {
await this.loadModule(module, container)
}
}
// Load single module
private async loadModule(module: Module, container: NestContainer) {
// 1. Load imported modules
await this.loadImports(module, container)
// 2. Initialize providers
await this.initializeProviders(module, container)
// 3. Initialize controllers
await this.initializeControllers(module, container)
}
}Dependency Injection Source Code Implementation
Reflection Metadata Parsing:
// packages/core/src/di/reflect-metadata.ts
export function reflectMetadata<T>(metadataKey: string, target: any, propertyKey?: string | symbol): T {
if (propertyKey) {
return Reflect.getMetadata(metadataKey, target, propertyKey)
}
return Reflect.getMetadata(metadataKey, target)
}
// PROVIDERS metadata example
function Controller() {
return (target: Type<any>) => {
Reflect.defineMetadata(CONTROLLERS, [target], target)
Reflect.defineMetadata(PROVIDERS, [
...Reflect.getMetadata(PROVIDERS, target) || [],
target
], target)
}
}Provider Resolution Process:
// packages/core/src/di/provider-resolver.ts
export class ProviderResolver {
resolve<T>(
provider: Provider,
container: NestContainer,
contextId = STATIC_CONTEXT
): Promise<T> {
// 1. Handle different types of Provider
if (isValueProvider(provider)) {
return Promise.resolve(provider.useValue)
} else if (isFactoryProvider(provider)) {
return this.resolveFactoryProvider(provider, container, contextId)
} else if (isClassProvider(provider)) {
return this.resolveClassProvider(provider, container, contextId)
}
}
// Resolve circular dependencies
private async resolveWithCircularDependency(
provider: ClassProvider,
container: NestContainer,
contextId: ContextId
): Promise<any> {
const instanceWrapper = container.getInstanceWrapper(provider.provide)
if (instanceWrapper.isResolved) {
return instanceWrapper.instance
}
// Mark as resolving
instanceWrapper.isResolving = true
// Resolve dependencies
const dependencies = this.reflectConstructorParams(provider.provide)
const resolvedDependencies = await this.resolveDependencies(dependencies, container, contextId)
// Instantiate
instanceWrapper.instance = new provider.provide(...resolvedDependencies)
instanceWrapper.isResolved = true
instanceWrapper.isResolving = false
return instanceWrapper.instance
}
}Request Lifecycle Source Code
Complete Request Processing Flow:
// packages/core/src/router/router-executor.ts
export class RouterExecutor {
async execute(
request: Request,
response: Response,
next: NextFunction,
module: Module
) {
// 1. Find matching route
const route = this.findRoute(request, module)
if (!route) {
return next()
}
// 2. Get controller instance
const instance = module.getInstance(route.controller)
// 3. Create execution context
const context = this.createContext(request, response, next)
// 4. Execute middleware
await this.executeMiddleware(module, route, context)
// 5. Execute route handler
const result = await this.executeHandler(instance, route, context)
// 6. Handle response
this.handleResponse(result, response)
}
// Execute middleware chain
private async executeMiddleware(
module: Module,
route: Route,
context: ExecutionContext
) {
const middleware = module.getMiddlewareForRoute(route)
for (const mw of middleware) {
await mw.use(context.getRequest(), context.getResponse(), context.getNext())
}
}
}Performance Optimization Source Code Implementation
Cache Implementation:
// packages/core/src/cache/cache-manager.ts
export class CacheManager {
private cache = new Map<string, { value: any; ttl: number }>()
async get<T>(key: string): Promise<T | undefined> {
const entry = this.cache.get(key)
if (!entry) return undefined
// Check TTL
if (entry.ttl < Date.now()) {
this.cache.delete(key)
return undefined
}
return entry.value
}
async set<T>(key: string, value: T, ttl: number): Promise<void> {
this.cache.set(key, {
value,
ttl: Date.now() + ttl
})
}
}
// Using cache in dependency injection
export class CachedProviderResolver {
constructor(private resolver: ProviderResolver, private cache: CacheManager) {}
async resolve<T>(
provider: Provider,
container: NestContainer,
contextId = STATIC_CONTEXT
): Promise<T> {
const cacheKey = this.getCacheKey(provider, contextId)
const cached = await this.cache.get<T>(cacheKey)
if (cached) return cached
const resolved = await this.resolver.resolve(provider, container, contextId)
await this.cache.set(cacheKey, resolved, 60 * 1000) // Cache for 1 minute
return resolved
}
}Lazy Loading Implementation:
// packages/core/src/core/lazy-loading.ts
export class LazyModuleLoader {
private loadedModules = new Map<string, Module>()
async load(module: Type<any>, container: NestContainer): Promise<Module> {
const moduleName = this.getModuleName(module)
if (this.loadedModules.has(moduleName)) {
return this.loadedModules.get(moduleName)
}
// 1. Create module instance without immediately loading dependencies
const moduleRef = new Module(
module,
[],
[],
[],
[],
[]
)
// 2. Register to container without initialization
container.addModule(moduleRef, true) // Mark as lazy-loaded
// 3. Load dependencies on first access
const proxy = this.createProxy(moduleRef, container)
this.loadedModules.set(moduleName, proxy)
return proxy
}
// Create proxy module
private createProxy(module: Module, container: NestContainer): Module {
return new Proxy(module, {
get(target, prop) {
if (prop === 'getInstance') {
// Load dependencies on first access to getInstance
container.initializeModule(target)
}
return Reflect.get(target, prop)
}
})
}
}



