Express Cheatsheet

Express 4 to 5 Migration

Use this Express reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Express 5 at a Glance

Express 5 is the npm latest install (5.0.0 shipped September 2024). It requires Node.js 18+, forwards rejected promises to error middleware automatically, swaps the route matcher to path-to-regexp v8, and removes long-deprecated API signatures.

npm install express       # → 5.x
npm install express@4     # stay on 4.x

Async Handlers — No More Wrapper

The biggest win: middleware and handlers that return a rejected promise now call next(err) for you.

// Express 5 — a throw inside async lands in the error handler
app.get('/users/:id', async (req, res) => {
  const user = await db.users.findById(req.params.id); // rejection → error middleware
  if (!user) throw Object.assign(new Error('Not found'), { status: 404 });
  res.json(user);
});
// Express 4 required try/catch or a wrapper on EVERY async handler
const asyncHandler = (fn) => (req, res, next) => fn(req, res, next).catch(next);
app.get('/users/:id', asyncHandler(async (req, res) => { /* ... */ }));

Delete express-async-errors / express-async-handler when migrating.

Route Path Syntax Changes (path-to-regexp v8)

These throw TypeError: Missing parameter name (or similar) at startup on Express 5:

Express 4Express 5
app.get('*') / app.all('*')app.get('/*splat') — wildcards must be named; '/{*splat}' also matches /
'/users/:id?''/users{/:id}' — optional segments use braces
'/files/*''/files/*rest' (req.params.rest is an array of segments)
'/report/:id(\d+)'Regexp-in-string removed — use a real RegExp or validate in the handler
'/ab+cd', '/ab?cd', '/ab(cd)?e'String pattern operators removed — use a RegExp

Parameter names must now be valid JS identifiers (or quoted: :"user-id").

Removed / Renamed APIs

Express 4Express 5
app.del(path, fn)app.delete(path, fn)
req.param('name')req.params.name / req.query.name / req.body.name
res.send(404)res.sendStatus(404)
res.send(body, status) / res.json(obj, status)res.status(status).send(body) / .json(obj)
res.redirect(url, status)res.redirect(status, url)
res.redirect('back')res.redirect(req.get('Referrer') || '/')
res.sendfile()res.sendFile()
req.acceptsCharset / Encoding / LanguagePluralized: req.acceptsCharsets() etc.

Behavior Changes

WhatExpress 4Express 5
req.queryWritable object; parsed with qs ('extended')Read-only getter; default parser 'simple'?a[b]=1 no longer nests
req.body{} from parsers even on empty/unmatched bodiesundefined when no body was parsed
express.urlencoded()extended: true defaultextended: false default — pass it explicitly
res.status(code)Coerced looselyThrows unless an integer 100–999
req.hostStrips the portKeeps the port
res.clearCookie(name, opts)Accepted maxAge/expiresIgnores maxAge/expires
Response compressiongzip/deflateAdds Brotli (Accept-Encoding: br) support from 5.1

Ecosystem Gotchas

  • express-mongo-sanitize crashes on v5 (it assigns to the read-only req.query).
  • Middleware that mutates req.query (some old sanitizers/HPP setups) needs a v5-compatible release or a req.body-only strategy.
  • @types/express v5 typings ship under the same package — update it together with express.

Migration Checklist

npm install express@latest
npx @expressjs/codemod upgrade   # official codemod rewrites most removed signatures
  1. Fix route strings: '*''/*splat', :param?{/:param}, regex-in-string → RegExp.
  2. Remove async error wrappers; rely on automatic promise rejection forwarding.
  3. Grep for removed signatures: res.send(number), res.json(obj, status), req.param(, redirect('back').
  4. Set extended explicitly on express.urlencoded(); re-check any code that writes to req.query.
  5. Run the app — v5 fails fast at startup on invalid paths, so smoke-starting catches most breakage.