# koa-body is the body parser Koa does not ship with

> koa-body is a Koa middleware that reads request bodies, and its job is wider than parsing JSON. It handles multipart form data with file uploads, urlencoded forms, JSON and text bodies, it lets you set a different size limit for each of them, it refuses to parse bodies on methods where HTTP does not define one, and it can hand you the raw bytes so you can verify a webhook signature. The option list is long, and most of it exists because bodies are the part of a web framework where the defaults quietly hurt you.

**koajs/koa-body** — koa body parser middleware

- Repository: https://github.com/koajs/koa-body
- Stars: 954 · Forks: 130
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/koajs-koa-body

## The middleware Koa leaves out

The description calls it a full-featured Koa body parser middleware that supports multipart, urlencoded and JSON request bodies, and it says it provides the same functionality as Express's bodyParser and multer, which is a useful way to place it because those are the two Express packages that everybody reaches for. Koa itself is deliberately small, and the body parsing has always lived in a separate package. Installing it is the expected single command:

```sh
npm install koa-body
```

and the quickstart is a handful of lines, since the middleware is mounted like any other and the parsed result lands on the request object:

```js
const Koa = require('koa');
const { koaBody } = require('koa-body');

const app = new Koa();

app.use(koaBody());
app.use((ctx) => {
  ctx.body = `Request Body: ${JSON.stringify(ctx.request.body)}`;
});

app.listen(3000);
```

The quickstart notes that it needs Node.js 22 or newer, and the middleware is exported as a named function, `koaBody`, so the parentheses in `koaBody()` are the options object.

## Four body kinds, each with its own content type list

The parser is told what to do with a request by matching the content type, and each body kind has its own configurable list of matchers. The JSON list defaults to `application/json`, `application/json-patch+json`, `application/vnd.api+json`, `application/csp-report` and `application/reports+json`, which is a useful default set because it covers the media types that the various API specifications settled on rather than only the plain one. The urlencoded list defaults to `urlencoded`, the text list to `text/*` and the multipart list to `multipart`. Each list is passed to the `ctx.is()` check, so a vendor mime type is a one line change. Which kinds are enabled is a separate set of booleans, with multipart off by default and urlencoded, text and JSON on, so the default configuration parses most things and a multipart body is something you opt into.

## The size limits are not the same for every body

Three separate limit options exist, and the defaults are worth reading closely because they are not uniform. The JSON limit defaults to `1mb`, while the form limit and the text limit both default to `56kb`. That asymmetry is sensible once you see what the limits are for, since a form body is a set of key and value pairs that a browser will not send beyond a certain size, while a JSON body is often a document. The limits can be a byte count or a string, and they are enforced separately, so an application that accepts a large JSON payload does not have to also accept a large multipart upload. The formidable options are passed straight through for the multipart parser, and the readme lists a `maxFields` default of 1000 and a `maxFieldsSize` limit on the memory used by all the fields together, so the multipart path has its own set of ceilings.

## parsedMethods is where the strictness lives

The `parsedMethods` option declares the HTTP methods whose bodies will be parsed, and it defaults to POST, PUT and PATCH. The readme explains the reasoning with a reference to the HTTP semantics draft, noting that GET, HEAD and DELETE have no defined semantics for a request body, while also acknowledging that this does not mean a body on those methods may not be valid in some use cases. The point is that by default the middleware will not read a body from a GET, and if your application does need that, you change the option rather than discovering that it quietly stopped working. The option replaces an earlier `strict` flag, and the readme notes that you can use the enumeration or the strings to choose the methods, with `HttpMethodEnum.PATCH` given as the example.

## The raw body, for when a signature has to be checked

One option exists for a specific and important case, applications that need cryptographic verification of request bodies, and the readme names Slack and Stripe webhooks as the examples. Setting `includeUnparsed` to true attaches the raw, unparsed request body to `ctx.request.rawBody` for form encoded and JSON requests, so you can compute an HMAC over the exact bytes the sender signed rather than over a re-serialised object, which would change the bytes and break the signature. The limitation is stated plainly, this only works for non-multipart bodies, which is the boundary you hit first when you try to verify a signed upload. There is a second use for the same option, and it comes with the text body support, since for a text content type such as XML the body arrives unparsed and the `includeUnparsed` setting is not required to get it, with the example showing the raw text being handed to an XML converter.

## Files are available, but multipart is opt in

File uploads are supported and the uploaded files are reachable at `ctx.request.files`, with the parsing itself done by the formidable library whose options can be passed through the `formidable` option. The part to notice is that multipart parsing is off by default, so an application that expects uploads has to turn it on, and the size limits for that path come from formidable rather than from the three top level limit options. The repository ships examples for the three interesting cases, with a multipart example, an example using the Koa router, and a multer example, and the router example is the pattern the readme recommends. It is generally better to only parse the body as needed, so if the router supports middleware composition the body parser can be injected for certain routes only, which is a better default than parsing everything and then ignoring most of it.

## How the package is built, tested and released

The repository is a pnpm workspace with a `src/` directory, the examples, a changeset configuration and a biome configuration, and the build is a chain that is worth reading because it does more than compile. The `build` script cleans, lints, tests, then runs tshy and tshy-after, and finally runs the arethetypeswrong tool against the packed artefact, which checks that the type definitions and the exports map actually work for consumers on both module systems. The lint script is a TypeScript no-emit check plus biome, and the tests run with the Node test runner through tsx. Releases go through changesets, with a changelog generator for GitHub, and the version is 8.0.1 with the major bump to 8.0.0 in May 2026. The package is marked as an ES module, and the tshy configuration excludes the test files from the published build, with the exports map pointing at the generated source and declaration files.

## Conclusion

koa-body suits a Koa application that accepts forms, uploads or webhooks, since it covers the content types a real application receives rather than only JSON, and it suits a team that wants the strictness of a framework that only parses bodies where HTTP defines them. It is a poor fit if you only ever accept JSON, since the default configuration already does that with no options at all, and it is a poor fit if you need the raw bytes of a multipart upload, because the unparsed body is only available for non-multipart requests. Before you add it, check three things: which methods you want bodies parsed on, since the default is POST, PUT and PATCH only, the size limits, since the form and text defaults are much smaller than the JSON one, and whether you need webhook signature verification, which requires turning on the unparsed body option and reading it from the request.

## FAQ

### What does koa-body parse?

Multipart form data, urlencoded forms, JSON and text bodies. The JSON matchers default to application/json, application/json-patch+json, application/vnd.api+json, application/csp-report and application/reports+json, the text matchers to text/*, and the multipart and urlencoded matchers to multipart and urlencoded. Each list is configurable for vendor or custom mime types.

### What are the default body size limits in koa-body?

The JSON body limit defaults to 1mb, while the form and text limits both default to 56kb. Multipart uploads are limited through the formidable options instead, where maxFields defaults to 1000 and there is a separate limit on the memory used by the fields together.

### Which HTTP methods does koa-body parse bodies for?

POST, PUT and PATCH by default, through the parsedMethods option, which replaced the earlier strict flag. The readme notes that GET, HEAD and DELETE have no defined semantics for a request body even though a body on those methods can be valid in some use cases, and the methods can be given as strings or as an enumeration such as HttpMethodEnum.PATCH.

### How do I verify a webhook signature with koa-body?

Set the includeUnparsed option to true, which attaches the raw body to `ctx.request.rawBody` for form encoded and JSON requests, so you can compute the HMAC over the exact bytes that were signed. It does not work for multipart bodies, and for a text content type such as XML the unparsed body is available without that option.

### How are uploaded files accessed in koa-body?

Uploaded files are available at `ctx.request.files`, and multipart parsing is off by default, so an application that expects uploads has to enable it. The readme also recommends injecting the body parser only on the routes that need it when the router supports middleware composition. The package is MIT licensed, at version 8.0.1 from 2026-09-07, and the last push to the repository was on 2026-10-14.

## Sources

- [Issues](https://github.com/koajs/koa-body/issues)
- [koajs/koa-body on GitHub](https://github.com/koajs/koa-body)
- [License: MIT](https://github.com/koajs/koa-body/blob/master/LICENSE)
- [README](https://github.com/koajs/koa-body/blob/master/README.md)
- [Releases](https://github.com/koajs/koa-body/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/koajs-koa-body
