How Base64 Encoding Actually Works
Base64 is not encryption, not compression, and not magic. It is a very specific mapping from 3 bytes to 4 characters — and that constraint explains almost everything strange about it.
Base64 is one of the most common things in a working developer's day and one of the most misunderstood. It looks like a code — obviously encrypted, right? — but a random stranger with a laptop can decode it in a second. This is a short explainer on what it actually does, why the output looks the way it does, and where it fits.
The problem Base64 solves
Some transports only handle text. Email bodies (historically), URLs, JSON string fields, HTTP headers,data: URIs — all of these choke on raw binary bytes. Any byte with the high bit set, any control character, any NUL byte can get mangled or truncated. If you want to shove an image, a signed token, or an arbitrary blob through one of these channels, you need a way to represent bytes using only the "safe" subset of ASCII.
Base64 is that representation. It uses 64 safe characters — A-Z, a-z,0-9, plus + and / — and maps every 3 bytes of input to exactly 4 characters of output. That is the whole trick.
The 3-byte / 4-character dance
Three bytes is 24 bits. Four Base64 characters is also 24 bits — because 64 = 2⁶, each character carries 6 bits. Every 3 bytes in becomes 4 characters out. Perfect fit.
Input: M a n
01001101 01100001 01101110 (3 bytes = 24 bits)
Regroup as 6-bit chunks:
010011 010110 000101 101110
Look each up in the Base64 alphabet:
19 22 5 46
T W F u
Output: TWFuThat is why Man becomes TWFu. Not encryption, not a hash — just a change of how the same 24 bits are grouped and named.
Why the output ends in =
When the input length isn't a multiple of 3, the encoder pads with zero bits so the last group still contains 24 bits — and marks the padding with = so the decoder knows how many bits to throw away. One byte left over → two output characters + ==. Two bytes left over → three output characters + =. That is all = means.
URL-safe Base64 (base64url)
Standard Base64 uses + and /, which have special meaning in URLs (space and path separator). The URL-safe variant substitutes them: + becomes -,/ becomes _, and the trailing = padding is often dropped entirely. JWTs use this variant — so does every OAuth code you have ever seen in a query string.
Common confusions
- "Is Base64 secure?" No. It is trivial to reverse. Anything you Base64 is one command away from being plain text again. Never use it as a substitute for encryption.
- "Does it compress?" No — it inflates. Every 3 bytes in becomes 4 bytes out, so Base64 output is always ~33% larger than the input.
- "Why does JavaScript's
btoabreak on emoji?" Becausebtoaassumes each character is a single byte, which is only true for the ASCII range. For UTF-8 text you have to encode to bytes first, then Base64 those bytes.
When to reach for it
- Embedding a small image directly in HTML/CSS via
data:image/png;base64,... - Sending a binary blob through a JSON API that only accepts strings.
- Serialising bytes into a URL, cookie, or environment variable.
- Encoding parts of a JWT (header and payload, with base64url).
For any of those, the Base64 encoder/decoder handles both standard and URL-safe variants and gets the UTF-8 encoding right so emoji and accented characters round-trip cleanly.