What Is Base64 Encoding and How Does It Work?
Base64 is one of those things developers use constantly without fully understanding. You've seen it in data URIs, API authentication headers, email attachments, and JWTs. This guide explains what Base64 actually does, how it works under the hood, and when you should (and shouldn't) use it.
What Is Base64?
Base64 is a binary-to-text encoding scheme that converts binary data into a string of ASCII characters. It uses 64 printable characters (hence the name) to represent arbitrary binary data:
A-Z (26 characters)
a-z (26 characters)
0-9 (10 characters)
+ (1 character)
/ (1 character)
= (padding character) That's 64 characters for encoding, plus = for padding. Every 3 bytes of binary input become 4 Base64 characters of output.
Why Does Base64 Exist?
The core problem: many systems can only safely handle text, not raw binary data.
- Email (SMTP) was designed to transmit 7-bit ASCII text. Binary file attachments (images, PDFs) need to be encoded as text to pass through email servers without corruption.
- JSON and XML are text formats. You can't embed raw binary data in a JSON string — but you can embed a Base64-encoded string.
- URLs have restrictions on which characters are allowed. Base64url (a URL-safe variant) encodes data for safe inclusion in query parameters.
- HTML data URIs let you embed images directly in HTML/CSS:
data:image/png;base64,iVBORw0K...
Base64 isn't encryption or compression — it's a transport encoding. It makes binary data safe for text-only channels.
How Base64 Encoding Works
The algorithm is straightforward:
- Take the input bytes and convert them to a stream of bits
- Split the bit stream into groups of 6 bits (since 2^6 = 64 possible values)
- Map each 6-bit group to one of the 64 Base64 characters
- If the input isn't divisible by 3, add
=padding
Worked Example
Encoding the text "Hi":
Step 1: ASCII values
H = 72, i = 105
Step 2: Convert to binary (8 bits each)
01001000 01101001
Step 3: Regroup into 6-bit chunks
010010 000110 1001XX
(XX = padding, filled with 00)
010010 000110 100100
Step 4: Convert each 6-bit value to Base64 character
010010 = 18 = S
000110 = 6 = G
100100 = 36 = k
Step 5: Add padding (input was 2 bytes, need 1 pad)
Result: "SGk=" The 33% Size Overhead
Base64 always increases data size by approximately 33%. Three input bytes become four output characters. This is the fundamental tradeoff:
Original: 1,000 bytes
Base64: 1,334 characters (1,000 * 4/3, rounded up)
Original: 1 MB image
Base64: ~1.33 MB as text This size increase matters for performance-sensitive applications. A 50KB image embedded as a Base64 data URI in your CSS becomes ~67KB and can't be cached separately from the stylesheet.
Base64 in JavaScript
Browsers provide built-in functions for Base64:
// Encoding
const encoded = btoa("Hello, World!");
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="
// Decoding
const decoded = atob("SGVsbG8sIFdvcmxkIQ==");
console.log(decoded); // "Hello, World!"
// Handle Unicode (btoa only works with Latin1)
function encodeUnicode(str) {
return btoa(
encodeURIComponent(str).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(parseInt(p1, 16))
)
);
}
// Modern approach using TextEncoder
function base64Encode(str) {
const bytes = new TextEncoder().encode(str);
const binString = Array.from(bytes, b => String.fromCodePoint(b)).join("");
return btoa(binString);
} Base64 in Python
import base64
# Encoding
encoded = base64.b64encode(b"Hello, World!")
print(encoded) # b'SGVsbG8sIFdvcmxkIQ=='
# Decoding
decoded = base64.b64decode(b"SGVsbG8sIFdvcmxkIQ==")
print(decoded) # b'Hello, World!'
# Encoding a file
with open("image.png", "rb") as f:
encoded_image = base64.b64encode(f.read())
data_uri = f"data:image/png;base64,{encoded_image.decode()}" Base64url: The URL-Safe Variant
Standard Base64 uses + and /, which have special meaning in URLs. Base64url replaces them:
Standard Base64: + / =
Base64url: - _ (no padding) Base64url is used in JWTs (JSON Web Tokens), OAuth tokens, and URL query parameters. When you see a JWT like eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.abc, each segment between dots is Base64url-encoded JSON.
Common Use Cases
Data URIs in HTML/CSS
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEU..." />
/* CSS background */
.icon {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bW...");
} Good for tiny images (under 2-4KB). Larger images should be separate files for caching.
HTTP Basic Authentication
// Authorization: Basic base64("username:password")
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ= Important: This is encoding, not encryption. The credentials are trivially reversible. Always use HTTPS.
Embedding Binary Data in JSON
{
"filename": "report.pdf",
"content": "JVBERi0xLjQKMSAwIG9iago8PCAvVHlwZS..."
} When NOT to Use Base64
- For encryption or security — Base64 is trivially reversible. It's encoding, not encryption. Never use it to "hide" passwords, tokens, or sensitive data.
- For large files in APIs — The 33% overhead is wasteful. Use multipart form uploads or presigned URLs for file uploads instead.
- For images in production CSS — Base64 images can't be cached independently, increase CSS file size, and block rendering. Use regular image files.
- For data compression — Base64 makes data larger, not smaller. If you need to reduce size, compress first (gzip, brotli) then encode if needed.
Quick Reference
| Language | Encode | Decode |
|---|---|---|
| JavaScript | btoa(str) | atob(str) |
| Python | base64.b64encode(bytes) | base64.b64decode(bytes) |
| Java | Base64.getEncoder().encodeToString(bytes) | Base64.getDecoder().decode(str) |
| Go | base64.StdEncoding.EncodeToString(bytes) | base64.StdEncoding.DecodeString(str) |
| CLI | echo -n "text" | base64 | echo "dGV4dA==" | base64 -d |
Need to quickly encode or decode Base64? Try our Base64 Encoder/Decoder — paste your data and get instant results, all processed in your browser.