Base64 in Web Development: Encoding, URLs, and Common Mistakes
Base64 turns binary into ASCII text for JSON, data URLs, and some tokens. It is not encryption and it is not compression. Output is about 33% larger than the bytes. Cap decode size, and prefer a real upload for large files.
By Rehan Baqir
Base64 turns binary into ASCII text so a text-only channel can carry it. It is not encryption, not compression, and not a file-upload endpoint. The encoded form is roughly 33% larger than the raw bytes, anyone can decode it without a key, and a huge string can exhaust memory on decode. Use Base64 Encode and Base64 Decode to inspect small samples. Cap the size on the server, and prefer multipart upload or a signed object URL when the contract allows a real file.
A pull request passed CI because an avatar field was "just Base64." The value was a 2.4 MB PNG inlined in every API response. Encoding made it roughly 33% larger than the raw bytes. Mobile clients parsed the JSON. They spent battery and bandwidth shipping the same image on every poll.
What Base64 is on the web
Base64 encodes binary as ASCII using 64 printable characters: A to Z, a to z, 0 to 9, +, and /. Anyone can decode it without a key.
Developers use it to move binary through text-only channels:
- JSON fields that carry an image or a PDF chunk
- HTML
srcattributes and CSSurl()values that use data URLs - Email MIME parts in older systems
- OAuth state parameters and some token formats
For the 64-character alphabet and the padding rules, see Understanding Base64 Encoding. This article is about web patterns: where Base64 shows up in production, and what breaks when it is misused.
Why JSON does not carry raw bytes
JSON strings are Unicode text. Raw image bytes break parsers, inflate escaping, and fail in logs. Base64 turns the bytes into a safe string:
{
"avatar": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ..."
}
The cost is size. Base64 expands data by roughly 33% compared with the raw binary. You gain text-safe transport. You spend extra bytes on the wire.
Current APIs prefer multipart/form-data, or a direct binary upload to object storage with a signed URL. Base64 in JSON still shows up in legacy enterprise APIs, GraphQL attachments, Firebase sync payloads, and SOAP or XML inline content. Choose Base64 when the contract requires a JSON-only body. Otherwise a binary upload is more efficient.
Encode and decode
Encode, before you send binary in JSON or embed a small asset:
- Read the file bytes, with the File API in the browser or
fsin Node. - Base64-encode those bytes.
- Optionally prefix a MIME type for a data URL:
data:image/png;base64,...
Decode, when you receive Base64:
- Strip a data URL prefix if one is present (
data:*;base64,). - Decode to bytes or to a string.
- Check length and character set before you decode. Malformed input throws.
Data URLs in HTML and CSS
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0..." alt="" />
A data URL can remove an extra HTTP request for a tiny icon, and it can inline an image in email where external images are blocked.
There is no browser cache separate from the document. The bytes repeat on every page load. A huge data URL blocks rendering. Prefer a real URL for a photograph.
SVG in a data URL can carry script if it is sanitized poorly. Treat it as active content, not as a passive image. Read Base64 data URLs and performance for size budgets and for the cases where an inline asset hurts Core Web Vitals.
Base64url
URLs and JWTs use Base64url: + becomes -, / becomes _, and padding = is often stripped. A standard decoder may need the padding restored until the length is a multiple of 4.
A JWT payload is Base64url-encoded JSON. Decode the middle segment with the URL-safe alphabet. Anyone can read the claims. The signature, the third segment, provides integrity through the signing keys. It does not make the payload secret.
JWT encoding is not encryption. Percent-encoding, such as %20 for a space, is a different layer. See the URL encoding and decoding guide.
UTF-8 text inside Base64
To encode plain text:
- UTF-8-encode the string to bytes.
- Base64-encode those bytes.
Decoding has to UTF-8-decode the bytes. A Latin-1 decode corrupts emoji and CJK text. Test with non-ASCII samples such as café and a multi-byte emoji when you build anything internationalized.
Security
- Base64 does not protect secrets. Encoding a password before a POST does not protect it. Use TLS and real authentication. See the password security guide.
- Cap size. Decoding an attacker-controlled string of megabytes can exhaust memory.
- SVG in a data URL can carry script if sanitizing is weak. Treat it as active content.
- Base64 in an API log is readable once decoded. Scrub sensitive payloads before they hit the logging pipeline.
For passwords, use a strong generator such as the Password Generator. Encoding is the wrong tool.
APIs and other ways to upload
| Approach | Best for | Tradeoff | | --- | --- | --- | | Base64 in JSON | Legacy text-only contracts | About 33% size overhead | | Multipart upload | Current REST file endpoints | The server has to handle multipart | | Signed object URL | Large files to S3 or GCS | Extra infrastructure | | Data URL inline | Tiny icons and email | Bloats HTML, and there is no separate cache |
When a payload nests structured data, run the decoded JSON through JSON Formatter. Truncation is easier to see there than in a raw string.
Hashes and Base64
The Hash Generator produces a digest such as SHA-256, a one-way fingerprint. Base64 often wraps those hash bytes for display. Decoding a hash does not return the original content.
Debugging
| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Padding errors | A missing trailing = | Add = until the length is a multiple of 4 |
| Newlines in PEM | Line breaks inside a certificate block | Strip them before decode |
| Wrong alphabet | Hex or Base32 treated as Base64 | Check the source format |
| Corrupted emoji | Decoded as Latin-1 | UTF-8-decode after Base64 |
| Truncated string | A chat or email clipped a long line | Compare a checksum of the bytes |
Streaming large payloads
Node and browser APIs can Base64-encode a large file in chunks instead of one string. A manual tool is for a small payload. A production pipeline should stream, so a multi-megabyte upload encoded inside JSON does not spike memory.
An inline PDF in an API response
An API returns a contract PDF as:
{
"document": "JVBERi0xLjQKJeLjz9MKMy...",
"filename": "contract.pdf"
}
The client workflow:
- Decode the Base64 to bytes.
- Write a
Blobwith typeapplication/pdf. - Open it in a viewer, or download it.
A 200 KB PDF can work this way. A 15 MB scanned contract becomes about a 20 MB JSON response. That is slow on mobile and painful in logs. A better pattern: the API returns a signed URL, and the client fetches the binary directly.
Common mistakes
"Base64 secures the password." Encoding is reversible. TLS encrypts the transport. A salted hash is what you store for a password. Encoding does neither.
Inlining a large image in every response. Encode once at upload, and serve a CDN URL on read.
Skipping a length cap. A client can send a 50 MB Base64 string, and the decoder allocates before it validates.
Mixing Base64url and standard Base64. A JWT's middle segment fails in a standard decoder until you swap the alphabet and restore padding.
Forgetting the data URL prefix. Decoding data:image/png;base64,iVBOR... as raw Base64 throws an invalid-character error.
Limitations
Base64 does not compress data. The output is larger than the input. It does not encrypt data. Anyone can decode it. It does not validate integrity. Use a hash or a signature for that. It does not replace a file system or object storage for a large asset.
Use it where a text channel has to carry binary. Cap the size. Move to a binary upload when the contract allows it.
Related articles
- Understanding Base64 Encoding: how the alphabet and padding work
- Base64 Data URLs and Performance: size budgets for inline assets
- URL Encoding and Decoding Guide: percent-encoding compared with Base64url
- Password Security Guide: why encoding is not protection
Base64 is a reliable bridge between binary and text for a tiny inline asset, a legacy JSON contract, and a quick look at a payload. It fails when a team treats it as security, as compression, or as the default for every file. Encode for a reason, cap the decode, prefer a real upload for large content, and test with non-ASCII text. When you need to inspect a payload quickly, Base64 Decode is faster than guessing from a log line.
Frequently Asked Questions
Common questions answered to help you get the most from this tool.