Toolypet
Back to Blog
Dev

Everything About Base64 Encoding - From Principles to Practical Applications

Learn everything about Base64 encoding: what it is, why it's needed, and how to use it with practical examples. From inline images to JWT.

Toolypet Team

Toolypet Team

Development Team

8 min read

Everything About Base64 Encoding

"How do I send this image via API?" "How do I put this binary data in JSON?"

The answer is Base64.

This guide covers everything from Base64 principles to practical applications.


What is Base64?

Base64 is an encoding method that converts binary data to text.

Why is it needed?

ProblemBase64 Solution
Cannot send binary via emailConvert to text for transmission
Cannot include binary in JSONConvert to string for inclusion
Special characters not allowed in URLUse only URL-safe characters
Inline image embedding in HTMLConvert to Data URL

Features

  • 64 characters used: A-Z, a-z, 0-9, +, / (standard)
  • Size increase: Approximately 33% larger than original
  • Reversible: Perfect encoding <-> decoding restoration
  • Not encryption: Anyone can decode

How Base64 Works

Encoding Process

Original string: "Man"

1. ASCII conversion
   M = 77 = 01001101
   a = 97 = 01100001
   n = 110 = 01101110

2. Split into 6-bit chunks
   010011 | 010110 | 000101 | 101110
      19  |   22   |    5   |   46

3. Convert to Base64 characters (A=0, B=1, ... Z=25, a=26, ...)
   19 = T
   22 = W
   5  = F
   46 = u

Result: "TWFu"

Base64 Character Table

Index: Character
0-25:   A-Z
26-51:  a-z
52-61:  0-9
62:     +
63:     /
Padding:   =

Padding (=)

If original length is not divisible by 3, add padding

"M"   -> "TQ=="  (2 padding)
"Ma"  -> "TWE="  (1 padding)
"Man" -> "TWFu"  (no padding)

Language-Specific Implementation

JavaScript (Browser)

// Encoding
const encoded = btoa('Hello, World!');
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="

// Decoding
const decoded = atob('SGVsbG8sIFdvcmxkIQ==');
console.log(decoded); // "Hello, World!"

// Unicode handling (non-ASCII characters)
function encodeUnicode(str) {
  return btoa(encodeURIComponent(str).replace(
    /%([0-9A-F]{2})/g,
    (_, p1) => String.fromCharCode(parseInt(p1, 16))
  ));
}

function decodeUnicode(str) {
  return decodeURIComponent(
    Array.from(atob(str), c =>
      '%' + c.charCodeAt(0).toString(16).padStart(2, '0')
    ).join('')
  );
}

// Unicode test
const text = 'Hello World';
const encodedText = encodeUnicode(text);
console.log(encodedText);
console.log(decodeUnicode(encodedText)); // "Hello World"

Node.js

// Using Buffer
const encoded = Buffer.from('Hello, World!').toString('base64');
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="

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

// File encoding
const fs = require('fs');

const imageBuffer = fs.readFileSync('image.png');
const base64Image = imageBuffer.toString('base64');
console.log(base64Image.substring(0, 50) + '...');

Python

import base64

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

# Decoding
decoded = base64.b64decode('SGVsbG8sIFdvcmxkIQ==').decode('utf-8')
print(decoded)  # "Hello, World!"

# Unicode
text = 'Hello World'
encoded_text = base64.b64encode(text.encode('utf-8')).decode('utf-8')
print(encoded_text)

# File encoding
with open('image.png', 'rb') as f:
    base64_image = base64.b64encode(f.read()).decode('utf-8')

Go

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    // Encoding
    data := "Hello, World!"
    encoded := base64.StdEncoding.EncodeToString([]byte(data))
    fmt.Println(encoded) // "SGVsbG8sIFdvcmxkIQ=="

    // Decoding
    decoded, _ := base64.StdEncoding.DecodeString(encoded)
    fmt.Println(string(decoded)) // "Hello, World!"

    // URL-safe Base64
    urlSafe := base64.URLEncoding.EncodeToString([]byte(data))
    fmt.Println(urlSafe)
}

Practical Applications

1. Inline Image Embedding (Data URL)

<!-- Embed image directly in HTML -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="1x1 red pixel">
// File -> Base64 Data URL
function fileToDataUrl(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

// Usage
const file = document.getElementById('fileInput').files[0];
const dataUrl = await fileToDataUrl(file);
document.getElementById('preview').src = dataUrl;

2. Sending Images via API

// Client
async function uploadImage(file) {
  const base64 = await fileToBase64(file);

  const response = await fetch('/api/upload', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      filename: file.name,
      contentType: file.type,
      data: base64,
    }),
  });

  return response.json();
}

function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      // Remove data:image/png;base64, prefix
      const base64 = reader.result.split(',')[1];
      resolve(base64);
    };
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}
// Server (Node.js)
app.post('/api/upload', (req, res) => {
  const { filename, contentType, data } = req.body;

  // Base64 -> Buffer -> Save file
  const buffer = Buffer.from(data, 'base64');
  fs.writeFileSync(`uploads/${filename}`, buffer);

  res.json({ success: true, filename });
});

3. JWT Tokens

// JWT = Header.Payload.Signature (each Base64URL encoded)

const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';

// Decode Payload
const payload = token.split('.')[1];
const decoded = JSON.parse(atob(payload));
console.log(decoded);
// { sub: "1234567890", name: "John Doe", iat: 1516239022 }

4. Basic Authentication

// HTTP Basic Authentication
const username = 'user';
const password = 'password';

const credentials = btoa(`${username}:${password}`);

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

// Header: Authorization: Basic dXNlcjpwYXNzd29yZA==

5. Email Attachments (MIME)

Content-Type: application/pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="document.pdf"

JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIK
Pj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0K
...

Base64 Variants

URL-safe Base64

StandardURL-safe
+-
/_
=Can be omitted
// URL-safe encoding
function toUrlSafeBase64(str) {
  return btoa(str)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

// URL-safe decoding
function fromUrlSafeBase64(str) {
  // Restore padding
  const pad = str.length % 4;
  const padded = pad ? str + '='.repeat(4 - pad) : str;

  return atob(
    padded
      .replace(/-/g, '+')
      .replace(/_/g, '/')
  );
}

Base64 vs Base32 vs Base16

EncodingCharactersSize IncreaseUse Case
Base6464+33%General purpose
Base3232+60%Case-insensitive needed
Base16 (Hex)16+100%Hashes, color codes

Cautions

1. Not Encryption

// Do NOT use for security
const password = btoa('mySecretPassword');
// Anyone can restore with atob()!

// Encrypt first, then Base64 if needed
const encrypted = await encryptAES(data, key);
const encoded = btoa(encrypted);

2. Size Increase

// Original: 1MB image
// Base64: ~1.33MB (33% increase)

// For large files, direct upload is more efficient
// Use FormData + multipart/form-data

3. Unicode Handling

// Browser btoa() only supports Latin-1
btoa('Special chars'); // Works
// Non-ASCII needs special handling

// Unicode handling required
function encodeUnicode(str) {
  return btoa(unescape(encodeURIComponent(str)));
}

4. Line Breaks

// Some systems add line breaks every 76 characters
// MIME standard: 76 character line breaks

// Remove line breaks
const cleaned = base64String.replace(/[\r\n]/g, '');

Performance Optimization

Streaming Encoding

// Process large files in chunks
async function* encodeFileInChunks(file, chunkSize = 1024 * 1024) {
  const reader = file.stream().getReader();

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

    // Base64 encode each chunk
    yield Buffer.from(value).toString('base64');
  }
}

Web Worker Usage

// worker.js
self.onmessage = function(e) {
  const { action, data } = e.data;

  if (action === 'encode') {
    const result = btoa(data);
    self.postMessage({ result });
  }
};

// main.js
const worker = new Worker('worker.js');
worker.postMessage({ action: 'encode', data: largeString });
worker.onmessage = (e) => console.log(e.data.result);

Debugging Tools

Base64 Encoder/Decoder

  1. Enter text or file
  2. Click encode/decode button
  3. Copy result

CLI

# Encoding
echo -n "Hello, World!" | base64
# SGVsbG8sIFdvcmxkIQ==

# Decoding
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d
# Hello, World!

# File encoding
base64 image.png > image.txt

# File decoding
base64 -d image.txt > restored.png

FAQ

Q1: Why does Base64 increase size by 33%?

A: Because 3 bytes (24 bits) are represented as 4 characters (4x6=24 bits).

  • 3 bytes -> 4 characters
  • Increase: (4-3)/3 = 33%

Q2: Why is padding (=) needed?

A: The decoder needs it to know the original length. The number of padding characters indicates the number of bytes in the last group.

Q3: When should I use Base64URL?

A: When using in URLs or filenames. Standard Base64's + and / have special meaning in URLs, so they're replaced with - and _.

Q4: What are the pros and cons of inline image embedding?

A:

  • Pros: Fewer HTTP requests, simplified caching
  • Cons: Larger HTML, no individual image caching
  • Recommendation: Only use for small icons (under 2KB)

Q5: How do I check if a string is valid Base64?

A: Use regex for format validation, then try decoding:

function isBase64(str) {
  const regex = /^[A-Za-z0-9+/]*={0,2}$/;
  if (!regex.test(str)) return false;

  try {
    atob(str);
    return true;
  } catch {
    return false;
  }
}

Conclusion

Base64 key points:

  1. Purpose: Binary -> Text conversion
  2. Size: 33% larger than original
  3. Security: Not encryption (anyone can decode)
  4. Variants: URL-safe uses - and _
  5. Applications: Data URL, JWT, Basic Auth, MIME

Related Tools

ToolPurpose
Base64 Encoder/DecoderBase64 encoding/decoding
JWT DecoderJWT token analysis
JSON FormatterJSON formatting
Base64EncodingDevelopmentDataAPIJavaScript

About the Author

Toolypet Team

Toolypet Team

Development Team

The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.

Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity