Paste any 8 bytes into a Base64 encoder, a Base62 encoder, and a Base58 encoder and you get three different-looking strings — all representing the same data, all reversible, none of them encrypted. The outputs look like gibberish but they are not: they are just different alphabets for writing binary data as printable text.
The choice between them is not arbitrary. Base64 is the right choice for email attachments, JWTs, and most web APIs. Base62 fits URL shortener IDs where you need no special characters. Base58 is designed for human-readable cryptocurrency addresses where visual ambiguity must be zero. Using the wrong one in the wrong context causes bugs that are subtle enough to reach production.
What Base Encoding Is
Binary data — bytes, files, keys, tokens — cannot always travel safely through systems that expect text. Email protocols, JSON fields, and URLs all have reserved characters or encoding assumptions. Base encoding solves this by representing arbitrary byte sequences using only characters from a predefined safe alphabet.
The "base" number is the alphabet size. Base64 uses 64 characters. Base62 uses 62. Base58 uses 58. Larger alphabets mean shorter output: Base64 represents 6 bits per character, Base62 represents slightly less (~5.95 bits), Base58 slightly less still (~5.86 bits). The efficiency differences are small in practice — the character set restrictions matter far more than the output length.
None of these are encryption. They are all publicly specified, fully reversible transformations that provide zero confidentiality. A Base64 string decoded in one second with a standard library function. This is worth stating explicitly because Base64 output looks like encrypted data and is routinely misused as if it were.
Base64
The alphabet
Base64 uses A–Z (26), a–z (26), 0–9 (10), + (1), / (1) = 64 characters. Output is padded with = characters to make the length a multiple of 4.
The standard
RFC 4648 (published 2006, IETF) defines Base64 and several variants. The same RFC also defines Base32 and Base16. RFC 4648 superseded the earlier RFC 3548.
The problem with URLs
RFC 3986 defines the characters permitted in a URL. The characters + and / are reserved: + means space in query strings (HTML form encoding), / delimits URL path components. A Base64 string containing + or / will be misinterpreted or percent-encoded (%2B, %2F) by URL parsers.
The solution is Base64url, also defined in RFC 4648 Section 5: replace + with - and / with _. This produces URL-safe Base64. The = padding is often omitted in URL contexts. JWTs (JSON Web Tokens) use Base64url with padding stripped — which is why JWT segments do not end in =.
Where it belongs
Base64 is the right choice for email MIME attachments (defined in RFC 2045), JWT header/payload/signature encoding, encoding binary data in JSON or XML, and HTTP Basic authentication headers. The Base64 encoder/decoder handles both standard and URL-safe variants.
Base62
The alphabet
Base62 uses 0–9 (10), A–Z (26), a–z (26) = 62 characters. No special characters at all.
The URL shortener use case
URL shorteners (bit.ly, t.co, tinyurl) need to encode a large integer — a row ID from a database — into a short string that can appear in a URL without any encoding. The integer 1,000,000 in Base62 is 4c92 — four characters. In Base64, the same integer would produce output containing potential + or / characters requiring encoding.
Because Base62 uses only alphanumeric characters, the output is natively URL-safe without any character substitution. It also looks clean in a URL: https://short.example/4c92 is unambiguous in any browser or terminal.
JavaScript and BigInt limits
Base62 encoding of large integers (beyond Number.MAX_SAFE_INTEGER = 2^53 − 1) requires BigInt in JavaScript. Standard Base62 libraries in Node.js handle this, but older code using parseInt() or float arithmetic will silently produce wrong results for IDs above about 9 quadrillion. This is a real production bug in URL shorteners that grow to scale. The Base62 encoder/decoder handles BigInt correctly.
Base58
The alphabet
Base58 uses 1–9 (9), A–H, J–N, P–Z (22), a–k, m–z (22) = 58 characters. Specifically excluded are: 0 (zero), O (capital O), I (capital I), l (lowercase L).
Satoshi Nakamoto's rationale
The Bitcoin source code comment in src/base58.h explains the exclusions directly: "Avoid visually identical-looking characters — 0/O and I/l look similar and can cause errors when copying." Bitcoin addresses are typically written on paper, typed manually, or printed on receipts — contexts where OCR or human transcription errors are possible.
Base58 also excludes + and / (as Base64 has them), avoiding URL encoding issues. The result is a character set designed for human handling: no character in Base58 can be confused with any other character, even in a low-quality font.
Base58Check
Bitcoin addresses and private keys use a variant called Base58Check, which appends a 4-byte checksum (the first 4 bytes of a double-SHA256 hash of the payload) before encoding. This means a mistyped character in a Bitcoin address will almost certainly produce an invalid checksum, preventing you from sending funds to a non-existent address. The checksum step is not part of basic Base58 — it is a higher-level protocol. Other cryptocurrencies (Litecoin, Monero) use similar schemes. Use our Base58 encoder/decoder for the raw encoding.
Comparison
| Property | Base64 | Base62 | Base58 |
|---|---|---|---|
| Alphabet size | 64 | 62 | 58 |
| Special characters | + / = | None | None |
| URL-safe (native) | No (use Base64url) | Yes | Yes |
| Human-copyable | No | Partially | Yes (designed for it) |
| Checksum variant | No | No | Base58Check |
| Standard document | RFC 4648 | None (de facto) | Bitcoin wiki / BIPs |
| Primary use | JWTs, email, APIs | URL shorteners, IDs | Cryptocurrency addresses |
Picking the right one
Use Base64 when you are following an existing standard (JWT, MIME, HTTP auth). Use Base62 when you need URL-safe short strings from integer IDs and you do not need a standard. Use Base58 when humans will read, copy, or type the output and correctness is critical.
For URL encoding of individual characters in a URL path or query string — which is a different operation from base encoding — use the URL encoder/decoder.
Practical Applications
Building a URL shortener: Generate an auto-incrementing integer ID in your database. Encode it with Base62 to produce the short code. On redirect, decode the Base62 back to the integer and look up the original URL. The Base62 encoder/decoder shows the exact integer-to-string mapping.
Reading a JWT: A JWT has three parts separated by dots: header.payload.signature. Each part is Base64url-encoded (not padded). Decoding the payload part reveals the JSON claims object — subject, expiration time, issued-at. No secret key is needed to decode the header and payload; they are not encrypted, only encoded. Our JWT decoder handles this.
Verifying a Bitcoin address: A Bitcoin address (P2PKH format) starting with 1 is Base58Check encoded. If you remove the last 4 bytes (the checksum) and double-SHA256 the remainder, the first 4 bytes of that hash should match the bytes you removed. Any address that fails this check is invalid. The Base58 encoding ensures a transposition or typo in one character will produce a checksum failure.
Limitations
All three are encodings, not encryption. Any Base64, Base62, or Base58 string can be decoded instantly by anyone without any key or secret. Do not store passwords as Base64. Do not transmit sensitive data over HTTP just because it "looks encoded." Encoding changes the representation of data — it does not protect it.
Base64 padding (= characters) causes issues in some URL contexts even when using the standard variant. Always use Base64url (with - and _ substitutions) in URLs, JWTs, and cookie values.
Base58 output is longer than Base62 output for the same input because the alphabet is smaller. For very large integers, this difference matters. Choose Base58 only when human readability and transcription safety are worth the extra characters.