You've seen Base64 everywhere — in data: URIs, JWT tokens, email attachments, and API responses. But do you know why it exists and when you should actually reach for it?
This article explains Base64 from first principles, walks through real-world use cases, and covers some traps developers fall into.
What Problem Does Base64 Solve?
Many systems that transport data were designed for text — not arbitrary binary data. Email protocols, HTTP headers, URLs, and XML documents all have rules about which characters are allowed. A byte value of 0x00 (null), 0x0A (newline), or 0x3C (<) can break parsing or get stripped in transit.
Base64 solves this by encoding any binary data into a safe subset of printable ASCII characters: A–Z, a–z, 0–9, +, /, and = for padding.
How Base64 Works
Base64 takes 3 bytes (24 bits) of binary data at a time and splits them into four 6-bit chunks. Each 6-bit chunk maps to one of 64 characters.
Binary: 01001101 01100001 01101110
Split: 010011 010110 000101 101110
Index: 19 22 5 46
Char: T W F u
This is why Base64 output is always 4/3 longer than the input — 3 bytes become 4 characters. If the input isn't divisible by 3, padding = characters fill the remaining positions.
Common Use Cases
1. Embedding Images in HTML/CSS
You can embed small images directly in HTML or CSS without a separate HTTP request:
<img src="data:image/png;base64,iVBORw0KGgo...">
Or in CSS:
background-image: url('data:image/svg+xml;base64,PHN2Zy...');
When to use this: Icons under ~5 KB where saving an HTTP round-trip matters. Larger images will bloat your HTML and outweigh the saving.
2. JWT Tokens
JSON Web Tokens (JWTs) use Base64URL encoding (a variant that replaces + with - and / with _ to make tokens URL-safe). A JWT has three Base64URL-encoded sections separated by dots:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Decode the first section and you get the header: {"alg":"HS256"}. The payload and signature follow the same format.
3. API Credentials
Many APIs expect credentials in HTTP Basic Auth headers:
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
That's just username:password encoded in Base64. A common debugging mistake: thinking this is encrypted. It is not — it is trivially reversible.
4. Email Attachments (MIME)
Email was designed for ASCII text. MIME (Multipurpose Internet Mail Extensions) uses Base64 to encode binary attachments — PDFs, images, spreadsheets — so they survive transit through email servers that might otherwise corrupt non-text bytes.
5. Storing Binary Data in JSON
JSON has no native binary type. When APIs need to pass binary blobs (images, audio, certificates), Base64 is the conventional encoding:
{
"thumbnail": "iVBORw0KGgoAAAANSUhEUgAA...",
"format": "png"
}
When Not to Use Base64
Don't Use It for Passwords
Base64 is not encryption and not a hash. It's a reversible encoding that any developer can decode in seconds. Store passwords with a proper slow hash (bcrypt, Argon2), never encoded.
Don't Use It for Large Files in APIs
A 1 MB file becomes ~1.37 MB as Base64. For large payloads, use multipart/form-data uploads or pre-signed URLs to object storage instead. Base64 in JSON is convenient for small blobs; it's painful for anything over ~100 KB.
Don't Use It for URLs Unless You Use Base64URL
Standard Base64 uses +, /, and = — all characters with special meaning in URLs. If you're putting Base64 in a query string or path segment, use Base64URL (or percent-encode the standard output). Many bugs come from standard Base64 breaking URL parsing.
Quick Cheat Sheet
| Use case | Appropriate? |
|---|---|
| Embedding small images in CSS/HTML | ✅ |
| JWT token structure | ✅ |
| HTTP Basic Auth headers | ✅ |
| Email attachments (MIME) | ✅ |
| Binary blobs in JSON APIs | ✅ for small (<100 KB) |
| Password storage | ❌ |
| Large file transfers | ❌ |
| Encryption | ❌ |
Encoding and Decoding in JavaScript
// Encode a string
const encoded = btoa('Hello, world!');
// → "SGVsbG8sIHdvcmxkIQ=="
// Decode a string
const decoded = atob('SGVsbG8sIHdvcmxkIQ==');
// → "Hello, world!"
For binary data (like a File or ArrayBuffer), use FileReader or Uint8Array:
function arrayBufferToBase64(buffer) {
const bytes = new Uint8Array(buffer);
let binary = '';
for (const byte of bytes) binary += String.fromCharCode(byte);
return btoa(binary);
}
Note: btoa() and atob() don't handle Unicode strings directly — wrap them with encodeURIComponent + decodeURIComponent or use TextEncoder for UTF-8 text.
Try It Yourself
If you need to encode or decode Base64 quickly — strings, files, or just to verify a JWT payload — SnappyTools' Base64 Encoder / Decoder handles standard Base64, URL-safe Base64, and Unicode text, entirely in your browser. No upload, no account.
Have questions about Base64 or a use case not covered here? Drop a comment below.
Top comments (0)