application/x-www-form-urlencoded or multipart/form-data?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
application/x-www-form-urlencoded and multipart/form-data are the two main Content-Type encodings for sending form data in HTTP POST requests. The URL-encoded format sends key-value pairs as a single string (key1=value1&key2=value2), which is compact for text data but cannot handle binary files. The multipart format sends each field as a separate part with its own content type, making it the only option for file uploads. Use URL-encoded for simple text forms and multipart when the form includes file inputs.
application/x-www-form-urlencoded
The browser sends:
Key-value pairs are joined by &, keys and values are separated by =, and special characters are percent-encoded (spaces become + or %20). This is the default encoding when no enctype is specified on the form.
multipart/form-data
The browser sends:
Each field is a separate "part" delimited by a boundary string. File parts include the filename and content type. Binary data is sent as-is, without encoding.
Sending with JavaScript (fetch)
When using FormData, do not set the Content-Type header manually. The browser generates the boundary string and includes it in the header automatically.
Sending with Python (requests)
In Python's requests library, the data parameter sends URL-encoded data. The files parameter switches to multipart encoding automatically.
Sending with cURL
cURL's -d flag sends URL-encoded data. The -F flag sends multipart data. The @ prefix in -F reads a file from disk.
Server-Side Parsing
Most web frameworks parse both encodings transparently. File uploads require multipart-specific middleware (like multer in Express).
Comparison Table
| Feature | URL-encoded | Multipart |
| Default for forms | Yes | No (requires enctype) |
| File uploads | No | Yes |
| Binary data | No (must base64 encode) | Yes (native) |
| Encoding overhead | ~3x for non-ASCII | Boundary per field |
| Body size | Compact for text | Larger for text-only forms |
| Content-Type | application/x-www-form-urlencoded | multipart/form-data; boundary=... |
Common Pitfalls
- Using URL-encoded for file uploads: File data cannot be sent with URL encoding unless you base64-encode it first, which inflates the size by 33%. Always use
multipart/form-datafor file inputs. - Setting Content-Type manually for multipart: When using
fetchwithFormDataorrequestswithfiles, do not set theContent-Typeheader manually. The library generates the boundary string and must include it in the header. Setting it manually omits the boundary, causing parse failures. - Percent-encoding overhead for binary data: URL encoding replaces each non-ASCII byte with
%XX, tripling the data size. For binary or non-ASCII heavy payloads, multipart is far more efficient. - Forgetting enctype on HTML forms: Without
enctype="multipart/form-data", the form defaults to URL encoding. File inputs submit only the filename, not the file contents. - Maximum URL-encoded body size: Some servers and proxies limit the body size for URL-encoded data (e.g., Tomcat defaults to 2MB). Multipart uploads typically have higher or configurable limits. Check server configuration for large form submissions.
Summary
- Use
application/x-www-form-urlencodedfor simple text forms (login, search, settings) - Use
multipart/form-datawhen the form includes file uploads or binary data - URL-encoded is the default — no
enctypeneeded on the HTML form - Multipart requires
enctype="multipart/form-data"on the form tag - Do not set
Content-Typemanually when sendingFormDatain JavaScript — the browser adds the boundary - Server frameworks parse both formats through
request.form(text) andrequest.files(uploads)

