req.body being undefined is one of the most common Express.js beginner issues. Express does not parse request bodies by default — you have to explicitly tell it how to handle incoming data.
The Root Cause
Express is a minimal framework. It receives the raw HTTP request but leaves body parsing to middleware. Without registering the correct middleware, Express will not attempt to parse the request body, so req.body stays undefined.
Symptom — POST handler receives undefined body:
app.post('/api/user', (req, res) => {
console.log(req.body); // ❌ undefined
res.json({ received: req.body });
});Fix 1: Add express.json() Middleware
Since Express 4.16.0, body parsing is built in. Add express.json() to parse JSON request bodies. You no longer need the separate body-parser package.
Broken — no body parsing middleware:
const express = require('express');
const app = express();
// ❌ Missing middleware — req.body will be undefined
app.post('/login', (req, res) => {
const { username, password } = req.body; // ❌ crashes
});Fixed — add express.json() before routes:
const express = require('express');
const app = express();
app.use(express.json()); // ✅ parse JSON bodies
app.post('/login', (req, res) => {
const { username, password } = req.body; // ✅ works
res.json({ username });
});Fix 2: Middleware ORDER Matters
Express processes middleware top to bottom. If you define a route before registering express.json(), that route will never see a parsed body.
Broken — route defined before middleware:
app.post('/api/data', (req, res) => {
console.log(req.body); // ❌ undefined — middleware not yet registered
});
app.use(express.json()); // too late!Fixed — middleware before all routes:
app.use(express.json()); // ✅ registered first
app.post('/api/data', (req, res) => {
console.log(req.body); // ✅ parsed JSON object
});Fix 3: Wrong Content-Type Header
express.json() only parses requests with Content-Type: application/json. If your HTTP client sends a different content type, Express will skip parsing and req.body stays undefined.
Broken — missing or wrong Content-Type:
// fetch without Content-Type header
fetch('/api/user', {
method: 'POST',
body: JSON.stringify({ name: 'Alice' }), // ❌ no Content-Type
});
// OR wrong Content-Type:
fetch('/api/user', {
method: 'POST',
headers: { 'Content-Type': 'text/plain' }, // ❌ wrong type
body: JSON.stringify({ name: 'Alice' }),
});Fixed — correct Content-Type header:
fetch('/api/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // ✅ required
},
body: JSON.stringify({ name: 'Alice' }),
});Fix 4: Form Data vs JSON — Use express.urlencoded()
HTML form submissions send data as application/x-www-form-urlencoded, not JSON. Use express.urlencoded() alongside express.json() to handle both.
Handle both JSON and form data:
app.use(express.json()); // for JSON APIs
app.use(express.urlencoded({ extended: true })); // for HTML forms
// Now req.body works for both:
// - fetch with Content-Type: application/json
// - <form method="POST"> submissionsFix 5: Route-Specific Middleware
Sometimes you only want to apply body parsing to specific routes rather than globally. Pass the middleware directly to the route handler.
Apply middleware to a single route:
const jsonParser = express.json();
// Only this route gets JSON parsing
app.post('/webhook', jsonParser, (req, res) => {
console.log(req.body); // ✅ parsed
res.sendStatus(200);
});
// This route is unaffected
app.post('/upload', (req, res) => {
// req.body is undefined here — intentional
});Fix 6: Multer for multipart/form-data (File Uploads)
Neither express.json() nor express.urlencoded() can parse multipart/form-data (used for file uploads). You need the multer package.
File upload with multer:
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });
app.post('/profile', upload.single('avatar'), (req, res) => {
console.log(req.file); // ✅ uploaded file info
console.log(req.body); // ✅ other form fields
res.json({ success: true });
});Full Working Express POST Route
Complete Express server setup:
const express = require('express');
const app = express();
// ✅ Register middleware FIRST
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// JSON API endpoint
app.post('/api/users', (req, res) => {
const { name, email } = req.body;
if (!name || !email) {
return res.status(400).json({ error: 'name and email are required' });
}
// Process the data...
res.status(201).json({ id: 1, name, email });
});
// HTML form endpoint
app.post('/contact', (req, res) => {
const { message } = req.body; // works for form submissions too
res.redirect('/thank-you');
});
app.listen(3000, () => console.log('Server running on port 3000'));Convert your HAR file to cURL commands to debug requests →
Inspect request headers and body payloads with our free HAR to cURL tool.
Frequently Asked Questions
Why is req.body undefined in Express?
Express does not parse request bodies by default. Add app.use(express.json()) before your routes.
Does Express 4 still need the body-parser package?
No. Since Express 4.16.0, use express.json() and express.urlencoded() directly. The separate body-parser package is no longer required.
Why does middleware order matter in Express?
Express applies middleware in the order they are registered. Routes defined before app.use(express.json()) will not have body parsing applied to them.
req.body is still undefined even with express.json() — why?
Your HTTP client must send Content-Type: application/json. Without this header, Express will not attempt to parse the body as JSON.
How do I handle file uploads in Express?
File uploads use multipart/form-data, which requires the multer package. Use upload.single('fieldname') as route middleware.