cheat sheet

body-parser

Package-level reference for body-parser on npm — JSON, urlencoded, raw and text middleware, webhook signatures, and Express 4.16+ bundling.

body-parser

What it is

body-parser is the canonical Node middleware for parsing HTTP request bodies into req.body. It exposes four parsers — json, urlencoded, raw, and text — each as an Express-compatible middleware factory. Since Express 4.16 (released 2017), the same parsers are exposed under express.json(), express.urlencoded(), express.raw(), and express.text(). The standalone body-parser package remains the right install only for non-Express servers (Connect, Polka, raw Node) or when you want to mount a parser before Express's bundled version is loaded.

Reach for body-parser directly when you need fine-grained limits, custom verify callbacks (e.g. preserving raw bytes for webhook signatures), or when running on a non-Express stack.

Install

bash
npm install body-parser

Output: added body-parser to dependencies

bash
pnpm add body-parser

Output: added 1 package, linked from store

bash
yarn add body-parser

Output: added body-parser

bash
bun add body-parser

Output: installed body-parser

Types ship in-tree as of @types/body-parser for legacy projects; modern Express projects get the typings via @types/express directly.

Versioning & Node support

Current line is body-parser@1.x (the package has stayed on the 1.x major for years; semantic versioning is loose for a mid-2010s Express ecosystem package).

  • body-parser@1 — Node 0.10+ (effective floor today is whatever Express supports, currently Node 18+ for express@5). The 1.x line continues to receive security patches.
  • body-parser@2 — early-2025 release that aligned the package with Express 5's stricter defaults. Adoption is still gradual; Express 4 projects can stay on 1.x.

Pin minor in production. Express 4.16+ bundles a compatible copy as express.json() / express.urlencoded() — most apps don't need a separate install at all.

Package metadata

  • Maintainer: Express TC (expressjs/body-parser)
  • Project home: github.com/expressjs/body-parser
  • Docs: github.com/expressjs/body-parser#readme
  • npm: npmjs.com/package/body-parser
  • License: MIT
  • First released: 2014
  • Downloads: ~25 million+ weekly downloads.

Peer dependencies & extras

No peer-deps. Transitive dependencies include bytes (parse "10mb" strings), content-type, debug, iconv-lite (charset decoding), raw-body, qs or querystring for urlencoded parsing, on-finished, and type-is.

Commonly paired with:

  • express — bundles a copy as of 4.16+
  • multer — multipart/form-data (NOT covered by body-parser; multipart needs a separate parser)
  • cookie-parser — sibling middleware for cookies
  • express-validator — validation on top of parsed bodies
  • zod / valibot / joi — schema validation against parsed bodies
  • helmet — security headers; pair with body-parser limits
  • cors — CORS handling

Alternatives

ApproachTrade-off
express.json() / .urlencoded()Bundled in Express 4.16+. Same package under the hood. Default for Express apps.
fastify's built-in parsersFastify parses JSON / urlencoded itself; no body-parser needed.
hono.req.json() / .parseBody()Hono is async-pull; no middleware install required.
koa-bodyparserKoa equivalent. Same authors / similar API.
raw-bodyThe lower-level package body-parser is built on. Use when you need just the bytes without parsing.
multer / busboyMultipart/form-data parsing (file uploads). Body-parser does NOT handle multipart.

Real-world recipes

JSON middleware

The most common parser. Reads a JSON body, parses into req.body. Default size limit is 100 KB.

javascript
import express from "express";
import bodyParser from "body-parser";

const app = express();
app.use(bodyParser.json({ limit: "1mb" }));

app.post("/users", (req, res) => {
  console.log(req.body);
  res.json({ ok: true });
});

app.listen(3000);

Output: posting {"email":"alice@example.com"} makes req.body.email available. Bodies over 1 MB return PayloadTooLargeError.

Inside Express, prefer app.use(express.json({ limit: "1mb" })) — identical behaviour, no extra dep.

URL-encoded middleware

For HTML form posts. extended: true uses the qs parser (supports nested objects); extended: false uses querystring (flat keys only).

javascript
import express from "express";
import bodyParser from "body-parser";

const app = express();
app.use(bodyParser.urlencoded({ extended: true, limit: "100kb" }));

app.post("/contact", (req, res) => {
  console.log(req.body);
  res.send("thanks");
});

app.listen(3000);

Output: posting name=Alice&tags[]=draft&tags[]=urgent produces { name: "Alice", tags: ["draft", "urgent"] }. With extended: false you'd get strings only.

For pure-API services that never accept HTML forms, omit this middleware entirely — there's no reason to parse what you never receive.

Raw body for webhook signatures

Many webhook providers (Stripe, Slack, GitHub) sign the raw request body. JSON parsing breaks signature verification because key order and whitespace change. Use bodyParser.raw (or verify callback on json) to preserve the raw bytes.

javascript
import express from "express";
import bodyParser from "body-parser";
import crypto from "node:crypto";

const app = express();

app.post("/webhook",
  bodyParser.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.headers["x-signature"];
    const expected = crypto
      .createHmac("sha256", process.env.WEBHOOK_SECRET)
      .update(req.body)
      .digest("hex");
    if (signature !== expected) return res.status(401).send("bad sig");

    const event = JSON.parse(req.body.toString("utf8"));
    console.log(event);
    res.sendStatus(204);
  }
);

app.listen(3000);

Output: signature verified against the exact bytes; mismatch returns 401. req.body is a Buffer.

Alternative: use bodyParser.json({ verify: (req, _res, buf) => { req.rawBody = buf; } }) to retain raw bytes alongside parsed JSON.

Per-route parsers with strict size limits

Mount parsers per route to enforce different limits — bulk imports may allow 10 MB, write endpoints 10 KB. Per-route parsers also reduce attack surface: routes that never accept bodies don't parse them.

javascript
import express from "express";
import bodyParser from "body-parser";

const app = express();
const smallJson = bodyParser.json({ limit: "10kb" });
const largeJson = bodyParser.json({ limit: "10mb" });

app.post("/api/users", smallJson, (req, res) => res.json({ id: "u-1" }));
app.post("/api/imports", largeJson, (req, res) => res.json({ ok: true }));
app.get("/api/health", (req, res) => res.json({ ok: true })); // no parser at all

app.listen(3000);

Output: /api/users rejects bodies >10 KB; /api/imports allows up to 10 MB; /api/health doesn't even attempt to parse.

Production deployment

Size limits are mandatory

Without limit, a malicious client can post gigabytes of JSON and exhaust memory. The default 100 KB JSON limit is sane for most APIs; raise only where needed.

javascript
app.use(bodyParser.json({ limit: "100kb" }));

Output: any Content-Length over 100 KB returns 413 Payload Too Large before allocation begins.

Strict content-type matching

type accepts a string, array, or function. Restrictive content-type filters prevent a JSON parser from accidentally trying to parse application/octet-stream.

javascript
app.use(bodyParser.json({ type: "application/json", strict: true }));

Output: non-JSON content types pass through unparsed; strict: true rejects primitives like "hello" (top-level must be object or array).

Behind a reverse proxy

Body parsers care about Content-Length and Transfer-Encoding. If your proxy buffers requests (Cloudflare, AWS ALB) the size limit applies to the proxied length, which matches what your app actually receives. If you stream uploads, the limit may behave differently — test with curl --data-binary @largefile.

Mount order

Mount body-parser before any route that consumes req.body. Mounting after the route means req.body is undefined because the middleware never runs.

javascript
app.use(bodyParser.json()); // before routes
app.post("/x", handler);

Memory pressure

Body parsing copies the full request into memory before invoking the handler. For multi-megabyte payloads (file uploads, bulk imports), consider streaming instead — multer for multipart, or read req directly as a stream.

Performance tuning

  • Use the bundled express.json() instead of body-parser when on Express. One fewer dep; identical hot path.
  • Smaller limit values fail faster. Express short-circuits on Content-Length before allocation.
  • inflate: false disables gzip/deflate decompression on bodies. Default true; set false if your proxy already decompresses.
  • Avoid extended: true urlencoded if you don't need nesting. qs is slower than querystring.
  • Per-route mounting over global. Don't parse what you don't read.
  • Skip body-parser entirely for routes without bodies (GET, HEAD, DELETE without body).
  • reviver callbacks on JSON are slow. If you need post-parsing transforms, do them in the handler.

Version migration guide

body-parser@1 is the long-stable line

Most production projects are on a recent 1.x patch release. The 1.x line continues to receive security fixes.

Migrating from standalone to Express-bundled

If you're on Express 4.16+ and using body-parser separately:

javascript
// before
import bodyParser from "body-parser";
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

// after
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

Then npm uninstall body-parser. No behaviour change.

body-parser@2

Aligned defaults with express@5:

  • strict: true is the default for JSON (top-level must be object/array).
  • extended: false is the default for urlencoded (was true in 1.x for a long time, then false, then back — this finally settles it).
  • Stricter error envelopes on malformed bodies.
  • Node 18+ floor.

Migration is mostly checking defaults; opt back into old behaviour explicitly if your tests fail.

Security considerations

  • Always set limit. Unlimited bodies are a denial-of-service vector. 100 KB is a safe default for most APIs.
  • Strict content-type. Only parse the content types you expect. A type: "*/*" catch-all accepts attacker-supplied content types.
  • extended: true urlencoded uses qs, which historically had prototype-pollution CVEs. Keep qs updated via npm audit; consider extended: false for pure flat forms.
  • Preserve raw bytes for signed webhooks. JSON parsing alters whitespace; signatures break.
  • Don't trust Content-Length. body-parser checks it, but chunked encoding can bypass declared lengths. The limit enforces actual consumed bytes.
  • No multipart support. body-parser does NOT parse multipart/form-data. Pair with multer and apply equivalent size limits there.
  • JSON null-prototype. JSON.parse returns objects with Object.prototype — careless property access can hit prototype-polluted globals. Use Object.hasOwn for untrusted input.
  • Reject malformed bodies firmly. Express 5 + body-parser 2 return 400 on syntax errors. Older defaults silently set req.body = {} — verify your version and behaviour.
  • Audit verify callbacks. They run before parsing and can throw to reject the request. A heavy verify adds per-request cost.

Testing & CI integration

For unit tests, use supertest against an Express app — body-parser participates in the full pipeline without binding a port.

javascript
import { test, expect } from "vitest";
import express from "express";
import request from "supertest";
import bodyParser from "body-parser";

const app = express();
app.use(bodyParser.json({ limit: "10kb" }));
app.post("/echo", (req, res) => res.json(req.body));

test("parses small JSON", async () => {
  const res = await request(app).post("/echo").send({ ok: true });
  expect(res.status).toBe(200);
  expect(res.body).toEqual({ ok: true });
});

test("rejects oversized payload", async () => {
  const big = { x: "a".repeat(20_000) };
  const res = await request(app).post("/echo").send(big);
  expect(res.status).toBe(413);
});

Output: small JSON returns 200; oversized returns 413 Payload Too Large.

For webhook signature paths, capture the raw body in a test fixture and assert verification logic against known good and known bad signatures.

Ecosystem integrations

ToolRole
expressBundles body-parser as express.json() / express.urlencoded() since 4.16.
express-validatorValidation layer over parsed bodies.
zod / valibot / joiSchema validators applied to req.body.
multermultipart/form-data parser. Complements body-parser.
morganRequest logger; body parsing happens before logging.
helmetSets security headers; orthogonal to body-parser.
corsCORS middleware; mount before body-parser to avoid parsing OPTIONS bodies.
connectBody-parser works in raw Connect apps too.

Troubleshooting common errors

PayloadTooLargeError: request entity too large — body exceeded limit. Raise the limit if legitimate, or reject upstream.

SyntaxError: Unexpected token in JSON — malformed JSON body. Inspect the raw body with a temporary verify callback; reject with a sanitized error.

req.body is undefined — middleware not mounted before the route. Move app.use(bodyParser.json()) above route registrations.

req.body is {} even with a valid JSON body — content-type mismatch. body-parser only parses bodies whose Content-Type matches its type option. Check req.headers["content-type"].

Webhook signature fails — JSON parsing altered the body. Switch to bodyParser.raw or capture raw bytes via verify.

UnexpectedTokenError for empty bodystrict: true rejects empty / non-object payloads. Set strict: false if you intentionally accept primitives.

Slow handler with large payloads — body parsing is synchronous after the body arrives. The middleware itself is fast; the handler doing JSON.parse twice is slow. Audit double-parsing.

HPE_HEADER_OVERFLOW — Node rejects huge headers before body-parser sees them. Not a body-parser issue; configure --max-http-header-size if necessary.

Cannot read properties of undefined (reading '...') in handler — accessing req.body.foo when no body was sent. Validate or guard with optional chaining.

Unsupported Content-Encoding — gzip body but inflate: false. Re-enable inflation.

When NOT to use this

  • You're on Express 4.16+ — use the bundled express.json() / express.urlencoded(). Same code, one fewer dep.
  • You're on Fastify / Hono / Koa. Each has its own body parsing. body-parser is Express-shaped.
  • You need multipart/form-data. Use multer or busboy. body-parser explicitly doesn't handle multipart.
  • You stream large uploads. Body-parser buffers the full body in memory. For >10 MB uploads, stream directly from req.
  • Edge runtimes. Cloudflare Workers / Vercel Edge use Web Request.json() / Request.formData() — no middleware required.
  • You only support GET requests. No bodies to parse.

See also