Upload a file
  1. base64hub
  2. Learn Base64
  3. Base64 vs other encodings
Explainer

Base64 vs Hex, Base32, Base58 and Base85 Compared

Every binary-to-text encoding trades size against readability and the set of characters it is allowed to use. Here is the same input in nine of them, with their size overhead and character sets.

Comparison table

All of these encodings turn arbitrary bytes into printable text and back without loss. They differ in how many characters they use, which characters, and how much bigger the output gets.

EncodingAlphabetOutput sizeCase-sensitiveURL-safeTypical uses
Hex (Base16)0-9 a-f200%NoYesHashes, MAC addresses, byte dumps, color codes
Base32 (RFC 4648)A-Z 2-7, pad =160%No (uppercase by spec)Yes, without =TOTP secrets, Tor onion addresses, DNSSEC (base32hex)
Base58 (Bitcoin)1-9 A-Z a-z minus 0 O I labout 137%YesYesBitcoin addresses, IPFS CIDv0 (Qm…), Solana keys
Base64A-Z a-z 0-9 + /, pad =133%YesNoEmail attachments, data URIs, PEM, JSON payloads
Base64URLA-Z a-z 0-9 - _133%YesYesJWT, URL tokens, file names
Ascii85! to u, plus z125%YesNoPDF and PostScript streams
Z8585 chars incl. .-:+=^!/*?&<>()[]{}@%$#125%YesNoZeroMQ CURVE keys
Base45 (RFC 9285)0-9 A-Z, space, $%*+-./:150%No (uppercase only)NoQR codes, EU Digital COVID Certificates

“Output size” is the encoded length as a share of the input length, for large inputs. Base64 needs 4 characters per 3 bytes, Base32 needs 8 per 5, Base85 needs 5 per 4, Base45 needs 3 per 2. Base58 has no fixed block size, so its ratio is log(256) / log(58), about 1.366. For the exact numbers on a specific input, the size calculator shows all of them at once.

The same input in each encoding

Here is the 12-byte ASCII string Hello world! encoded nine ways. Twelve bytes is a multiple of 3 and 4, so Base64 and the Base85 variants need no padding.

EncodingOutputLength
Hex48656c6c6f20776f726c642124
Base32JBSWY3DPEB3W64TMMQQQ====24 (20 without padding)
Base32hex91IMOR3F41RMUSJCCGGG====24
Base58 (Bitcoin alphabet)2NEpo7TZRhna7vSvL17
Base64SGVsbG8gd29ybGQh16
Base45%69 VD82EK4F.KESTC18
Ascii8587cURD]j7BEbo8015
Z85nm=QNzY<mxA+]nf15
Base85 (RFC 1924 / git)NM&qnZy<MXa%^NF15

Base64URL is identical to Base64 here because the output contains no + or /. The difference only shows up for certain bytes: fb ef be is ++++ in Base64 and ---- in Base64URL.

Python’s standard library covers most of the table. z85encode was added in Python 3.13:

import base64

data = b"Hello world!"
print(data.hex())                           # 48656c6c6f20776f726c6421
print(base64.b32encode(data).decode())      # JBSWY3DPEB3W64TMMQQQ====
print(base64.b64encode(data).decode())      # SGVsbG8gd29ybGQh
print(base64.a85encode(data).decode())      # 87cURD]j7BEbo80
print(base64.b85encode(data).decode())      # NM&qnZy<MXa%^NF
print(base64.z85encode(data).decode())      # nm=QNzY<mxA+]nf

Base58 is not in the standard library, but it fits in a few lines because it is plain base conversion of one big integer:

B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

def b58encode(data: bytes) -> str:
    n = int.from_bytes(data, "big")
    out = ""
    while n:
        n, r = divmod(n, 58)
        out = B58[r] + out
    zeros = len(data) - len(data.lstrip(b"\0"))
    return "1" * zeros + out

print(b58encode(b"Hello world!"))   # 2NEpo7TZRhna7vSvL
print(b58encode(b"\0\0\x01"))       # 112

Each leading zero byte becomes a literal 1, because a big integer has no way to remember leading zeros. That is why every legacy Bitcoin address that starts with a zero version byte begins with 1.

Where each encoding is used

Hex

Hex spends two characters per byte, which makes it the largest option here and the easiest to read. Each character maps to exactly 4 bits, so the byte at offset n always sits at characters 2n and 2n+1. That property is why hashes, checksums and debug dumps are almost always hex. Decoders accept both DEADBEEF and deadbeef. Convert with Base64 to hex and hex to Base64.

Base32

Base32 uses only uppercase letters and the digits 2 to 7. It survives case-insensitive systems (DNS names, some file systems, people typing codes into a phone), and it avoids 0, 1 and 8, which look like O, I and B. Authenticator apps store TOTP secrets in Base32, and Tor v3 onion addresses are 56 lowercase Base32 characters. RFC 4648 also defines base32hex (0-9 A-V), which keeps the sort order of the original bytes. Try the Base32 encoder.

Base58

Base58 started with Bitcoin. It removes 0, O, I and l (easy to confuse) and + and / (which break double-click selection and URLs). Bitcoin addresses add a version byte and a 4-byte checksum on top, a format called Base58Check. IPFS CIDv0 hashes are Base58 too, and since they start with the multihash bytes 12 20, they always begin with Qm. Because the whole input is treated as one number, conversion time grows quadratically with length, so Base58 is used for short values such as keys and hashes. Try the Base58 encoder.

Ascii85, Z85 and git’s Base85

The Base85 family packs 4 bytes into 5 characters, the densest of the widely supported encodings. The catch is the alphabet: 85 printable characters means quotes, backslashes, <, > or &, depending on the variant.

  • Ascii85 (Adobe) uses ! through u, wraps output in <~ and ~> and writes four zero bytes as a single z. PostScript and PDF (the ASCII85Decode filter) use it.
  • Z85 (ZeroMQ) picks characters that are safe inside C and JSON string literals, with no quotes or backslash. It requires the input length to be a multiple of 4. A 32-byte CURVE key is 40 characters.
  • RFC 1924 Base85 was an April Fools’ proposal for IPv6 addresses. Its alphabet lives on in git binary patches and in Python’s b85encode.

The Base85 tool handles all three; Z85 has its own page.

Base45

Base45 exists for QR codes. A QR code’s alphanumeric mode stores exactly 45 characters (digits, uppercase letters, space and $%*+-./:) at 5.5 bits each, against 8 bits per character in byte mode. Base45 turns 2 bytes into 3 of those characters, which costs about 3% inside the QR code. Base64 text has to use byte mode and costs 33%. The EU Digital COVID Certificate used Base45 for exactly this reason. Try the Base45 encoder.

How to choose

Pick the encoding the receiving side expects. A JWT library wants Base64URL, an authenticator app wants Base32, a Bitcoin wallet wants Base58Check. When you control both ends, these rules of thumb hold:

  • Bytes inside JSON, XML, email or HTTP bodies: Base64. Every language has a fast built-in implementation, and 33% overhead is acceptable.
  • Inside a URL, cookie or file name: Base64URL without padding.
  • People will read, type or compare the value: hex for short hashes, Base32 when case may be lost, Base58 when it should look compact and have no look-alike characters.
  • Every byte counts and you control the decoder: Z85 or Ascii85.
  • QR codes: Base45.

The tradeoff is always the same: a bigger alphabet gives shorter output and more characters that need escaping somewhere. For background on why Base64 grows by a third, see Base64 size overhead. For the URL-safe variant, see Base64 vs Base64URL.

FAQ

Which binary-to-text encoding is the most compact?

Of the common ones, Base85 (Ascii85 and Z85) at 25% overhead, then Base64 at 33%. basE91 can do slightly better, but it is rarely supported. See the Base91 tool if you need it.

Why does Bitcoin use Base58 instead of Base64?

Base58 drops 0, O, I, l, + and /, so addresses are easier to read aloud, copy by hand and double-click in a text field. The cost is a slower big-number conversion, which does not matter for 25-byte addresses.

Does letter case matter in Base32 and Base58?

The RFC 4648 alphabet is uppercase, and strict decoders reject lowercase. Many accept both: Python needs casefold=True. Base58 is case-sensitive: a and A are different digits. Hex is case-insensitive in practically every decoder.

Can I convert Base64 to Base58 or Base32 directly?

Yes, by decoding to bytes and encoding again. The Base64 to Base58 and Base64 to Base32 converters do both steps locally in your browser.

Keep reading