DeveloperApril 18, 2026 · 11 min read

Base64 Explained Simply: Encoding, Decoding, and When to Use It

What Base64 actually is, how 3 bytes become 4 characters, why it makes files 33% bigger, and the real places you encounter it — data URLs, JWTs, PEM keys, HTTP Basic auth.

Base64 is one of those things every developer bumps into, few actually understand, and even fewer need to understand deeply. It shows up in data URLs, JWT tokens, email attachments, PEM keys, HTTP Basic auth headers. It gets confused with encryption constantly. It makes your files about 33% bigger. It has a URL-safe variant that breaks when mixed with the standard one.

This post is the version I wish I had read the first time I saw data:image/png;base64,iVBORw0KGgo... in a CSS file and thought "what is this, and why". We will cover what Base64 really does at the bit level, the actual problem it solves, where you legitimately need it, the URL-safe variant you trip over when working with JWTs, and the three big misunderstandings that cause hours of avoidable debugging.

If you only read one section, read "The 30-second version" and "Things Base64 is NOT". Most Base64 confusion collapses once those click.

The 30-second version

Base64 is a way to represent arbitrary binary data as plain ASCII text. Every 3 bytes of binary become 4 ASCII characters drawn from a fixed 64-character alphabet — A-Z, a-z, 0-9, plus two symbols (+ and / in the standard alphabet, - and _ in the URL-safe one), with = as padding. Nothing is encrypted. Nothing is compressed. In fact the output is about 33% bigger than the input.

It is a pure format conversion, like transliterating a message from one writing system to another. The information is unchanged; only the representation is different. That is the whole idea.

One-line definition
Base64 = "take any bytes, output only safe ASCII characters that every text protocol can carry without corruption".

Why Base64 exists

Networks and protocols built decades ago could only safely carry text. SMTP, the email protocol standardised in 1982, was explicitly 7-bit ASCII — if you sent raw binary through it, intermediate mail servers could corrupt bytes or interpret them as control characters. Early HTTP, Telnet, and countless text-based formats had the same issue.

So someone decided: pick 64 characters that every text protocol agrees on as safe, then use those characters to represent arbitrary bytes. 64 is chosen because 64 = 2^6, which means each character represents exactly 6 bits. Pack 4 characters together and you get 24 bits, which is exactly 3 bytes. Clean math, no waste except at the edges.

Today, most transports handle binary fine. But the convention stuck because it is universal — if it fits in a JSON string, a URL, an HTTP header, or a CSS file, it can carry Base64 bytes. That is why you still see it everywhere in 2026.

How the encoding actually works

The algorithm is easy enough to follow by hand on a short input. Let us encode the ASCII string Hello into Base64 step by step.

Step 1 — bytes to bits

Hello is 5 ASCII bytes: 72 101 108 108 111. Written as binary, each byte is 8 bits, so we have 40 bits total:

H        e        l        l        o
01001000 01100101 01101100 01101100 01101111

Step 2 — regroup into 6-bit chunks

Base64 works in 6-bit chunks, so we read the bit stream in groups of 6 instead of 8:

010010 000110 010101 101100 011011 000110 1111
  18     6    21    44    27     6    ?

40 bits does not divide evenly into 6, so the last group has only 4 bits. We pad it on the right with zeros to make it 6: 111100 = 60.

Step 3 — map each 6-bit value to a character

The Base64 alphabet assigns an index 0-63 to each of 64 characters: A=0, B=1, ..., Z=25, a=26, ..., z=51, 0=52, ..., 9=61, +=62, /=63. Plugging in our values:

18 -> S
 6 -> G
21 -> V
44 -> s
27 -> b
 6 -> G
60 -> 8

"Hello" -> SGVsbG8

Step 4 — add padding with `=`

Base64 output must be a multiple of 4 characters. Our result SGVsbG8 is 7 characters, so we pad with one =:

Hello -> SGVsbG8=

The padding rule is simple. If the input length is a multiple of 3 bytes, no padding is needed. If it is 3k+1 bytes, two = are added. If it is 3k+2 bytes (our case here, since 5 = 3+2), one = is added. The = characters are not information — they just tell the decoder how many trailing bits to ignore.

Free Tool
Open the Base64 Encoder (free)
Encode text to Base64 in your browser. Free online Base64 encoder with UTF-8 support for safe transport in URLs, emails, and headers.

Things Base64 is NOT

These three confusions show up in code reviews and forum posts constantly. None of them are true.

Base64 is NOT encryption

Anyone can decode Base64 — the algorithm is fully public, there is no key, and every programming language ships a decoder in its standard library. If you Base64 a password and call it "protected", you have done nothing useful. Run the Base64 Decode tool on any Base64 string and it comes back in plain text in milliseconds.

When you see Base64 in places that look security-adjacent — JWTs, API keys, signed URLs — the security comes from a signature or a secret that is combined with the Base64, not from the Base64 itself. If you only see the encoded part, it is opaque to your eyes but trivially readable to anyone with a decoder.

Base64 is NOT compression

Base64 makes data bigger, not smaller. Each 3 bytes of input become 4 bytes of output — exactly 4/3 the size, or about 33% overhead. A 1 MB image embedded as a Base64 data URL is roughly 1.37 MB on the wire. That is the trade-off: you gain the ability to ship the image inside a text file, and you pay 33% extra bytes for the privilege.

Base64 is NOT a hash or checksum

Hashing is one-way — given a hash you cannot recover the input. Base64 is fully reversible by definition. It provides no integrity check, no tamper detection, nothing. If you need integrity, use the Hash Generator to produce a SHA-256 and ship it alongside the data. Do not mistake a Base64 string that looks random for a cryptographic fingerprint.

Where you actually see Base64 in the wild

Once you know what to look for, Base64 is everywhere. Here are the places you will definitely run into it.

Data URLs (images embedded in CSS/HTML)

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAU..." />

The entire image is stuffed into a single src attribute. No separate HTTP request, no caching, but the HTML/CSS file gets larger. Useful for tiny icons where an extra HTTP round-trip costs more than the 33% overhead. Painful for anything bigger than a few KB.

JWT payloads

A JSON Web Token has three dot-separated parts, each of which is a Base64url-encoded JSON object (header, payload) or signature. The header and payload are only encoded, not encrypted, so anyone can decode them. That is by design — JWTs prove origin via the signature, not via secrecy. If you need the payload hidden, wrap the JWT in a second encryption layer or use JWE instead.

HTTP Basic authentication

Authorization: Basic dXNlcjpwYXNzd29yZA==

That header value decodes to user:password. No hashing, no salt, no protection — just the credentials in plain text after you Base64-decode them. This is why HTTP Basic is only safe over HTTPS, and why you should prefer token-based auth for anything serious.

Email attachments

MIME, the standard that made email handle anything other than plain text, uses Base64 to carry binary attachments through SMTP. Every PDF, every image, every ZIP you have ever sent as an email attachment was Base64-encoded during transit. This is the original use case that made Base64 popular.

PEM-format keys and certificates

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7VJTUt9Us8cKj
...
-----END PRIVATE KEY-----

PEM wraps binary cryptographic data (DER bytes) in Base64 and adds -----BEGIN----- / -----END----- markers. It is a text format that survives email, config files, and copy-paste without corruption. Nearly every .crt, .pem, .key file on your disk is Base64 inside.

URL-safe Base64 vs standard Base64

Standard Base64 uses + and / as its last two characters. Both of those have special meaning inside a URL — + is sometimes interpreted as a space in query strings, and / is the path separator. Padding = is also reserved. So if you take a Base64 string and drop it into a URL without escaping, it may silently corrupt.

The URL-safe variant (specified in RFC 4648) swaps the two problem characters: + becomes -, and / becomes _. Padding = is often omitted entirely because its length is derivable from the content. That gives you a string made only of letters, digits, hyphen, and underscore — safe to drop anywhere in a URL without further escaping.

Standard:  MY+STRING/HERE==
URL-safe:  MY-STRING_HERE

Mixing the two is the classic bug. You encode with standard Base64, someone else decodes with URL-safe rules (or vice versa), and the decoder either throws "invalid character" or silently misinterprets + as nothing. Symptom: decoding works for 99% of inputs and fails on the 1% that happened to contain a + or a /.

JWT gotcha
JWTs use Base64url (URL-safe, no padding). If you paste a JWT payload into a standard decoder and it complains about an invalid character, convert - to +, _ to /, and add enough = to make the length a multiple of 4. Then decode.

When NOT to reach for Base64

Because Base64 is cheap and easy, it gets used in places where it is genuinely wrong. A few guidelines.

Do not Base64 large binary files unnecessarily

Embedding a 500 KB image as a data URL in your HTML means every page load pays for 670 KB of text that never gets cached separately. If the image will be reused across pages, a plain <img src="/path.png"> with a cache-friendly URL is dramatically faster. Reserve data URLs for icons, tiny inline illustrations, or one-off attachments.

Do not Base64 when the channel already handles binary

If you are POSTing to an endpoint that accepts multipart/form-data or application/octet-stream, send the raw bytes. Base64-ing first just adds 33% overhead and CPU cost on both sides. Only encode when the container is actually text-only — JSON string values, URLs, HTTP headers, CSS.

Do not Base64 passwords, ever

Storing a Base64 password is identical to storing it in plain text because anyone can reverse it in one line of code. Use bcrypt, scrypt, or argon2 for passwords. If you genuinely need a one-way fingerprint, use the Hash Generator with SHA-256 or higher. Base64 is never the right tool for authentication secrets.

Watch the performance on large inputs

Decoding a multi-megabyte Base64 string in the browser can take noticeable time and blocks the main thread while it runs. If your app ships large encoded payloads, decode them in a Web Worker, or reconsider whether the payload really needs to be Base64 in the first place.

Free Tool
Decode a Base64 string
Decode Base64 to readable text in your browser. Free online Base64 decoder with Unicode support and validation for malformed input.

Related encoders and decoders

Base64 is one of a small family of encodings you will encounter in the same workflows. The tool kit below covers encode/decode in both directions, plus the URL and hash tools you typically need next.

If your Base64 is wrapped in a URL, start with the URL Decoder to peel off the percent-encoding before feeding the inner value to the Base64 decoder. If you need to encode the result safely for another URL, flip the order: Base64 first, then the URL Encoder.

Summary

Base64 is a text representation of binary bytes. Not encryption, not compression, not a hash. It exists because old protocols only carry text, and it survives because text containers — JSON, URLs, HTTP headers, CSS — are everywhere.

  1. Use Base64 when you need to put bytes inside a text container.
  2. Expect a 33% size overhead — never call it compression.
  3. Watch for the URL-safe variant (-_ instead of +/) when working with JWTs or anything in URL paths.
  4. Never use it for passwords, integrity, or any security goal — it is fully public and fully reversible.
  5. For a quick encode or decode, open the Base64 Encoder or Base64 Decoder — both run entirely in your browser.

Now that the 30-second version is clear, you will notice Base64 constantly. It lives inside every data URL, every JWT, every PEM key, every HTTP Basic header, every MIME email. Knowing what it is (and what it is not) is one of those small pieces of knowledge that pays off every month for the rest of your career.

Frequently Asked Questions

What is Base64 encoding, in one sentence?

Base64 is a way to represent arbitrary binary data using only 64 ASCII characters (A-Z, a-z, 0-9, plus two symbols) so the data can travel safely through text-only channels like email, URLs, and JSON. It is a format conversion, not encryption.

Is Base64 secure or encrypted?

No. Base64 provides no security at all. Anyone can decode it in one line of code using a standard library, and the algorithm is fully public with no key. If you need secrecy, use real encryption; if you need integrity, use a hash. Never rely on Base64 to protect sensitive data.

Why is Base64-encoded data bigger than the original?

Every 3 bytes of input become 4 characters of output, which is a 4/3 size ratio — about 33% larger. This overhead is the price of using only 64 safe characters instead of the full 256 possible byte values. There is no way to make Base64 smaller than the input; if you need compression, apply gzip first and then Base64.

What is the difference between standard and URL-safe Base64?

Standard Base64 uses `+` and `/` as its last two alphabet characters, both of which have special meaning in URLs. URL-safe Base64 (RFC 4648) replaces them with `-` and `_`, and often omits the `=` padding. JWTs use URL-safe Base64, so if you paste a JWT payload into a standard decoder you may have to translate `-` to `+`, `_` to `/`, and re-add padding first.

Why does Base64 have equals signs (=) at the end?

Base64 emits characters in groups of 4 that represent 3 bytes each. When the input length is not a multiple of 3, the last group is incomplete, and `=` characters are added to round it out to a full group. One `=` means the original input was 3k+2 bytes; two `=` means 3k+1 bytes; no `=` means a multiple of 3. Decoders use the padding to know how many trailing bits to discard.

Should I Base64-encode images in CSS or HTML?

Only for very small images like icons and tiny illustrations. Data URLs save an HTTP round-trip but inflate the file by 33% and cannot be cached separately from the HTML or CSS. For anything bigger than a few KB, a regular image URL with proper caching is faster overall.

How do I decode a Base64 string that fails to decode?

The most common causes are missing padding (add `=` until length is a multiple of 4), URL-safe characters in a standard decoder (convert `-` to `+` and `_` to `/`), and embedded whitespace from line-wrapped input (strip it first). Once those are fixed, the Base64 Decode tool will parse the string and hand back the original bytes.

Tools in this guide