The Complete Guide to Base64 Encoding
Base64 is one of the most widely used encoding schemes on the web, yet it is also one of the most misunderstood. This guide explains exactly what Base64 is, how the algorithm transforms bytes into text bit by bit, when you should (and should not) use it, and how to encode and decode Base64 in five different environments — with working code you can copy.
What is Base64?
Base64 is a binary-to-text encoding scheme. It takes arbitrary binary data — the raw bytes that make up an image, a file, a cryptographic key, or a piece of text — and represents it using only 64 "safe" printable characters. Those characters are the uppercase letters A–Z, the lowercase letters a–z, the digits 0–9, and the two symbols + and /. A 65th character, =, is used for padding.
The key idea is that these 64 characters survive transport through systems that were only ever designed to handle text. Email servers, JSON documents, URLs, XML, and many older protocols can mangle or reject raw binary data. By converting that data to Base64 first, you guarantee it arrives intact on the other side.
It is important to state clearly: Base64 is not encryption and not compression. It provides no security whatsoever, and it actually makes data slightly larger, not smaller. Its single purpose is compatibility.
Why Base64 exists
To understand Base64, it helps to understand the problem it solves. Computers store everything as bytes — values from 0 to 255. But many of those byte values correspond to control characters or are simply not valid in a text-based context. For example, byte value 0 is the "null" character, and bytes like 10 and 13 represent line breaks. If you tried to paste raw binary into an email body or a JSON string, these bytes would break the format.
Base64 sidesteps the problem entirely by never using any "dangerous" character. Every possible input — no matter how wild the byte values — comes out as a clean, predictable string of letters, digits, and a couple of symbols. This is why Base64 shows up everywhere:
- Email attachments — the MIME standard (RFC 2045) encodes binary attachments as Base64 so they travel safely through mail relays.
- Data URLs — small images and fonts are embedded directly inside HTML or CSS as
data:image/png;base64,…, removing an extra network request. - HTTP Basic Authentication — credentials are sent as
Base64(username:password)in the Authorization header. - JSON Web Tokens (JWTs) — each segment of a JWT is Base64URL-encoded.
- Storing binary in text databases or config files — certificates and keys (the familiar
-----BEGIN CERTIFICATE-----blocks) are Base64.
How the algorithm works (step by step)
Base64 works on the principle that 3 bytes of input (24 bits) can be evenly divided into 4 groups of 6 bits. Because 26 = 64, each 6-bit group maps to exactly one of the 64 Base64 characters. Let's walk through encoding the three-letter word Man.
Step 1 — Convert each character to its 8-bit binary value:
M = 77 = 01001101
a = 97 = 01100001
n = 110 = 01101110
Step 2 — Join the bits into one 24-bit stream:
010011010110000101101110
Step 3 — Split the 24 bits into four 6-bit groups:
010011 010110 000101 101110
=19 =22 =5 =46
Step 4 — Map each 6-bit value to the Base64 alphabet (0→A, 1→B, … 25→Z, 26→a, … 51→z, 52→0, … 61→9, 62→+, 63→/):
19 → T
22 → W
5 → F
46 → u
So Man encodes to TWFu. Every group of 3 input bytes always becomes exactly 4 output characters, which is why Base64 output is always about 33% larger than the original (4 ÷ 3 ≈ 1.33).
Padding and the "=" sign
The neat 3-bytes-to-4-characters mapping only works when the input length is a multiple of 3. When it isn't, Base64 pads the final group. This is where the trailing = characters come from.
| Input bytes in final group | Output characters | Padding added |
|---|---|---|
| 3 bytes | 4 chars | none |
| 2 bytes | 3 chars + = | one = |
| 1 byte | 2 chars + == | two == |
For example, encoding the two-letter Ma produces TWE= (one padding sign), and the single letter M produces TQ== (two padding signs). The padding keeps the total output length a clean multiple of four, which makes decoding unambiguous.
Base64 vs Base64URL
Standard Base64 uses + and /, but both of those characters have special meaning inside URLs: + can be interpreted as a space, and / is a path separator. Putting raw Base64 into a query string or filename therefore requires extra percent-encoding.
Base64URL (defined in RFC 4648 §5) is a small variant that fixes this:
+is replaced with-(minus)/is replaced with_(underscore)- trailing
=padding is usually omitted
The result is safe to drop directly into URLs, cookie values, and filenames without any further escaping. This is the variant used by JSON Web Tokens, OAuth, and many web APIs.
Encoding & decoding in code
Almost every language ships with Base64 support built in. Here are correct, UTF-8-safe examples in five common environments.
JavaScript (browser)
The native btoa/atob functions only handle Latin-1, so for Unicode text you must round-trip through UTF-8 first:
// Encode (UTF-8 safe)
const encoded = btoa(
new TextEncoder().encode("Héllo 😀")
.reduce((s, b) => s + String.fromCharCode(b), "")
);
// Decode (UTF-8 safe)
const bytes = Uint8Array.from(atob(encoded), c => c.charCodeAt(0));
const decoded = new TextDecoder().decode(bytes);
Node.js
const encoded = Buffer.from("Hello", "utf8").toString("base64");
const decoded = Buffer.from(encoded, "base64").toString("utf8");
Python
import base64
encoded = base64.b64encode("Hello".encode("utf-8")).decode("ascii")
decoded = base64.b64decode(encoded).decode("utf-8")
PHP
$encoded = base64_encode("Hello");
$decoded = base64_decode($encoded);
Java
import java.util.Base64;
String encoded = Base64.getEncoder().encodeToString("Hello".getBytes("UTF-8"));
String decoded = new String(Base64.getDecoder().decode(encoded), "UTF-8");
Command line (Linux / macOS)
echo -n "Hello" | base64 # encode
echo "SGVsbG8=" | base64 --decode # decode
Common mistakes to avoid
- Treating Base64 as security. Anyone can decode it instantly. Never use it to "hide" passwords, tokens, or personal data. Use real encryption such as AES-GCM.
- Forgetting UTF-8. Base64 operates on bytes, not characters. If you skip the UTF-8 step in JavaScript, emojis and accented characters will break.
- Mixing up Base64 and Base64URL. A token encoded with Base64URL will fail to decode with a strict standard-Base64 decoder, and vice versa, because of the
-_vs+/alphabet. - Expecting it to save space. Base64 always grows data by ~33%. If size matters, compress before encoding.
- Stripping padding carelessly. Some decoders are strict about the trailing
=; if you remove it, make sure the decoder you use tolerates missing padding.
Want to try it yourself? Use the free Base64 encoder & decoder on the home page — everything runs locally in your browser, so your data never leaves your device.