Bird
Raised Fist0
NestJSframework~15 mins

Creating middleware in NestJS - Mechanics & Internals

Choose your learning style10 modes available
Overview - Creating middleware
What is it?
Middleware in NestJS is a function that runs before the route handler. It can modify the request or response objects or end the request-response cycle. Middleware helps add common logic like logging, authentication, or data parsing to many routes without repeating code. It acts as a checkpoint for incoming requests.
Why it matters
Without middleware, you would have to write the same code inside every route handler, making your app messy and hard to maintain. Middleware lets you keep your code clean and organized by handling shared tasks in one place. This saves time and reduces bugs, making your app more reliable and easier to update.
Where it fits
Before learning middleware, you should understand basic NestJS concepts like modules, controllers, and providers. After mastering middleware, you can explore advanced topics like guards, interceptors, and exception filters to control request flow and error handling.
Mental Model
Core Idea
Middleware is a gatekeeper function that processes requests before they reach the main route handler.
Think of it like...
Middleware is like a security guard at a building entrance who checks visitors before letting them inside. The guard can ask questions, check IDs, or stop people from entering if needed.
Incoming Request
     ↓
┌───────────────┐
│   Middleware  │  → modifies or blocks request
└───────────────┘
     ↓
┌───────────────┐
│ Route Handler │  → processes request and sends response
└───────────────┘
     ↓
Outgoing Response
Build-Up - 6 Steps
1
FoundationWhat is Middleware in NestJS
🤔
Concept: Middleware is a function that runs before route handlers to process requests.
In NestJS, middleware functions receive the request and response objects and a next function. They can read or change the request, perform actions like logging, and then call next() to pass control to the next middleware or route handler.
Result
Middleware runs automatically on matching routes before the main handler.
Understanding middleware as a pre-route step helps you see how to insert shared logic without repeating code.
2
FoundationHow to Create Basic Middleware
🤔
Concept: Middleware is created as a class implementing NestJS's MiddlewareInterface.
Create a class with a method called 'use' that takes request, response, and next. Inside 'use', add your logic and call next() to continue. Then, apply this middleware in a module to specific routes.
Result
Middleware class runs its 'use' method on requests to configured routes.
Knowing the class structure and 'use' method is key to writing middleware that fits NestJS patterns.
3
IntermediateApplying Middleware to Routes
🤔Before reading on: Do you think middleware applies globally or only to routes you specify? Commit to your answer.
Concept: Middleware can be applied globally or to specific routes using the module's configure method.
In your module, implement the 'configure' method from NestModule. Use 'consumer.apply(MyMiddleware).forRoutes('path')' to apply middleware only to certain routes. You can also use '*' to apply to all routes.
Result
Middleware runs only on routes you specify, giving control over where logic applies.
Knowing how to target middleware prevents unnecessary processing and improves app performance.
4
IntermediateUsing Middleware for Common Tasks
🤔Before reading on: Can middleware modify the request object for later handlers? Commit to yes or no.
Concept: Middleware can add or change data on the request object for use in route handlers.
For example, middleware can add a 'user' property to the request after verifying a token. Later, route handlers can read 'request.user' to know who is making the request.
Result
Middleware enriches requests with useful data, enabling cleaner route handlers.
Understanding request modification unlocks powerful patterns like authentication and data validation.
5
AdvancedMiddleware Execution Order and Stacking
🤔Before reading on: If multiple middleware apply to a route, do they run in the order declared or reverse? Commit to your answer.
Concept: Middleware runs in the order they are applied, one after another, before the route handler.
When you apply multiple middleware, NestJS calls them sequentially. Each must call next() to pass control. If one middleware does not call next(), the chain stops and the request ends there.
Result
Middleware stacking allows building complex request processing pipelines.
Knowing execution order helps avoid bugs where middleware unintentionally blocks requests.
6
ExpertMiddleware vs Guards and Interceptors
🤔Before reading on: Do you think middleware can handle authorization as well as guards? Commit to yes or no.
Concept: Middleware runs before guards and interceptors and is best for low-level tasks, while guards handle authorization and interceptors handle response transformation.
Middleware is good for tasks like logging, parsing, or adding data. Guards decide if a request can proceed based on roles or permissions. Interceptors modify responses or handle errors. Mixing these correctly leads to clean, maintainable code.
Result
Clear separation of concerns improves app security and maintainability.
Understanding the distinct roles of middleware, guards, and interceptors prevents misuse and design mistakes.
Under the Hood
NestJS middleware are functions or classes that the framework calls during the HTTP request lifecycle before reaching controllers. Internally, NestJS uses Express or Fastify under the hood, which handle middleware as a chain of functions. Each middleware receives the request and response objects and a next callback. Calling next() passes control to the next middleware or route handler. If next() is not called, the request stops there. NestJS wraps this native middleware mechanism in a class-based interface for consistency and dependency injection.
Why designed this way?
NestJS designed middleware to align with popular Node.js frameworks like Express, making it familiar and compatible. Using classes and interfaces fits NestJS's modular and injectable architecture, allowing middleware to use services and other dependencies easily. This design balances flexibility with structure, enabling developers to write reusable, testable middleware while leveraging existing Node.js middleware patterns.
Incoming HTTP Request
     ↓
┌─────────────────────┐
│ NestJS Middleware   │
│ (class with 'use')  │
└─────────┬───────────┘
          ↓ calls next()
┌─────────┴───────────┐
│ Next Middleware or  │
│ Route Handler       │
└─────────┬───────────┘
          ↓
┌─────────┴───────────┐
│ Response Sent Back  │
└─────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does middleware automatically handle errors if something goes wrong? Commit to yes or no.
Common Belief:Middleware automatically catches and handles errors in the request pipeline.
Tap to reveal reality
Reality:Middleware does not handle errors unless explicitly coded to do so. Errors must be passed to error-handling middleware or caught elsewhere.
Why it matters:Assuming middleware handles errors can cause unhandled exceptions and crash the app.
Quick: Can middleware modify the response after the route handler sends it? Commit to yes or no.
Common Belief:Middleware can change the response after the route handler finishes processing.
Tap to reveal reality
Reality:Middleware runs before the route handler and cannot modify the response after it is sent. For response modification, use interceptors.
Why it matters:Trying to modify response in middleware leads to bugs and unexpected behavior.
Quick: If middleware forgets to call next(), does the request continue? Commit to yes or no.
Common Belief:If middleware does not call next(), the request still proceeds to the route handler.
Tap to reveal reality
Reality:If next() is not called, the request stops and the client waits indefinitely or times out.
Why it matters:Forgetting next() causes requests to hang, making the app unresponsive.
Quick: Is middleware the best place to check user permissions? Commit to yes or no.
Common Belief:Middleware is the ideal place to handle user authorization and permissions.
Tap to reveal reality
Reality:Guards are designed for authorization logic; middleware is better for generic tasks like logging or parsing.
Why it matters:Using middleware for authorization can lead to security holes and harder-to-maintain code.
Expert Zone
1
Middleware can be asynchronous and return promises, but forgetting to await or call next() properly causes subtle bugs.
2
Middleware ordering affects performance and behavior; placing heavy middleware globally can slow all requests unnecessarily.
3
Middleware can share state via request properties, but this must be done carefully to avoid conflicts or leaks.
When NOT to use
Avoid using middleware for authorization or response transformation; use guards and interceptors instead. Also, do not use middleware for error handling; use dedicated error filters. For complex request lifecycle control, prefer NestJS's built-in guards and interceptors.
Production Patterns
In production, middleware is often used for logging requests, parsing JSON bodies, handling CORS, and adding security headers. Middleware chaining is carefully ordered to optimize performance. Authorization is handled by guards, while interceptors manage response formatting and caching.
Connections
HTTP Request Lifecycle
Middleware is an early step in the HTTP request lifecycle before controllers.
Understanding middleware clarifies how requests flow through a server and where to insert logic.
Express Middleware
NestJS middleware builds on Express middleware patterns but adds class-based structure.
Knowing Express middleware helps grasp NestJS middleware faster and leverage existing middleware packages.
Assembly Line Manufacturing
Middleware is like stations on an assembly line, each adding or checking something before the product moves on.
Seeing middleware as a stepwise process helps design clear, maintainable request handling.
Common Pitfalls
#1Middleware does not call next(), causing requests to hang.
Wrong approach:use(req, res, next) { console.log('Request received'); // forgot to call next() }
Correct approach:use(req, res, next) { console.log('Request received'); next(); }
Root cause:Misunderstanding that next() must be called to continue the request chain.
#2Trying to modify response after route handler in middleware.
Wrong approach:use(req, res, next) { next(); res.send('Modified response'); }
Correct approach:use(req, res, next) { res.setHeader('X-Custom', 'value'); next(); }
Root cause:Not realizing middleware runs before the route handler sends the response.
#3Using middleware for authorization logic instead of guards.
Wrong approach:use(req, res, next) { if (!req.user.isAdmin) { res.status(403).send('Forbidden'); } else { next(); } }
Correct approach:Implement a guard that checks user roles and returns true or false to allow or deny access.
Root cause:Confusing middleware's role with guards designed for authorization.
Key Takeaways
Middleware in NestJS runs before route handlers to process requests and add shared logic.
Middleware is implemented as classes with a 'use' method and applied to routes via the module's configure method.
Middleware can modify the request object but cannot change the response after it is sent.
Proper middleware ordering and calling next() are essential to avoid request hangs and bugs.
Middleware is best for generic tasks like logging and parsing; use guards and interceptors for authorization and response handling.

Practice

(1/5)
1. What is the main purpose of middleware in a NestJS application?
easy
A. To handle server errors automatically
B. To define database models
C. To run code before the request reaches the route handler
D. To create UI components

Solution

  1. Step 1: Understand middleware role

    Middleware is code that runs before the main route handler processes a request.
  2. Step 2: Compare options

    Only To run code before the request reaches the route handler describes this behavior correctly; others describe unrelated tasks.
  3. Final Answer:

    To run code before the request reaches the route handler -> Option C
  4. Quick Check:

    Middleware runs before routes [OK]
Hint: Middleware always runs before route handlers [OK]
Common Mistakes:
  • Confusing middleware with controllers
  • Thinking middleware handles UI rendering
  • Assuming middleware manages database models
2. Which of the following is the correct way to define a middleware class in NestJS?
easy
A. const MyMiddleware = (req, res, next) => { next(); }
B. class MyMiddleware { handle(req, res, next) { next(); } }
C. function MyMiddleware(req, res, next) { next(); }
D. class MyMiddleware { use(req, res, next) { next(); } }

Solution

  1. Step 1: Recall NestJS middleware pattern

    Middleware must be a class with a method named use that takes req, res, next.
  2. Step 2: Check options

    Only class MyMiddleware { use(req, res, next) { next(); } } defines a class with a use method correctly. class MyMiddleware { handle(req, res, next) { next(); } } uses handle, which is invalid. Options C and D define functions, not classes.
  3. Final Answer:

    class MyMiddleware { use(req, res, next) { next(); } } -> Option D
  4. Quick Check:

    Middleware class must have use() method [OK]
Hint: Middleware class must have a use() method [OK]
Common Mistakes:
  • Using method name other than use
  • Defining middleware as a function instead of class
  • Forgetting to call next() inside use
3. Given this middleware class, what will be logged when a request to '/some-path' hits the route?
class LoggerMiddleware {
  use(req, res, next) {
    console.log('Request URL:', req.url);
    next();
  }
}
medium
A. Request URL: /some-path
B. Request URL: undefined
C. No output because next() is missing
D. Error: use method not found

Solution

  1. Step 1: Analyze middleware behavior

    The middleware logs the request URL from req.url and then calls next() to continue.
  2. Step 2: Predict output

    When a request to '/some-path' arrives, it logs 'Request URL: /some-path'. No errors occur because use is defined and next() is called.
  3. Final Answer:

    Request URL: /some-path -> Option A
  4. Quick Check:

    Middleware logs req.url correctly [OK]
Hint: Middleware logs req.url before calling next() [OK]
Common Mistakes:
  • Forgetting to call next() causing no further processing
  • Assuming req.url is undefined
  • Confusing method name use with handle
4. What is wrong with this middleware code?
class LoggerMiddleware {
  use(req, res, next) {
    console.log('Request received');
  }
}

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(LoggerMiddleware).forRoutes('users');
  }
}
medium
A. Missing call to next() inside LoggerMiddleware
B. MiddlewareConsumer must be imported from '@nestjs/common' not '@nestjs/core'
C. The configure method should return a value
D. No semicolon after forRoutes call

Solution

  1. Step 1: Check middleware code

    The registration uses MiddlewareConsumer correctly, but examine the LoggerMiddleware class.
  2. Step 2: Identify the error

    The use method does not call next(), causing the request to hang without reaching the route handler.
  3. Final Answer:

    Missing call to next() inside LoggerMiddleware -> Option A
  4. Quick Check:

    Middleware must call next() to continue [OK]
Hint: Always call next() inside middleware use() method [OK]
Common Mistakes:
  • Forgetting next() call causing request hang
  • Thinking configure must return a value
  • Confusing import sources for MiddlewareConsumer
5. You want to apply a middleware only to POST requests on the '/login' route. How can you achieve this in NestJS?
hard
A. Use consumer.apply(MyMiddleware).forRoutes('/login') and check method inside middleware
B. Use consumer.apply(MyMiddleware).forRoutes({ path: '/login', method: RequestMethod.POST })
C. Apply middleware globally and filter POST requests inside middleware
D. NestJS does not support method-specific middleware

Solution

  1. Step 1: Understand method-specific middleware application

    In NestJS, you can specify route and HTTP method using an object with path and method in forRoutes.
  2. Step 2: Evaluate options

    Use consumer.apply(MyMiddleware).forRoutes({ path: '/login', method: RequestMethod.POST }) correctly uses { path: '/login', method: RequestMethod.POST }. Use consumer.apply(MyMiddleware).forRoutes('/login') and check method inside middleware applies middleware to all methods on '/login', requiring manual filtering. Apply middleware globally and filter POST requests inside middleware applies globally, which is less efficient. NestJS does not support method-specific middleware is false.
  3. Final Answer:

    Use consumer.apply(MyMiddleware).forRoutes({ path: '/login', method: RequestMethod.POST }) -> Option B
  4. Quick Check:

    Use forRoutes with path and method object [OK]
Hint: Use forRoutes with path and method object for specific HTTP verbs [OK]
Common Mistakes:
  • Applying middleware to all methods unintentionally
  • Not importing RequestMethod enum
  • Assuming method-specific middleware is unsupported
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard