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 <code>multipart/form-data</code>. 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
<code>multipart/form-data</code> 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 |
| <strong>Total overhead</strong> | <strong>Approximately 200–350 B</strong> |
For a simple form with just one file, the overhead is approximately <strong>200–400 bytes</strong>. 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 <code>client_max_body_size</code> limits the size of the <strong>entire request body</strong>. 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: <code>upload_max_filesize</code> (per file) and <code>post_max_size</code> (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 <code>curl</code> 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 <code>multipart/form-data</code>, binary file data is sent as-is (without Base64 encoding). Base64 encoding is only needed when sending binary with <code>application/x-www-form-urlencoded</code> or sending files in JSON bodies (like <code>data:image/png;base64,...</code>).
| 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 <code>client_max_body_size</code> as well
- Simultaneous upload of multiple files increases overhead
- Overhead also includes additional form fields (name, comment, etc.)
Using the <a href="/ja/files/threshold/">threshold test files</a> 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 <code>multipart/form-data</code> is approximately <strong>200–400 bytes</strong> (for a single file)
- Since Nginx's <code>client_max_body_size</code> limits the entire request body, set it slightly larger than the file size limit
- PHP requires setting two directives: <code>upload_max_filesize</code> (individual file) and <code>post_max_size</code> (entire POST body).
- When Sending via JSON + Base64, File Size Increases by Approximately 33%
Test files for this article
- → <a href="/ja/files/threshold/" class="text-primary-600 dark:text-primary-400 hover:underline">Threshold Test Files (9.9MB / 10MB / 10.1MB)</a>
- → <a href="/ja/files/images/png/" class="text-primary-600 dark:text-primary-400 hover:underline">PNG Image Test Files List</a>
Related articles
- → <a href="/ja/blog/how-to-test-upload-limit/" class="text-primary-600 dark:text-primary-400 hover:underline">How to Properly Test File Upload Limits</a>
- → <a href="/ja/blog/mb-vs-mib-file-size/" class="text-primary-600 dark:text-primary-400 hover:underline">MB and MiB Are Different! The Pitfalls of File Size Units</a>