Hex and Base64 both turn binary into printable text. They solve different problems. Teams that treat them as synonyms create oversized payloads, unreadable logs, or APIs that nobody can debug.
This article compares the two encodings the way you actually choose them in product work: size, readability, ecosystem defaults, and failure modes. Convert hex samples with Hex to String / String to Hex while you decide.
Side-by-side
| Hex | Base64 | |
|---|---|---|
| Alphabet | 0-9A-F | A-Za-z0-9+/ (+ padding =) |
| Size vs raw bytes | ~2× | ~4/3 ≈ 1.33× |
| Byte alignment in text | Excellent (2 chars = 1 byte) | Poor (4 chars = 3 bytes) |
| Debugging by eye | Strong | Weak |
| Typical homes | dumps, digests, colors, opcodes | JSON, email, data URLs, many HTTP APIs |
What hex is optimized for
Hex keeps a direct map to bytes. When you see FF D8 FF, you can talk about those three bytes without mental gymnastics. That is why hex dominates:
- Memory and packet dumps
- Cryptographic digests displayed to humans
- CSS colors (
#RRGGBB) - Instruction encodings and firmware notes
SHA-256 digest (hex):
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
People compare hex digests visually. Doing the same with Base64 is possible but uncommon in release notes.
What Base64 is optimized for
Base64 packs more binary into fewer characters and stays inside a safe ASCII subset for protocols that dislike raw bytes. Use it when:
- You embed binary inside JSON or XML.
- You put bytes into HTML attributes or email bodies.
- An API contract already mandates Base64 (JWT segments, many cloud SDKs).
Base64 is a transport encoding. It is not smaller than the original binary file on disk—only smaller than hex text.
Decision guide
- Need to debug or document bytes? → hex.
- Need compact text inside JSON/HTTP? → Base64.
- Need a human-compared fingerprint? → hex (usually lowercase).
- Already stuck with one format in a standard? → follow the standard; do not dual-encode.
Anti-patterns
- Hex is not encryption. Neither is Base64. Both are reversible encodings.
- Base64(hex(data)) stacks two encodings and helps nobody.
- Storing every DB blob as hex doubles size versus binary columns. Prefer BLOB/bytea; use hex at the edges.
- Logging Base64 for binary protocols when engineers need byte offsets—switch those logs to hex.
Worked example: same 5 bytes
Bytes: 48 65 6c 6c 6f ("Hello")
Hex: 48656c6c6f
Base64: SGVsbG8=
For five bytes, Base64 wins on size. For a 64-byte hash shown on a status page, hex usually wins on familiarity.
Language footnotes
- Python:
b.hex()/bytes.fromhexvsbase64.b64encode. - PHP:
bin2hex/hex2binvsbase64_encode. - JS/Node:
Buffer...(hex)vsbase64.
Deep dives: Python hex methods · PHP hex guide.
Migration tips if you picked wrong once
If an API already ships hex and you want Base64 (or the reverse), convert at the boundary—do not change historical rows in place without a version field.
- Add a
encodingfield (hex|base64) or bump an API version. - Accept both during a transition window.
- Emit only the new form after clients upgrade.
- Keep raw binary in storage when you control the database; encode only on the wire.
import base64
def hex_to_b64(h: str) -> str:
return base64.b64encode(bytes.fromhex(h)).decode("ascii")
def b64_to_hex(s: str) -> str:
return base64.b64decode(s).hex()
FAQ
Can I convert hex to Base64 without knowing the original file?
Yes: hex → bytes → Base64. You are changing representation, not meaning.
Which should JWT use?
JWT uses Base64url. Do not replace it with hex unless you control a private token format.
Is hex safer than Base64?
No. Safety comes from cryptography and access control, not from the printable encoding.
Related: odd-length pitfalls · file magic numbers · hex overview.