AXS TXT
← All articles

Base64 Explained: How It Works, Padding, URL-Safe and Common Errors

July 14, 2026 · Updated October 19, 2026 · Silviu Anca

If you've seen a long string of letters and numbers ending in = or ==, you've met Base64. It's everywhere on the web — in emails, JSON APIs, data URLs and login tokens — and it's often mistaken for encryption.

What Base64 is for

Many systems were built to carry text, not arbitrary bytes: email bodies, JSON, HTML attributes, URLs, HTTP headers. Base64 rewrites any data — an image, a PDF, text in any language — using only 64 safe characters: A–Z, a–z, 0–9, + and /. The data survives the trip untouched and can be turned back into the exact original bytes.

Typical uses:

How it works, in one example

Base64 takes the input 3 bytes at a time (24 bits), cuts them into four groups of 6 bits, and writes each group as one of the 64 characters. Three bytes in, four characters out.

TextBase64
HiSGk=
HelloSGVsbG8=
Hello!SGVsbG8h
ȘcoalăyJhjb2FsxIM=
👋8J+Riw==

"Hello!" is exactly 6 bytes, so it needs no padding. "Școală" looks like 6 letters but is 8 bytes in UTF-8 (each of Ș and ă takes two bytes), which is why it isn't a multiple of three and ends in =.

Why it ends in = or ==

The = signs are padding. When the input isn't a multiple of 3 bytes, the last group is filled up: one byte left over gives ==, two bytes give =. Padding carries no data, and some systems (JWTs, many URLs) leave it out entirely — a decoder can work out the length without it. Our Base64 decoder accepts both.

How much bigger does it make data?

Four characters for every three bytes: 33% larger, plus up to two padding characters. A 1 MB image becomes about 1.33 MB of Base64 text (1,398,104 characters). That's fine for a small icon in a stylesheet, but a poor trade for large photos — the browser can't cache an inlined image separately, and the page itself gets heavier.

URL-safe Base64 (Base64URL)

+ and / have special meanings in URLs and file names, so a variant replaces them with - and _ and usually drops the padding. That's what JWTs use: the header {"alg":"HS256","typ":"JWT"} becomes eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 — which is why almost every JWT starts with eyJ. The emoji above is 8J+Riw== in standard Base64 and 8J-Riw in Base64URL. You can paste either form into the decoder.

The "outside of the Latin1 range" error

If you've tried btoa("Școală") in a browser's JavaScript console, Chrome answers: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range. btoa only accepts characters with codes up to 255, so letters like Ș, ț, emoji or anything outside Western European Latin fail.

The fix is to encode the text as UTF-8 bytes first:

const toBase64 = (text) =>
  btoa(String.fromCharCode(...new TextEncoder().encode(text)));
const fromBase64 = (b64) =>
  new TextDecoder().decode(Uint8Array.from(atob(b64), (c) => c.charCodeAt(0)));

toBase64("Școală"); // "yJhjb2FsxIM="

Our encoder does exactly this, so text in any language round-trips correctly.

Base64 is not encryption

Anyone can decode Base64 instantly — it hides nothing. If a password, API key or personal data is "only Base64", it is effectively in plain text. To protect data, encrypt it; to check that a file hasn't changed, use a hash (see our hash generator).

You can try all the examples above in Base64 Encode / Decode. It runs in your browser, so the text you paste is never sent anywhere.

Try Base64 Encode / Decode

Encode text to Base64 or decode Base64 back to text, right in your browser.

Open Base64 Encode / Decode