Base64 encoding explained: when to use it, when not to

6 min read
encoding
guide

Base64 shows up everywhere — email attachments, data URIs, JWT segments, API payloads — but it is often misunderstood as a form of compression or security. It is neither. It is a way to represent arbitrary binary data using only 64 printable ASCII characters, so it can survive being passed through systems that only reliably handle text.

How it actually works

Base64 takes input three bytes (24 bits) at a time and re-slices those bits into four 6-bit groups. Each 6-bit group (0-63) maps to one character from the alphabet `A-Z`, `a-z`, `0-9`, `+`, `/` (or `-`, `_` for the URL-safe variant). If the input isn't a multiple of three bytes, `=` padding fills the gap.

btoa("Hi!");        // "SGkh"
atob("SGkh");       // "Hi!"

That 6-bits-per-character encoding is exactly why Base64 output is always about **33% larger** than the original binary — four output characters for every three input bytes. It is not compression; it is the opposite, since it trades space for text-safety.

Where it earns its keep

  • **Data URIs** — embedding a small icon or font directly in CSS/HTML (`data:image/png;base64,...`) avoids an extra HTTP request, which is worth it for tiny assets but not for anything large.
  • **JWTs** — the header and payload segments are Base64url-encoded JSON, chosen so tokens can travel safely in URLs and HTTP headers.
  • **Email (MIME)** — attachments are Base64-encoded because SMTP was designed for 7-bit ASCII text.
  • **Binary in JSON/XML** — these formats have no native binary type, so binary blobs (images, keys, signatures) get Base64-encoded to fit inside a string field.

Where it doesn't help

  • **"Encoding" as security.** Base64 is fully reversible with zero secret material — decoding it is a lookup table, not a cracking effort. Never use it to "hide" passwords, tokens or PII. If you need confidentiality, encrypt first; Base64 the ciphertext afterward if you need it to travel as text.
  • **Compression.** As covered above, it makes data bigger, not smaller. If size matters, gzip/br compress first and Base64-encode the compressed bytes, not the raw ones.
  • **Large binary payloads over the wire.** Sending a multi-megabyte file as a Base64 string in JSON adds ~33% overhead and forces the whole payload to be parsed as one string before any of it is usable. Prefer multipart uploads or raw binary endpoints for large files.

URL-safe variant

Standard Base64 uses `+` and `/`, both of which have special meaning in URLs and file paths. The URL-safe variant swaps them for `-` and `_`, and often drops the `=` padding entirely since the length is recoverable from context. JWTs use this variant — mixing the two up is a common cause of "valid Base64 that doesn't decode as a JWT."

A quick sanity check

If you're debugging a payload that looks like garbled ASCII with occasional `=` at the end, it's very likely Base64. Run it through a [Base64 encoder/decoder](/tools/crypto/base64-encoder) to see the decoded bytes, or use the [Base64 image encoder](/tools/images/base64-image-encoder) if you suspect it's an embedded image and want to preview it directly.

Takeaway

Reach for Base64 when you need binary data to survive a text-only channel. Reach for something else — encryption, compression, or a binary transport — for everything else it gets mistakenly used for.

Tools from this article

← All articles