All posts

Base64 Encoding Explained: What It Is and When to Use It

July 22, 2026 · DevTools

base64
encoding
data-uri
developer-tools

You've seen it everywhere: a long string of letters, numbers, and the occasional + or /, maybe ending in = — like SGVsbG8gV29ybGQh. That's Base64, the web's standard way of squeezing binary data into text. This guide explains what it actually does, why it exists, and the mistakes people make with it.

You can follow along with any example in the Base64 Toolbox — it encodes and decodes text, files, and images entirely in your browser, so nothing you paste ever leaves your machine.

What Base64 actually does

Computers store data as bytes. Many protocols — email, JSON, XML, URLs — were designed for text, not arbitrary bytes. Base64 bridges that gap: it takes any sequence of bytes and rewrites it using only 64 safe, printable characters:

A–Z  a–z  0–9  +  /

The encoding works in groups of 3 bytes (24 bits), which are split into four 6-bit chunks. Each 6-bit chunk maps to one character in the alphabet:

"Hi!"      → bytes:  72  105  33
           → bits:   01001000 01101001 00100001
           → chunks: 010010 000110 100100 100001
           → values: 18     6      36     33
           → Base64: S      G      k      h

So Hi! becomes SGkh. Three bytes in, four characters out — Base64 data is always about 33% larger than the original.

The padding = at the end

Input rarely divides neatly into groups of 3. When bytes are left over, the output is padded with = to reach a multiple of 4 characters:

  • 1 leftover byte → XX== (two pad characters)
  • 2 leftover bytes → XXX= (one pad character)

That's why SGVsbG8gV29ybGQh ("Hello World!") has no padding — 12 bytes is exactly 4 groups — while "Hello" (5 bytes) becomes SGVsbG8=. Missing or wrong padding is the most common cause of "invalid Base64" errors when you paste a partial string.

Base64 vs Base64URL

Two alphabet characters — + and / — have special meaning in URLs. Embedding standard Base64 in a query string can corrupt it, so Base64URL (RFC 4648 §5) swaps them:

Standard Base64Base64URLWhy
+-+ means "space" in query strings
/_/ splits URL path segments
= paddingoptionalpadding is often dropped in tokens

Base64URL is what JWTs use — look at any JSON Web Token and you'll see - and _ instead of + and /. You can decode the header and payload of a JWT with nothing more than a Base64URL decoder (try it: paste a token into the JWT Decoder).

MIME and line wrapping

If you decode a Base64 string copied from an email attachment or a PEM certificate and get errors, line wrapping is the usual suspect. MIME (RFC 2045) requires Base64 output to be broken into 76-character lines with CRLF breaks. Many decoders tolerate the newlines; strict ones don't. When a decode fails on data that "looks right", strip whitespace first — or use a tool that handles MIME wrapping for you.

Encoding is not encryption

This trips people up constantly: Base64 is reversible by anyone, instantly. It obscures nothing. QWxhZGluOk9wZW5TZXNhbWU= looks cryptic, but it's just Aladdin:OpenSesame — and HTTP Basic Auth sends credentials in exactly this form. Base64 protects data from transport damage, not from readers. If you need secrecy, you want encryption (e.g., AES), not encoding.

Where you'll actually meet Base64

  • Data URIs — embed a file directly in HTML/CSS: data:image/png;base64,iVBOR...
  • Email (MIME) — attachments are Base64-encoded to survive text-only transport
  • HTTP Basic AuthAuthorization: Basic <base64(user:password)>
  • JWTs — header and payload are Base64URL-encoded JSON
  • APIs & JSON — binary payloads (certificates, small files) inside JSON fields

Encoding and decoding in code

Every language has it built in:

// JavaScript (browser) — careful with Unicode!
btoa("hello")              // "aGVsbG8="
btoa("türkçe")             // ❌ throws: btoa only accepts Latin-1
btoa(String.fromCharCode(...new TextEncoder().encode("türkçe"))) // ✅
# Python
import base64
base64.b64encode(b"t\xc3\xbcrk\xc3\xa7e")  # b'dMO8cmtDp2U='
base64.urlsafe_b64encode(b"...")          # Base64URL variant
# Command line
echo -n "hello" | base64          # aGVsbG8=
echo "aGVsbG8=" | base64 -d       # hello  (-D on macOS)

The JavaScript btoa gotcha deserves emphasis: it predates UTF-8 and rejects any character outside Latin-1. Encode to UTF-8 bytes first (as above), or you'll crash on the first emoji or accented character.

Common mistakes

  1. Decoding Base64URL as standard Base64 (or vice versa) — wrong alphabet, garbage output. If a string has - or _, it's probably Base64URL.
  2. Assuming it's encrypted — see above. Never treat Base64 secrets as safe.
  3. Stripping the padding — some systems tolerate it, others reject the string.
  4. Double-encoding — encoding an already-encoded string (SGVsbG8=U0dWc2JHOD0=) is a classic bug in pipelines. If your decoded output still looks like Base64, this is probably what happened.
  5. Ignoring the size cost — a 10 MB file becomes ~13.3 MB of text, plus memory copies. Don't Base64 large assets into your CSS "for performance"; it usually does the opposite.

Working with files and images

Text is the simple case. For real work you often need to encode an entire file — an image for a Data URI, a certificate for a config variable. The Base64 Toolbox has dedicated workspaces for both: drop a file to get its Base64 (with MIME type detection), or use the Base64 Image Encoder to resize an image and copy ready-to-use HTML, CSS, Markdown, or JavaScript snippets.

A complete Data URI example

Data URIs are where Base64 becomes visible in everyday frontend work. Instead of a separate request, the file travels inside the document:

<img src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...">
.icon {
  background: url("data:image/png;base64,iVBORw0KGgoAAAANS...");
}

The format is data:[<mime-type>][;base64],<data>. Note that the ;base64 flag is optional — without it, the data is plain (percent-encoded) text, which for SVG is often smaller than Base64. Reserve Base64 Data URIs for genuinely binary content (PNG, fonts, PDFs), and keep them small: every kilobyte in a Data URI is a kilobyte your HTML can't cache separately.

Decoding by hand: a worked example

Understanding one decode round makes the format click. Take TWE=:

T  W  E  =
19 22 4  (pad)
→ 010011 010110 000100
→ regroup into bytes: 01001101 01101000 (last 4 bits dropped with the pad)
→ 77, 109 → "Ma"  (from "Man")

Two input bytes became three characters plus one pad — exactly the "2 leftover bytes" rule from earlier. Once you've done this by hand once, Base64 stops being magic: it's just bit shuffling with a printable alphabet.

Performance and storage notes

  • Size: +33% always. 100 MB of Base64 is 133 MB — on the wire, in memory, and often again in a JSON string copy.
  • CPU: encoding is cheap but not free; hot paths that re-encode the same payload should cache the result.
  • Databases: storing Base64 in a column instead of a blob wastes a third of your storage and defeats index-friendly comparisons. Prefer binary columns or object storage with a URL.

Everything stays in your browser

The toolbox runs 100% client-side. Production tokens, credentials buried in config files, unreleased images — none of it is uploaded anywhere, which is exactly what you want when decoding something sensitive.

Next steps