What is Base64?

Base64 is a binary-to-text encoding scheme that converts binary data into an ASCII string. The name comes from the fact that the encoding uses 64 different characters to represent data.

The 64 Characters

Base64 uses:

  • A-Z (26 characters)
  • a-z (26 characters)
  • 0-9 (10 characters)
    • and / (2 characters)
  • = (padding)

Total of 64 characters that are safe to use in most systems.

Why Base64?

Problems Base64 Solves

1. Binary data in text-based systems Many systems are built to handle text, not binary data:

  • Email (SMTP)
  • JSON and XML
  • URL query parameters
  • HTML and CSS

2. Safe transmission Base64 uses only characters that are not interpreted specially by various systems:

  • No whitespace problems
  • No issues with different charsets
  • Works in URLs (with Base64URL variant)

3. Data embedding Allows embedding files directly in code or markup:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUg..." />

How Does Base64 Work?

Encoding Process

  1. Take 3 bytes (24 bits) of data
  2. Split into 4 groups of 6 bits each
  3. Convert each group to a Base64 character
  4. Add padding if necessary

Example: โ€œHiโ€

Text:     H        i
ASCII:    72       105
Binary:   01001000 01101001
Grouped:  010010 000110 1001
Padded:   010010 000110 100100 (padding)
Base64:   S      G      k      =
Result:   SGk=

Why Does It Get Larger?

Base64 increases size by ~33%:

  • 3 bytes โ†’ 4 Base64 characters
  • 24 bits โ†’ 32 bits (with padding)
  • 100 KB file โ†’ 133 KB Base64

This is the tradeoff for compatibility!

Base64 vs Base64URL

Standard Base64

+ / =

Problematic in URLs because these characters have special meaning.

Base64URL

- _ (no padding)

URL-safe variant used in:

  • JWT tokens
  • URL parameters
  • Filenames
// Standard Base64
"hello+world/test=";

// Base64URL
"hello-world_test";

Common Use Cases

1. Data URLs in HTML/CSS

Embed images directly:

<img src="data:image/png;base64,iVBORw0KG..." alt="Logo" />

Advantages:

  • Fewer HTTP requests
  • Faster loading for small images
  • No external file to handle

Disadvantages:

  • Larger HTML size
  • Cannot be cached separately
  • Not suitable for large images

2. API Authentication

Basic Authentication:

const credentials = btoa("username:password");
// "dXNlcm5hbWU6cGFzc3dvcmQ="

fetch("/api/data", {
  headers: {
    Authorization: `Basic ${credentials}`,
  },
});

JWT Tokens:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Each part is Base64URL-encoded JSON.

3. File Upload Preview

Show image before upload:

function previewImage(file) {
  const reader = new FileReader();

  reader.onload = (e) => {
    const base64 = e.target.result;
    document.getElementById("preview").src = base64;
  };

  reader.readAsDataURL(file);
}

4. Email Attachments

MIME uses Base64 to send attachments:

Content-Type: image/png
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI
12P4//8/w38GIAXDIBKE0DHxgljN
BAAO9TXL0Y4OHwAAAABJRU5ErkJggg==

5. Store Binary Data in JSON

{
  "filename": "document.pdf",
  "content": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBl...",
  "encoding": "base64"
}

6. WebSocket Binary Data

const base64Data = btoa(String.fromCharCode(...new Uint8Array(buffer)));
websocket.send(
  JSON.stringify({
    type: "binary",
    data: base64Data,
  })
);

JavaScript Implementation

Browser (Native)

Encoding:

// String to Base64
const encoded = btoa("Hello World");
console.log(encoded); // "SGVsbG8gV29ybGQ="

// Decode
const decoded = atob(encoded);
console.log(decoded); // "Hello World"

Unicode Problem:

// This will NOT work!
btoa("Hello ๐Ÿ‘‹"); // Error!

// Solution:
function encodeUnicode(str) {
  return btoa(
    encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) =>
      String.fromCharCode("0x" + p1)
    )
  );
}

function decodeUnicode(str) {
  return decodeURIComponent(
    atob(str)
      .split("")
      .map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
      .join("")
  );
}

Node.js

// Encoding
const encoded = Buffer.from("Hello World").toString("base64");
console.log(encoded); // "SGVsbG8gV29ybGQ="

// Decoding
const decoded = Buffer.from(encoded, "base64").toString("utf-8");
console.log(decoded); // "Hello World"

// Base64URL
const base64url = encoded
  .replace(/\+/g, "-")
  .replace(/\//g, "_")
  .replace(/=/g, "");

Modern Web API

// TextEncoder/TextDecoder (Unicode-safe)
function base64Encode(str) {
  const bytes = new TextEncoder().encode(str);
  const binString = String.fromCodePoint(...bytes);
  return btoa(binString);
}

function base64Decode(base64) {
  const binString = atob(base64);
  const bytes = Uint8Array.from(binString, (m) => m.codePointAt(0));
  return new TextDecoder().decode(bytes);
}

Performance Tips

1. Large Files

For large files, use streaming:

async function encodeFileInChunks(file) {
  const chunkSize = 1024 * 1024; // 1MB chunks
  const reader = file.stream().getReader();
  let result = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    result += btoa(String.fromCharCode(...value));
  }

  return result;
}

2. Worker Threads

Move encoding to a Web Worker for large datasets:

// worker.js
self.onmessage = (e) => {
  const encoded = btoa(e.data);
  self.postMessage(encoded);
};

// main.js
const worker = new Worker("worker.js");
worker.postMessage(largeString);
worker.onmessage = (e) => console.log(e.data);

3. Caching

Cache encoded results when possible:

const cache = new Map();

function cachedEncode(data) {
  const key = data.slice(0, 100); // Sample for key

  if (cache.has(key)) {
    return cache.get(key);
  }

  const encoded = btoa(data);
  cache.set(key, encoded);
  return encoded;
}

Security Considerations

1. Base64 is NOT Encryption!

// DANGEROUS - visible to everyone!
const password = btoa("mySecretPassword123");
// "bXlTZWNyZXRQYXNzd29yZDEyMw=="

// Easy to decode:
atob("bXlTZWNyZXRQYXNzd29yZDEyMw==");
// "mySecretPassword123"

Base64 is encoding, not encryption. Never use it to โ€œhideโ€ sensitive data!

2. Always Validate Input

function safeBase64Decode(str) {
  // Validate Base64 format
  const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;

  if (!base64Regex.test(str)) {
    throw new Error("Invalid Base64 string");
  }

  try {
    return atob(str);
  } catch (e) {
    throw new Error("Failed to decode Base64");
  }
}

3. Size Limitations

const MAX_SIZE = 10 * 1024 * 1024; // 10MB

function encodeWithLimit(data) {
  const encoded = btoa(data);

  if (encoded.length > MAX_SIZE) {
    throw new Error("Encoded data too large");
  }

  return encoded;
}

Common Pitfalls

1. Unicode Handling

// Wrong - doesn't work with emoji/unicode
btoa("Hello ๐ŸŒ"); // Error!

// Right - handle unicode correctly
btoa(unescape(encodeURIComponent("Hello ๐ŸŒ")));

2. Newlines in Output

Some Base64 implementations add newlines:

const encoded = "SGVsbG8g\nV29ybGQ=";
const cleaned = encoded.replace(/\n/g, "");

3. Padding

// Standard Base64 - padding required
"SGVsbG8="; // OK

// Base64URL - no padding
"SGVsbG8"; // OK

// Mixed - problematic!
"SGVsbG8-"; // Wrong!

Best Practices

1. Use the Right Variant

  • Standard Base64: Email, MIME, general encoding
  • Base64URL: JWTs, URL parameters, filenames
  • Base64 no-padding: Some databases, compact format

2. Document Encoding

interface FileData {
  filename: string;
  content: string; // Base64-encoded binary data
  encoding: "base64";
  mimeType: string;
}

3. Handle Errors Gracefully

function tryDecode(base64String) {
  try {
    return {
      success: true,
      data: atob(base64String),
    };
  } catch (error) {
    return {
      success: false,
      error: "Invalid Base64 string",
    };
  }
}

4. Consider Alternatives for Large Files

For files > 5MB, consider:

  • Direct file upload (multipart/form-data)
  • Chunked upload
  • Signed URLs (S3, CloudFlare R2)
  • Binary WebSocket

Tools

Use our online tools for Base64:

Conclusion

Base64 is an invaluable tool for modern web developers:

Use Base64 for:

  • โœ… Small images in HTML/CSS
  • โœ… API authentication headers
  • โœ… JWT tokens
  • โœ… Email attachments
  • โœ… Binary data in JSON

Avoid Base64 for:

  • โŒ Encryption or security
  • โŒ Large files (>5MB)
  • โŒ Data that needs to be searched/indexed
  • โŒ When direct HTTP uploads are possible

Remember: Base64 is encoding for compatibility, not security or compression!