Base64 Encoding & Decoding: The Complete Guide
Base64 is one of the most widely used encoding schemes in computing. Whether you are embedding images in HTML, sending binary data through email, working with JSON Web Tokens (JWTs), or transmitting data over HTTP, Base64 plays a critical role behind the scenes. This guide covers everything you need to know about Base64 — from the underlying mechanics to practical applications and important security considerations.
🔄 Try our free Base64 Encoder / Decoder
Open Base64 Tool →What Is Base64?
Base64 is a binary-to-text encoding scheme that converts binary data into a string of ASCII characters. It uses a set of 64 characters: uppercase letters A-Z, lowercase letters a-z, digits 0-9, and two special characters + and /. The padding character = is used to fill the output to a multiple of 4 characters.
The term "Base64" comes from the fact that each encoded character represents 6 bits of data (2^6 = 64 possible values). Since the original data is read in 8-bit bytes, Base64 takes groups of 3 bytes (24 bits) and converts them into 4 Base64 characters (4 × 6 = 24 bits). This is why Base64-encoded data is approximately 33% larger than the original — every 3 bytes become 4 characters.
The Base64 Character Table
| Value | Character | Value | Character | Value | Character | Value | Character |
|---|---|---|---|---|---|---|---|
| 0-25 | A-Z | 26-51 | a-z | 52-61 | 0-9 | 62 | + |
| 63 | / | ||||||
The padding character = is appended when the input length is not a multiple of 3. One = means 1 byte of padding was needed; two = means 2 bytes were needed.
How Base64 Encoding Works
Understanding the encoding process helps you work with Base64 confidently. Here is a step-by-step breakdown:
- Convert text to bytes: The input string is converted to its byte representation using the specified character encoding (typically UTF-8).
- Group into 3-byte chunks: The byte stream is divided into groups of 3 bytes (24 bits each).
- Split into 6-bit segments: Each 24-bit group is split into four 6-bit segments.
- Map to Base64 alphabet: Each 6-bit value (0-63) is looked up in the Base64 character table.
- Handle padding: If the last group has fewer than 3 bytes, padding characters are added.
Here is a concrete example — encoding the word "Man":
Input: M a n
ASCII: 77 97 110
Binary: 01001101 01100001 01101110
Split into 6-bit groups:
010011 010110 000101 101110
= 19 = 22 = 5 = 46
Base64: T W F u
Result: "TWFu"
Now consider a case with padding — encoding "Ma" (only 2 bytes):
Input: M a
ASCII: 77 97
Binary: 01001101 01100001 00000000 (padded with zeros)
Split into 6-bit groups:
010011 010110 000100 000000
= 19 = 22 = 4 = 0
Base64: T W E A =
Result: "TWE="
Common Use Cases
Data URIs in HTML and CSS
One of the most common uses of Base64 is embedding small images, fonts, or other binary assets directly into HTML or CSS files using data URIs. This eliminates additional HTTP requests and can simplify deployment.
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="Embedded">
background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...") no-repeat;
This technique is especially useful for small icons, logos, and SVG graphics. However, for large images, Base64 encoding significantly increases file size and can hurt performance because the data cannot be cached separately.
Email Attachments (MIME)
Email protocols like SMTP were designed to handle 7-bit ASCII text. Binary attachments like images, PDFs, and audio files must be encoded as text before transmission. MIME (Multipurpose Internet Mail Extensions) uses Base64 to encode these attachments. When you receive an email with an attachment, your email client decodes the Base64 data back into the original binary file.
Content-Type: image/png; name="photo.png"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="photo.png"
iVBORw0KGgoAAAANSUhEUgAA... (Base64 data)
JSON Web Tokens (JWT)
JWTs, widely used for authentication in web applications, consist of three parts separated by dots — each part is Base64URL-encoded (a variant of Base64 that replaces + with - and / with _, and omits padding). The header and payload are Base64URL-encoded JSON objects, while the signature is a cryptographic hash.
eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiSm9obiJ9.SflKxwRJ... (Base64URL)
↑ Header ↑ Payload ↑ Signature
APIs and Data Transmission
When APIs need to transmit binary data in JSON payloads (which only support text), Base64 is the go-to solution. Common examples include uploading profile pictures via REST APIs, sending encrypted data, and transmitting certificate or key data. Many cloud storage APIs accept file uploads as Base64-encoded strings in their JSON request bodies.
Storing Binary Data in Databases
Some databases and data formats handle text better than raw binary. Storing small binary blobs as Base64 strings in JSON columns, NoSQL documents, or configuration files is a common pattern. This is especially practical for small assets like thumbnails, signatures, or serialized protocol buffers.
Base64 Variants
While the standard Base64 (RFC 4648) is most common, several variants exist for specific use cases:
- Base64URL: Replaces
+with-and/with_, removes padding. Used in JWTs, URL-safe tokens, and web applications where+and/would cause issues in query parameters. - Base32: Uses A-Z and 2-7 (32 characters). Produces larger output but is more human-readable and case-insensitive. Used in some two-factor authentication codes.
- Base16 / Hex: Uses 0-9 and A-F. Each byte becomes two characters. Commonly seen in color codes, cryptographic hashes, and network addresses.
Base64 in Programming Languages
JavaScript (Browser)
// Encode
const encoded = btoa("Hello, World!");
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="
// Decode
const decoded = atob("SGVsbG8sIFdvcmxkIQ==");
console.log(decoded); // "Hello, World!"
// For Unicode text (UTF-8)
const encoder = new TextEncoder();
const bytes = encoder.encode("你好世界");
const binary = String.fromCharCode(...bytes);
const base64 = btoa(binary);
Python
import base64
# Encode
encoded = base64.b64encode(b"Hello, World!").decode()
print(encoded) # "SGVsbG8sIFdvcmxkIQ=="
# Decode
decoded = base64.b64decode("SGVsbG8sIFdvcmxkIQ==").decode()
print(decoded) # "Hello, World!"
Node.js
// Encode
const encoded = Buffer.from("Hello, World!").toString('base64');
// Decode
const decoded = Buffer.from("SGVsbG8sIFdvcmxkIQ==", 'base64').toString();
Command Line
# Encode
echo -n "Hello, World!" | base64
# Decode
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d
Security Considerations
Common Security Mistakes
One of the most dangerous misconceptions in web development is treating Base64 as a form of encryption. This mistake appears in production systems far too often:
- Storing passwords as Base64: Storing
base64(password)in a database is equivalent to storing plaintext. Always use proper password hashing (bcrypt, Argon2, scrypt). - "Encrypting" API payloads with Base64: Base64 provides zero confidentiality. Anyone who intercepts the data can decode it immediately.
- Hiding secrets in source code: Encoding API keys or credentials in Base64 and committing them to version control is not hiding them — it is practically the same as committing them in plaintext.
When to Use Base64 Securely
Base64 is perfectly safe to use for its intended purpose — encoding binary data as text. In security-sensitive contexts, Base64 is often used after encryption:
// Correct: Encrypt first, then Base64-encode the ciphertext
const ciphertext = encrypt(plaintext, key);
const transmission = base64Encode(ciphertext);
This is exactly how JWTs work — the payload may contain sensitive claims, but the entire token is cryptographically signed (and optionally encrypted) before being Base64-encoded.
Base64 and Injection Risks
When decoding Base64 data and using the result in HTML, SQL queries, or shell commands, always sanitize the decoded output. Base64 can encode malicious payloads (XSS scripts, SQL injection strings, command injection sequences). The decoding process itself is safe, but the decoded content may not be.
Performance Tips
- Size overhead: Remember that Base64 adds ~33% to data size. For large files, consider compression before encoding (gzip + Base64) or use multipart form data instead.
- CPU cost: Encoding and decoding are relatively fast, but processing very large Base64 strings can be CPU-intensive. Batch operations when possible.
- Streaming: For large files, use streaming Base64 encoders/decoders instead of loading everything into memory at once.
- Browser performance: Avoid embedding large Base64 images in HTML. External image files benefit from browser caching, while inline Base64 data is re-downloaded with every page load.
Frequently Asked Questions
Is Base64 encryption?
No, Base64 is encoding, not encryption. It converts binary data into ASCII text using a publicly known algorithm. Anyone can decode Base64 strings without a key. It provides no security or confidentiality whatsoever. If you need to protect data, use proper encryption algorithms like AES-256.
Does Base64 encoding increase file size?
Yes, Base64 encoding increases data size by approximately 33%. Every 3 bytes of input produce 4 characters of output. This overhead is inherent to the encoding scheme. For example, a 3 KB file becomes roughly 4 KB after Base64 encoding. Consider this overhead when transmitting or storing large amounts of data.
What is the difference between Base64 and URL encoding?
Base64 converts arbitrary binary data into a 64-character ASCII alphabet. It is designed to safely represent binary data in text-based formats. URL encoding (percent encoding) represents individual unsafe characters as %XX hex sequences. Base64 is used for embedding binary in text documents, while URL encoding makes text safe for inclusion in URLs.
Can Base64 encode any type of data?
Yes. Base64 operates on raw bytes, so it can encode any binary data — images, audio, video, PDFs, compiled binaries, or raw byte sequences. The encoded output is always plain ASCII text, making it universally safe for transmission through text-based protocols like email (SMTP), HTTP, and JSON.
How do I decode a Base64 string in JavaScript?
In the browser, use atob() to decode and btoa() to encode. For Unicode strings, convert to UTF-8 bytes first using TextEncoder. In Node.js, use Buffer.from(str, 'base64').toString() to decode and Buffer.from(str).toString('base64') to encode.