Calculate the overhead of multipart/form-data accurately
Have you ever experienced a 413 error when a file is only 9MB during file upload size limit testing? One of the causes is the overhead of multipart/form-data. When uploading a file via an HTML form, the HTTP request body contains not only the file itself but also additional metadata. This article explains the precise calculation method for that overhead and points to consider during testing.
Structure of multipart/form-data
multipart/form-data defined in RFC 2046 has a structure where each part is separated by a boundary string. An actual HTTP request body looks like this.
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
Content-Length: 10000xyz
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="file"; filename="test.png"
Content-Type: image/png
[ファイルのバイナリデータ]
------WebKitFormBoundaryABC123--
Overhead Breakdown
The overhead of a typical file upload request consists of the following elements.
| Element | Example | Number of Bytes (Approximate) |
|---|---|---|
| Starting boundary | ------WebKitFormBoundaryABC123\r\n | Approximately 40–80 B |
| Content-Disposition Header | Content-Disposition: form-data; name="file"; filename="test.png"\r\n | Approximately 60–120 B |
| Content-Type Header | Content-Type: image/png\r\n | Approximately 25–50 B |
| Blank line (end of headers) | \r\n | 2 B |
| Line Break at End of Part | \r\n | 2 B |
| Closing boundary | ------WebKitFormBoundaryABC123--\r\n | Approximately 42–82 B |
| Total overhead | Approximately 200–350 B |
For a simple form with just one file, the overhead is approximately 200–400 bytes. If there are additional form fields (such as text inputs), the overhead increases accordingly, but it typically stays within a few hundred bytes to several kilobytes.
Why does the 413 error occur
Nginx's client_max_body_size limits the size of the entire request body. In other words, the configured value must include overhead.
# 10MiB のファイルをアップロードさせたい場合
# オーバーヘッド(約1KB)を考慮して少し大きめに設定
client_max_body_size 11m; # MiB単位: 11 MiB = 11,534,336 バイト
For PHP, you need to configure two settings: upload_max_filesize (per file) and post_max_size (entire POST body).
; php.ini
upload_max_filesize = 10M ; ファイル単体の上限: 10 MiB
post_max_size = 11M ; POSTボディ全体の上限: 11 MiB(オーバーヘッド分を加算)
Accurate overhead measurement method
If you want to know the actual overhead accurately, you can send requests with curl and measure the request size.
# ファイルのバイト数を確認
wc -c test-10mb.png
# → 10485760 test-10mb.png
# curl でアップロードしてリクエストサイズを確認
curl -X POST https://example.com/upload \
-F "file=@test-10mb.png" \
-w "リクエストボディサイズ: %{size_upload} バイト\n" \
-o /dev/null -s
# → リクエストボディサイズ: 10486062 バイト(差: 302バイト)
Difference from Base64 Encoding
With multipart/form-data, binary file data is sent as-is (without Base64 encoding). Base64 encoding is only needed when sending binary with application/x-www-form-urlencoded or sending files in JSON bodies (like data:image/png;base64,...).
| Transmission method | Overhead | Use case |
|---|---|---|
| multipart/form-data (HTML Form) | Hundreds of bytes to several KB | Standard file upload |
| JSON + Base64 | Approximately 33% increase | File Transfer via API |
| application/octet-stream(PUT) | Nearly zero | S3 presigned URLs and more |
Testing considerations
- Understand whether the server's size limit check is for "individual files" or "entire request body"
- Since Nginx limits requests before PHP, check Nginx's
client_max_body_sizeas well - Simultaneous upload of multiple files increases overhead
- Overhead also includes additional form fields (name, comment, etc.)
Using the threshold test files on DevLab, you can verify actual upload behavior with file sizes near the boundary. Validate in conjunction with your Nginx/Apache/PHP configuration.
Summary
- The overhead of
multipart/form-datais approximately 200–400 bytes (for a single file) - Since Nginx's
client_max_body_sizelimits the entire request body, set it slightly larger than the file size limit - PHP requires setting two directives:
upload_max_filesize(individual file) andpost_max_size(entire POST body). - When Sending via JSON + Base64, File Size Increases by Approximately 33%