Express.js • Unit Learning Material

Middleware in Express.js

Think of middleware as a set of checkpoints between a client request and the final response. Each checkpoint can inspect, change, stop, or pass the request to the next step.

1. What is Middleware?

Middleware in Express.js consists of functions that run during the request–response lifecycle. They can process requests, modify responses, and control the application flow.

Client
→
HTTP
Request
→
Middleware
→
HTTP
Response
⚙ Custom logicRuns logic for a request.
🔎 Read / modifyCan read or modify req and res.
🛑 End cycleCan send a response and finish the cycle.
➡ next()Passes control to the next middleware.

2. Basic Middleware Syntax

Express middleware
app.use((req, res, next) => {
  console.log('Middleware executed');
  next();
});
Remember: next() means “I have finished my work; let the next middleware continue.”
  • (req, res, next) => { } — the middleware function that processes the request and response before the final handler.
  • next() — passes control to the next middleware if the request–response cycle has not already ended.

3. How Middleware Works

1Request arrives
The client sends a request to the server.
2Middleware runs
Middleware is applied one function at a time.
3Decision
It either sends a response or calls next().
4Route handler
If the cycle is not ended, the route handler sends the final response.
Key idea: Express executes middleware sequentially in the order in which the middleware functions are added to the application.

4. Types of Middleware

ExpressJS provides different types of middleware. Choose the type according to the functionality required.

1. Application-level Middleware

Runs across the entire Express application and handles common logic for incoming requests.

  • Registered using app.use() or app.METHOD().
  • Executes for routes and HTTP methods according to how it is registered.
  • Common uses: logging, authentication, body parsing, and headers.
app.use(express.json());

app.use((req, res, next) => {
  console.log('Request received:', req.method, req.url);
  next();
});

2. Router-level Middleware

Applies to a specific router, so middleware can be limited to a defined group of routes.

  • Registered using router.use() or router.METHOD().
  • Runs only for routes within that router.
  • Useful for modular route groups such as user or authentication routes.
  • Helps code organization and maintainability.
const router = express.Router();

router.use((req, res, next) => {
  console.log('Router-specific middleware');
  next();
});

router.get('/dashboard', (req, res) => {
  res.send('Dashboard Page');
});

app.use('/user', router);

3. Error-handling Middleware

Captures and processes runtime errors during the request–response cycle.

  • Defined with four parameters: err, req, res, next.
  • Can send consistent error responses.
  • Helps prevent an error from leaving the application without a handled response.
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something went wrong!');
});

4. Built-in Middleware

Express provides built-in middleware for common server-side tasks.

  • express.static() serves static files such as images, CSS, and JS.
  • express.json() parses incoming JSON request bodies.
app.use(express.static('public'));
app.use(express.json());

5. Third-party Middleware

Third-party middleware extends an Express application through npm packages.

  • Developed by external contributors and installed through npm.
  • Adds features such as logging, security, and validation.
  • Examples in the source: morgan and body-parser.
const morgan = require('morgan');
app.use(morgan('dev'));

const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));

5. Middleware Chaining

Middleware can be connected like a chain. Each function gets a chance to process the request before the next step.

Request
→
1Body Parsing
→ next() →
2Authentication
→ next() →
3Router
→
Response
  • Middleware runs in order as a chain.
  • Each middleware can process or modify the request.
  • The final handler sends the response to the client.
  • next() passes control to the next middleware in the chain.

6. Complete Middleware Chaining Example

const express = require('express');
const app = express();

// Middleware 1: Log request method and URL
app.use((req, res, next) => {
  console.log(`${req.method} request to ${req.url}`);
  next();
});

// Middleware 2: Add a custom header
app.use((req, res, next) => {
  res.setHeader('X-Custom-Header', 'Middleware Chaining Example');
  next();
});

// Route handler
app.get('/', (req, res) => {
  res.send('Hello, World!');
});

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});
Middleware 1
Logs the HTTP method and URL of the incoming request.
Middleware 2
Sets the response header X-Custom-Header.
Route Handler
Sends Hello, World! as the response.

Expected output

When a client makes a GET request to http://localhost:3000/, the server responds:

Hello, World!

7. Quick Mind Map

MIDDLEWARE
↓
ApplicationWhole application
RouterSpecific router
Error-handlingHandles errors
Built-in / Third-partyReady-made functionality
Core flow: Request → Middleware → next() → Next Middleware → Route Handler → Response

8. Quick Self-Check

1. Which function passes control to the next middleware?
Answer: next()
2. What are the four parameters of error-handling middleware?
Answer: err, req, res, next
3. Which built-in middleware serves static files?
Answer: express.static()
4. In what order does Express execute middleware?
Answer: Sequentially, in the order the middleware is added.