Base64 vs Hex Encoding: When to Use Each (with Examples)
Both Base64 and hexadecimal are ways to represent binary data as readable text - but they make very different trade-offs. Choosing the wrong one for your use case increases payload size, breaks URLs, or makes debugging harder than it needs to be.
The Core Problem: Binary Data in Text Systems
Computers store everything as bytes: sequences of 0s and 1s grouped into 8-bit values ranging from 0 to 255. When you need to transmit or store binary data - a cryptographic hash, an image, a private key - in a system that was designed for human-readable text, you need to encode it first.
Two encoding schemes dominate in software development: hexadecimal (hex) and Base64. They solve the same problem but in different ways, and understanding the trade-offs is essential for making the right choice in your code.
How Hexadecimal Encoding Works
Hexadecimal uses 16 symbols: the digits 0-9 and letters a-f (or A-F). Each symbol represents exactly 4 bits (a "nibble"). Since one byte is 8 bits, every byte becomes exactly two hex characters:
// Binary byte: 11001010 (decimal 202)
// Split into two nibbles: 1100 = 12 = 'c', 1010 = 10 = 'a'
// Hex: "ca"
// Practical example: SHA-256 hash in hex
const crypto = require('crypto');
const hash = crypto.createHash('sha256').update('hello').digest('hex');
// "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
// 64 hex chars = 32 bytes
The math is simple: each byte produces 2 characters, so hex encoding always produces output that is exactly twice the size of the input - a 100% overhead.
How Base64 Encoding Works
Base64 uses 64 symbols: A-Z, a-z, 0-9, +, and / (plus the = padding character). The algorithm groups the input into 3-byte chunks (24 bits) and maps each chunk to four 6-bit values, each represented as one Base64 character:
// 3 input bytes → 4 Base64 characters
// Each 6-bit group maps to one of 64 characters
// Example: "Man" → 3 bytes → 4 Base64 chars
// M = 01001101, a = 01100001, n = 01101110
// 6-bit groups: 010011, 010110, 000101, 101110
// Base64 chars: T, W, F, u → "TWFu"
Buffer.from('Man').toString('base64'); // "TWFu"
Because 3 bytes become 4 characters, Base64 encoding produces output that is 4/3 the size of the input - approximately 33% overhead. If the input length is not divisible by 3, = padding characters are added to make the output length a multiple of 4.
Size Comparison: The Numbers
| Input size | Hex output | Base64 output | Base64 savings vs Hex |
|---|---|---|---|
| 16 bytes (MD5) | 32 chars | 24 chars | 25% smaller |
| 32 bytes (SHA-256) | 64 chars | 44 chars | 31% smaller |
| 64 bytes (SHA-512) | 128 chars | 88 chars | 31% smaller |
| 1,000 bytes | 2,000 chars | 1,368 chars | 32% smaller |
| 1 MB | 2 MB | ~1.37 MB | 32% smaller |
Base64 is always more compact than hex. For the same binary input, Base64 produces output that is roughly 25-33% smaller. This matters for large payloads like file uploads in JSON APIs or embedded image data URIs.
A SHA-256 hash in hex is 64 characters. In Base64 it is 44 characters. For a system that stores millions of hashes in a database, the column choice matters for both storage and index performance.
Readability and Human Usability
This is where hex wins. Consider a SHA-256 hash:
// Hex: 64 characters, easy to read and copy
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
// Base64: 44 characters, but less intuitive
LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=
Hex has several readability advantages:
- Every two characters map to exactly one byte - it is trivial to count bytes visually or parse them manually
- Only digits and a-f - no ambiguity between similar-looking characters (unlike Base64 where
l,I, and1can be confused in some fonts) - Human-recognizable patterns: color codes (
#ff5500), MAC addresses (00:1a:2b:3c:4d:5e), and UUID segments are all conventionally expressed in hex - Easier to compare: Two hex hashes can be visually compared starting from the left and spotting the first differing byte pair
URL and Transport Safety
Hex is completely URL safe: the characters 0-9 and a-f require no percent-encoding in any URL context. Standard Base64 is not URL safe because + and / have special meaning in URLs. There is a URL safe variant called Base64url that replaces these with - and _.
- Hex in URLs: Always safe, no conversion needed
- Standard Base64 in URLs: Requires percent-encoding or the Base64url variant
- Base64url in URLs: Safe, but requires explicit use of the url-safe alphabet
Code Examples: Encoding the Same Data Both Ways
JavaScript (Node.js)
const data = Buffer.from('Hello, World!');
// Hex encoding
const hex = data.toString('hex');
console.log(hex); // "48656c6c6f2c20576f726c6421"
// 26 chars for 13 bytes
// Base64 encoding
const b64 = data.toString('base64');
console.log(b64); // "SGVsbG8sIFdvcmxkIQ=="
// 20 chars for 13 bytes (including 2 padding chars)
// Decode hex
const fromHex = Buffer.from(hex, 'hex').toString();
// "Hello, World!"
// Decode Base64
const fromB64 = Buffer.from(b64, 'base64').toString();
// "Hello, World!"
Python
import base64, binascii
data = b"Hello, World!"
# Hex encoding
hex_str = binascii.hexlify(data).decode('ascii')
print(hex_str) # "48656c6c6f2c20576f726c6421"
# Base64 encoding
b64_str = base64.b64encode(data).decode('ascii')
print(b64_str) # "SGVsbG8sIFdvcmxkIQ=="
# Decode back
assert binascii.unhexlify(hex_str) == data
assert base64.b64decode(b64_str) == data
Convert Between Base64, Hex, and More
Our free Base64 tool encodes and decodes instantly in your browser. For hex conversion, try the Number Base Converter.
Open Base64 Tool →Real-World Use Cases: When to Choose Which
Use Hex When:
- Displaying cryptographic hashes to users: SHA-256, MD5, Git commit SHAs are conventionally shown in hex (
a3f8b2...). Users expect and recognize this format. - Color codes: HTML/CSS colors are hex (
#FF5500). This is an established universal convention. - Network addresses: MAC addresses (
00:1A:2B:3C:4D:5E) and IPv6 addresses are hex by convention. - Debugging binary data: Hex dumps are the standard for inspecting raw bytes in debuggers, network captures (Wireshark), and hex editors.
- Database storage of hashes or binary IDs: Many databases store hash columns as
VARCHAR(64)in hex for readability, or as aBINARY(32)column (raw bytes, no overhead). - Protocol specifications: Many binary protocols (TLS, SSH, Bluetooth) document field values in hex.
Use Base64 When:
- Embedding binary files in JSON: JSON cannot contain raw binary. Base64 is the standard way to embed images, PDFs, or certificates in JSON API responses.
- Data URIs: Inline images in HTML use Base64:
src="data:image/png;base64,..." - Email attachments: MIME email encodes attachments as Base64, which is what Base64 was originally designed for.
- JWT tokens and OAuth: JWTs use Base64url (the URL safe variant) for all three token parts.
- HTTP Basic Auth: The
Authorization: Basicheader value isBase64(username:password) - Large binary payloads: When transferring a 1MB file, Base64 produces 1.37MB while hex produces 2MB - a significant difference in bandwidth-constrained environments.
- Kubernetes and Docker secrets: Kubernetes Secrets encode values in Base64. Docker image layers use Base64 in their JSON manifests.
Quick Decision Guide
- Showing a hash to a developer or in a log? → Hex
- Embedding an image in a JSON API response? → Base64
- Storing a hash in a database? → BINARY column (raw bytes) or hex string
- A token in a URL or JWT? → Base64url
- A color or MAC address? → Hex (convention)
- Transmitting large binary data over a text channel? → Base64 (smaller output)
FAQ
Can you convert between hex and Base64?
Yes, both are just different text representations of the same underlying bytes. In Node.js: Buffer.from(hexString, 'hex').toString('base64') converts hex to Base64. In reverse: Buffer.from(b64String, 'base64').toString('hex').
Which is more secure: hex or Base64?
Neither provides any security. Both are reversible encodings with no key. Security comes from the underlying data (e.g., the entropy of a random token) and any cryptographic algorithm applied before encoding, not from the encoding format itself.
Why does Base64 sometimes end with == or =?
Base64 encodes 3 bytes at a time into 4 characters. If the input length is not a multiple of 3, padding characters (=) are added to make the output length a multiple of 4. One = means one extra padding byte; == means two extra padding bytes. A string with neither is a multiple of 3 bytes exactly.
Why is hex used for Git commit SHAs and not Base64?
Readability and convention. Hex SHAs are shorter to copy from a terminal, unambiguous to compare, and have no special URL characters. A Base64 SHA would be shorter (27 chars vs 40) but harder to recognize and type. Git values human usability over space efficiency for display purposes.
Is there an overhead-free way to store binary data in text?
No lossless text encoding of binary data is without overhead. The theoretical minimum is about 6 bits per character for ASCII (log2(64)), which is what Base64 achieves. Binary columntypes in databases (e.g., BYTEA in PostgreSQL, BLOB in MySQL) store raw bytes without overhead, which is the right choice when you control the storage format.
Use our free tool here → Base64 Encoder / Decoder on SecureBin.ai
Usman has 10+ years of experience securing enterprise infrastructure, managing high-traffic servers, and building zero-knowledge security tools. Read more about the author.