Base64 vs Hex Encoding: When to Use Which? Density vs Readability
When you need to represent binary data as text, Base64 and Hex are the two default choices. Both work, but they differ significantly in density, readability, and the contexts where they shine. Choosing wrong usually isn't fatal, but it inflates storage, complicates debugging, or bloats URL length.
This guide covers how each encoding works under the hood, where each fits, and how to choose. Want to try encoding and decoding both formats yourself? Use the Base64 Decoder: after Encode it shows the same bytes as hex under the output, and Hex → Base64 accepts 0x / colon / space dumps so you can compare density without leaving the page.
The Mechanism
Hex (base-16): each byte is written as two hexadecimal characters (0-9, a-f). The 256 possible byte values map onto these two-character combinations.
byte 0x48 → "48"
byte 0x65 → "65"
byte 0xFF → "ff"
Base64: every 3 bytes are written as 4 Base64 characters (A-Z, a-z, 0-9, +, /). Each character carries 6 bits of data.
3 bytes = 24 bits → 4 six-bit characters
That's where the density difference comes from: Hex packs 4 bits per character, Base64 packs 6.
Density Compared
| Encoding | Chars per byte | Size overhead | Alphabet size |
|---|---|---|---|
| Hex | 2.0 | 100% | 16 |
| Base64 | ~1.33 | 33% | 64 |
For 1 KB of binary data:
- Hex encoded: 2 KB
- Base64 encoded: ~1.33 KB
The gap matters at scale. A 100 MB file becomes 200 MB in hex but only 133 MB in Base64.
Worked Example: Encoding "Hello"
Five bytes of "Hello", encoded both ways:
import base64
data = b"Hello"
# Hex
hex_encoded = data.hex()
# "48656c6c6f" (10 characters)
# Base64
b64_encoded = base64.b64encode(data).decode()
# "SGVsbG8=" (8 characters, including one padding =)
print(f"raw: {len(data)} bytes") # 5
print(f"hex: {len(hex_encoded)} chars") # 10
print(f"base64: {len(b64_encoded)} chars") # 8
Note the = padding. Base64 processes input in 3-byte groups; "Hello" is 5 bytes (one group of 3, one group of 2). The second group has only 2 bytes, so the encoded output gets 1 = to reach a multiple of 4.
Where Hex Wins
1. Readability
Every byte is independently readable, with clear byte boundaries. This is critical when debugging binary protocols:
# Hex: the third byte is visibly 0x6c
48 65 6c 6c 6f
# Base64: byte boundaries are obscured by the 6-bit grouping
SGVsbG8=
2. Case-insensitive in practice
Many systems accept uppercase or lowercase hex interchangeably, simplifying format conventions. Base64 is strictly case-sensitive.
3. Easy manual construction
Short data like color codes, MAC addresses, and memory addresses fits hex naturally:
# Colors are hex
#FFFFFF # white
#FF0000 # red
# MAC addresses use hex with separators
01:23:45:67:89:ab
# Memory addresses
0x7ffeefbff5c8
4. The standard for hash digests
SHA-256, MD5, and similar hash outputs are almost universally displayed in hex:
# SHA-256 produces 32 bytes, shown as 64 hex characters
echo -n "hello" | shasum -a 256
# 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
Base64 would be more compact (44 characters vs 64), but the convention is hex, and every tool expects hex.
Where Base64 Wins
1. Compactness
33% vs 100% overhead. The difference shows up clearly on larger payloads.
2. URL-safe variant available
Standard Base64 uses + and /, which need escaping in URLs. Base64URL substitutes - and _, dropping directly into URLs without escaping:
import base64
# Standard Base64 (URL-unfriendly)
standard = base64.b64encode(b"\xfb\xff") # b'+/8='
# Base64URL (URL-safe)
urlsafe = base64.urlsafe_b64encode(b"\xfb\xff") # b'-_8='
3. Embeds in text formats
JSON, XML, and HTML can't hold raw binary. Base64 packs binary data into a text field:
{
"image": "data:image/png;base64,iVBORw0KGgo..."
}
4. Handles multibyte data gracefully
When hex-encoding a UTF-8 string, each byte is encoded separately, so the output obscures the original structure. Base64 encodes the whole byte stream, yielding a more compact result.
When To Use Hex
- Hash digests: standard representation for SHA-256, MD5, HMAC outputs
- Cryptographic keys and IVs: easy manual comparison during debugging
- Binary protocol debugging: network protocols, file formats, serialized data
- Short binary values: colors, MAC addresses, UUIDs, memory addresses
- Blockchain and cryptocurrency: addresses, transaction hashes, block hashes
When To Use Base64
- Data URIs: images and fonts embedded in HTML or CSS
- JWT: all three segments are Base64URL
- Email attachments: MIME uses Base64 for binary attachments
- Large binary payloads: storage and bandwidth savings add up
- Binary fields in JSON or XML: API responses that embed binary
Performance Notes
Encoding speed is comparable between the two and rarely the bottleneck. But Base64 decoding requires careful padding handling; malformed padding breaks decoding. Hex decoding is simpler, just map every two characters to one byte.
# Command-line encoding
echo -n "Hello" | xxd -p # hex: 48656c6c6f
echo -n "Hello" | base64 # base64: SGVsbG8=
Hex input hygiene (prefixes and separators)
Real-world hex rarely arrives as a clean even-length string:
| Form | Example | Risk if you strip badly |
|---|---|---|
0x prefix | 0x48656c6c6f | Leaving 0x in the decoder → non-hex error |
| Colon MAC | 01:23:45:67:89:ab | Treating : as data |
| xxd / dumps | 48 65 6c 6c 6f | Spaces counted as characters |
| Uppercase digests | 2CF24DBA… | Fine if decoder is case-insensitive |
Paste those into Hex → Base64 on the Base64 tool to get SGVsbG8= (for Hello) and confirm round-trips. For integer values (not opaque byte strings), use the Number Base Converter instead — it treats digits as a single big integer, which is the wrong model for binary blobs.
When protocols mix both
TLS and crypto libraries often store keys as Base64 PEM but print fingerprints as hex. JWT segments are Base64URL; many debug UIs re-show the decoded header bytes as hex. Mixing the two without a clear “these are the same bytes” check is how SGVsbG8= and 48656c6c6f get treated as different secrets. Habit: encode once, display both views from the same buffer (the tool’s hex companion line does exactly that).
Fingerprint workflows: hash with the SHA-256 Hash Generator (hex digest is the convention), then only Base64-encode if an API field requires it — do not Base64 the hex text.
Do It In Your Browser
Whether you're decoding a Base64 field from an API response, converting an image to a data URI, or shifting a number between hex and decimal, you should not be sending data to an unfamiliar server.
The Base64 Decoder, Number Base Converter, and SHA-256 Hash Generator tools all run entirely in your browser. Your binary data, API responses, and configuration snippets never leave your machine. That matters most when you're encoding content with embedded credentials, user data, or proprietary source.
The short version: reach for hex when debugging, working with short data, or displaying hash digests. Reach for Base64 when embedding in text formats, handling large payloads, or working in URL contexts. Each has its strengths, and understanding the density-vs-readability tradeoff tells you which fits.
Triage notes
The selection table assigns hash digests to hex rather than the denser Base64 (64 vs 44 characters), and says so openly: industry convention and tooling are built around hex — density is not the only criterion. The first listed hex advantage is readability: each byte reads out individually with clean boundaries, while Base64's 6-bit grouping scrambles byte boundaries, the decisive difference when debugging binary protocols. The "mixed encodings in one protocol" section captures a real trap: TLS stores keys as Base64 PEM but prints fingerprints in hex, and without checking both views of the same buffer, the two outputs get treated as two different secrets — the Hex comparison row under the tool output exists precisely for that check.
Related Tools
Related Articles
JPG to WebP: When It's Worth It, and How to Convert Without Losing Quality
How much smaller is WebP than JPG, when you should NOT convert, and which quality setting to pick? The decision criteria, browser-local conversion walkthrough (no uploads), and a WebP/JPG/PNG selection table.
PDF to JPG: How to Pick the Right Resolution (DPI Guide + 3 Ways)
A complete guide to converting PDF pages to JPG: how DPI maps to sharpness, two-page and batch conversion, three approaches compared (in-browser local, command line, desktop software), plus a quality settings cheat sheet.
PDF Too Large for Email? How to Choose the Right Compression Quality (3 Local Levels)
How PDF compression works: lossy rasterization vs. lossless structure optimization, which of the three quality levels fits which use, and how to compare sizes before and after — entirely in your browser.