{ }formatter Nothing leaves your browser

How Base64 encoding actually works

Base64 turns arbitrary binary data into plain ASCII text so it can travel through channels that only expect text. It shows up in data URIs, email attachments, JWTs, API keys, and configuration files — and it's routinely misunderstood as a form of encryption. Here's what it really does, one byte at a time.

The problem Base64 solves

Plenty of systems were designed to carry text, not raw bytes. Email bodies, JSON string values, URLs, XML documents, and HTTP headers all have characters that mean something structural — a quote, a newline, a null byte — and raw binary data will sooner or later contain those bytes and break the format.

Base64 sidesteps this by re-expressing any byte sequence using only 64 characters that are safe nearly everywhere: A–Z, a–z, 0–9, +, and /. Every one of them survives a trip through a text-only pipeline unchanged.

Three bytes become four characters

The trick is a change of units. A byte is 8 bits; a Base64 character encodes 6 bits. The least common multiple of 8 and 6 is 24 — so Base64 works on three bytes (24 bits) at a time and emits four characters.

Take the string Man. Its three bytes are 77, 97, and 110:

Concatenate those into one 24-bit run, then re-split it into four 6-bit groups:

01001101 01100001 01101110010011 010110 000101 101110

Read as numbers, those groups are 19, 22, 5, 46. Now index into the Base64 alphabet, where positions 0–25 are A–Z, 26–51 are a–z, 52–61 are 0–9, 62 is +, and 63 is /. That gives T, W, F, u — so Man encodes to TWFu. No compression, no secret, just a different way of slicing the same bits.

What the = padding means

Not every input is a clean multiple of three bytes, so the last group may be short. Base64 zero-fills the final 6-bit group and then appends = characters to record how much of the last block was real data:

Because the padding only ever appears at the end, a decoder can use it to know whether to discard one or two trailing bytes. Some implementations accept unpadded input and infer the length from the character count instead, which is why you'll see Base64 in the wild both with and without the trailing =.

Base64 costs you 33% in size

Four output characters for every three input bytes means encoded data is always about 133% of the original — a third larger. If the output is then stored as UTF-8 text (one byte per Base64 character, since they're all ASCII), that overhead is real bytes on disk and on the wire.

This is worth remembering before base64-ing a large image into a data URI or a JSON payload. It's cheap for a 2 KB icon and expensive for a 5 MB photo, and it's why HTTP generally moves binary bodies as binary rather than encoding them.

base64url: the URL-safe variant

The standard alphabet's last two characters are a problem in some contexts. + and / both have meaning inside URLs and filenames, and = is reserved in query strings. The base64url variant (defined alongside the standard in RFC 4648) fixes this with two substitutions and usually drops the padding:

So bytes that encode to +/++ in standard Base64 become -_-- in base64url. This is the variant used for the three segments of a JSON Web Token, and generally anywhere the encoded value ends up in a path, query parameter, or filename. Decoding is the same process in reverse — you just translate the two characters back first.

Base64 is not encryption

This is the single most consequential misunderstanding about Base64, and it's worth stating bluntly: Base64 provides no confidentiality whatsoever. There is no key. The transformation is fully specified, public, and reversible by anyone in one step — including with the tool on this site.

Practical consequences:

If you need secrecy, you need actual encryption. If you need to prove a message wasn't tampered with, you want an HMAC or a signature. Base64 is a transport format, nothing more.

Text, bytes, and UTF-8

Strictly speaking Base64 encodes bytes, not characters — so when you encode a string, something has to turn that string into bytes first. Virtually always that's UTF-8. It matters because non-ASCII characters become multiple bytes before encoding: héllo 🚀 encodes to aMOpbGxvIPCfmoA=, which is longer than the seven visible characters suggest, since é takes two bytes and the emoji takes four.

Mismatched assumptions here are a classic source of mojibake — encode as UTF-8 and decode as Latin-1 and you'll get plausible-looking garbage rather than an obvious error.

Where you'll actually meet it

Common pitfalls

Try it yourself

The quickest way to build intuition is to encode a few things and watch the output. Encode M, then Ma, then Man, and see the padding disappear step by step. The Base64 encoder and decoder on this site runs entirely in your browser — including a hex view for binary results and a switch between the standard and URL-safe alphabets — so you can safely paste real tokens without them leaving your machine.