Parsing Request Bodies
HTTP requests carry their payload in the body — but the body arrives as a raw stream of bytes. Parsing turns those bytes into something usable on req.body, and which parser you need depends entirely on the request's Content-Type. JSON, URL-encoded forms, multipart file uploads, and raw binary each need different handling. This page pulls together the built-in parsers and the multipart story into one mental model.
Content-Type decides the parser
Content-Type | Parser | req.body becomes |
|---|---|---|
|
| A parsed object/array |
|
| A key/value object |
|
| Fields + files |
|
| A string |
|
| A |
JSON bodies
app.use(express.json({ limit: '1mb' }))
app.post('/api/users', (req, res) => {
const { name, email } = req.body // parsed object
res.status(201).json({ name, email })
})URL-encoded form bodies
app.use(express.urlencoded({ extended: true }))
// <form method="post" action="/contact">
// <input name="email"> <textarea name="message">
// </form>
app.post('/contact', (req, res) => {
const { email, message } = req.body
res.send('Thanks!')
})Multipart / file uploads — multer
File uploads use multipart/form-data, which the built-in parsers do not handle. The standard tool is multer, which writes uploads to disk (or memory) and fills req.file/req.files plus req.body for text fields:
import multer from 'multer'
const upload = multer({
dest: 'uploads/',
limits: { fileSize: 5 * 1024 * 1024 }, // 5 MB cap
fileFilter: (req, file, cb) => {
// Accept only images — reject everything else:
cb(null, file.mimetype.startsWith('image/'))
},
})
// 'avatar' = the form field name; .single() = one file:
app.post('/profile', upload.single('avatar'), (req, res) => {
res.json({ file: req.file, fields: req.body })
})Raw and text bodies
// Webhook needing exact bytes for signature verification:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
verify(req.body, req.get('X-Signature')) // req.body is a Buffer
res.sendStatus(200)
})
// A plain-text endpoint:
app.post('/notes', express.text(), (req, res) => {
saveNote(req.body) // req.body is a string
res.sendStatus(201)
})Always cap the body size
// A tiny limit on auth endpoints; larger where genuinely needed:
app.use('/auth', express.json({ limit: '10kb' }))
app.use('/import', express.json({ limit: '10mb' }))Decision guide
JSON API or SPA →
express.json().Classic HTML form →
express.urlencoded({ extended: true }).File upload →
multer(it handlesmultipart/form-data).Webhook signature verification →
express.raw()on that route.Plain text payload →
express.text().Whatever you choose, set a
limitand validate the result.