Skip to content
Back to Blog
EncodingMarch 15, 2026·8 min read

Base64 Encoding Explained: What, Why, and How

Everything you need to know about Base64 encoding — how it works, when to use it, performance implications, and common pitfalls to avoid.

Digital data encoding and binary code visualization

Base64 is the silent workhorse of the modern web — every JWT, every data: URI, every email attachment, every Authorization: Basic header rides on it. Defined in RFC 4648, it converts arbitrary bytes into 64 printable ASCII characters at the cost of a fixed 33% size overhead. This guide explains exactly how the encoding works bit-by-bit, when to use the URL-safe variant, JavaScript pitfalls with Unicode, performance implications, and security misconceptions — including the critical fact that Base64 is not encryption.

What Is Base64?

Base64 is a binary-to-text encoding scheme that represents arbitrary bytes using only 64 printable ASCII characters. It exists because many internet protocols — SMTP for email, HTTP headers, JSON, URL query strings — were designed for text and break (or are mangled by intermediaries) when fed raw binary.

📖 Definition — Base64 is defined in RFC 4648. The standard alphabet uses A-Z, a-z, 0-9, +, and /, with = as the padding character.

How the Encoding Actually Works

Base64 takes 3 bytes (24 bits) at a time and re-groups them into 4 chunks of 6 bits. Each 6-bit value (0–63) maps to one character of the alphabet.

Input:    "Man"
Bytes:     M (77)     a (97)     n (110)
Binary:    01001101   01100001   01101110
Re-group:  010011 010110 000101 101110
Decimal:    19     22      5      46
Base64:     T      W       F      u
Output:    "TWFu"

💡 The math is simple: 3 bytes × 8 bits = 24 bits = 4 × 6 bits. So every 3 input bytes always produce exactly 4 output characters, with padding for the leftovers.

The Base64 Alphabet

ValueCharValueCharValueCharValueChar
0A16Q32g48w
1B17R33h49x
........................
25Z26a51z520
531......61962+
63/Padding: =

Padding & the 33% Overhead

When the input length is not a multiple of 3, Base64 pads with = so the output is always a multiple of 4 characters:

Input length mod 3Output ends withExample
0(no padding)"Man""TWFu"
1=="M""TQ=="
2="Ma""TWE="

⚠️ Base64 always inflates data by ~33% (4/3 ratio). For a 100 KB binary, expect ~133 KB Base64 output. This is why embedding large images as data: URIs hurts page-load size.

Standard vs URL-Safe (Base64url)

Standard Base64 uses + and /, both of which have special meaning in URLs. The URL-safe variant (also called Base64url) substitutes them:

PositionStandardURL-SafeWhy
62+-+ becomes space when URL-decoded
63/_/ is path separator
padding=(omitted)= must be percent-encoded

JWTs, S3 pre-signed URLs, OAuth tokens, and most modern web APIs use Base64url. Always toggle the URL-Safe option in our Base64 Encoder when working with these.

Common Use Cases

Use caseVariantNotes
data: URIs in CSS/HTMLStandardBest for icons < 2 KB
Email attachments (MIME)Standard76-char line wrap (RFC 2045)
JWT (header + payload)Base64urlNo padding
HTTP Basic AuthStandardbase64("user:pass")
Binary in JSON APIsEitherPick one and document it
S3 pre-signed URLsBase64urlHMAC signature encoding
WebAuthn / passkeysBase64urlCred IDs & challenges
QR code payloadsStandardQR alphanumeric mode is more efficient

Base64 in JavaScript

// ASCII-only (legacy, fails on Unicode!)
btoa("Hello");                // "SGVsbG8="
atob("SGVsbG8=");             // "Hello"

// Unicode-safe encode (UTF-8)
const utf8  = new TextEncoder().encode("Café ☕");
const b64   = btoa(String.fromCharCode(...utf8));   // legacy way
// or modern (Node 16+, modern browsers):
const b64m  = Buffer.from("Café ☕", "utf8").toString("base64");

// URL-safe variant
const urlSafe = b64.replace(/\+/g, "-")
                   .replace(/\//g, "_")
                   .replace(/=+$/g, "");

// Decode URL-safe back
function fromUrlSafe(s) {
  const pad = "=".repeat((4 - (s.length % 4)) % 4);
  return atob((s + pad).replace(/-/g, "+").replace(/_/g, "/"));
}

🚫 btoa() throws InvalidCharacterError on any character above U+00FF. Always UTF-8-encode first when dealing with non-Latin text or emoji.

Other Languages Cheat Sheet

LanguageEncodeDecode
Python 3base64.b64encode(b"...")base64.b64decode("...")
Python URL-safebase64.urlsafe_b64encode(...)base64.urlsafe_b64decode(...)
Node.jsBuffer.from(s).toString("base64")Buffer.from(b64, "base64").toString()
Bashecho -n "..." | base64echo "..." | base64 -d
PHPbase64_encode($s)base64_decode($s)
Gobase64.StdEncoding.EncodeToString(b)base64.StdEncoding.DecodeString(s)
JavaBase64.getEncoder().encodeToString(b)Base64.getDecoder().decode(s)
RustBASE64_STANDARD.encode(&b)BASE64_STANDARD.decode(&s)

Security: Encoding ≠ Encryption

🚫 Base64 is NOT encryption. It is fully reversible by anyone who sees the string. Never use it to "hide" passwords, API keys, or PII.

Use TLS — Base64-encoded credentials in HTTP Basic Auth must travel over HTTPS or anyone on the wire reads them.

Sign tokens — JWTs are Base64url-encoded but the security comes from the HMAC/RSA signature, not the encoding.

Validate input — A decoded payload is still untrusted input. Apply normal length limits, content-type checks, and schema validation.

Common Mistakes

MistakeSymptomFix
Using btoa on UnicodeInvalidCharacterErrorUTF-8 encode first
Mixing Base64 and Base64urlDecode fails on JWTChoose one and document
Stripping = from standard Base64Length not divisible by 4Re-add padding before decoding
Base64 inside Base64Triples the sizeEncode once at the boundary
Embedding 1 MB image as data: URISlow page load, large CSSUse real <img> with HTTP cache
Storing Base64 in DB blob column33% wasted storageUse BYTEA/BLOB and store raw bytes

Tools

Frequently Asked Questions

Is Base64 encryption?

No. It is a reversible encoding, not a cipher. Anyone can decode it instantly with built-in tools. Use TLS for confidentiality, and JWS/JWE for cryptographic protection.

Why is Base64 33% larger than the original?

Because each 6-bit Base64 character carries less information than an 8-bit byte. The exact ratio is 4/3 ≈ 1.333, so 3 input bytes always become 4 output characters.

What is the difference between Base64 and Base64url?

Base64url is a variant defined in RFC 4648 §5 that uses - and _ instead of + and /, and typically omits the = padding. It is safe for URLs, filenames, and JWT segments.

Should I embed images as Base64 data URIs?

Only for very small images (< 2 KB) where saving the HTTP request matters more than the 33% size overhead. For larger images, regular <img> tags benefit from HTTP caching and parallel downloads.

Why does btoa("é") fail in JavaScript?

Because btoa only handles characters in the Latin-1 range (U+0000–U+00FF interpreted as bytes). For Unicode, encode to UTF-8 bytes first using TextEncoder or Buffer.from(s, "utf8"), then Base64 those bytes.

Is it safe to store passwords in Base64?

Absolutely not. Base64 is reversible. Use a memory-hard password hash (Argon2id, bcrypt) for storage, never Base64.


References

🚀 Free ToolZilla tools used in this article

All client-side, no signup, no upload — open them in a new tab while you read:


Base64 is a binary-to-text encoding, not encryption. Use the standard alphabet for email and HTML, Base64url for URLs and JWTs. Expect a fixed 33% size inflation, keep data: URIs to small icons, and never roll your own UTF-8 handling — let TextEncoder / Buffer.from(..., "utf8") or our Base64 Encoder do it for you.

Continue Reading

Related Articles

Free & Private

Explore Our Free Tools

40+ browser-based utilities — fast, private, and always free. No sign-up required.

Browse All Tools