What Base64 Is and When (Not) to Use It

What Base64 encoding actually does, why it adds about 33% overhead, and when it's the right tool versus encryption.

What Base64 actually is

Base64 is a way of writing arbitrary binary data using only characters that are safe to put in plain text. It doesn't compress anything and it doesn't hide anything — it re-encodes bytes into a 64-symbol alphabet: A–Z, a–z, 0–9, plus two more symbols (+ and / in standard Base64) to reach 64. The scheme is standardised in RFC 4648, which also defines the URL-safe variant discussed below.

The reason it exists: a lot of the infrastructure that moves text around — email, JSON, XML, URLs, older protocols — was built to carry printable characters, not arbitrary bytes. A raw binary byte can be any value from 0 to 255, including control characters that email systems, terminals or JSON strings were never designed to carry safely. Base64 sidesteps the problem entirely by never using those bytes: every character it outputs is one of the 64 safe symbols, so the result can go anywhere plain text can go.

The maths behind the 4/3 size overhead

Base64 works in fixed groups. Three bytes of input is 24 bits. Rather than output those as three 8-bit characters, Base64 slices the 24 bits into four 6-bit chunks — because 26 = 64, each 6-bit chunk maps directly onto one symbol in the alphabet. Three bytes in, four characters out, every time input divides evenly by three.

Size overhead
output length = ceil(input bytes ÷ 3) × 4  ·  ≈ 133% of input

That is where the well-known "Base64 is a third bigger" rule of thumb comes from: 4 output characters for every 3 input bytes is exactly a 4/3 ratio, roughly a 33% size increase. It is a fixed cost of the encoding, not something that varies with content the way compression does — Base64ing the same file twice always produces the same size increase.

Worked example — the classic 3-byte case

Encoding Man gives TWFu. "Man" is exactly 3 bytes (M=77, a=97, n=110), which is 24 bits, so it splits cleanly into four 6-bit groups with no leftover bits and no padding needed.

Worked example — when the input doesn't divide evenly

Encoding hello gives aGVsbG8=. "hello" is 5 bytes — one full group of 3, plus 2 bytes left over. Those last 2 bytes (16 bits) still need to fill an output group of four 6-bit chunks (24 bits), so the encoder pads the missing bits with zeros and appends a single = to the output, signalling "the last group represents only 2 real bytes, not 3." A single leftover byte, rather than two, would instead get two = signs. An output with no = at all simply means the input length happened to be an exact multiple of three — as with "Man" above.

The URL-safe variant

Standard Base64's + and / characters, and the padding =, are all problematic in a URL or filename: + can be interpreted as a space, / looks like a path separator, and = can clash with query-string syntax. RFC 4648 defines a URL-safe alphabet that substitutes - for + and _ for /, and padding is often dropped entirely since the decoder can infer it from length. This variant is what you'll see inside a JWT (JSON Web Token) and in many URL query parameters that carry encoded data.

Legitimate uses

  • Email attachments (MIME). Email was designed for 7-bit text. Attachments — images, PDFs, anything binary — are Base64-encoded into the message body so they survive transport through mail servers that were never built to carry raw bytes.
  • Data URIs. An image or font can be embedded directly in HTML or CSS as data:image/png;base64,…, avoiding a separate network request for genuinely small assets.
  • Embedding binary in JSON. JSON strings can only hold Unicode text, not raw bytes. Base64-encoding a small file or binary blob turns it into an ordinary JSON string value that survives serialisation intact.
  • HTTP Basic authentication. The Authorization header sends username:password Base64-encoded — encoded for safe transport as a header value, never for secrecy, which is exactly why Basic auth is only acceptable over HTTPS.
  • Tokens, keys and certificates. JWT segments, many API keys, and PEM-formatted certificates are Base64 so they stay copy-paste-safe across text fields, config files and terminals.

The big misconception: Base64 is not encryption

Base64 has no key, no secret, and no cryptographic property whatsoever. It is a public, fully reversible transformation — anyone who recognises the pattern can decode it by hand or with any of thousands of free tools, this one included.

Worked example — decoding requires nothing secret

Encoding hare=speed produces aGFyZT1zcGVlZA==. There is no password, key or step that was hidden from you in that process — and decoding aGFyZT1zcGVlZA== straight back to hare=speed takes the same tool, in reverse, with nothing to unlock. If a string on a screen or in a URL "looks scrambled," that is a strong sign it is Base64, not that it is protected: paste it into the Base64 decoder and it comes straight back out as plain text.

This matters because Base64 sometimes gets mistaken for a security measure — a config file with an "encoded" password, or a URL parameter that "hides" an ID. Neither is protected. Anyone who inspects network traffic, opens the browser's developer tools, or simply recognises the character pattern can decode it in seconds with no special access.

When not to use Base64

  • Large images in CSS or data URIs. The 4/3 overhead is a fixed cost that gets worse as files get bigger, and a data URI can't be cached separately from the page or stylesheet that contains it the way a normal image request can. For anything beyond a small icon or tiny sprite, a regular file reference outperforms a data URI.
  • "Obfuscating" secrets. Because it's trivially reversible, Base64 provides zero protection for a password, API key or personal data. If something needs to stay confidential, it needs actual encryption with a real key — Base64 is not a lightweight substitute.
  • As a substitute for compression. Base64 output is always larger than its input, never smaller. If the goal is reducing size, Base64 is working against you, not for you.

Worked example — Unicode text encodes by its bytes, not its characters

Encoding I ♥ ToolHare 🐇 produces SSDimaUgVG9vbEhhcmUg8J+Qhw==. The emoji is a 4-byte UTF-8 sequence, not a single byte, which is a useful reminder that Base64 always operates on the underlying bytes of a string, not the characters a person sees — text first has to be turned into bytes (typically UTF-8) before Base64 applies. Consistently, an empty input has no bytes to group at all, so it encodes to an empty output.

Frequently asked

Is Base64 the same as encryption?

No. Encryption requires a secret key and is designed to be computationally infeasible to reverse without it. Base64 requires nothing and reverses instantly for anyone who tries. They solve different problems: encryption protects confidentiality, Base64 only makes binary data safe to carry inside text-only channels.

Why does a Base64 string sometimes end in one or two equals signs?

Padding. Base64 processes input three bytes at a time; when the input isn't an exact multiple of three, the final group is padded and one or two = characters mark exactly how much padding was added, so a decoder can reconstruct precisely the right number of original bytes.

Does Base64 make data smaller?

No, the opposite — it reliably makes data about a third larger, because four output characters carry only three bytes of information. Any apparent size saving people report is usually from removing whitespace or switching format, not from the Base64 step itself.

Why do JWTs and URLs use a different Base64 alphabet?

Standard Base64's +, / and = characters can collide with meaningful syntax in a URL or filename. The URL-safe variant defined in RFC 4648 swaps in - and _ and typically omits padding, so the encoded value can sit directly inside a URL without being escaped.