0
0
Expressframework~15 mins

Middleware factory pattern in Express - Deep Dive

Choose your learning style9 modes available
Overview - Middleware factory pattern
What is it?
The middleware factory pattern in Express is a way to create middleware functions that can be customized with parameters. Instead of writing a fixed middleware, you write a function that returns a middleware function. This lets you reuse middleware logic with different settings easily. It helps keep your code clean and flexible.
Why it matters
Without middleware factories, you would have to write many similar middleware functions for different cases, causing repeated code and harder maintenance. Middleware factories solve this by letting you create configurable middleware on the fly, making your app easier to extend and adapt. This saves time and reduces bugs in real projects.
Where it fits
Before learning middleware factories, you should understand basic Express middleware and how functions work in JavaScript. After this, you can learn about advanced middleware patterns, error handling middleware, and how to compose middleware chains for complex apps.
Mental Model
Core Idea
A middleware factory is a function that creates and returns a middleware function customized with specific settings.
Think of it like...
It's like a cookie cutter that you can adjust to make cookies of different shapes and sizes, instead of having one fixed cookie shape.
Middleware Factory Pattern

┌───────────────┐
│ Factory Func  │
│ (with params) │
└──────┬────────┘
       │ returns
       ▼
┌───────────────┐
│ Middleware    │
│ Function      │
└───────────────┘
       │ used by
       ▼
┌───────────────┐
│ Express App   │
└───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Express Middleware Basics
🤔
Concept: Learn what middleware functions are and how they work in Express.
Middleware in Express is a function that has access to the request and response objects and can modify them or control the flow. It usually looks like (req, res, next) => { ... } and calls next() to pass control to the next middleware.
Result
You can add reusable logic that runs on every request or specific routes.
Understanding middleware basics is essential because middleware factories build on this concept by creating middleware functions dynamically.
2
FoundationFunctions Returning Functions in JavaScript
🤔
Concept: Learn that in JavaScript, functions can return other functions.
A function can create and return another function. For example, function makeAdder(x) { return function(y) { return x + y; }; } creates a function that adds x to y.
Result
You can create customized functions by calling a factory function with parameters.
Knowing that functions can return functions unlocks the ability to create middleware factories that produce middleware with different behaviors.
3
IntermediateCreating a Simple Middleware Factory
🤔Before reading on: do you think a middleware factory can accept parameters and still behave like normal middleware? Commit to yes or no.
Concept: Combine middleware and function-returning-function concepts to create a middleware factory.
Write a function that takes parameters and returns a middleware function. For example: function logger(prefix) { return function(req, res, next) { console.log(prefix, req.method, req.url); next(); }; } Use it as app.use(logger('INFO:')) to log requests with a prefix.
Result
You get middleware that logs requests with a custom prefix each time you call the factory with a different prefix.
Understanding that middleware factories let you customize middleware behavior per use case makes your code more flexible and reusable.
4
IntermediateUsing Middleware Factories for Authorization
🤔Before reading on: can middleware factories help create different authorization checks with one function? Commit to yes or no.
Concept: Use middleware factories to create middleware that checks user roles or permissions dynamically.
Example: function checkRole(role) { return function(req, res, next) { if (req.user && req.user.role === role) { next(); } else { res.status(403).send('Forbidden'); } }; } Use as app.use('/admin', checkRole('admin')) to protect admin routes.
Result
You can protect routes with different role checks using one factory function.
Middleware factories enable powerful, reusable security checks tailored to different routes or users.
5
IntermediatePassing Configuration Objects to Middleware Factories
🤔
Concept: Middleware factories can accept complex configuration objects, not just simple parameters.
Example: function rateLimiter(options) { const { maxRequests, windowMs } = options; return function(req, res, next) { // logic to limit requests based on maxRequests and windowMs next(); }; } Use as app.use(rateLimiter({ maxRequests: 10, windowMs: 60000 }));
Result
Middleware behavior can be finely tuned with detailed settings passed to the factory.
Accepting configuration objects makes middleware factories scalable and adaptable to many scenarios.
6
AdvancedStacking Multiple Middleware Factories
🤔Before reading on: do you think multiple middleware factories can be combined in one route? Commit to yes or no.
Concept: You can use several middleware factories together to build complex middleware chains.
Example: app.use( logger('DEBUG:'), checkRole('user'), rateLimiter({ maxRequests: 5, windowMs: 30000 }) ); Each factory returns middleware that runs in order.
Result
Middleware factories compose well, letting you build layered request handling.
Knowing how to combine middleware factories helps build modular and maintainable Express apps.
7
ExpertPerformance and Memory Considerations in Middleware Factories
🤔Before reading on: do you think creating middleware factories inside request handlers is a good idea? Commit to yes or no.
Concept: Middleware factories should be created once during app setup, not on every request, to avoid performance issues.
If you create middleware factories inside request handlers, you create new functions every time, causing memory bloat and slower performance. Instead, create middleware once and reuse it. Example of bad practice: app.get('/data', (req, res, next) => { const mw = checkRole('user'); // creates new middleware every request mw(req, res, next); }); Better: const userCheck = checkRole('user'); app.get('/data', userCheck, (req, res) => { ... });
Result
Middleware factories used properly improve performance and avoid memory leaks.
Understanding when and where to create middleware factories prevents subtle bugs and resource waste in production.
Under the Hood
Middleware factories are just functions that return other functions. When Express receives a request, it calls the middleware functions in order. The factory function runs once when the app starts or when the middleware is added, producing a middleware function that Express calls on each request. This means the factory sets up any configuration or state once, and the returned middleware handles requests efficiently.
Why designed this way?
This pattern was designed to avoid repeating similar middleware code for different configurations. It leverages JavaScript's first-class functions to create flexible middleware without changing Express's core. Alternatives like hardcoding middleware for each case would be less maintainable and scalable.
App Setup Phase

┌───────────────┐
│ Middleware    │
│ Factory Func  │
│ (runs once)   │
└──────┬────────┘
       │ returns
       ▼
┌───────────────┐
│ Middleware    │
│ Function      │
│ (runs per req)│
└──────┬────────┘
       │ called by
       ▼
┌───────────────┐
│ Express       │
│ Request Flow  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do you think middleware factories run their inner middleware code every time the app starts? Commit to yes or no.
Common Belief:Middleware factories run their inner middleware code every time the app starts or on every request.
Tap to reveal reality
Reality:Middleware factories run only once when the middleware is added, producing a middleware function that runs on each request.
Why it matters:Thinking factories run middleware code multiple times can lead to confusion about performance and state management.
Quick: Do you think middleware factories can be created inside request handlers safely? Commit to yes or no.
Common Belief:It's fine to create middleware factories inside request handlers to customize behavior per request.
Tap to reveal reality
Reality:Creating middleware factories inside request handlers causes new functions to be created on every request, hurting performance and memory.
Why it matters:Misusing middleware factories this way can cause slowdowns and memory leaks in production apps.
Quick: Do you think middleware factories can only accept simple parameters like strings or numbers? Commit to yes or no.
Common Belief:Middleware factories can only accept simple parameters like strings or numbers.
Tap to reveal reality
Reality:Middleware factories can accept complex objects, functions, or any data to configure middleware behavior.
Why it matters:Limiting parameters reduces flexibility and prevents building powerful, reusable middleware.
Quick: Do you think middleware factories replace the need for regular middleware? Commit to yes or no.
Common Belief:Middleware factories replace regular middleware and should always be used.
Tap to reveal reality
Reality:Middleware factories are a pattern to create configurable middleware but do not replace simple middleware that doesn't need parameters.
Why it matters:Overusing factories can add unnecessary complexity when simple middleware suffices.
Expert Zone
1
Middleware factories can close over variables, allowing them to maintain private state between requests if designed carefully.
2
Using middleware factories with async functions requires careful error handling to avoid unhandled promise rejections.
3
Middleware factories can be combined with dependency injection patterns to improve testability and modularity.
When NOT to use
Avoid middleware factories when your middleware does not need configuration or parameters; simple middleware functions are clearer and more efficient. Also, do not create middleware factories inside request handlers or loops; instead, create them once during app setup. For very complex middleware, consider using classes or external libraries that provide more structure.
Production Patterns
In production, middleware factories are used to create reusable logging, authentication, authorization, and rate-limiting middleware. They are often combined with environment-based configuration to enable or disable features. Factories help build modular Express apps where middleware can be shared across routes or even projects.
Connections
Higher-Order Functions
Middleware factories are a specific use of higher-order functions that return functions.
Understanding higher-order functions in JavaScript helps grasp how middleware factories create customized middleware dynamically.
Dependency Injection
Middleware factories can be used to inject dependencies or configuration into middleware functions.
Knowing dependency injection patterns helps design middleware factories that are easier to test and maintain.
Factory Design Pattern (Software Engineering)
Middleware factories implement the factory design pattern by creating objects (middleware functions) with specific configurations.
Recognizing middleware factories as an application of the factory pattern connects Express middleware design to broader software engineering principles.
Common Pitfalls
#1Creating middleware factories inside request handlers causing performance issues.
Wrong approach:app.get('/data', (req, res, next) => { const mw = checkRole('user'); mw(req, res, next); });
Correct approach:const userCheck = checkRole('user'); app.get('/data', userCheck, (req, res) => { ... });
Root cause:Misunderstanding that middleware factories should be created once, not per request.
#2Passing fixed middleware instead of a factory when customization is needed.
Wrong approach:app.use(checkRole); // no parameters, can't customize role
Correct approach:app.use(checkRole('admin')); // factory called with parameter
Root cause:Not realizing middleware factories require calling the factory function to get middleware.
#3Assuming middleware factories run middleware code on app start, causing confusion about side effects.
Wrong approach:function logger(prefix) { console.log('Logger factory running'); return function(req, res, next) { ... }; } app.use(logger('INFO'));
Correct approach:function logger(prefix) { return function(req, res, next) { ... }; } app.use(logger('INFO'));
Root cause:Confusing factory execution (once) with middleware execution (per request).
Key Takeaways
Middleware factory pattern lets you create middleware functions customized with parameters, improving code reuse and flexibility.
It relies on JavaScript functions returning functions, a powerful concept for dynamic behavior.
Middleware factories should be created once during app setup to avoid performance and memory issues.
They enable modular, configurable middleware for logging, authorization, rate limiting, and more in Express apps.
Understanding middleware factories connects Express middleware design to broader software engineering patterns like factories and dependency injection.