Base64 shows up everywhere once you start looking: in email attachments, in data: URLs inside CSS, in the middle segment of a JWT, in the Authorization header of an API request. It's the standard way to move binary data through places that only expect text.
It also has a cost. Base64 output is always about a third larger than the input. Here's how it works, where that 33% comes from, and when it's the right tool.
What Base64 is for
Computers store everything as bytes, and a byte can hold any of 256 values. Many older protocols and formats were built for text, though, and some byte values cause trouble there: control characters can end a line, a zero byte can end a string, and some email systems were only guaranteed to pass 7-bit ASCII intact.
Base64 solves this by rewriting any bytes using only 64 safe characters: A–Z, a–z, 0–9, + and /, plus = for padding. The result survives almost any text channel and can be turned back into the exact original bytes. The encoding is defined in RFC 4648.
How the encoding works
Base64 works on groups of 3 bytes, which is 24 bits. It splits those 24 bits into four groups of 6 bits. Six bits can hold 64 different values, and each value maps to one character of the alphabet.
Take the text Hi!, which is 3 bytes:
| H | i | ! | |
|---|---|---|---|
| Byte value | 72 | 105 | 33 |
| Bits | 01001000 | 01101001 | 00100001 |
Joined and regrouped into 6-bit chunks: 010010 000110 100100 100001. Those are the numbers 18, 6, 36 and 33, which are the characters S, G, k and h in the Base64 alphabet. So Hi! becomes SGkh. You can confirm it in our Base64 Encoder.
Padding with =
When the input isn't a multiple of 3 bytes, the last group is short. Base64 fills it with zero bits and adds = signs so the output length stays a multiple of 4:
Hi! → SGkh
Hi → SGk=
H → SA==
One = means the last group had 2 bytes, two == mean it had 1. Some formats leave the padding off, since the decoder can work out the length without it.
Why Base64 makes data 33% bigger
Every 3 bytes of input become 4 characters of output. Each output character is stored as one byte, so 3 bytes turn into 4: an increase of exactly one third, about 33%.
A 1,000,000-byte file encodes to 1,333,336 characters (the extra 4 come from padding the last group). If the encoded text is wrapped into lines, as email requires, the line breaks add a bit more: RFC 2045 limits MIME Base64 lines to 76 characters, so each line adds a line break.
The overhead has a few practical effects:
- Email attachments count against size limits after encoding, so a 15 MB file takes up roughly 20 MB in the message.
- Inlined images in HTML or CSS are a third larger than the image file, and they can't be cached separately from the page or stylesheet that contains them.
- Binary data in JSON grows by a third and costs CPU time to encode and decode.
HTTP compression such as gzip or Brotli recovers part of the overhead, because Base64 text only uses 64 symbols, but compressed data like JPEG or PNG images still ends up larger than the original file.
Where you'll see Base64
Email attachments
MIME email, defined in RFC 2045, uses Base64 as a content transfer encoding. Your email client encodes attachments before sending and decodes them on arrival. This is where Base64 started.
Data URLs
A data URL puts a whole file inside a URL: data:[mediatype][;base64],data. For example, a single-pixel PNG image is 70 bytes and becomes:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==
Data URLs save a request for tiny icons, but for anything bigger than a few kilobytes a normal image file is usually better, since it can be cached and loaded in parallel. MDN's data URL reference covers the details. The encoder's File mode can output a ready-made data URL.
HTTP Basic authentication
RFC 7617 sends the user name and password as user:password encoded in Base64. The example from the RFC:
Aladdin:open sesame → QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Anyone who sees this header can decode the password instantly, which is why Basic authentication must only be used over HTTPS.
JSON Web Tokens
A JWT is three Base64url-encoded parts separated by dots. RFC 7515 specifies the URL-safe alphabet with the trailing = removed. Paste the first or second part of a token into the Base64 Decoder and you'll see readable JSON, which is a good reminder that a JWT's contents are not secret, only signed.
Certificates and keys
The PEM files used for TLS certificates and private keys are Base64-encoded binary data between -----BEGIN …----- and -----END …----- lines.
Base64 vs. Base64url
Standard Base64 uses + and /, which have special meanings in URLs and file paths. RFC 4648 section 5 defines a URL- and filename-safe variant, usually called Base64url, that swaps them for - and _. The same three bytes in each:
Standard: +/+/
URL-safe: -_-_
A decoder for one variant may reject the other, so check which one a system expects. If you put standard Base64 into a URL query string instead, the +, / and = characters need to be percent-encoded, for example with our URL Encoder.
Base64 is not encryption
This is the most common misunderstanding. Base64 has no key and no secret. Anyone can reverse it, and decoders are built into every browser and programming language. Encoding a password, an API key or personal data in Base64 hides it from nobody.
Base64 is also not hashing. A hash can't be reversed to get the input back, while Base64 is designed to be reversed exactly. If you need to protect data, use real encryption. If you need to store passwords, use a password hash, as explained in MD5 vs SHA-256 vs bcrypt.
Text and character encodings
Base64 encodes bytes, not characters. Text has to be turned into bytes first, and the result depends on which character encoding you use. With UTF-8, the standard on the web, Grüße 👋 is 12 bytes and encodes to R3LDvMOfZSDwn5GL. A system that uses Latin-1 or UTF-16 for the same text produces different bytes and therefore different Base64. When decoded text shows up as garbled characters, a mismatched character encoding is the usual cause.
FAQ
How do I calculate the Base64 size of a file?
Divide the size in bytes by 3, round up, and multiply by 4. That gives the length without line breaks. A 30 KB image (30,720 bytes) becomes 40,960 characters.
Why does Base64 output end with = or ==?
The = signs are padding. They appear when the input length isn't a multiple of 3 bytes, and they never appear anywhere except the end.
Can Base64 contain spaces or line breaks?
Line breaks are allowed in MIME email, which wraps at 76 characters. Most decoders ignore whitespace, but strict ones reject it, so remove it if decoding fails.
Is Base64 safe to put in a URL?
Standard Base64 isn't, because of +, / and =. Use the Base64url variant, or percent-encode the value.