Base64 vs Hex Encoding: Data Formats Compared

8 minMay 24, 2026

Base64 vs Hex: The Core Tradeoff

The base64 vs hex encoding choice comes down to one question: do you need compactness or readability? Hex encoding converts each byte into two hexadecimal characters (00-FF), producing output that's exactly 2× the input size. Base64 converts every 3 bytes into 4 characters, producing output that's 1.33× the input size. For a 1 MB file: hex gives you 2 MB, Base64 gives you 1.33 MB. Base64 wins on size; hex wins on simplicity.

Hex is easier to read and debug. Each byte maps to exactly two characters, so you can visually parse the data byte by byte. The hex string "48656c6c6f" is clearly 5 bytes, and you can look up each pair in an ASCII table (48=H, 65=e, 6c=l, 6c=l, 6f=o). Base64's "SGVsbG8=" is more compact but you can't eyeball individual bytes — the 6-bit grouping crosses byte boundaries.

Both are text-safe encodings — they convert arbitrary binary data into printable ASCII characters. The difference is the character set: hex uses 16 characters (0-9, a-f), Base64 uses 64 characters (A-Z, a-z, 0-9, +, /). More characters per symbol means more information per character, which is why Base64 is more compact. It's the same principle as why base-10 numbers are shorter than binary numbers.

When to Use Hex Encoding

Hash outputs: SHA-256 produces 32 bytes. As hex, that's 64 characters: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855". Every hash tool, every documentation, every API uses hex for hash values. It's the universal convention. Our hash-generator tool outputs hex by default because that's what developers expect to see and compare.

Debugging binary protocols: When you're looking at network packets, file headers, or memory dumps, hex is the standard representation. Wireshark shows hex. Hex editors show hex. The first bytes of a PNG file are "89504e47" — you can memorize these magic numbers. In Base64, the same bytes would be "iVBORw==" which is less recognizable and harder to search for in documentation.

Color codes: CSS colors (#FF6B35), MAC addresses (00:1A:2B:3C:4D:5E), and UUIDs (550e8400-e29b-41d4-a716-446655440000) all use hex because each component maps cleanly to bytes. A color is 3 bytes (RGB), a MAC address is 6 bytes, a UUID is 16 bytes. Hex preserves this byte-level structure visually.

Small binary values: For data under ~100 bytes (cryptographic keys, short binary identifiers, protocol headers), hex's 2× overhead is acceptable and the readability advantage is worth it. For a 32-byte encryption key, hex gives you 64 characters vs Base64's 44 characters. The 20-character difference rarely matters, but being able to visually verify "yes, that's 32 bytes" by counting 64 hex chars is useful during development.

When to Use Base64 Encoding

Email attachments (MIME): The original use case. SMTP is 7-bit ASCII, so binary attachments must be text-encoded. Base64's 33% overhead beats hex's 100% overhead significantly for multi-megabyte files. Every email attachment you've ever sent uses Base64. The MIME standard (RFC 2045) specifies Base64 with line breaks every 76 characters.

Embedding binary in JSON/XML: When an API needs to include an image, file, or binary blob in a text-based format, Base64 is the standard. AWS S3 presigned POST policies use Base64-encoded JSON. JWTs encode their payload as Base64url. Data URIs in HTML (data:image/png;base64,...) embed images directly in markup. The 33% overhead is the cost of text-safety.

Large binary data in text contexts: For anything over a few hundred bytes where size matters, Base64 wins. A 100 KB image as hex is 200 KB; as Base64 it's 133 KB. Over a network connection, that 67 KB difference adds up. Our base64-encoder tool handles files up to 50 MB and shows the encoded size so you can evaluate the overhead.

Authentication tokens and cookies: OAuth tokens, session IDs, and API keys often use Base64 or Base64url encoding. The compact representation fits better in HTTP headers (which have practical size limits around 8 KB) and cookies (4 KB limit per cookie). Base64url (using - and _ instead of + and /) is specifically designed for URL-safe contexts without additional percent-encoding.

URL Encoding: The Special Case

URL encoding (percent-encoding) isn't really a binary-to-text encoding — it's a text-to-text encoding that makes strings safe for URLs. Each unsafe byte becomes %XX (percent sign + two hex digits). A space becomes %20, an ampersand becomes %26, a Chinese character (3 UTF-8 bytes) becomes %E4%B8%AD. The overhead varies wildly: ASCII letters have 0% overhead, but a string of all special characters triples in size.

URL encoding is context-specific. In a URL path, / is structural (don't encode it). In a query parameter value, / is data (encode it). In a fragment, almost nothing needs encoding. This context-dependence makes URL encoding fundamentally different from Base64 or hex, which encode everything uniformly regardless of context. See our url-encoder tool for interactive encoding with context selection.

When URL encoding meets Base64: if you need to put Base64 data in a URL, standard Base64's + and / characters need percent-encoding (%2B and %2F). This is why Base64url exists — it replaces + with - and / with _ to avoid this double-encoding. JWTs use Base64url specifically because they appear in URLs and HTTP headers. Always use Base64url (not standard Base64) for data that will travel in URLs.

Size comparison for a typical use case: encoding the binary string "Hello, World! 你好" (19 UTF-8 bytes). Hex: 38 characters. Base64: 28 characters. URL-encoding: "Hello%2C%20World%21%20%E4%BD%A0%E5%A5%BD" = 41 characters. URL encoding is the worst for binary data because it encodes each byte as 3 characters (%XX) while leaving ASCII letters unencoded — the overhead depends entirely on the input content.

Raw Binary: When Text Encoding Is Wrong

Sometimes the answer is "don't encode at all." If both the sender and receiver can handle binary data, text encoding adds unnecessary overhead and processing time. HTTP responses with Content-Type: application/octet-stream send raw bytes. WebSocket binary frames send raw bytes. File uploads with multipart/form-data send raw bytes. Protocol Buffers and MessagePack are binary serialization formats that are smaller and faster than JSON+Base64.

The rule: use text encoding (Base64, hex) only when the transport channel requires text. Email (SMTP) requires text → use Base64. JSON payloads require text → use Base64 for binary fields. URL parameters require text → use URL-encoding or Base64url. But HTTP bodies, WebSocket messages, gRPC calls, and file I/O all support binary natively — encoding binary data for these channels wastes bandwidth and CPU.

Performance comparison: encoding 1 MB of binary data. Base64 encoding takes ~2ms and produces 1.33 MB. Hex encoding takes ~3ms and produces 2 MB. Sending raw binary takes 0ms encoding time and produces 1 MB. For a REST API returning a 5 MB image, Base64-encoding it into JSON costs 6.67 MB transfer + encoding/decoding CPU time. Serving it as a separate binary response costs 5 MB transfer + zero encoding overhead. The choice is obvious for large payloads.

Hybrid approach: use JSON for metadata and binary for payloads. A common pattern: the API returns JSON with a URL pointing to the binary resource, which the client fetches separately. This gives you structured metadata (title, size, content-type) in a text-friendly format plus efficient binary transfer for the actual data. Every CDN, object storage service, and media platform uses this pattern.

Comparison Table and Decision Guide

Size overhead: Raw binary = 0%. Base64 = 33%. Hex = 100%. URL-encoding = 0-200% (depends on content). For size-sensitive applications (mobile APIs, embedded systems, high-throughput services), minimize encoding overhead by using binary transport when possible and Base64 when text encoding is required.

Readability: Hex is most readable for developers (byte-aligned, familiar from debugging tools). Base64 is compact but opaque (can't visually parse individual bytes). URL-encoding is readable for ASCII text but ugly for binary. Raw binary is unreadable without a hex viewer. Choose based on whether humans need to inspect the data during development and debugging.

Compatibility: URL-encoding works in URLs (by definition). Base64 works in JSON, XML, email, and most text contexts. Hex works everywhere text works but is rarely the standard choice for large data. Raw binary works in HTTP bodies, WebSocket, files, and binary protocols but not in JSON or URLs. Match the encoding to your transport channel's requirements.

My decision tree: Is the transport binary-capable? → Use raw binary. Is it a URL? → Use URL-encoding for text values, Base64url for binary values. Is it JSON/XML? → Use Base64 for binary fields. Is it for debugging/display? → Use hex. Is it a hash or cryptographic value? → Use hex (convention). Is it an email attachment? → Use Base64 (MIME standard). When in doubt, Base64 is the safest default for binary-in-text scenarios.

Encoding comparison for 16 bytes of binary data (a UUID):

Raw binary:  16 bytes (not displayable as text)
Hex:         "550e8400e29b41d4a716446655440000" (32 chars)
Base64:      "VQ6EAOKbQdSnFkRmVUQAAA==" (24 chars)
Base64url:   "VQ6EAOKbQdSnFkRmVUQAAA" (22 chars, no padding)

Encoding comparison for 1 KB of binary data:

Raw binary:  1,024 bytes
Hex:         2,048 characters (+100%)
Base64:      1,368 characters (+33%)
URL-encoded: ~3,072 characters (+200%, worst case)

Speed (encoding 10 MB, Node.js on M1 Mac):
  Buffer.toString('hex'):    ~8ms
  Buffer.toString('base64'): ~5ms
  No encoding (raw):         ~0ms

Common Mistakes When Choosing Encoding Formats

Mistake 1: Base64-encoding data that's already text. If you have a JSON string and you Base64-encode it before putting it in another JSON field, you've added 33% overhead for no benefit. JSON can contain JSON (as an escaped string or nested object). Only Base64-encode actual binary data (images, files, cryptographic material). Text data should stay as text.

Mistake 2: Using hex for large binary payloads. A 10 MB file as hex is 20 MB — that's 10 MB of pure waste compared to Base64 (13.3 MB) or raw binary (10 MB). Hex is for display and debugging, not for data transfer. If you're sending hex-encoded files over an API, switch to Base64 or binary and save 33-50% bandwidth immediately.

Mistake 3: Mixing encoding formats in the same system. I've seen APIs that return some binary fields as hex and others as Base64, with no documentation about which is which. Pick one format for all binary data in your API and document it clearly. Consistency prevents bugs where a consumer decodes hex as Base64 (or vice versa) and gets garbage.

Mistake 4: Not considering the decode cost. Encoding and decoding aren't free — they consume CPU and memory. For a high-throughput service processing millions of requests, the cumulative cost of Base64 encoding/decoding can be significant. If you're encoding data just to put it in JSON and then immediately decoding it on the other end, consider whether a binary protocol (gRPC, MessagePack, Protocol Buffers) would eliminate this overhead entirely.