CodingNic

Middleware

What Is Middleware?

Middleware 12 min read

What Is Middleware?

Objectives

By the end of this lesson, you should be able to:

  • Explain what a middleware function is and its three parameters
  • Register middleware with app.use()
  • Explain why calling next() is required, and what happens if it’s forgotten

💡 Why this matters: Almost every non-trivial thing an Express app does, parsing a JSON body (Module 5), serving static files (Module 5), logging, authentication, runs through middleware. It’s the single most important pattern for understanding how a real Express app is actually built.

⚠️ A note on verification: every snippet and every response shown below was actually run and tested with real HTTP requests.

A Middleware Function

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

function logger(req, res, next) {
  console.log(`[middleware] ${req.method} ${req.url}`);
  next();
}

app.use(logger);

app.get('/', (req, res) => {
  res.send('Homepage');
});

app.listen(4201);
bash
curl http://localhost:4201/

Server-side log:

text
[middleware] GET /

Response:

text
Homepage

A middleware function takes three parameters, (req, res, next), the same req/res from every route handler (Module 5), plus next, a function that hands control to whatever comes after this middleware. app.use(middlewareFn) registers it to run on every incoming request, before any route handler.

Calling next() Is Required

javascript
app.use((req, res, next) => {
  console.log('middleware ran, forgot to call next()');
  // next() intentionally omitted
});

app.get('/', (req, res) => {
  console.log('this never runs');
  res.send('done');
});
bash
curl http://localhost:4205/
text
(request hangs, no response ever arrives)

Without calling next(), Express has no way to know the middleware finished, the request simply hangs forever, the route handler never runs, and the client never gets a response. This is one of the most common real Express bugs, forgetting next() inside a middleware function that doesn’t itself send a response.

Middleware Runs in Registration Order

javascript
app.use((req, res, next) => {
  console.log('step 1: first middleware');
  next();
});

app.use((req, res, next) => {
  console.log('step 2: second middleware');
  next();
});

app.get('/', (req, res) => {
  console.log('step 3: route handler');
  res.send('done');
});
text
step 1: first middleware
step 2: second middleware
step 3: route handler

Each middleware runs, calls next(), and control passes to the next one registered, in order, a route handler is really just the last step in this same chain, the one that actually sends a response instead of calling next(). This ordered, pass-it-along design is called a pipeline, every request flows through it from top to bottom.

Try It

  1. Write a middleware function that logs the current timestamp (new Date().toISOString()) for every request, register it with app.use(), and confirm it logs on every route.
  2. Temporarily remove the next() call from your middleware, send a request, and confirm it hangs, then add next() back.
  3. Register two separate logging middleware functions, each printing a different message, and confirm both run, in order, before the route handler.
  4. Explain, in your own words, why a middleware function needs next as a parameter at all, when a route handler doesn’t.

Recap

  • Middleware is a function with (req, res, next), registered with app.use(), running before route handlers.
  • Forgetting to call next() (in middleware that doesn’t itself send a response) hangs the request forever.
  • Middleware runs in the order it’s registered, forming a pipeline every request flows through, a route handler is the final step in that same pipeline.

Next lesson: Express’s built-in middleware, express.json(), express.urlencoded(), and static file serving.