Base64 Encoding & Decoding Explained: How It Works

Base64 is one of the most ubiquitous encoding schemes in computing. From embedding images in HTML and CSS, to transmitting binary data over email, to encoding JWT tokens โ€” Base64 is used anywhere binary data needs to travel through text-only channels. This guide explains exactly how it works, when to use it, and provides practical code examples.

What Is Base64?

Base64 is a binary-to-text encoding scheme that represents binary data using 64 printable ASCII characters. It is defined in RFC 4648 and uses the following character set:

  • Uppercase letters: Aโ€“Z (indices 0โ€“25)
  • Lowercase letters: aโ€“z (indices 26โ€“51)
  • Digits: 0โ€“9 (indices 52โ€“61)
  • Two special characters: + (index 62) and / (index 63)
  • Padding character: =

How Base64 Encoding Works

The encoding process converts every 3 bytes (24 bits) of input into 4 Base64 characters (6 bits each):

  1. Take 3 bytes of input data (24 bits total)
  2. Split into four 6-bit groups
  3. Map each 6-bit value to the corresponding Base64 character
  4. If the input length isn't a multiple of 3, pad with =

Step-by-Step Example

Let's encode the string "Hi" (2 bytes: 0x48 0x69):

Input:    H        i
ASCII:    72       105
Binary:   01001000 01101001

Split into 6-bit groups (pad with zeros to fill last group):
010010 000110 100100

Base64:   S        G        k        =
(The = pads because input was 2 bytes, not 3)
๐Ÿ’ก Key insight: Base64 increases data size by approximately 33%. Every 3 bytes become 4 characters. This overhead is the trade-off for text-safe encoding.

Base64 in JavaScript

The browser provides two built-in functions for Base64:

// Encoding a string to Base64
const encoded = btoa("Hello, World!");
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="

// Decoding Base64 back to a string
const decoded = atob("SGVsbG8sIFdvcmxkIQ==");
console.log(decoded); // "Hello, World!"
โš ๏ธ Unicode caveat: btoa() only handles Latin-1 characters. For Unicode strings, encode to UTF-8 first:
// Encoding Unicode to Base64
function utf8ToBase64(str) {
  return btoa(
    new TextEncoder().encode(str)
      .reduce((acc, byte) => acc + String.fromCharCode(byte), '')
  );
}

// Decoding Base64 to Unicode
function base64ToUtf8(b64) {
  const binary = atob(b64);
  const bytes = Uint8Array.from(binary, c => c.charCodeAt(0));
  return new TextDecoder().decode(bytes);
}

console.log(utf8ToBase64("ไฝ ๅฅฝ"));  // "5L2g5aW9"
console.log(base64ToUtf8("5L2g5aW9")); // "ไฝ ๅฅฝ"

Base64 in Python

import base64

# Encoding
encoded = base64.b64encode(b"Hello, World!")
print(encoded)  # b'SGVsbG8sIFdvcmxkIQ=='

# Decoding
decoded = base64.b64decode(encoded)
print(decoded)  # b'Hello, World!'

# Encoding a file
with open("image.png", "rb") as f:
    img_b64 = base64.b64encode(f.read()).decode("ascii")
    print(f"data:image/png;base64,{img_b64[:50]}...")

Base64 on the Command Line

# macOS / Linux
echo -n "Hello" | base64          # SGVsbG8=
echo "SGVsbG8=" | base64 -d       # Hello (use -D on macOS)

# Encode a file
base64 image.png > image.b64

# Decode a Base64 file
base64 -d image.b64 > image_copy.png

URL-Safe Base64

Standard Base64 uses + and /, which have special meaning in URLs. URL-safe Base64 (RFC 4648 ยง5) replaces them:

  • + โ†’ - (hyphen)
  • / โ†’ _ (underscore)
  • Padding = is often omitted
# Python: URL-safe Base64
import base64

data = b"\xfb\xff\xfe"
print(base64.b64encode(data))        # b'+//+'
print(base64.urlsafe_b64encode(data)) # b'-__-'
๐Ÿ’ก JWT uses URL-safe Base64 (without padding) for its Header and Payload segments. See our JWT Guide for details.

Common Use Cases

  • Data URIs: Embedding images directly in HTML/CSS โ€” data:image/png;base64,iVBOR...
  • Email attachments: MIME encodes binary attachments as Base64
  • JWT tokens: Header and payload are Base64url-encoded JSON
  • API payloads: Sending binary data (files, images) in JSON API requests
  • Basic HTTP authentication: Authorization: Basic dXNlcjpwYXNz
โš ๏ธ Base64 is NOT encryption. It is a reversible encoding with zero security. Never use Base64 to "hide" passwords or sensitive data.

Performance Considerations

While convenient, Base64 has trade-offs to keep in mind:

  • 33% size overhead: A 1 MB file becomes ~1.33 MB when Base64-encoded
  • No streaming: The entire payload must be decoded before use
  • CPU cost: Encoding/decoding adds processing overhead

For large files, prefer direct binary transfer (multipart form data) over Base64 encoding in JSON payloads.

๐Ÿ› ๏ธ Try the Online Base64 Encoder/Decoder

Open Base64 Tool โ†’

Further Reading