Express Cheatsheet
Routing
Use this Express reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Basic Route Definition
app.METHOD(path, ...handlers)| Method | Usage |
|---|---|
app.get(path, cb) | Handle GET |
app.post(path, cb) | Handle POST |
app.put(path, cb) | Handle PUT |
app.patch(path, cb) | Handle PATCH |
app.delete(path, cb) | Handle DELETE |
app.head(path, cb) | Handle HEAD |
app.options(path, cb) | Handle OPTIONS |
app.all(path, cb) | Match ANY method |
app.get('/users', (req, res) => res.json(users)); app.post('/users', (req, res) => res.status(201).json(created)); app.put('/users/:id', (req, res) => res.json(updated)); app.delete('/users/:id', (req, res) => res.sendStatus(204)); // Match every method on every path (catch-all, use carefully) app.all('/{*splat}', (req, res) => res.status(405).send('Method not allowed')); // Express 4 only: app.all('*', ...) — throws a path-to-regexp error on Express 5
Route Paths
Paths can be exact strings, strings with named parameters/wildcards, or regular expressions. Express 5 uses path-to-regexp v8; Express 4 used v0.1.x with a different pattern syntax.
// Exact string app.get('/about', handler); // Named parameter app.get('/users/:id', handler); // req.params.id // Optional segment (Express 5 brace syntax) app.get('/users{/:id}', handler); // matches /users and /users/42 app.get('/files/:name{.:ext}', handler); // matches /files/a and /files/a.txt // Named wildcard (Express 5) — matches one or more segments app.get('/files/*filepath', handler); // req.params.filepath = ['a', 'b', 'c'] // RegExp (works in both majors) app.get(/\/users\/\d+/, handler); // matches /users/123 etc.
Legacy — Express 4 only. These string patterns throw path-to-regexp errors on Express 5:
app.get('/ab?cd', handler); // v5: use /ab{c}d-style braces instead of ? app.get('/ab+cd', handler); // v5: + repetition removed — use a RegExp app.get('/ab*cd', handler); // v5: wildcards must be named (*splat) and fill a whole segment app.get('/ab(cd)?e', handler); // v5: regex groups inside strings removed — use a RegExp app.get('/users/:id?', handler); // v5: :id? optional marker → '/users{/:id}'
Route Handlers (Chaining)
Multiple handlers are called in order; pass control with next().
// Two handlers app.get('/secure', authenticate, (req, res) => { res.send(`Hello ${req.user.name}`); }); // Array of handlers const steps = [logRequest, checkCache, fetchData]; app.get('/data', steps, sendResponse); // Chained .get()/.post() on same path app.route('/books') .get((req, res) => res.json(books)) .post((req, res) => res.status(201).json(created)) .put((req, res) => res.json(updated));
express.Router
Group routes into modular, mountable mini-apps.
// routes/users.js const router = require('express').Router(); // Middleware scoped to this router router.use(authenticate); router.get('/', (req, res) => res.json(all)); router.get('/:id', (req, res) => res.json(one)); router.post('/', (req, res) => res.status(201).json(created)); router.put('/:id', (req, res) => res.json(updated)); router.delete('/:id', (req, res) => res.sendStatus(204)); module.exports = router;
// app.js — mount with a prefix const usersRouter = require('./routes/users'); app.use('/users', usersRouter); // → GET /users, GET /users/:id, POST /users, …
Router Options
const router = express.Router({ caseSensitive: true, // match case of app setting strict: false, // allow optional trailing slash mergeParams: true, // inherit req.params from parent router });
mergeParams: trueis needed when a child router uses params defined in the parent'sapp.use()mount path: ``js app.use('/users/:userId/posts', postsRouter); // postsRouter can read req.params.userId only if mergeParams: true``
Nested Routers
// routes/api.js const router = express.Router(); router.use('/users', require('./users')); router.use('/products', require('./products')); module.exports = router; // app.js app.use('/api/v1', require('./routes/api')); // → /api/v1/users, /api/v1/products
Route Ordering and Precedence
Routes are matched top-to-bottom in registration order. First match wins.
// Specific routes BEFORE generic ones app.get('/users/me', getMeHandler); // ✓ matched first app.get('/users/:id', getByIdHandler); // would swallow 'me' if registered first // Static segments beat params app.get('/files/upload', uploadHandler); // ✓ wins over /files/:name for /files/upload app.get('/files/:name', serveFile);
app.param() — Route Parameter Pre-processing
Runs before any handler that has a matching param name.
// Automatically load user for any route with :userId app.param('userId', async (req, res, next, id) => { try { req.targetUser = await User.findById(id); if (!req.targetUser) return res.status(404).json({ error: 'User not found' }); next(); } catch (err) { next(err); } }); app.get('/users/:userId', (req, res) => res.json(req.targetUser)); app.put('/users/:userId', (req, res) => { /* req.targetUser already loaded */ });
Wildcard and Catch-All Routes
// 404 catch-all — must be LAST, after all real routes. // app.use() with no path matches everything on both Express 4 and 5. app.use((req, res) => { res.status(404).json({ error: `Cannot ${req.method} ${req.path}` }); }); // Method-specific catch-all (Express 5): wildcards must be named app.get('/*splat', (req, res) => res.status(404).send('Page not found')); // everything except '/' app.get('/{*splat}', (req, res) => res.status(404).send('Page not found')); // including '/'
app.get('*')/app.all('*')are Express 4 syntax — on Express 5 they throwTypeError: Missing parameter nameat startup. Use a named wildcard (/*splat) or a pathlessapp.use().
Conditional Route Skipping — next('route')
Skip remaining handlers in the current route and jump to the next matching route.
app.get('/items/:id', (req, res, next) => { if (req.params.id === 'special') return next('route'); // skip to next .get('/items/:id') next(); // continue in this route }, (req, res) => res.send('Normal item') ); app.get('/items/:id', (req, res) => res.send('Special item'));
next('router')
Skip the rest of the current router entirely.
router.use((req, res, next) => { if (!req.headers.authorization) return next('router'); // bail out of this router next(); });