Base64 rewrites arbitrary bytes using only 64 characters that survive any text channel. The alphabet is fixed:
| Index | Characters |
|---|---|
| 0–25 | A–Z |
| 26–51 | a–z |
| 52–61 | 0–9 |
| 62 | + |
| 63 | / |
The mechanism is a regrouping of bits. Three bytes are 24 bits; 24 divides evenly into four 6-bit groups; each 6-bit group is a number from 0 to 63, which indexes the table above. Nothing is compressed, encrypted or hashed — the bits are identical, only the grouping changed.
Encode the three characters Man:
| Step | Value |
|---|---|
| ASCII codes | M = 77, a = 97, n = 110 |
| As bytes | 01001101 01100001 01101110 |
| Regrouped into 6 bits | 010011 010110 000101 101110 |
| As numbers | 19, 22, 5, 46 |
| Alphabet lookup | T, W, F, u |
So Man becomes TWFu. Four characters out for three bytes in, every time.
When the input is not a multiple of three bytes, the final group is incomplete. It is zero-padded up to six bits, and then = characters are appended so the output length stays a multiple of four:
| Input | Bytes | Output | Padding |
|---|---|---|---|
| Man | 3 | TWFu | none |
| Ma | 2 | TWE= | one |
| M | 1 | TQ== | two |
So the number of equals signs tells you the remainder: one means the input length left 2 over, two means it left 1 over, and you will never see three. Padding is only a length marker — some decoders accept its absence.
Output length is ceil(bytes ÷ 3) × 4, which is roughly a third larger than the input:
| Original | Base64 | Increase |
|---|---|---|
| 1 KB | 1.37 KB | +37% |
| 100 KB | 136.7 KB | +37% |
| 1 MB | 1.37 MB | +37% |
The theoretical floor is 33.3%; real figures land nearer 37% once line breaks are counted, since the MIME specification wraps encoded output at 76 characters per line. This is the practical argument against inlining large images as data URIs — you pay a third more bytes, and unlike a separate file the result cannot be cached independently or loaded lazily.
This is the error most developers hit. The browser function btoa operates on bytes, and it treats each character of its input as one byte. Any character above code point 255 — an emoji, an accented letter in some cases, anything in Arabic, Devanagari or Han — makes it throw an InvalidCharacterError.
The cause is a category error rather than a bug: Base64 encodes bytes, and a string is not bytes until you choose an encoding. The fix is to convert the text to UTF-8 first, usually with TextEncoder, then Base64 the resulting byte array. Decoding runs the reverse: Base64 to bytes, then TextDecoder back to text. Skipping that step produces silent corruption of every non-ASCII character.
Base64 appears in email attachments through MIME, in HTTP Basic authentication headers, in data URIs inside CSS and HTML, in PEM-wrapped certificates and keys, and in binary fields inside JSON, which has no byte type of its own.
Because + and / have meaning in URLs and filenames, a second alphabet exists — base64url, defined in RFC 4648, which substitutes - and _ and usually drops the padding. JSON Web Tokens use this variant, which is why a JWT contains dashes and underscores and no equals signs. Feeding base64url into a standard decoder that does not translate those two characters yields garbage or an error.
The single most important point: Base64 is not encryption and provides no security whatsoever. It is a reversible public transformation with no key. Anything Base64-encoded is readable by anyone in one step, so it must never be used to protect a password, token or personal data. Encoded credentials in a Basic auth header are protected by the transport layer, not by Base64.
It is also not a checksum — it will not detect corruption — and it is not compression, since it makes data larger. Very large inputs can exhaust browser memory, because the whole string plus its decoded form must be held at once.
Usually one of three causes: the input was base64url and the decoder expected the standard alphabet, the padding was stripped by a system that trimmed the string, or the original was binary rather than text and there is nothing readable to show.
Generally yes. The correct length is inferable from the character count, and most decoders reconstruct it. Some strict implementations refuse, which is why padding still exists.
To remove an HTTP request, which mattered a great deal before HTTP/2 multiplexing. For small icons it can still help; for anything sizeable the 37% overhead and the loss of separate caching outweigh the saved request.
No. Encoding and decoding happen in your browser and nothing you paste is transmitted or logged.
Every tool comes with a written guide, and every category is one click away.