Embedding Binary Data in JSON APIs
JSON APIs solve binary transport by turning bytes into strings.
JSON is a text format. It has no binary type , only strings, numbers, booleans, nulls, objects, and arrays.1 Yet APIs routinely need to transport binary data: profile photos, file uploads, cryptographic signatures, and audio clips.
Base64 encoding converts binary bytes into a JSON-safe string. The receiving end decodes the string back to bytes. The trade-off is a 33% increase in payload size and the CPU cost of encoding and decoding on both sides.2
How binary fields work in JSON APIs
A Base64-encoded binary field in JSON is a plain string property: {"avatar": "iVBORw0KGgo...", "type": "image/png"}. The receiving API decodes the string back to bytes before processing or storing the binary content. This encoding step is necessary because JSON has no native binary type, so any binary data must be represented as a text string using an encoding that is safe for JSON string syntax.
Keeping binary metadata explicit
REST APIs for image upload, cloud storage signed URLs, and document management systems all use this pattern to embed binary data directly in JSON payloads. Consequently, your JSON payload grows by 33% compared to a multipart/form-data upload that sends the raw bytes, making multipart preferable for large files. Furthermore, streaming APIs that send binary frames (WebSocket binary messages) avoid Base64 entirely because the protocol supports binary frames natively. When you design the JSON schema, include a companion field for the MIME type or file extension so the decoding side knows how to interpret the bytes. Without that metadata, the receiver must guess the file format from the decoded content, which adds complexity and can produce incorrect results for ambiguous byte sequences that match multiple format signatures.
This matters because the cost of missing metadata shows up at decode time, not at send time: a base64 field with no type hint forces the receiver to inspect magic bytes and guess, which is exactly the kind of fragile step that produces the wrong file type when two formats share a prefix.
Common pitfalls and variants
Embedding very large files in JSON payloads causes performance and reliability problems. JSON parsers buffer the entire document in memory before exposing any field , a 10 MB Base64 image forces 13.3 MB of JSON into memory before decoding begins.3 API gateways enforce payload size limits (AWS API Gateway defaults to 10 MB with base64 enabled, 6 MB without).4 Conversely, multipart/form-data streams binary data without JSON overhead and without memory-buffering the entire payload. Furthermore, some JSON APIs use URLs instead of inline binary: accept a file, store it, and return a URL. This pattern scales better for large files and works with standard CDN caching.
Security and best practice
Validate the decoded bytes before processing them. A client that sends a truncated or malformed Base64 string may cause a buffer parsing crash downstream. Confirm the length and MIME type of the decoded data before passing it to image decoders, PDF parsers, or file-writing functions. Furthermore, Base64 encoding does not sanitize content , a valid PNG Base64 string that happens to embed a different format does not become a PNG. Always verify the magic bytes of the decoded binary before accepting the declared Content-Type. Limit Base64 binary JSON fields to small payloads; redirect large uploads to a pre-signed storage URL.
Setting limits before decoding
Set maximum field length, decoded byte length, and allowed MIME types before your API accepts a Base64 JSON value. These limits keep malformed or oversized uploads from reaching parsers that expect well-formed files. A practical configuration sets the maximum decoded size to the largest file your application genuinely needs, rejects MIME types outside a narrow allowlist, and returns a descriptive 422 response that tells the client exactly which limit was exceeded rather than a generic error.
Comparing Base64 JSON to multipart uploads in practice
Multipart form data streams binary content with no encoding overhead, while Base64 in JSON adds 33% overhead and requires the JSON parser to buffer the entire payload before exposing any field. For a 1 MB image upload, multipart sends 1 MB over the wire; Base64 in JSON sends 1.33 MB and holds 1.33 MB in parser memory before decoding starts. This difference is negligible for payloads under 50 KB and significant for payloads over 500 KB.
When Base64 in JSON makes sense
From an implementation perspective, multipart requires parsing MIME boundary strings and Content-Disposition headers, which adds code complexity on both client and server. Base64 in JSON integrates naturally with existing JSON middleware: no additional parsing libraries, no multipart boundary generation, and no risk of boundary collision with binary content. For REST APIs where most payloads are small binary fields embedded alongside structured data, Base64 in JSON is simpler to implement and maintain than adding a separate multipart upload endpoint.
Protocol Buffers and CBOR as structured alternatives
Protocol Buffers and CBOR (Concise Binary Object Representation) include native binary types and avoid the 33% overhead of Base64 entirely. Protocol Buffers represent binary fields as bytes in the schema, serializing them as a length-prefixed byte sequence with no encoding step.5 CBOR, defined in RFC 8949, is a binary-safe encoding of JSON-like structures that preserves all JSON types and adds a native byte string type.6
For APIs where Base64 in JSON works today but throughput or payload size is a concern, migrating to Protocol Buffers or CBOR reduces wire size and eliminates the CPU cost of encoding and decoding on both sides. The trade-off is tooling: JSON requires no schema and works in any HTTP client or browser developer tool without additional setup, while Protocol Buffers require a .proto schema and generated client and server code. CBOR is a middle ground; libraries exist for most languages and the format is schema-free like JSON.
When to use this
Use Base64 in JSON for small binary fields (icons, thumbnails, signatures, tokens) where a separate multipart endpoint would add unnecessary complexity. For files over 100 KB, use multipart/form-data or a pre-signed upload URL. To size a field before you commit to inlining it, measure the encoded length against your payload limit and confirm the result stays under your API gateway threshold.
Examples
Upload a small image in a JSON request
POST /api/profile Content-Type: multipart/form-data [binary file data]
POST /api/profile
Content-Type: application/json
{
"name": "Jane Smith",
"avatar": "iVBORw0KGgoAAAANSUhEUg...",
"avatarType": "image/png"
} Suitable for avatars under 64 KB. Use multipart for larger images.
Return a generated QR code in a JSON response
{ "qr_url": "https://cdn.example.com/qr/abc123.png" } {
"qr_base64": "iVBORw0KGgo...",
"qr_mime": "image/png"
} Inline Base64 eliminates the extra GET request for the image, useful in single-call mobile flows.
- 1.
D. Crockford, "The JavaScript Object Notation (JSON) Data Interchange Format," RFC 8259, IETF, December 2017. https://datatracker.ietf.org/doc/html/rfc8259
- 2.
"Base64," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/Base64
- 3.
"API Gateway payload encoding," docs.aws.amazon.com, accessed June 2026. https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-payload-encodings.html
- 4.
"Protocol Buffers Encoding Guide," developers.google.com, accessed June 2026. https://protobuf.dev/programming-guides/encoding/
- 5.
C. Bormann and P. Hoffman, "Concise Binary Object Representation (CBOR)," RFC 8949, IETF, December 2020. https://datatracker.ietf.org/doc/html/rfc8949
- 6.
"Understanding and Tuning Memory," nodejs.org, accessed June 2026. https://nodejs.org/learn/diagnostics/memory/understanding-and-tuning-memory