Express ships with a handful of built-in middleware functions. You’ll use these in nearly every app. They used to live in a separate body-parser package, but since Express 4.16 they’re bundled directly.
express.json()
Parses incoming requests with Content-Type: application/json and attaches the parsed body to req.body.
const express = require('express');
const app = express();
app.use(express.json());
app.post('/users', (req, res) => {
console.log(req.body); // { name: 'Manish', age: 28 }
res.status(201).json(req.body);
});
Without this middleware, req.body would be undefined for JSON POST/PUT requests. The Node http module gives us a raw stream — Express needs to read it, decode it, and JSON-parse it.
Common options:
app.use(express.json({
limit: '1mb', // max body size (default: 100kb)
strict: true, // only accept arrays/objects (default: true)
}));
The limit is important — without it, an attacker can flood your server with massive payloads. Set it as tight as your real use case allows.
express.urlencoded()
Parses application/x-www-form-urlencoded bodies — the format HTML forms submit by default.
app.use(express.urlencoded({ extended: true }));
app.post('/login', (req, res) => {
const { email, password } = req.body;
// ... handle login
});
The extended option:
extended: false— uses Node’s built-inquerystring. Only string/array values.extended: true— uses theqslibrary. Supports nested objects likeuser[name]=Manish.
For modern APIs that only accept JSON, you may not need this at all. Add it if you serve HTML forms.
express.static()
Serves static files (HTML, CSS, JS, images) from a directory:
app.use(express.static('public'));
Now GET /logo.png serves ./public/logo.png. GET / serves ./public/index.html if it exists.
We usually mount it at a path:
app.use('/assets', express.static('public'));
// /assets/logo.png → ./public/logo.png
Options worth knowing:
app.use(express.static('public', {
maxAge: '1d', // Cache-Control: max-age=86400
etag: true, // ETag header for revalidation
index: 'home.html', // default file (default: 'index.html')
}));
Production tip: in real deployments, static files should be served by nginx or a CDN, not Express. Express is fine for dev or low-traffic apps.
express.Router()
Already covered in detail in the Router & Modular Routes note. The TL;DR — creates a mini sub-app to organize routes across files.
const router = express.Router();
router.get('/', (req, res) => res.json([]));
module.exports = router;
| Middleware | Purpose | When you need it |
|---|---|---|
| express.json() | Parse JSON bodies | REST APIs (always) |
| express.urlencoded() | Parse form bodies | HTML form submissions |
| express.static() | Serve files | Dev / small sites |
| express.Router() | Modular routes | Any non-trivial app |
A realistic setup
A typical Express app’s middleware stack looks like this:
const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const morgan = require('morgan');
const app = express();
// Security & logging
app.use(helmet()); // 3rd party
app.use(cors({ origin: 'https://pman47.cc' })); // 3rd party
app.use(morgan('combined')); // 3rd party
// Body parsing (built-in)
app.use(express.json({ limit: '1mb' }));
app.use(express.urlencoded({ extended: true }));
// Static files (built-in)
app.use('/assets', express.static('public'));
// Routes
app.use('/api', require('./routes'));
// Error handler (last)
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Internal' });
});
app.listen(3000);
That’s almost every production Express app’s skeleton. The built-ins cover body parsing and static files; everything else (CORS, security headers, logging, rate limiting) comes from npm.
What about cookie-parser, session, multer?
These are common but not built-in:
cookie-parser— parses cookies intoreq.cookiesexpress-session— server-side sessionsmulter— multipart/form-data (file uploads)
They were part of Express 3 but split out in Express 4. Install them separately when needed.