Base64, Base64URL and Base32: a protocol selection checklist

Compare six-bit and five-bit encodings, case sensitivity, padding and human transcription before choosing a format.

These three names describe related binary-to-text schemes, but they serve different constraints. Base64 and Base64URL use six-bit groups. Standard Base32 uses five-bit groups and a smaller alphabet. The right choice is the one your transport, storage and receiving application can preserve exactly.

Compare alphabets before lengths

Standard Base64 uses upper- and lowercase letters, digits, plus and slash. Base64URL substitutes dash and underscore for the last two characters. Both are case-sensitive. Standard RFC Base32 uses uppercase A–Z and digits 2–7. A decoder may accept lowercase as a convenience, but a protocol should state whether that is allowed and define its canonical output.

A case-insensitive channel can destroy a Base64 value while preserving a properly specified Base32 one. A URL token has different constraints from a code read aloud over a phone. Do not choose purely by how short a sample looks.

Understand the size tradeoff

Ignoring the final partial group, Base64 needs about 1.33 characters per byte and Base32 needs 1.6. Standard padded Base32 emits eight-character groups for five bytes. For one byte containing the letter f, the common vectors are Zg== in Base64 and MY====== in Base32. Small inputs exaggerate padding overhead, so compare realistic payload lengths.

Payload bytes: 66 (ASCII f)
Base64:        Zg==
Base64URL:     Zg==  (or Zg when the protocol omits padding)
RFC Base32:    MY======

Do not mix Base32 variants

Crockford Base32 is designed around human-readable identifiers and uses a different alphabet and ambiguity rules from RFC Base32. Base32hex also differs. A value produced by one variant cannot be handed blindly to another decoder. Name the variant, alphabet, padding policy and any checksum behavior in your documentation.

Encoding also does not supply authentication. A mistyped value may still be syntactically valid and decode to different bytes. If users transcribe a code, consider a protocol-defined checksum or verification step rather than assuming that the alphabet catches every error.

Write down the complete contract

Specify input byte order where relevant, empty-input behavior, leading-zero preservation, maximum length, whitespace acceptance and invalid-character handling. Include test vectors with high-valued bytes and partial groups. Use your chosen encoder and decoder independently against those vectors, not only against each other; matching bugs can otherwise appear to pass a roundtrip. The standard forms and reference vectors are in RFC 4648.