Base64 File Upload Encoding — A Practical Guide
Web forms and REST APIs can't send raw binary through a JSON body — JSON is text-only. Base64 solves that by turning any file into a plain string, at the cost of extra bytes on the wire. This guide explains when that trade-off makes sense and when it doesn't.
Why files get Base64 encoded at all
JSON, XML, and many database text columns can only store printable characters — they choke on arbitrary binary bytes (null bytes, control characters). Base64 maps any binary data to 64 safe printable ASCII characters, so a PNG, PDF, or ZIP file can travel inside a JSON string field without corruption.
// A file embedded directly in a JSON API request body
{
"fileName": "invoice.pdf",
"mimeType": "application/pdf",
"fileData": "JVBERi0xLjQKJeLjz9MK..." // Base64-encoded PDF bytes
}Encoding a file to Base64 for upload
In the browser, use the FileReader API to convert a selected file into a Base64 data URI, then strip the prefix before sending just the encoded payload:
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
// result looks like: "data:image/png;base64,iVBORw0KG..."
const base64 = reader.result.split(',')[1];
resolve(base64);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// Usage with a file input
const file = document.querySelector('input[type="file"]').files[0];
const base64Data = await fileToBase64(file);
await fetch('/api/upload', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ fileName: file.name, fileData: base64Data }),
});Decoding on the server (Node.js)
import fs from 'fs';
app.post('/api/upload', (req, res) => {
const { fileName, fileData } = req.body;
const buffer = Buffer.from(fileData, 'base64');
fs.writeFileSync(`./uploads/${fileName}`, buffer);
res.json({ ok: true, sizeBytes: buffer.length });
});The size overhead — why Base64 isn't free
Base64 encodes every 3 bytes of input as 4 characters of output, so encoded data is always about 33% larger than the original. For a 3 MB image, that's roughly 4 MB of actual bytes sent over the network — plus JSON escaping overhead if wrapped in quotes.
- 10 KB file → ~13.3 KB encoded
- 1 MB file → ~1.37 MB encoded
- 10 MB file → ~13.7 MB encoded, plus more CPU time to encode/decode
When to use multipart/form-data instead
For standard file uploads from an HTML form, multipart/form-data sends the raw binary bytes directly with no encoding overhead. It's the right default for large files, bulk uploads, or anywhere bandwidth and server CPU matter.
<form action="/api/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="document" />
<button type="submit">Upload</button>
</form>
// Fetch equivalent
const formData = new FormData();
formData.append('document', file);
await fetch('/api/upload', { method: 'POST', body: formData });
// No Base64 conversion, no 33% overheadDecision guide
- Use Base64 when the transport is text-only: JSON APIs, GraphQL mutations, XML/SOAP, or embedding small icons as CSS/HTML data URIs.
- Use multipart/form-data for browser file-upload forms, large attachments, and any case where you control both client and server.
- For files over a few MB, prefer multipart or direct binary streaming — Base64's overhead and in-memory string handling become expensive.
- If you must use Base64 for large files, consider chunking the upload rather than encoding the whole file in memory at once.
Frequently Asked Questions
Base64 turns binary file data into plain text, which lets you embed a file directly inside a JSON payload, a database text column, or an HTML data URI — formats that cannot natively hold raw binary bytes.
Base64 encoding increases size by approximately 33%, because every 3 bytes of binary input become 4 characters of text output. A 1 MB file becomes roughly 1.37 MB once encoded.
Use multipart/form-data for standard file uploads from a browser form — it sends raw binary with no size penalty. Use Base64 only when the transport requires text, such as JSON APIs, GraphQL, or embedding small files inline in HTML or CSS.