Express Cheatsheet

Body Parsing

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

Built-in Parsers (Express 4.16+)

No external packages needed for JSON and URL-encoded bodies.

// Parse application/json
app.use(express.json());

// Parse application/x-www-form-urlencoded (HTML forms)
app.use(express.urlencoded({ extended: true }));

// Parse raw Buffer body
app.use(express.raw({ type: 'application/octet-stream' }));

// Parse plain text body
app.use(express.text({ type: 'text/plain' }));

After any of these, the parsed body is available on req.body.

express.json() Options

app.use(express.json({
  limit:    '100kb',       // max body size (default '100kb')
  strict:   true,          // only accept arrays and objects (default true)
  type:     'application/json', // MIME types to parse (string, array, or function)
  reviver:  null,          // JSON.parse reviver function
  inflate:  true,          // handle deflated/gzip bodies
}));
// Accept multiple content types
app.use(express.json({ type: ['application/json', 'application/cjson'] }));

// Custom reviver — convert ISO date strings to Date objects
app.use(express.json({
  reviver: (key, value) => {
    if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T/.test(value))
      return new Date(value);
    return value;
  }
}));

express.urlencoded() Options

app.use(express.urlencoded({
  extended: true,    // true = qs (nested objects); false = querystring (flat)
  limit:    '100kb',
  parameterLimit: 1000,  // max number of parameters (default 1000)
  type: 'application/x-www-form-urlencoded',
}));

extended: true (qs) supports nested objects:

// Form: filter[price][gte]=10&filter[price][lte]=100
req.body.filter.price.gte // '10'

extended: false (querystring) is flat:

// filter[price][gte]=10 → req.body['filter[price][gte]'] = '10'

express.raw() Options

app.use(express.raw({
  type:   'application/octet-stream',
  limit:  '10mb',
  inflate: true,
}));

app.post('/upload', (req, res) => {
  req.body; // Buffer
  req.body.length; // byte count
});

express.text() Options

app.use(express.text({
  type:         'text/plain',
  defaultCharset: 'utf-8',
  limit:        '100kb',
}));

app.post('/webhook', (req, res) => {
  typeof req.body; // 'string'
});

Route-Scoped Parsing

Apply parsers only to specific routes to avoid overhead or to use different limits.

// High limit only for file endpoint
app.post('/import', express.json({ limit: '10mb' }), (req, res) => {
  // large JSON allowed here only
});

// Raw body for Stripe webhook (must NOT go through express.json first)
app.post(
  '/webhook',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const sig  = req.headers['stripe-signature'];
    const event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_SECRET);
    // req.body is a Buffer here
  }
);

// JSON everywhere else
app.use(express.json());

Stripe / webhook gotcha: raw body parsers must run before express.json() on the webhook route. Mount the raw route before the global JSON middleware, or use a type discriminator.

Multipart / File Uploads — multer

express.json() does not handle multipart/form-data. Use multer.

const multer = require('multer');

// Memory storage (file in req.file.buffer)
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 5 * 1024 * 1024 } });

// Disk storage
const disk = multer.diskStorage({
  destination: (req, file, cb) => cb(null, './uploads'),
  filename:    (req, file, cb) => cb(null, `${Date.now()}-${file.originalname}`),
});
const uploadDisk = multer({ storage: disk });

// Single file
router.post('/avatar', upload.single('avatar'), (req, res) => {
  req.file;    // { fieldname, originalname, mimetype, buffer, size }
  req.body;    // other form fields
});

// Multiple files, same field
router.post('/photos', upload.array('photos', 5), (req, res) => {
  req.files; // array
});

// Multiple fields
router.post('/form', upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'gallery', maxCount: 10 },
]), (req, res) => {
  req.files.avatar[0];    // single avatar file
  req.files.gallery;      // array
});

// No file — just multipart form fields
router.post('/form', upload.none(), (req, res) => {
  req.body; // parsed fields
});

multer File Object Properties

PropertyDescription
fieldnameField name from the form
originalnameOriginal filename from client
encodingFile encoding
mimetypeMIME type
sizeSize in bytes
bufferBuffer (memoryStorage only)
pathSaved path (diskStorage only)
filenameSaved filename (diskStorage only)
destinationDirectory (diskStorage only)

File Type Validation with multer

const upload = multer({
  fileFilter: (req, file, cb) => {
    const allowed = ['image/jpeg', 'image/png', 'image/webp'];
    if (!allowed.includes(file.mimetype)) {
      return cb(new Error('Only JPEG, PNG, and WebP allowed'));
    }
    cb(null, true);
  },
  limits: { fileSize: 2 * 1024 * 1024 }, // 2 MB
});

Checking req.body is Populated

app.post('/data', express.json(), (req, res) => {
  if (!req.body || Object.keys(req.body).length === 0) {
    return res.status(400).json({ error: 'Empty body' });
  }
  // ...
});

Body Size Limit Errors

When the body exceeds the limit, Express emits a PayloadTooLargeError. Catch it in your error handler:

app.use((err, req, res, next) => {
  if (err.type === 'entity.too.large') {
    return res.status(413).json({ error: 'Payload too large' });
  }
  next(err);
});

Unsupported Media Type

When a client sends an unrecognized Content-Type and no parser handles it, req.body is undefined. Respond with 415:

app.post('/data', express.json(), (req, res) => {
  if (req.body === undefined) {
    return res.status(415).json({ error: 'Unsupported Media Type' });
  }
});