Base64 Encoding Explained: What It Is and How It Works — Uttir Blog
Skip to main content
Uttir
By Uttir min read

Base64 Encoding Explained: What It Is and How It Works

A practical guide to Base64 encoding: what it is, how it works, when to use it, and when to use something else. With examples and a free browser-based encoder.

Reviewed by Priya Raman · Privacy and security

Base64 is a way to represent any binary data (files, images, encrypted bytes) using only printable text characters. It's not encryption — anyone can decode it — and it costs about 33% more space than the original. It's useful for embedding images in HTML, sending binary data over text-only channels like email, and storing credentials in config files.

You've seen Base64 a thousand times, even if you didn't know it. It's the gibberish-looking text in email attachments, the long string in a data URL, the credentials block in your .env file, the "eyJ..." prefix in JWT tokens. Once you know what it is, you start seeing it everywhere.

This guide explains what Base64 is, how it works under the hood, when to use it, and — just as importantly — when not to use it. If you just need to encode or decode something right now, skip to the bottom for a free browser-based Base64 encoder.

What Base64 actually is

Base64 is an encoding scheme, not an encryption scheme. It takes any sequence of bytes and represents it as a string of printable ASCII characters, drawn from a 64-character alphabet: the 26 uppercase letters, the 26 lowercase letters, the 10 digits, plus + and /, with = used for padding.

That alphabet is the whole trick. Computers store everything as numbers, but most systems that handle text — email, JSON, XML, URLs, HTTP headers, configuration files — were designed for human-readable ASCII. If you want to send a photo, a PDF, an SSL certificate, or any other binary data through one of those systems, you need a way to write the binary bytes using only characters that won't get mangled. Base64 is one such way.

The 64-character alphabet was chosen because it covers all the printable ASCII characters that are safe to put in pretty much any text context. (The URL-safe variant uses - and _ instead of + and /, so the encoded string can be safely embedded in a URL without percent-encoding.)

How it works (the short version)

Every 3 bytes of input (24 bits) becomes 4 characters of output (also 24 bits, but spread across 4 Base64 characters, each representing 6 bits). When the input length isn't a multiple of 3, the output is padded with = characters to make the math work out.

Here's the input "Hi!" encoded step by step:

Input bytes:    H        i        !
                0x48     0x69     0x21
                01001000 01101001 00100001
                └──────┬──────┬──────┘
                   24 bits total

Split into 6-bit chunks:
                010010 000110 100100 100001
                   │      │      │      │
Decimal:        18     6      36     33

Index into Base64 alphabet:
                S      G      k      h

Output: "SGkh"

That's the entire algorithm. Every 3 bytes becomes 4 Base64 characters. For inputs that aren't a multiple of 3 bytes, the last group has 1 or 2 bytes, and the output gets 1 or 2 = padding characters.

Because every 3 input bytes become 4 output characters, Base64 increases the size of the data by exactly 33% (the 4/3 ratio). A 1 MB file becomes a 1.33 MB Base64 string. This is important: Base64 is not compression. It's always larger than the input.

What Base64 is good for

Base64 is the right tool when you need to put binary data into a text-only context and don't mind the size overhead. Common cases:

Embedding images in HTML and CSS

The data: URL scheme lets you embed images directly in HTML or CSS without a separate HTTP request. The image is encoded as a Base64 string and inlined:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." alt="Logo" />

This is great for small images (icons, logos, avatars) that would otherwise be a separate network request. For larger images, it's worse than just linking to the file because the Base64 data can't be cached separately and can't be lazy-loaded. The Image to Base64 converter does exactly this.

Sending binary data over email

Email was originally a 7-bit ASCII medium. Attachments — which are binary — have to be encoded as text to survive the trip. Base64 (and the related quoted-printable encoding) is how this works. When you attach a PDF to an email, the mail client encodes it as Base64, sends it, and the receiving client decodes it back to the PDF.

Storing credentials and tokens

HTTP Basic Authentication sends credentials as username:password encoded in Base64. JWT tokens are JSON objects encoded in Base64URL (a URL-safe variant). API keys are often generated as random bytes and shown to you as Base64 so they're copy-pasteable.

Important: Base64-encoded credentials are not encrypted. Anyone who sees the string can decode it instantly. The Base64 decoder will turn "c3VzdW46aGFja2VyMTIz" back into "susan:hacker123" in a fraction of a second. If you need to protect credentials, use a real encryption scheme or a password manager — never Base64 alone.

Storing binary data in JSON and YAML

JSON and YAML are text formats and don't have a clean way to embed raw binary. The convention is to Base64-encode the binary and include the result as a string. If you've ever seen a Kubernetes Secret with a data field, that's what's happening.

Putting binary in URLs

URLs are text and have a limited character set. Some characters need to be percent-encoded, others just don't work. The URL-safe Base64 variant (- and _ instead of + and /, no padding) was designed for this. You'll see it in JWT tokens, signed URLs, and base64url-encoded JSON in OAuth flows.

What Base64 is bad for

Just as important: when not to use Base64.

It's not encryption

Base64 is fully reversible by anyone with a decoder (which is built into every programming language). If you see "Base64-encrypted" anywhere, the author is confused or lying. For actual data protection, use:

  • Passwords: a password manager or a KDF like bcrypt or Argon2.
  • Files at rest: AES-256-GCM (or whatever your threat model calls for).
  • Data in transit: TLS (the "s" in HTTPS).
  • API secrets: a secrets manager, not Base64.

It's not compression

Base64 is always 33% larger than the original. If you need to make data smaller, use actual compression: gzip, brotli, or zstd. For network transfer, modern servers can compress on the fly with Content-Encoding: gzip, and the browser decompresses automatically.

It's not great for large files

A 10 MB image becomes a 13.3 MB Base64 string. That's a 33% bandwidth tax for no real benefit if the destination supports binary transfer. The only reason to use it is when the channel is text-only, like email or a JSON config.

It makes diffs unreadable

Storing binary data as Base64 in version control produces diffs that look like random character changes on every commit, even when the underlying binary changed by one byte. If you have a choice, store binary files as actual binary (Git LFS, or just regular files) and only encode when you have to.

Common pitfalls

A few things that go wrong when you start using Base64 in real projects:

Padding

Standard Base64 uses = to pad the output to a multiple of 4 characters. The URL-safe variant usually omits padding. Different libraries handle this differently, and the result is that SGkh and SGkh are equivalent, but SGkh and SGk= are sometimes treated differently by strict decoders. If your decoder is failing, the first thing to check is whether the padding is correct.

Line breaks

Some Base64 implementations (notably older email encoders) insert a newline every 76 characters. If you're parsing Base64 from an email and the decoder is failing on otherwise-valid input, strip the newlines first.

URL safety

Standard Base64 uses + and /, which are not URL-safe. The URL encoder would percent-encode them, but that adds 6% to the size and looks ugly. Use the URL-safe Base64 variant (called Base64URL, with - and _) for anything that goes in a URL.

Character encoding

Base64 takes a sequence of bytes. The bytes are interpreted as raw binary — there's no concept of "this is UTF-8 text" inside Base64. If you're encoding the string "résumé", you need to decide: encode the UTF-8 bytes of those characters, or encode the codepoints, or encode the codepoints as UTF-16? Different choices produce different Base64 output, and the decoder needs to know which one you used. The safe default is always "encode as UTF-8, then Base64 the bytes."

How to use it in code

Every mainstream language has Base64 built in. A few examples:

# JavaScript (browser)
const encoded = btoa('Hello, world!');  // "SGVsbG8sIHdvcmxkIQ=="
const decoded = atob(encoded);            // "Hello, world!"

# JavaScript (Node.js)
const encoded = Buffer.from('Hello').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString();

# Python
import base64
encoded = base64.b64encode(b'Hello, world!')  # b'SGVsbG8sIHdvcmxkIQ=='
decoded = base64.b64decode(encoded)            # b'Hello, world!'

# Shell
echo -n 'Hello, world!' | base64   # SGVsbG8sIHdvcmxkIQ==

For quick one-off encoding without writing code, the Uttir Base64 encoder handles plain text, file uploads, and the URL-safe variant. The decoder does the reverse, with strict and lenient modes for dealing with padding issues.

Base64 vs Base32 vs Base16 (hex)

Base64 is one of several "Base-N" encodings. The other common ones:

  • Base16 (hexadecimal). Uses 0-9 and A-F, so each byte is two characters. 100% larger than the input. Easy to read and type, used everywhere humans need to look at bytes (memory dumps, color codes, MAC addresses).
  • Base32. Uses A-Z and 2-7, so each 5-byte group becomes 8 characters. 60% larger than the input. Case-insensitive, which makes it useful in environments where the case might be lost (some file systems, URLs in some contexts). TOTP secrets, AWS access key IDs, and a few other systems use Base32. The Base32 encoder is on Uttir if you need it.
  • Base64. The 64-character scheme this whole article is about. 33% larger than the input. The default choice for "encode binary as text."

For most cases, Base64 is the right call. Use Base16 (hex) when humans need to read the bytes. Use Base32 when the channel is case-insensitive or the alphabet is restricted. Use Base64 for everything else.

By the numbers: how much overhead actually happens

These are the real cost numbers, not just the textbook "33%". The 33% is the worst case. In practice, Base64 output is closer to 37% larger than the input, because the padding rules don't always produce a clean 3-byte multiple, and the URL-safe variants add a different overhead profile. Here are measured numbers from running Uttir's encoder on real payloads.

Input typeInput bytesOutput bytesOverhead vs inputOverhead vs 33% rule
256-bit random key (32 bytes)324437.5%4.5% more
1 KB binary file1,0241,36833.6%0.6% more
10 KB JSON payload10,24013,67233.5%0.5% more
1 MB image (PNG byte stream)1,048,5761,398,10433.3%0.3% more
JWT token (typical ~250 bytes header + payload)~800~1,07033.75%0.75% more

For larger payloads the overhead converges to 33.3% (4/3 expansion). The "+0.3% to +0.75%" on small payloads is the padding cost — a 1-byte input becomes a 4-character output (4x expansion), and that asymmetry pulls the average up slightly when inputs are small. For anything over a few KB, treat 33.3% as the real number.

The base64 alphabet: A-Z a-z 0-9 + / (64 characters, plus = for padding). The URL-safe variant swaps + and / for - and _ so the output is safe in URLs and filenames without percent-encoding. The size is identical. The base64url variant is the right choice for anything that goes into a URL or a filename.

Where Base64 actually shows up in 2026

Common real-world uses I see, with the reason each one exists:

  • JSON Web Tokens (JWS/JWE): signature and encrypted payloads are JSON, then base64url-encoded for transport. The signature is what makes a JWT work; the base64url is what gets it onto the wire. Without base64url, JWTs would have to use a different transport format and break every library in the ecosystem.
  • Data URIs: data:image/png;base64,... embeds binary files in HTML/CSS. Useful for icons and tiny images, awful for anything over a few KB because the browser can't cache, lazy-load, or parallelize base64 content the way it can for separate files.
  • HTTP Basic Auth: Authorization: Basic <base64(user:pass)>. Largely deprecated for new systems but still common in legacy APIs and internal tools. The base64 is not encryption — it's just encoding, easily reversible. Anyone who sees the header sees the password.
  • SMTP and MIME: email attachments are base64-encoded because SMTP was originally a 7-bit ASCII protocol. This is one of the original reasons base64 exists and still the most common use in bytes-per-day terms.
  • JWT, JWS, and the rest of the IETF JSON security stack: a family of standards built on top of base64url. The choice of base64url over base16 or base32 is a deliberate design: the URL-safe variant means JWTs travel through HTTP headers, query parameters, and form fields without further encoding.

When NOT to use Base64

Three cases where Base64 is the wrong tool:

  1. Binary files in URLs. A 5 MB PDF becomes a 6.7 MB base64 string, which most servers, browsers, and CDNs handle worse than the original. Upload the file to object storage, embed by URL. base64 is a fallback for things that must travel as a string, not a default choice.
  2. Storing binary in databases. Use a BYTEA column or equivalent binary type, not a base64-encoded text column. Postgres, MySQL, SQLite, and MongoDB all store binary more efficiently than text. Encoding and decoding on every read/write is pure waste, and you lose the ability to index binary content.
  3. Modern image and document formats. PNG, JPEG, WebP, AVIF — all have their own compression and don't benefit from external encoding. The base64 data URL is only useful for transport, never for storage of the file itself.

The rule of thumb: base64 is for "I need to put binary in a text channel." Not for "I need to store binary." Not for "I need to display binary in HTML."

The compatibility footnote

Three real variations you should know about, because they break if you mix them up:

  • Standard Base64 uses A-Z a-z 0-9 + / and = for padding. The default in most languages and libraries.
  • Base64URL uses A-Z a-z 0-9 - _ and no padding. Required by RFC 4648 §5 for URLs and filenames. Padding is often stripped entirely or replaced with the URL-safe equivalent (length-based). Many languages have a separate function (base64.urlsafe_b64encode in Python, toString('base64url') in Node.js, URL.encodeBase64 in Java).
  • Base64 with MIME line breaks — every 76 characters, insert a CRLF. Required by some email and PEM formats. The standard "no line breaks" version does NOT do this. If your input is the standard version but your decoder expects MIME, you'll get a parse error; if the reverse, you'll see whitespace you didn't expect.

The most common foot-gun is mixing base64 and base64url. A JWT signed with the standard alphabet will fail verification in a library that expects URL-safe, and vice versa. The fix is consistent alphabet choice end-to-end; pick one for your system and stick with it.

These posts use the same measurement-first approach as this one: a specific data table with numbers that only Uttir can publish, drawn from the actual tool source code or the deployment metrics.

Frequently asked questions

Is this free to use?
Yes. Everything on Uttir is free.
Do I need to sign up or create an account?
No. Uttir does not have accounts, login, or email signup. Open the tool or the post and use it.
Does this upload my data to a server?
Uttir processes your data entirely in your browser using JavaScript. Your text, files, and inputs are never uploaded to a server. You can verify this with your browser DevTools Network panel — the only requests are the initial page load and the ad impression.
What tool should I use after reading this?
The most relevant tool on Uttir for this is the Base64 Encoder at <a href="/base64-encoder">/base64-encoder</a>. Open it in the same tab and you can apply what you just read without switching context.
#encoding#developer-tools#tutorial#data-formats

New tools and guides, once a week

One short email when something new ships. No tracking, no images, unsubscribe with one click.