Multipart Parser Overview
When a browser submits a <form> with enctype="multipart/form-data", the request body is encoded in a format called multipart. Multipart encoding splits the body into parts separated by a boundary string. Each part carries its own headers (like Content-Disposition and Content-Type) followed by the part's body bytes. This is how file uploads travel over HTTP.
The multipart-parser package gives you a streaming parser for this format. It works in any JavaScript runtime -- Node.js, Deno, Bun, Cloudflare Workers, and browsers -- because it builds on web-standard APIs (ReadableStream, Uint8Array, Headers).
When to Use This Package
Most applications should reach for form-data-parser instead, which provides a higher-level API that returns a standard FormData object. Use multipart-parser directly when you need:
- Fine-grained control over how individual parts are processed
- To stream file parts directly to storage without buffering
- Custom limits on header size, file size, or total request size
- Access to raw part headers and bodies
Quick Example
import {
parseMultipartStream,
isMultipartRequest,
getMultipartBoundary,
} from 'remix/multipart-parser'
async function handleUpload(request: Request) {
if (!isMultipartRequest(request)) {
return new Response('Expected multipart form data', { status: 400 })
}
let boundary = getMultipartBoundary(request)!
for await (let part of parseMultipartStream(request.body!, boundary)) {
let disposition = part.headers.get('Content-Disposition')
console.log(disposition) // 'form-data; name="avatar"; filename="photo.jpg"'
console.log(part.body.byteLength)
}
return new Response('Upload received')
}Key Concepts
- Boundary -- A unique string embedded in the
Content-Typeheader that separates parts in the multipart body. The parser needs this to know where one part ends and the next begins. - Part -- A single field or file in the multipart body. Each part has its own
Headersobject and aUint8Arraybody. - Streaming --
parseMultipartStreamyields parts one at a time via an async iterator, so you never need to hold the entire request body in memory.
Three Parsing Modes
| Function | Use Case |
|---|---|
parseMultipart(body, boundary) | Buffer all parts into an array. Simple but uses more memory. |
parseMultipartStream(body, boundary) | Async iterator that yields parts one at a time. Memory-efficient. |
new MultipartParser(boundary) | Low-level class with write/end for full control over buffering. |
Safety Limits
The parser accepts options to enforce size and count limits:
let parts = await parseMultipart(request.body!, boundary, {
maxFileSize: 10 * 1024 * 1024, // 10 MB per file
maxParts: 20, // 20 fields/files max
maxTotalSize: 50 * 1024 * 1024, // 50 MB total
})When a limit is exceeded, the parser throws a typed error (MaxFileSizeExceededError, MaxPartsExceededError, etc.) that you can catch and return an appropriate HTTP response.
Related
- form-data-parser -- Higher-level API that returns standard
FormData - file-storage -- Store uploaded files to disk, memory, or S3
- API Reference -- Full API documentation