Configurable NestJS Middleware Module Creator

raw JSON →
0.4.0 verified Thu Apr 23 auth: no javascript

create-nestjs-middleware-module is a lightweight utility library designed to simplify the integration and configuration of Express or Fastify middleware into NestJS applications. It abstracts away the boilerplate of implementing `NestModule` and `MiddlewareConsumer` by providing a `createModule` function, allowing developers to define middleware factories that can accept options. The library currently supports NestJS versions 8 through 11 and requires Node.js >=18.0.0. It aims to provide an idiomatic NestJS way to encapsulate middleware logic within a modular structure, enabling configuration via `forRoot` or `forRootAsync` methods, and offering fine-grained control over routing, similar to NestJS's built-in `MiddlewareConfigProxy`. Its current stable version is 0.4.0, with releases occurring as needed to maintain compatibility with new NestJS versions.

error TypeError: Cannot read properties of undefined (reading 'forRoot')
cause Attempting to call `.forRoot()` on the module created by `createModule` before it has been properly initialized or if the import path is incorrect.
fix
Ensure the module is correctly imported and that createModule has been called with the middleware factory. Double-check the import path from 'create-nestjs-middleware-module' and verify the export name of your custom module. If the error occurs when calling forRoot() without arguments, ensure FacadeModuleStaticOptional type assertion is used.
error Error: Nest can't resolve dependencies of the XModule (?). Please make sure that the argument at index [0] is available in the XModule context.
cause Your middleware factory (passed to `createModule`) has dependencies that NestJS's DI container cannot resolve because the module isn't providing them or the dependencies aren't globally available.
fix
Ensure any services or providers required by your middleware factory are either provided directly within the createModule's configuration (if supported by a future API), made available globally, or refactor your middleware to receive only configuration options directly.
error TS2345: Argument of type '(req: Request, res: Response, next: NextFunction) => void' is not assignable to parameter of type 'MiddlewareFactory<T>'.
cause The middleware factory function passed to `createModule` does not match the expected signature (e.g., it expects options but is called without, or vice-versa, or the return type is incorrect).
fix
Ensure your middleware factory function correctly accepts an options parameter of type T (or void if no options are expected) and returns either a single middleware function (req, res, next) => void or an array of such functions. Verify the T generic type argument passed to createModule matches your Options interface.
breaking Version 0.3.0 dropped support for NestJS versions older than 8 and Node.js versions older than 16. Ensure your project meets these minimum requirements before upgrading.
fix Upgrade your NestJS version to >=8.0.0 and your Node.js version to >=16.0.0. Consider updating your `package.json` `engines` and `@nestjs/common` peer dependency.
gotcha When using `createModule` with optional configurations, it's recommended to cast the result to `FacadeModuleStaticOptional<Options>` to allow calling `forRoot()` without arguments. Without this, TypeScript will require an empty object even if options are truly optional.
fix Apply the `as FacadeModuleStaticOptional<YourOptionsInterface>` type assertion to the module created by `createModule` if you intend to allow `forRoot()` without any arguments.
gotcha This library supports both Express and Fastify platforms; however, not all middleware created for one platform will inherently work with the other. Ensure your custom middleware functions are compatible with the NestJS platform adapter you are using.
fix Test your custom middleware on the target platform (Express or Fastify). You might need to conditionally implement logic or create separate middleware factories for different platforms if incompatibilities arise.
breaking NestJS v11 introduced changes to how middleware registered in global modules is executed, now always running first regardless of dependency graph position. While this library simplifies middleware creation, be aware of the overall middleware execution order in NestJS v11+ applications.
fix Review your application's middleware order, especially if you have global middleware defined both natively and via `create-nestjs-middleware-module` in NestJS v11.
npm install create-nestjs-middleware-module
yarn add create-nestjs-middleware-module
pnpm add create-nestjs-middleware-module

This quickstart demonstrates how to define a functional middleware with options, convert it into a configurable NestJS module using `createModule`, and then integrate it into a `AppModule` with both explicit options and default usage.

import { Module, NestModule, MiddlewareConsumer, INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { Request, Response, NextFunction } from 'express';
import { createModule, FacadeModuleStaticOptional } from 'create-nestjs-middleware-module';

// 1. Define your middleware factory and its options
interface LoggerMiddlewareOptions {
  prefix?: string;
}

function createCustomLoggerMiddleware(options?: LoggerMiddlewareOptions) {
  const prefix = options?.prefix || 'APP';
  return (req: Request, res: Response, next: NextFunction) => {
    console.log(`[${prefix}] Request: ${req.method} ${req.url}`);
    next();
  };
}

// 2. Create your NestJS module using createModule
export const CustomLoggerModule = createModule<LoggerMiddlewareOptions>(
  createCustomLoggerMiddleware
) as FacadeModuleStaticOptional<LoggerMiddlewareOptions>;

// 3. Use the module in your main application
@Module({
  imports: [
    // Example: Configure with options
    CustomLoggerModule.forRoot({
      prefix: 'API',
      forRoutes: ['/data*'] // Apply to routes starting with /data
    }),
    // Example: Use without options (requires FacadeModuleStaticOptional assertion)
    CustomLoggerModule.forRoot(), // Apply to all routes by default
  ],
  controllers: [],
  providers: [],
})
class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    // Additional NestJS native middleware configuration if needed
    // For instance, if you want to exclude specific paths from the CustomLoggerModule's default application
    // consumer
    //   .apply(SomeOtherMiddleware)
    //   .exclude('/admin*')
    //   .forRoutes('*');
  }
}

async function bootstrap() {
  const app: INestApplication = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT || 3000);
  console.log(`Application is running on: ${await app.getUrl()}`);
}

// To run this example, you would typically have an Express/Fastify adapter configured
// and a controller responding to /data* or other routes.
bootstrap();