Base64 and hexadecimal (Base16) both solve the same fundamental problem: transmitting raw binary data across network protocols, databases, and formats that only safely handle printable ASCII text.
Choosing the right format depends on whether your priority is human readability, byte inspection, or payload size optimization.
The Mathematical Difference#
| Metric | Hexadecimal (Base16) | Base64 (RFC 4648) |
|---|---|---|
| Bits per Character | 4 bits (2^4 = 16) | 6 bits (2^6 = 64) |
| Characters per Byte | Exactly 2 characters | ~1.33 characters (4 chars per 3 bytes) |
| Size Overhead | +100% (2x original size) | +33.3% (1.33x original size) |
| Character Set | 0-9, a-f / A-F | A-Z, a-z, 0-9, +, /, = |
| Case Sensitivity | Case-insensitive | Case-sensitive |
| URL-Safe Variant | Naturally URL-safe | Requires Base64Url (- and _) |
When to Choose Hexadecimal#
Hexadecimal represents each byte as exactly two characters (00 to FF). This direct 1:1 byte mapping makes Hex ideal for:
- 1Cryptographic Hashes & Checksums: SHA-256, MD5, and Git commit hashes are standardly formatted in hex because each byte is immediately inspectable.
- 2Memory Dumps & Low-Level Protocols: Reading binary file headers (e.g.
89 50 4E 47for PNG files orFF D8 FFfor JPEG). - 3MAC Addresses & UUIDs: Hardware identifiers where byte grouping matters.
- 4Color Representations: Web colors map red, green, blue, and alpha directly to two hex digits each (
#FF5733).
When to Choose Base64#
Base64 packs 3 raw bytes (24 bits) into 4 printable ASCII characters. It saves significant bandwidth over Hex and is the standard for:
- 1Data URLs: Embedding inline images, fonts, or SVGs in HTML and CSS (
data:image/png;base64,...). - 2Email Attachments (MIME): Standard transport for email binaries.
- 3JWT Segments: Compact transmission of JSON claims in HTTP headers.
- 4API Payloads: Embedding encrypted blobs, certificates, or serialized protobufs inside JSON strings.
High-Performance Browser Conversion#
You can convert between binary, hex, and base64 efficiently using modern Typed Arrays:
// Uint8Array to Hex string
function bytesToHex(bytes: Uint8Array): string {
return Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
}
// Uint8Array to Base64 string
function bytesToBase64(bytes: Uint8Array): string {
let binary = '';
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}Important: Neither Encoding Is Encryption!#
This distinction is crucial: Base64 and Hex provide zero confidentiality or security. Anyone with access to the encoded string can reverse it to raw bytes in microseconds without a key. If data must remain secret, encrypt it using AES-GCM or RSA first, then encode the resulting ciphertext for transport.