Why JSON APIs need Base64 at all
JSON's type system has no native "binary" or "bytes" type — only strings, numbers, booleans, arrays, objects, and null. Any binary payload (a file upload, an image, an encryption key, a protobuf blob) that needs to travel inside a JSON request or response body has to be represented as one of those existing types — and Base64-encoding it into a string field is the standard way to do that without inventing a custom format.
{
"filename": "report.pdf",
"contentType": "application/pdf",
"data": "JVBERi0xLjQKJ..."
}
The real cost: size and streaming
Base64 inflates payload size by roughly a third (see Base64 vs Hex for the exact math) — for a REST API handling large file uploads, that overhead adds up in bandwidth and server-side memory, since the entire Base64 string typically has to be buffered and decoded before it's usable, unlike raw binary which can potentially stream. This is exactly why large file uploads (multi-megabyte files, video, bulk exports) are usually handled differently — via multipart/form-data or direct binary upload endpoints — reserving JSON+Base64 for smaller payloads: thumbnails, encryption keys, signatures, small attachments.
Common patterns
- Data URIs in API responses: an API returning a small generated image (a QR code, a chart) often embeds it directly as a
data:image/png;base64,...string, letting the client render it with no separate request. - Encrypted payloads: ciphertext is binary; APIs exchanging encrypted data typically Base64-encode the ciphertext to fit it into a JSON field, exactly the "encode after encrypting" pattern from the Complete Guide to Base64.
- Basic Authentication:
Authorization: Basic <base64(username:password)>— an HTTP header convention, not a JSON body pattern, but it's the same underlying mechanism: encoding binary-adjacent data into a text-safe format.
Common mistakes
- Using JSON+Base64 for large file uploads by default. It works, but multipart or direct binary upload is more size- and memory-efficient for anything beyond a small file.
- Forgetting to specify a
contentType/MIME type alongside the encoded data. The Base64 string alone doesn't say what kind of file it represents — the API needs that metadata explicitly, in a separate field. - Not accounting for the size inflation in request size limits. A file just under an API's raw size limit can exceed it once Base64-encoded, due to the ~33% overhead.
FAQ
Why can't JSON just carry binary data directly?
JSON's spec only defines six types, none of which is "raw binary" — a binary payload has to be represented through one of the existing types, and Base64-encoded strings are the standard convention.
Is Base64 the best choice for large file uploads in an API?
Not usually — the size overhead and lack of streaming make multipart/form-data or a dedicated binary upload endpoint more efficient for large files; Base64-in-JSON fits best for small payloads.
Do I need to include the file type separately from the Base64 data?
Yes — the encoded string alone doesn't indicate MIME type or file format; that information needs its own field in the request/response.
Encode and inspect Base64 payloads alongside your JSON with the Base64 Encoder/Decoder and JSON Toolkit — both run client-side.