BytePane

Base64 Encode & Decode Online: Free Converter Tool

Encoding15 min read

What Is Base64 and Why Do You Need It?

Base64 is a binary-to-text encoding scheme that converts arbitrary binary data into a string of 64 printable ASCII characters. It exists to solve a fundamental problem in software: many systems were designed to handle text, not raw binary bytes. Email protocols (SMTP), JSON payloads, HTML attributes, HTTP headers, environment variables, and configuration files all operate on text. Base64 bridges the gap by making any sequence of bytes safe to embed in those text-only channels.

The encoding was formally standardized in RFC 4648 (published October 2006 by IETF), which defines the Base64 alphabet, padding rules, and the URL-safe variant. The scheme itself predates the RFC by decades — MIME email attachments have used Base64 since RFC 2045 (1996). Today, Base64 is ubiquitous: it appears in JWT tokens, HTTP Basic Authentication headers, Kubernetes Secrets, Data URIs in CSS, and TLS certificate files.

To encode or decode a Base64 string immediately, use BytePane's free Base64 Encoder & Decoder. It runs entirely in your browser, supports text and binary file input, and handles both standard Base64 and URL-safe Base64url — your data never leaves your device.

RFC 4648: The Base64 Specification

RFC 4648, authored by Simon Josefsson, defines three encoding schemes: Base64 (§4), Base64url (§5), and Base32 (§6). The Base64 alphabet consists of exactly 64 characters: uppercase A–Z (indices 0–25), lowercase a–z (indices 26–51), digits 0–9 (indices 52–61), + (index 62), and / (index 63). The equals sign = is used exclusively for padding.

RFC 4648 §3.3 explicitly states that decoders MUST reject encoded data that contains characters outside the base alphabet, unless a specific implementation permits it for backwards compatibility. This is why a stray whitespace character or newline in a Base64 string causes decoding failures in strict parsers.

// The Base64 alphabet (RFC 4648 Table 1)
Index:  0-25  -> A-Z   (26 uppercase letters)
Index: 26-51  -> a-z   (26 lowercase letters)
Index: 52-61  -> 0-9   (10 digits)
Index: 62     -> +     (standard Base64)
Index: 63     -> /     (standard Base64)
Index: 62     -> -     (Base64url variant)
Index: 63     -> _     (Base64url variant)
Padding       -> =     (not in the 64-character alphabet)

How the Base64 Encoding Algorithm Works

Base64 processes input in groups of 3 bytes (24 bits). Each group is split into four 6-bit values. Each 6-bit value (0–63) maps to one character in the Base64 alphabet. This is why Base64-encoded output is always exactly 4/3 the size of the input — every 3 bytes become 4 characters.

Step-by-Step: Encoding "Man"

Input:    M         a         n
ASCII:    77        97        110
Binary:   01001101  01100001  01101110

// Concatenate all 24 bits:
01001101 01100001 01101110

// Split into four 6-bit groups:
010011  010110  000101  101110
19      22      5       46

// Map to Base64 alphabet:
T       W       F       u

// Result: "Man" -> "TWFu" (no padding needed: 3 bytes → 4 chars)

// Encoding "Ma" (2 bytes, needs 1 padding char):
01001101 01100001
010011  010110  000100  (pad last 4 bits with zeros)
19      22      4
T       W       E       =
// Result: "Ma" -> "TWE="

// Encoding "M" (1 byte, needs 2 padding chars):
01001101
010011  01xxxx  (pad last 10 bits with zeros)
19      16
T       Q       =       =
// Result: "M" -> "TQ=="

Padding Rules

Input Bytes (mod 3)Output CharactersPadding AddedExample
0 (divisible by 3)4n charsNoneMan → TWFu
1 byte remaining2 chars + ==2 × =M → TQ==
2 bytes remaining3 chars + =1 × =Ma → TWE=

Padding ensures the encoded output length is always a multiple of 4 characters, which simplifies decoder implementations. However, padding is technically optional in many contexts. JWT tokens (RFC 7519) explicitly strip all padding characters from Base64url-encoded header and payload sections. Always check the target system's expectations before stripping or adding padding.

Base64 Encode & Decode in Every Language

Every major runtime ships Base64 support in its standard library. Here is a complete reference with production-ready code for the most common languages, including notes on Unicode handling, URL-safe variants, and file encoding.

JavaScript (Browser)

// Built-in: btoa() and atob()
btoa("Hello, World!");        // "SGVsbG8sIFdvcmxkIQ=="
atob("SGVsbG8sIFdvcmxkIQ=="); // "Hello, World!"

// IMPORTANT: btoa() only accepts Latin-1 (code points 0-255).
// This throws a DOMException for Unicode:
btoa("Hello 🌍"); // Uncaught DOMException: Invalid character

// Correct approach for Unicode with TextEncoder:
function encodeToBase64(str) {
  const bytes = new TextEncoder().encode(str);
  const binStr = Array.from(bytes, b => String.fromCodePoint(b)).join('');
  return btoa(binStr);
}
encodeToBase64("Hello 🌍"); // "SGVsbG8g8J+MjQ=="

// Decoding Unicode Base64:
function decodeFromBase64(b64) {
  const binStr = atob(b64);
  const bytes = Uint8Array.from(binStr, c => c.charCodeAt(0));
  return new TextDecoder().decode(bytes);
}
decodeFromBase64("SGVsbG8g8J+MjQ=="); // "Hello 🌍"

Node.js

// Node.js Buffer API — handles Unicode natively
const encoded = Buffer.from("Hello 🌍").toString("base64");
// "SGVsbG8g8J+MjQ=="

const decoded = Buffer.from("SGVsbG8g8J+MjQ==", "base64").toString("utf-8");
// "Hello 🌍"

// URL-safe Base64 (base64url) — no +, /, or = characters
const urlSafe = Buffer.from("data+with/special").toString("base64url");
// "ZGF0YSt3aXRoL3NwZWNpYWw" (no padding)

// Encode a file to Base64
import { readFileSync } from 'fs';
const fileBase64 = readFileSync('image.png').toString('base64');

// Create a Data URI from a file
const mimeType = 'image/png';
const dataUri = `data:${mimeType};base64,${fileBase64}`;

Python

import base64

# Encode a string
encoded = base64.b64encode(b"Hello, World!").decode()
# "SGVsbG8sIFdvcmxkIQ=="

# Encode a Unicode string (encode to bytes first)
text = "Hello 🌍"
encoded = base64.b64encode(text.encode("utf-8")).decode()
# "SGVsbG8g8J+MjQ=="

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

# URL-safe variant (replaces + with - and / with _)
url_safe = base64.urlsafe_b64encode(b"data+with/special").decode()
# "ZGF0YSt3aXRoL3NwZWNpYWw="

# Encode a file
with open("image.png", "rb") as f:
    file_b64 = base64.b64encode(f.read()).decode()

# Decode with missing padding (common with JWT sections)
def decode_b64_padding(s: str) -> bytes:
    padding = 4 - len(s) % 4
    return base64.b64decode(s + "=" * (padding % 4))

Go

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    input := []byte("Hello, World!")

    // Standard Base64 (with padding)
    std := base64.StdEncoding.EncodeToString(input)
    fmt.Println(std) // "SGVsbG8sIFdvcmxkIQ=="

    // URL-safe Base64 (with padding)
    url := base64.URLEncoding.EncodeToString(input)
    fmt.Println(url) // "SGVsbG8sIFdvcmxkIQ=="

    // Raw (no padding) variants
    rawStd := base64.RawStdEncoding.EncodeToString(input)
    rawURL := base64.RawURLEncoding.EncodeToString(input)
    fmt.Println(rawStd) // "SGVsbG8sIFdvcmxkIQ"
    fmt.Println(rawURL) // "SGVsbG8sIFdvcmxkIQ"

    // Decode
    decoded, err := base64.StdEncoding.DecodeString(std)
    if err != nil {
        panic(err)
    }
    fmt.Println(string(decoded)) // "Hello, World!"
}

Rust

// Add to Cargo.toml: base64 = "0.22"
use base64::{Engine as _, engine::general_purpose};

fn main() {
    let input = b"Hello, World!";

    // Encode (standard)
    let encoded = general_purpose::STANDARD.encode(input);
    println!("{}", encoded); // "SGVsbG8sIFdvcmxkIQ=="

    // URL-safe (no padding)
    let url_safe = general_purpose::URL_SAFE_NO_PAD.encode(input);
    println!("{}", url_safe); // "SGVsbG8sIFdvcmxkIQ"

    // Decode
    let decoded = general_purpose::STANDARD.decode(&encoded).unwrap();
    println!("{}", String::from_utf8(decoded).unwrap()); // "Hello, World!"
}

Command Line (Linux / macOS)

# Encode a string (-n prevents trailing newline from being encoded)
echo -n "Hello, World!" | base64
# SGVsbG8sIFdvcmxkIQ==

# Decode
echo "SGVsbG8sIFdvcmxkIQ==" | base64 --decode
# Hello, World!

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

# Decode a file
base64 --decode image.b64 > image.png

# macOS uses -D flag instead of --decode:
base64 -D <<< "SGVsbG8sIFdvcmxkIQ=="

# Strip whitespace/newlines before decoding (MIME-wrapped Base64):
tr -d '\n' < encoded.txt | base64 --decode

URL-Safe Base64 (Base64url): RFC 4648 §5

Standard Base64 uses + and /, which are reserved characters in URLs (RFC 3986). Embedding standard Base64 in a URL requires percent-encoding those characters (+%2B, /%2F), which adds unnecessary complexity. Base64url solves this by swapping the two problematic characters.

Base64url is also safe for use in filenames (where / is a path separator on Unix) and in HTTP headers without quoting. It is the mandatory encoding for JWT token sections (RFC 7519 §2), Google API credentials, Amazon S3 pre-signed URLs, and PKCE code verifiers in OAuth 2.0.

// Convert standard Base64 to Base64url in JavaScript
function toBase64url(base64) {
  return base64
    .replace(/\+/g, '-')   // + -> -
    .replace(/\//g, '_')   // / -> _
    .replace(/=+$/, '');   // strip padding
}

// Convert Base64url back to standard Base64
function fromBase64url(base64url) {
  // Restore padding
  const pad = base64url.length % 4;
  const padded = pad ? base64url + '='.repeat(4 - pad) : base64url;
  return padded.replace(/-/g, '+').replace(/_/g, '/');
}

// Decode a JWT payload (always Base64url, never padded)
function decodeJwtPayload(token) {
  const parts = token.split('.');
  if (parts.length !== 3) throw new Error('Not a JWT');
  const payload = fromBase64url(parts[1]);
  return JSON.parse(atob(payload));
}

// Example JWT inspection
const payload = decodeJwtPayload(token);
console.log(payload.sub, payload.exp); // user ID, expiry timestamp

JWT tokens encode their header and payload with Base64url without padding, then sign the concatenated result. For a deep dive into how JWT tokens are structured and secured, read our guide on JWT Tokens Explained. For URL parameter encoding needs, our URL Encoder/Decoder handles percent-encoding correctly.

Real-World Use Cases with Code

1. HTTP Basic Authentication

RFC 7617 defines HTTP Basic Authentication: credentials are formatted as username:password, Base64-encoded, and sent in the Authorization header. This is the scheme used by countless CI/CD systems, npm registries, and legacy APIs.

// HTTP Basic Auth — always use HTTPS, never HTTP
const username = "deploy_bot";
const password = process.env.API_TOKEN; // never hardcode secrets
const credentials = btoa(`${username}:${password}`);

const response = await fetch('https://api.example.com/releases', {
  headers: {
    'Authorization': `Basic ${credentials}`,
    'Content-Type': 'application/json',
  },
});

// Server-side decoding (Express.js middleware):
function basicAuth(req, res, next) {
  const auth = req.headers.authorization ?? '';
  if (!auth.startsWith('Basic ')) return res.status(401).end();
  const [user, pass] = atob(auth.slice(6)).split(':');
  // validate user and pass against your auth store...
}

2. Data URIs for Inline Assets

<!-- Inline a small SVG icon (eliminates one HTTP request) -->
<img
  src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiI+PHBhdGggZD0iTTggMkM0LjcgMiAyIDQuNyAyIDhzMi43IDYgNiA2IDYtMi43IDYtNi0yLjctNi02LTZ6Ii8+PC9zdmc+"
  alt="icon"
  width="16"
  height="16"
/>

<!-- Inline font in CSS (eliminates one HTTP request) -->
<style>
@font-face {
  font-family: 'MyFont';
  src: url(data:font/woff2;base64,d09GMgABAAAA...) format('woff2');
}
</style>

<!-- Rule of thumb from MDN: only inline assets smaller than 2-5 KB.
     Larger Data URIs bloat the HTML, bypass the browser cache,
     and cannot be shared across multiple pages. -->

3. Kubernetes Secrets

# Kubernetes stores all Secret values as Base64-encoded strings
# Create a secret from the CLI:
kubectl create secret generic db-credentials \
  --from-literal=username=admin \
  --from-literal=password=supersecret

# kubectl automatically Base64-encodes the values. Inspect the result:
kubectl get secret db-credentials -o yaml

# Output:
# apiVersion: v1
# kind: Secret
# data:
#   password: c3VwZXJzZWNyZXQ=   <- "supersecret" Base64-encoded
#   username: YWRtaW4=           <- "admin" Base64-encoded

# Decode manually to verify:
echo "c3VwZXJzZWNyZXQ=" | base64 --decode   # supersecret
echo "YWRtaW4=" | base64 --decode            # admin

# NOTE: Base64 is NOT encryption. Kubernetes Secrets are only as
# secure as the RBAC policies and etcd encryption at rest you configure.

4. MIME Email Attachments (RFC 2045)

# SMTP was designed for 7-bit ASCII text.
# All binary attachments must be Base64-encoded in MIME parts.
# RFC 2045 §6.8 mandates line breaks every 76 characters.

# MIME structure of an email with a PDF attachment:
Content-Type: multipart/mixed; boundary="boundary42"

--boundary42
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit

Please find the report attached.

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

JVBERi0xLjUKJYCBgoMKMSAwIG9iago8PC9GaWx0ZXIgL0ZsYXRlRGVjb2Rl
L0xlbmd0aCAxMDY+PgpzdHJlYW0KeJxLSkktLk5VslIqS80rVrICABPJBcI=

--boundary42--

# The 37% overhead (vs 33%) comes from these mandatory line breaks.

5. Binary Data in JSON API Payloads

// JSON only supports UTF-8 text values, not raw binary bytes.
// Base64 is the standard way to include binary in JSON.

// Request: upload a file via JSON API
const file = document.querySelector('input[type="file"]').files[0];
const buffer = await file.arrayBuffer();
const base64 = btoa(String.fromCharCode(...new Uint8Array(buffer)));

await fetch('/api/documents', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    filename: file.name,
    content_type: file.type,
    size_bytes: file.size,
    data: base64,   // <-- Base64-encoded binary content
  }),
});

// For files > 1 MB, prefer multipart/form-data or pre-signed S3 URLs.
// Base64 adds 33% overhead and forces the entire file into memory.

When debugging JSON payloads that contain Base64 fields, paste the full response into our JSON Formatter to inspect the structure, then copy the Base64 value into our Base64 Decoder to check its content.

Base64 vs Other Encoding Schemes

Base64 is not the only binary-to-text encoding. Choosing the right one depends on your character set constraints, size budget, and the downstream system consuming the data.

EncodingAlphabet SizeSize OverheadURL-SafePrimary Use
Base6464+33%No (+, /)APIs, MIME email, Data URIs
Base64url64+33%Yes (-, _)JWTs, OAuth tokens, URLs
Base3232+60%YesTOTP codes, case-insensitive systems
Hex (Base16)16+100%YesHash display, debugging, CSS colors
URL encoding (%)VariableVariableBy definitionURL query parameters, form data
ASCII8585+25%NoPDF streams, PostScript

For URL encoding specifically, our guide on URL Encoding explains when percent-encoding is required and how it differs from Base64. For password hashing (which is often confused with encoding), read our deep dive on Hash Functions Explained.

Performance: Size Overhead and Compression Behavior

The 33% size overhead is the most significant trade-off when choosing Base64. But the interaction with compression makes the real-world impact worse than the raw number suggests.

Base64 output has high entropy — the encoded alphabet is pseudo-random relative to typical text patterns. Gzip and Brotli compressors achieve much lower compression ratios on Base64 than on the equivalent binary data. A benchmark published in the Chromium issue tracker measured Base64-encoded images compressing 15–20% worse than raw binary served via HTTP/2, on top of the 33% encoding overhead.

For a production API serving thousands of requests per second, the math matters:

// Size impact calculation for a 1 MB binary file
const original_bytes   = 1_000_000;
const base64_bytes     = Math.ceil(original_bytes * 4 / 3); // 1,333,333 bytes
const overhead_percent = ((base64_bytes - original_bytes) / original_bytes) * 100;
// 33.3%

// Real-world benchmark: Node.js encode/decode throughput (Apple M2)
// Buffer.from(data).toString('base64')  ~2.1 GB/s
// Buffer.from(b64, 'base64')            ~1.8 GB/s
// CPU is not the bottleneck — network and memory are.

// Rule of thumb:
// < 5 KB  -> Base64 in JSON is fine
// 5-100 KB -> Consider multipart/form-data
// > 100 KB -> Use pre-signed upload URLs (S3, GCS, Azure Blob)

When NOT to Use Base64

Base64 is frequently misused. Knowing when to avoid it prevents silent performance problems and security misconceptions.

  1. As a security measure — Base64 is encoding, not encryption. It provides zero confidentiality. Anyone can decode it with one function call. Use TLS for transport security and AES-256-GCM for data-at-rest encryption.
  2. For large binary files in JSON — Embedding a 10 MB PDF as Base64 in JSON adds 3.3 MB of overhead, loads the entire payload into memory, and prevents streaming. Use multipart/form-data or pre-signed cloud storage URLs instead.
  3. For images in production HTML larger than 5 KB — Data URIs bypass the browser cache entirely. Every page load re-downloads the asset. Serve images from a CDN as separate files to leverage caching and HTTP/2 multiplexing.
  4. When the transport supports binary — HTTP/2, gRPC, WebSockets (binary frames), and multipart/form-data all handle raw bytes natively. Base64 adds unnecessary overhead in these contexts.
  5. For database storage — If your database supports BLOB, BYTEA, or BINARY columns, use them. Native binary columns are more storage-efficient and avoid the encode/decode round-trip on every read and write.
  6. Double encoding — Always check whether data is already Base64 before encoding it again. Double-encoded data decodes to a Base64 string, not the original binary — a subtle bug that manifests far from its source.

Key Takeaways

  • Base64 converts 3 input bytes → 4 ASCII characters, producing exactly 33% size overhead (37% with MIME line breaks).
  • RFC 4648 §4 defines standard Base64 (alphabet: A–Z, a–z, 0–9, +, /). §5 defines Base64url (replaces + with - and / with _).
  • JWT tokens always use Base64url without padding. Strip or add padding based on the target system's expectations.
  • JavaScript's btoa() only accepts Latin-1. Use TextEncoder to handle Unicode strings correctly.
  • Base64 is encoding, not encryption — zero security value. Always pair it with HTTPS and proper authentication.
  • For files over 5 KB, prefer multipart uploads, binary protocols, or cloud storage pre-signed URLs over Base64 in JSON.
  • Node.js, Python, Go, and Rust all have native Base64 support in their standard libraries — no third-party dependency needed.

Frequently Asked Questions

How do I encode text to Base64 online for free?

Paste your text into BytePane's free Base64 Encoder, click Encode, and copy the output in one click. The tool runs entirely in your browser — no account required, no server uploads. For binary files, use the file input to read and encode the raw bytes client-side without any size limits.

Is Base64 the same as encryption?

No. Base64 is a reversible encoding scheme, not encryption. Any developer can decode a Base64 string in milliseconds using btoa/atob or a command-line tool. It provides zero confidentiality. For protecting data, use AES-256 encryption for data at rest and TLS for data in transit.

Why does Base64 make data 33% larger?

Base64 encodes every 3 bytes (24 bits) of binary into 4 ASCII characters (6 bits each). Four ASCII characters occupy 4 bytes, so 3 input bytes become 4 output bytes — a 4/3 ratio, or ~33% overhead. MIME-wrapped Base64 adds required line breaks every 76 characters, pushing overhead to roughly 37%.

What is Base64url and when should I use it?

Base64url (RFC 4648 §5) swaps + for - and / for _ to make encoded output safe inside URLs and filenames without percent-encoding. It also omits the trailing = padding. Use Base64url for JWTs, OAuth tokens, Google API credentials, and any Base64 data embedded in URL query strings or path segments.

Why does JavaScript's btoa() throw an error on Unicode strings?

btoa() only accepts Latin-1 (ISO-8859-1) characters — code points 0–255. Multi-byte Unicode characters like emojis or CJK glyphs trigger a DOMException. The fix: encode the string to UTF-8 bytes first with TextEncoder, then convert the byte array to a Latin-1 binary string before calling btoa().

How do I decode a Base64 string that's missing padding?

Padding is optional in many systems — JWT tokens always strip it. Add = characters until the string length is a multiple of 4, then decode. In Python, base64.b64decode() accepts a validate=False flag and handles missing padding automatically without raising a binascii.Error.

Can I use Base64 to store passwords securely?

No. Base64 is fully reversible with zero security. Never store passwords in Base64, plaintext, or fast hashes like MD5 or SHA-1. Use a slow, salted password hashing algorithm specifically designed for this purpose: bcrypt, scrypt, or Argon2id. These algorithms are intentionally slow to resist brute-force attacks.

Encode or Decode Base64 Instantly

Paste text or drag in a file. BytePane's free Base64 tool encodes and decodes in real time, supports both standard Base64 and URL-safe Base64url, and never uploads your data to any server. No account, no ads, no limits.

Open Base64 Encoder & Decoder

Related Articles