Base64 Encoding Explained: How It Works and When to Use It

What Base64 Is

Base64 is a binary-to-text encoding scheme. It takes arbitrary bytes and represents them using only 64 printable ASCII characters: the uppercase letters A to Z, lowercase a to z, digits 0 to 9, plus `+` and slash `/`, with `=` used as padding at the end. The result is a string that any text-based system can carry without corruption.

The name comes from the radix. Each character encodes 6 bits, because 2 to the power of 6 is 64. The scheme packs 3 bytes of input (24 bits) into 4 characters of output (24 bits).

Base64 is everywhere. Email attachments, data URLs, JWT tokens, PEM certificates, and HTTP Basic Auth all rely on it. If you have ever pasted an image directly into HTML or copied a bearer token, you have used Base64.

How Base64 Works

The algorithm has three steps.

Step one, group the input bytes into blocks of 3. Three bytes give 24 bits.

Step two, split those 24 bits into 4 groups of 6 bits each.

Step three, map each 6-bit value to a character in the Base64 alphabet.


Input bytes:   01000001 01000010 01000011   ("ABC")
24-bit buffer: 010000 010100 001001 000011
Index:         16      20      9      3
Base64 chars:  Q       U       J       D
Output:        QUJD

The string "ABC" becomes "QUJD". Three ASCII bytes in, four Base64 characters out. That ratio is fixed.

Padding and Edge Cases

Input length is not always a multiple of 3. Base64 handles leftovers with padding.

  • If the input has 1 extra byte, the output has 2 Base64 characters plus two `=` padding characters.
  • If the input has 2 extra bytes, the output has 3 Base64 characters plus one `=`.
  • If the input is a clean multiple of 3, no padding is added.

"M"      -> "TQ=="
"Ma"     -> "TWE="
"Man"    -> "TWFu"

Parsers use the padding to recover the exact original byte length. Without it, the decoder would not know whether the final group held 1, 2, or 3 bytes.

Encoding and Decoding Examples

Most languages ship built-in support.

JavaScript:


const enc = btoa('Hello, world!');  // "SGVsbG8sIHdvcmxkIQ=="
const dec = atob(enc);              // "Hello, world!"

// For Unicode, encode through UTF-8 first
const encUni = btoa(new TextEncoder().encode('café'));

Python:


import base64
enc = base64.b64encode(b'Hello, world!').decode()  # "SGVsbG8sIHdvcmxkIQ=="
dec = base64.b64decode(enc)                          # b'Hello, world!'

# URL-safe variant uses - and _ instead of + and /
urlsafe = base64.urlsafe_b64encode(b'abc').decode()

Command line:


echo -n "Hello, world!" | base64
echo "SGVsbG8sIHdvcmxkIQ==" | base64 --decode

For quick checks without writing code, paste the value into the [Base64 encoder and decoder](/en/base64) and switch directions instantly.

The Data URI Scheme

Data URIs let you embed binary content directly in markup, removing a network request. The syntax pairs a MIME type with Base64-encoded bytes.


<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="inline icon">

.logo {
  background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxu...");
}

Data URIs shine for tiny assets: favicons, single-color icons, SVGs under a kilobyte. They hurt when overused. A 200 KB image becomes roughly 270 KB of Base64 inside the HTML, blocks rendering, and defeats caching because the bytes are now part of the document. A good rule: inline only assets below 4 KB, and link everything larger.

Where Base64 Is Used

Email attachments (MIME). SMTP was built for text. Binary files get Base64-encoded so they survive the text-only transport, then decoded by the receiving client.

HTTP Basic Authentication. Credentials travel as `Authorization: Basic <base64>`. The encoding lets arbitrary username and password characters pass through HTTP headers. It provides zero security on its own, so always pair it with HTTPS.

JSON Web Tokens. JWTs have three Base64URL-encoded parts: header, payload, signature. The URL-safe variant replaces `+` and `/` with `-` and `_` so the token can sit safely in URLs and query strings.

Cryptographic keys and certificates. PEM format wraps Base64 between `-----BEGIN-----` and `-----END-----` markers so keys can move through text channels like email and config files.

API tokens and source maps. Many services issue opaque tokens that are simply Base64-encoded JSON or random bytes. Source maps embed encoded payload sections.

The 33 Percent Size Overhead

This is the cost you pay. Three input bytes become four output characters, so the encoded form is 4/3 the size of the original, a 33 percent increase. Padding can add up to 2 more bytes, and line wrapping in MIME mode adds CRLF characters every 76 characters.

For a 300 KB image, expect around 400 KB of Base64. For a 1 MB file, expect about 1.37 MB. The overhead matters on the wire, in storage, and in memory. Compress binary data first, then encode, and you often come out ahead.

Base64 Is Not Encryption

This is the most common misconception. Base64 is reversible by design. Anyone with the string can decode it in seconds. It hides nothing from an attacker.


"admin:password"  ->  "YWRtaW46cGFzc3dvcmQ="

Treat Base64 as a transport encoding, not a protection layer. If the content is sensitive, encrypt it with a real cipher like AES, then encode the ciphertext if you need text form. Never store Base64-encoded passwords and never put secrets in client-side code under the assumption that the encoding hides them.

Variants and Alternatives

Base64 has variants tuned for different contexts.

VariantAlphabet changeUse case
Standard`+/`Email, certificates, general binary
Base64URL`-` and `_`URLs, query strings, JWTs
Base64URL (no padding)Drops `=`Compact tokens, file names

Other encodings solve related problems.

  • Base32 uses 32 characters (A to Z, 2 to 7). It is case-insensitive and easier to type or read aloud, at the cost of larger output (about 60 percent overhead).
  • Base58 drops look-alike characters (`0`, `O`, `I`, `l`) to avoid copy mistakes. Bitcoin addresses and short links use it.
  • Hex (Base16) uses 0 to 9 and a to f. It is the most readable for debugging binary, but doubles the size.

Pick the variant by where the value will live. URLs favor Base64URL. Human-typed values favor Base58 or Base32. Debugging favors hex.

Common Pitfalls

  • Encoding instead of encrypting. Base64 hides nothing. Pair it with encryption for sensitive data.
  • Forgetting the URL-safe variant. Standard Base64 with `/` and `+` breaks in URLs and file paths. Use Base64URL.
  • Ignoring character encoding. `btoa` in JavaScript only handles Latin1. Encode strings as UTF-8 first or you will mangle non-ASCII text.
  • Assuming padding is optional. Some decoders accept missing padding, others reject it. Be explicit when generating tokens.
  • Over-inlining assets. Large Base64 blobs in HTML bloat the document and bypass the browser cache. Link large files instead.

When to Reach for Base64

Use Base64 when you must move binary data through a text-only channel. Email bodies, JSON fields, HTTP headers, data URIs, and config files all qualify. Avoid it when a binary transport is available, because the 33 percent overhead is wasted. And always remember the rule that matters most: Base64 is for moving bytes, not for protecting them.

To encode or decode values quickly in the browser, with no server round trip, use the [Base64 encoder and decoder](/en/base64). It handles UTF-8 correctly and supports the URL-safe variant for tokens and query strings.