Base64 Encoding Explained: How It Works and When to Use It
By Tahsin Abrar · Updated
Base64 shows up everywhere in web development: data URIs, email attachments, HTTP Basic authentication, JSON Web Tokens, and binary values stored in JSON. It is a way to represent arbitrary bytes using only 64 "safe" printable characters, so binary data can travel through systems designed for text.
This guide explains the mechanics with a worked example, the URL-safe variant, and the Unicode trap in JavaScript's btoa(). Try the examples in the Base64 Encoder / Decoder.
How the encoding works
Base64 reads the input three bytes (24 bits) at a time and splits those 24 bits into four groups of 6 bits. Each 6-bit value (0–63) is mapped to one character of the alphabet A–Z, a–z, 0–9, + and /. Here is the word Man:
| Step | M | a | n |
|---|---|---|---|
| ASCII byte | 77 | 97 | 110 |
| Bits | 01001101 | 01100001 | 01101110 |
24 bits: 010011 010110 000101 101110
6-bit: 19 22 5 46
Base64: T W F u → "TWFu"Because every 3 input bytes become 4 output characters, Base64 output is about 33% larger than the input (plus line breaks, if the variant uses them). A 3 MB image becomes roughly 4 MB of Base64 text.
What the = padding means
When the input length is not a multiple of three, the last group is short. The encoder pads it with zero bits and appends = characters so the output length stays a multiple of four:
- 1 leftover byte → 2 Base64 characters +
==(e.g.M→TQ==) - 2 leftover bytes → 3 Base64 characters +
=(e.g.Ma→TWE=) - 0 leftover bytes → no padding (e.g.
Man→TWFu)
Padding carries no data. Many decoders accept input without it, and some formats (JWTs, for example) always omit it.
Base64 vs Base64URL
Standard Base64 uses + and /, which have special meanings in URLs and file names. RFC 4648 defines a URL- and filename-safe alphabet that swaps them:
| Variant | Index 62 | Index 63 | Padding | Used in |
|---|---|---|---|---|
| Base64 | + | / | Required = | MIME email, data URIs, PEM keys, Basic auth |
| Base64URL | - | _ | Usually omitted | JWTs, URL parameters, file names |
Mixing them up is a frequent bug: decoding a JWT segment with a standard Base64 decoder fails as soon as it contains - or _. Convert by replacing - with +, _ with /, and re-adding = until the length is a multiple of 4.
Base64 in JavaScript — and the Unicode trap
Browsers provide btoa() (binary to ASCII) and atob(). They operate on "binary strings" where each character is one byte, so any character above U+00FF throws:
btoa("café ☕");
// ✗ InvalidCharacterError: string contains characters outside of the Latin1 rangeEncode the text to UTF-8 bytes first, then Base64 those bytes:
function toBase64(text) {
const bytes = new TextEncoder().encode(text);
let bin = "";
for (const b of bytes) bin += String.fromCharCode(b);
return btoa(bin);
}
function fromBase64(b64) {
const bin = atob(b64);
const bytes = Uint8Array.from(bin, (c) => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
toBase64("café ☕"); // "Y2Fmw6kg4piV"In Node.js, use Buffer.from(text, "utf8").toString("base64") and Buffer.from(b64, "base64").toString("utf8"); "base64url" is also supported as an encoding name. Recent browsers additionally ship Uint8Array.prototype.toBase64() and Uint8Array.fromBase64(), which handle both alphabets directly. The encoder on this site is Unicode-safe.
When to use Base64 — and when not to
Good uses
- Embedding small binary data in text formats: JSON fields, XML, YAML, environment variables.
- Data URIs for tiny images or fonts, e.g.
data:image/png;base64,iVBORw0…. - HTTP Basic authentication, where
user:passwordis Base64-encoded in theAuthorizationheader — always over HTTPS, since anyone can decode it. - Binary-safe transport through systems that may mangle raw bytes, such as email (MIME).
Poor uses
- Hiding secrets. Base64 is an encoding, not encryption; decoding requires no key. Use real encryption, or a hash when you only need to compare values.
- Large files in JSON or HTML. The 33% overhead and loss of streaming add up. Upload binary data as
multipart/form-dataor serve it as a separate file. - Big inline images. Data URIs can't be cached separately from the page that contains them; keep them to small icons.
FAQ
- Is Base64 encryption?
- No. Base64 is a reversible encoding with a public alphabet — anyone can decode it without a key. It provides no confidentiality at all.
- Why does my Base64 string end with == ?
- The
=characters are padding. They appear when the input length isn't a multiple of 3 bytes: one leftover byte gives==, two leftover bytes give=. - How much bigger is Base64 than the original?
- About 33%: every 3 bytes become 4 characters. The exact length is 4 × ceil(n / 3) characters for n input bytes, before any line breaks.
More guides
- How JWT Signatures Work (HS256 vs RS256, Explained)What the three parts of a JSON Web Token are, how the signature is computed, why decoding is not verifying, and the mistakes that lead to JWT vulnerabilities.
- Cron Syntax Cheatsheet: Fields, Operators and 25 Ready-Made SchedulesA practical reference to the five-field cron format, the special characters, common schedules you can copy, and the gotchas in crontab, GitHub Actions and Kubernetes.
- Fixing "Unexpected token" and Other JSON Parse ErrorsWhat JSON.parse errors like "Unexpected token < in JSON", "Unexpected end of JSON input" and "Expected double-quoted property name" really mean, and how to fix each one.