| |

Node.js 31 🟢 Built-in and Third-Party Express Middleware

Express is a routing and middleware web framework with minimal functionality of its own. An Express application is essentially a series of middleware function calls. The framework provides a small set of built-in middleware, and a large ecosystem of third-party middleware extends the framework for the common tasks: security, logging, compression, cookies, and CORS. Knowing which middleware is built in, which is installed, and which order they run in is the difference between an application that works and an application that hangs.

Key point: Express has three built-in middleware functions: express.static for serving static files, express.json for parsing JSON bodies, and express.urlencoded for parsing URL-encoded form bodies. Everything else—helmet, cors, morgan, compression, cookie-parser—is a third-party module installed with npm. Middleware executes in the order it is registered with app.use(), and error-handling middleware (four arguments) must be registered last.


Why middleware matters

The minimal core problem. Express does not parse request bodies, set security headers, log requests, or compress responses by default. It provides the middleware chain and the routing, and the application composes the behavior. The built-in middleware covers the most common needs: static files and body parsing. The third-party middleware covers the rest.

The order problem. Middleware functions are executed in the order they are loaded. If the body parser is registered after the route that reads req.body, the route sees undefined. If the error handler is registered before the routes, it is never reached. The order is not arbitrary; it follows from the request-response cycle .

The error-handling problem. The error-handling middleware has four arguments, not three. Express identifies it by the arity of the function. A function with three arguments is a regular middleware; a function with four is an error handler. The error handler must be registered after all the other middleware and routes .

The third-party problem. The Express ecosystem is the framework’s strength. The middleware modules are small, focused, and composable. helmet sets security headers. cors enables cross-origin requests. morgan logs requests. compression compresses responses. cookie-parser parses cookies. Each one is a function with the middleware signature, and each one is registered with app.use() .

The performance problem. Middleware runs on every request. A middleware that does unnecessary work on every request is a performance cost. The order and the scope matter: a middleware registered on a specific path runs only for that path, while a middleware registered with app.use() without a path runs for every request .


a. The built-in middleware

Express provides three built-in middleware functions. They are part of the framework and do not require a separate installation.

express.static serves static files such as HTML, CSS, JavaScript, and images. It takes a directory path and serves the files from that directory .

app.use(express.static('public'))

A request for /logo.png serves public/logo.png. The middleware handles the file lookup, the content type, and the caching headers.

express.json parses incoming requests with JSON payloads. It reads the request body and populates req.body with the parsed object. It is available with Express 4.16.0 and later .

app.use(express.json())

A request with the Content-Type: application/json header and a JSON body produces req.body with the parsed data. Without the middleware, req.body is undefined.

express.urlencoded parses incoming requests with URL-encoded payloads, the format typically sent by HTML forms. It populates req.body with the parsed data .

app.use(express.urlencoded({ extended: true }))

The extended: true option uses the qs library for parsing, which supports nested objects and arrays. The extended: false option uses the querystring library, which does not.

The built-in middleware is registered with app.use() and runs on the requests that match the middleware’s scope. The order matters: express.json() must be registered before the routes that read req.body .


b. The third-party middleware

The third-party middleware is installed with npm and registered with app.use(). The Express team maintains a list of the common modules .

helmet helps secure the application by setting various HTTP headers. It sets headers like X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, and Content-Security-Policy .

const helmet = require('helmet')
app.use(helmet())

The middleware is registered early so that the headers are set on every response.

cors enables Cross-Origin Resource Sharing with various options. It sets the Access-Control-Allow-Origin header and handles the preflight requests .

const cors = require('cors')
app.use(cors())

The default configuration allows all origins. The options object restricts the origins, the methods, and the headers.

morgan is an HTTP request logger. It logs the requests in a configurable format .

const morgan = require('morgan')
app.use(morgan('combined'))

The combined format is the Apache combined log format. The dev format is the colored, concise format for development.

compression compresses the HTTP responses. It uses gzip or Brotli depending on the client’s Accept-Encoding header .

const compression = require('compression')
app.use(compression())

The middleware is registered early so that it wraps the response and compresses the body.

cookie-parser parses the Cookie header and populates req.cookies. It optionally parses the signed cookies into req.signedCookies .

const cookieParser = require('cookie-parser')
app.use(cookieParser())

The middleware is registered before the routes that read req.cookies.

express-session manages the user sessions. It stores the session data on the server and sets a session cookie on the client.

const session = require('express-session')
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))

The secret is used to sign the session ID cookie. The session middleware must be registered after cookie-parser if the application uses both .


c. The middleware order and the error handler

The order of the middleware is the order of the execution. The middleware registered first runs first, and the route handlers run after the middleware that applies to their path .

A recommended order for a typical application :

OrderMiddlewarePurpose
1express.json()Parse JSON bodies
2express.urlencoded()Parse form bodies
3cookie-parserParse cookies
4helmetSecurity headers
5corsCross-origin requests
6morganRequest logging
7compressionResponse compression
8Authentication middlewareVerify identity
9Route handlersProcess requests
10404 handlerUnmatched routes
11Error handlerCatch errors

The order is a guideline, not a rule. The body parsers must run before the routes that read req.body. The authentication middleware must run before the routes that require a user. The error handler must run last .

The error-handling middleware has four arguments. The signature is (err, req, res, next). Express identifies the middleware as an error handler by the number of arguments. The middleware must be registered after all the other middleware and routes .

app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

The error handler can be registered multiple times for different error types. When next(err) is called, Express skips the regular middleware and jumps to the next error handler .

The 404 handler is not an error handler in the Express sense, but it is often implemented as a middleware registered after the routes and before the error handler.

app.use((req, res, next) => {
  res.status(404).send('Not found')
})

The middleware runs for the requests that the routes did not match. It sends the 404 response and does not call next() .


Complete Example Session

// ============================================
// PART 1: BUILT-IN MIDDLEWARE
// ============================================
const express = require('express')
const app = express()

app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(express.static('public'))
// ============================================
// PART 2: THIRD-PARTY MIDDLEWARE
// ============================================
const helmet = require('helmet')
const cors = require('cors')
const morgan = require('morgan')
const compression = require('compression')
const cookieParser = require('cookie-parser')
// ============================================
// PART 3: REGISTERING THE MIDDLEWARE
// ============================================
app.use(helmet())
app.use(cors())
app.use(morgan('combined'))
app.use(compression())
app.use(cookieParser())
// ============================================
// PART 4: BODY PARSING ORDER
// ============================================
app.use(express.json())  // must run before routes
app.use(express.urlencoded({ extended: true }))
// ============================================
// PART 5: ROUTE HANDLER
// ============================================
app.post('/api/users', (req, res) => {
  res.json({ received: req.body })
})
// ============================================
// PART 6: AUTHENTICATION MIDDLEWARE
// ============================================
function requireAuth(req, res, next) {
  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Unauthorized' })
  }
  next()
}

app.get('/api/protected', requireAuth, (req, res) => {
  res.json({ data: 'secret' })
})
// ============================================
// PART 7: 404 HANDLER
// ============================================
app.use((req, res, next) => {
  res.status(404).json({ error: 'Not found' })
})
// ============================================
// PART 8: ERROR HANDLER
// ============================================
app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(err.statusCode || 500).json({
    error: err.message || 'Internal Server Error'
  })
})
// ============================================
// PART 9: MULTIPLE ERROR HANDLERS
// ============================================
app.use((err, req, res, next) => {
  console.error(`[${new Date().toISOString()}] ${err}`)
  next(err)
})

app.use((err, req, res, next) => {
  res.status(err.statusCode || 500).json({ error: err.message })
})
// ============================================
// PART 10: COMPLETE ORDER
// ============================================
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(cookieParser())
app.use(helmet())
app.use(cors())
app.use(morgan('combined'))
app.use(compression())
app.use(requireAuth)
app.use('/api', apiRouter)
app.use((req, res) => res.status(404).json({ error: 'Not found' }))
app.use((err, req, res, next) => {
  res.status(err.statusCode || 500).json({ error: err.message })
})

The ten parts covered the built-in middleware, the third-party middleware, the registration, the body parsing order, the route handler, the authentication middleware, the 404 handler, the error handler, the multiple error handlers, and the complete order.


Quick Reference

Built-in Middleware

MiddlewarePurpose
express.staticServe static files
express.jsonParse JSON bodies
express.urlencodedParse URL-encoded bodies

Third-Party Middleware

MiddlewarePurpose
helmetSecurity headers
corsCross-origin resource sharing
morganHTTP request logging
compressionCompress responses
cookie-parserParse cookies
express-sessionSession management

Recommended Order

OrderMiddleware
1Body parsers (express.json, express.urlencoded)
2Cookie parser
3Security (helmet)
4CORS
5Logging (morgan)
6Compression
7Authentication
8Route handlers
9404 handler
10Error handler

Error Handler Signature

ArgumentsMiddleware Type
(req, res, next)Regular middleware
(err, req, res, next)Error-handling middleware

Best Practices

✅ Do This:

// Register body parsers before routes
app.use(express.json())                                        // ✅

// Register the error handler last
app.use((err, req, res, next) => { })                          // ✅

// Use helmet for security headers
app.use(helmet())                                              // ✅

// Use morgan for logging
app.use(morgan('combined'))                                    // ✅

// Use compression for the responses
app.use(compression())                                         // ✅

// Use the four-argument signature for error handlers
app.use((err, req, res, next) => { })                          // ✅

// Register the 404 handler after the routes
app.use((req, res) => res.status(404).send('Not found'))       // ✅

❌ Don’t Do This:

// Don't register the error handler before the routes
app.use((err, req, res, next) => { })                          // ❌

// Don't read req.body without the body parser
app.post('/api', (req, res) => {
  res.json(req.body)  // undefined without express.json()      // ❌
})

// Don't use three arguments for an error handler
app.use((err, req, res) => { })                                // ❌

// Don't call next() after sending the response
res.json(data)
next()                                                         // ❌

// Don't forget to call next() in the middleware
app.use((req, res, next) => {
  console.log('middleware')
  // no next() -> the request hangs                            // ❌
})

// Don't register the middleware after the routes that need it
app.get('/api', handler)
app.use(express.json())                                        // ❌

Common Pitfalls

PitfallWhy It HappensFix
req.body is undefinedNo body parserRegister express.json()
Error handler not calledFewer than four argumentsUse (err, req, res, next)
Error handler not reachedRegistered before routesRegister last
Request hangsNo next() callCall next() or send a response
404 for a defined routeWrong orderCheck the middleware order
Cookie undefinedNo cookie-parserRegister the middleware
Security headers missingNo helmetRegister helmet()

Real-World Examples

1. JSON Body Parser

app.use(express.json())

2. Static Files

app.use(express.static('public'))

3. Security Headers

app.use(helmet())

4. CORS

app.use(cors())

5. Request Logger

app.use(morgan('combined'))

6. Compression

app.use(compression())

7. Cookie Parser

app.use(cookieParser())

8. Session

app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true }))

9. Error Handler

app.use((err, req, res, next) => {
  res.status(err.statusCode || 500).json({ error: err.message })
})

10. 404 Handler

app.use((req, res) => res.status(404).json({ error: 'Not found' }))

Visual

The Middleware Chain

┌─────────────────────────────────────────────────────────────┐
│  REQUEST                                                    │
│    │                                                        │
│    ▼                                                        │
│  express.json()       ← parse the JSON body                 │
│    │                                                        │
│    ▼                                                        │
│  cookie-parser        ← parse the cookies                   │
│    │                                                        │
│    ▼                                                        │
│  helmet()             ← set the security headers            │
│    │                                                        │
│    ▼                                                        │
│  cors()               ← set the CORS headers                │
│    │                                                        │
│    ▼                                                        │
│  morgan()             ← log the request                     │
│    │                                                        │
│    ▼                                                        │
│  requireAuth()        ← verify the identity                 │
│    │                                                        │
│    ▼                                                        │
│  Route handler        ← process the request                 │
│    │                                                        │
│    ▼                                                        │
│  RESPONSE                                                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Error Handling Flow

┌─────────────────────────────────────────────────────────────┐
│  Route handler throws an error                              │
│    │                                                        │
│    ▼                                                        │
│  Express catches the error                                  │
│    │                                                        │
│    ▼                                                        │
│  Skips all remaining regular middleware and routes          │
│    │                                                        │
│    ▼                                                        │
│  Jumps to the first error handler (4 arguments)             │
│    │                                                        │
│    ▼                                                        │
│  Error handler sends the response                           │
│                                                             │
│  The error handler must be registered last.                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Middleware Order

┌─────────────────────────────────────────────────────────────┐
│  CORRECT ORDER                                              │
│                                                             │
│  1. Body parsers                                            │
│  2. Cookie parser                                           │
│  3. Security headers                                        │
│  4. CORS                                                    │
│  5. Logging                                                 │
│  6. Compression                                             │
│  7. Authentication                                          │
│  8. Routes                                                  │
│  9. 404 handler                                             │
│  10. Error handler                                          │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  WRONG ORDER                                                │
│                                                             │
│  1. Error handler                                           │
│  2. Routes                                                  │
│  3. Body parser  ← too late, req.body is undefined          │
│                                                             │
│  The error handler is never reached.                        │
│  The body parser is too late.                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Built-in vs Third-Party

┌─────────────────────────────────────────────────────────────┐
│  BUILT-IN                                                   │
│                                                             │
│  express.static   ← static files                            │
│  express.json     ← JSON bodies                             │
│  express.urlencoded ← form bodies                           │
│                                                             │
│  No installation. Part of the framework.                    │
│                                                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  THIRD-PARTY                                                │
│                                                             │
│  helmet           ← security                                │
│  cors             ← cross-origin                            │
│  morgan           ← logging                                 │
│  compression      ← response compression                    │
│  cookie-parser    ← cookies                                 │
│  express-session  ← sessions                                │
│                                                             │
│  Install with npm. Register with app.use().                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Summary

ItemValue
Built-inexpress.static, express.json, express.urlencoded
Third-partyhelmet, cors, morgan, compression, cookie-parser
Registrationapp.use()
OrderRegistration order
Error handlerFour arguments, registered last
404 handlerAfter routes, before error handler
Body parserBefore the routes that read req.body
Cookie parserBefore the routes that read req.cookies

Key takeaways:

  • Express has three built-in middleware functions. express.static serves static files, express.json parses JSON bodies, and express.urlencoded parses URL-encoded bodies. They are part of the framework and require no installation .
  • The third-party middleware is installed with npm and registered with app.use(). helmet sets security headers, cors enables cross-origin requests, morgan logs requests, compression compresses responses, and cookie-parser parses cookies .
  • The middleware executes in the order it is registered. The body parser must run before the routes that read req.body. The authentication middleware must run before the routes that require a user. The error handler must run last .
  • The error-handling middleware has four arguments. The signature is (err, req, res, next). Express identifies the middleware as an error handler by the number of arguments. It must be registered after all the other middleware and routes .
  • The 404 handler is registered after the routes and before the error handler. It runs for the requests that the routes did not match. It sends the 404 response and does not call next() .
  • The order is a guideline, not a rule. The body parsers before the routes, the security middleware early, the routes in the middle, and the error handler last. The order follows from the request-response cycle .

Remember: Express is a middleware framework. The application is the chain of functions, and the chain is the order of the registration. The built-in middleware covers the common needs, and the third-party middleware covers the rest. Register the body parsers before the routes, the security middleware early, the routes in the middle, the 404 handler after the routes, and the error handler last. And remember the error handler: four arguments, registered last, and the only middleware that Express identifies by the signature. Get the order right, and the application behaves predictably. Get it wrong, and the request hangs, the body is undefined, and the error handler is never reached.



Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!