Script Valley
Express.js: APIs and Middleware
Middleware Deep DiveLesson 2.5

How to pass data between middleware using req object

req custom properties, attaching data to req, req.user, req.locals vs res.locals, middleware composition, auth middleware data passing, downstream access

Passing Data Through the Middleware Chain

Middleware can attach custom properties to the req object so downstream middleware and route handlers can access them. The most common pattern is attaching an authenticated user after verifying a token.

Auth middleware attaching req.user

const users = { token123: { id: 1, name: 'Alice', role: 'admin' } };

function authenticate(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }

  const user = users[token];
  if (!user) {
    return res.status(401).json({ error: 'Invalid token' });
  }

  req.user = user; // attach to req
  next();
}

function requireAdmin(req, res, next) {
  if (req.user.role !== 'admin') {
    return res.status(403).json({ error: 'Admin access required' });
  }
  next();
}

app.get('/admin/stats', authenticate, requireAdmin, (req, res) => {
  res.json({ message: `Welcome ${req.user.name}` });
});

Use res.locals for response-scoped data (accessible in templates). Use req properties for request-scoped data that flows through the chain. Always use namespaced properties (req.user, req.tenant) — never overwrite built-in properties like req.body or req.params.