← Back to Blog

Base64 Encoding Explained: Principles, Use Cases & Common Pitfalls

What is Base64

Base64 is a scheme that encodes arbitrary binary data into pure ASCII strings. It uses 64 printable characters (A-Z, a-z, 0-9, +, /) to represent data, plus = as padding. Because the output contains only ASCII, Base64-encoded data can safely pass through text-only channels—this is its core value.

Why Base64 Exists

Many legacy protocols (SMTP email, HTTP headers, JSON text) only handle printable ASCII. If you embed PNG binary data in a JSON field directly, the unprintable bytes break parsing. Base64 "translates" those bytes into safe text, solving the transport problem.

Encoding Principles

Core Algorithm

Base64 processes input in 3-byte (24-bit) groups:

  1. Take 3 bytes of binary data (24 bits)
  2. Split into 4 groups of 6 bits each
  3. Map each 6-bit value (0-63) to a Base64 alphabet character
  4. If the last group has fewer than 3 bytes, pad with = to 4 characters

Alphabet Table

Index  Char          Index  Char          Index  Char
0-25   A-Z           26-51  a-z           52-61  0-9
62     +             63     /             Pad    =

Encoding Example

Encoding the string Man:

Step Value
ASCII M=77, a=97, n=110
Binary 01001101 01100001 01101110
6-bit groups 010011 010110 000101 101110
Decimal 19, 22, 5, 46
Base64 TWFu

Overhead

3 input bytes become 4 output characters, a constant 4/3 ≈ 33.3% overhead. For inputs under 3 bytes, overhead is higher: 1 byte encodes to 4 characters (with 2 =), a 300% increase.

Variant: URL-Safe Base64

The + and / in standard Base64 have special meanings in URLs, causing ambiguity. RFC 4648 §5 defines a URL-safe variant:

  • +-
  • /_
  • Trailing = padding usually omitted

JWT, Data URLs, and similar contexts default to URL-safe Base64.

Practical Use Cases

1. Data URLs (Inline Resources)

Embed small images directly in HTML/CSS to avoid extra HTTP requests:

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

When to use: resources under 4KB. Larger images bloat the HTML and block parsing.

2. Email Attachments (MIME)

SMTP originally supported only 7-bit ASCII text. MIME uses Base64 to encode binary attachments (images, PDFs) as text. A line break (CRLF) is inserted every 76 characters—specific to MIME.

3. API Tokens & Credentials

Many APIs encode credentials with Base64:

  • HTTP Basic Auth: Authorization: Basic dXNlcjpwYXNz (Base64 of user:pass)
  • API Keys: some platforms' keys are Base64-encoded random bytes

4. JWT (JSON Web Token)

A JWT has three parts; the Header and Payload are Base64 URL-safe encoded:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

5. Source Maps & WASM

Frontend build artifacts (source maps) and WebAssembly modules use Base64 encoding in certain embedding scenarios.

Common Pitfalls

Pitfall 1: Base64 Is Not Encryption

Base64 is encoding, not encryption. Anyone can decode it; it provides zero confidentiality. Storing passwords Base64-encoded is equivalent to plaintext.

Pitfall 2: Ignoring Overhead

33% overhead matters for large files. A 10MB image becomes ~13.3MB in Base64. Passing large Base64 payloads in API responses slows both transfer and parsing.

Pitfall 3: Charset Confusion

The string "Hello" is first UTF-8 encoded to bytes, then Base64 encoded. Different charsets (UTF-8 vs GBK) produce different Base64 output. Always normalize to UTF-8 before encoding non-ASCII text like Chinese.

Pitfall 4: Padding = Issues

Some systems mishandle = in URLs. URL-safe Base64 typically omits =, but decoding requires padding to a multiple of 4. Some libraries handle this automatically; others need manual padding.

Pitfall 5: Newline Handling

MIME Base64 inserts a newline every 76 characters. Decoding MIME-formatted data with a standard decoder requires removing newlines first.

Language Reference

Language Encode Decode
JS (Browser) btoa(str) atob(b64)
Node.js Buffer.from(str).toString('base64') Buffer.from(b64, 'base64')
Python base64.b64encode(data) base64.b64decode(b64)
Go base64.StdEncoding.EncodeToString(data) base64.StdEncoding.DecodeString(b64)
Java Base64.getEncoder().encodeToString(bytes) Base64.getDecoder().decode(b64)

Browser Caveat

btoa() / atob() only handle Latin1 characters. For Chinese text:

const encoded = btoa(unescape(encodeURIComponent('中文')));
const decoded = decodeURIComponent(escape(atob(encoded)));

Or use TextEncoder with a manual Base64 implementation.

Performance & Best Practices

  • Inline resources under 4KB may use Base64; larger files use binary transfer
  • Avoid Base64 for data over 1MB—use Blob URLs or multipart upload
  • Use native APIs over pure-JS implementations for high-frequency scenarios
  • Storing Base64 in databases increases index size; prefer binary columns
  • Cache decoded results to avoid repeated computation
← Back to Blog