Skip to content
Blog

Base64 Encoding and Decoding: The Developer's Practical Cheatsheet

From text to images to JSON payloads - every Base64 operation a developer needs, explained with examples and linked directly to the free browser tool.

Share:Twitter/XLinkedIn

Every developer uses Base64 daily - in JWTs, data URLs, API responses, and config files. But when you need to do something with it, the documentation is scattered. This guide collects every Base64 operation you'll actually need, with working code and a browser tool to match.

No theory. No padding lecture. Just the stuff you Google at 11pm.

Base64 in 60 Seconds

Base64 converts binary data into a string of 64 safe ASCII characters. It exists because JSON, HTML, HTTP headers, and email were all designed for text - not raw bytes.

The same string encoded in Base64 is about 37% larger than the original binary. That's the price of safety.

Rule of thumb: Base64 is for transport, not storage. And it is absolutely not encryption.

Text → Base64

The most common operation. You have a string, you need the Base64 version.

JavaScript (browser or Node.js):

const text = "Hello, World!";
const encoded = btoa(text); // "SGVsbG8sIFdvcmxkIQ=="

Python:

import base64
text = "Hello, World!"
encoded = base64.b64encode(text.encode("utf-8")).decode("utf-8")
# "SGVsbG8sIFdvcmxkIQ=="

Node.js:

const Buffer = require("buffer").Buffer;
const text = "Hello, World!";
const encoded = Buffer.from(text).toString("base64");

The pitfall most developers hit: non-ASCII characters. btoa() fails on "café" in JavaScript. Handle it properly:

const encoded = btoa(unescape(encodeURIComponent("café")));
// To decode:
const decoded = decodeURIComponent(escape(atob(encoded)));

Base64 → Text

Reverse the operation to recover your original string.

JavaScript:

const encoded = "SGVsbG8sIFdvcmxkIQ==";
const decoded = atob(encoded); // "Hello, World!"

Python:

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

Node.js:

const decoded = Buffer.from(encoded, "base64").toString("utf-8");

Image → Base64 (Data URL)

This is where Base64 earns its keep. Converting an image to a Base64 data URL lets you embed it directly in HTML or CSS - no file to upload, no server to host it.

When to use data URLs:

  • Small images: icons, logos, flags, UI glyphs
  • Email HTML - attachments don't survive most email clients, but inline data URLs do
  • Single-file demos and prototypes where you can't reference external assets
  • Avoiding an extra HTTP request for a tiny image

When NOT to use:

  • Large photos - a 500KB JPEG becomes a ~670KB Base64 string, and that's inside your HTML
  • Anything that changes frequently - data URLs are static and uncacheable
  • Production web pages - browsers cache regular image files, but inline data URLs are re-downloaded with every page load

The format:

data:[<mediatype>][;base64],<data>

Example:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />

To convert an image to Base64 without uploading it anywhere, use the Toolblip Base64 Encoder - drag in a PNG, JPEG, WebP, or SVG, and it generates the data URL instantly in your browser. Your image never touches a server.

Base64 Image → File

Got a Base64 string and need the actual image file back? Here's how to decode it to disk.

JavaScript (download in browser):

const base64Data = "iVBORw0KGgoAAAANSUhEUgAAAA...";
const mimeType = "image/png";

const blob = new Blob(
  [Uint8Array.from(atob(base64Data), c => c.charCodeAt(0))],
  { type: mimeType }
);

const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "decoded-image.png";
link.click();

Python:

import base64

with open("image.txt", "r") as f:
    base64_data = f.read().strip()

image_bytes = base64.b64decode(base64_data)

with open("image.png", "wb") as f:
    f.write(image_bytes)

Bash (macOS/Linux with OpenSSL):

# Decode and save
echo "iVBORw0KGgoAAAANSUhEUgAAAA..." | base64 -d > image.png

# macOS uses -D instead of -d
echo "iVBORw0KGgoAAAANSUhEUgAAAA..." | base64 -D > image.png

Decoding API Responses

REST APIs love returning Base64-encoded data. Common patterns:

JSON response with Base64 field:

{
  "id": "usr_123",
  "name": "Avery Chen",
  "avatar": "iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHL...",
  "document": "JVBERi0xLjQKJeLjz9MKNSAwIG9iago8PC9MZW5ndGggNDA..."
}

Decode in JavaScript:

const response = await fetch("/api/user/123");
const { avatar, document } = await response.json();

// Render avatar directly as data URL
const avatarUrl = `data:image/png;base64,${avatar}`;
document.querySelector("#avatar").src = avatarUrl;

// Decode document
const docBytes = Uint8Array.from(atob(document), c => c.charCodeAt(0));
const docBlob = new Blob([docBytes], { type: "application/pdf" });

Decode in Python:

import base64
import json

response = requests.get("/api/user/123")
data = response.json()

avatar_bytes = base64.b64decode(data["avatar"])
with open("avatar.png", "wb") as f:
    f.write(avatar_bytes)

JWT Payload Inspection

Every JWT has three Base64-encoded parts separated by dots. You can read the payload without any library:

JavaScript:

const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfMTIzIiwibmFtZSI6IkFhcm9uIiwiaWF0IjoxNzQ...";
const [, payload] = token.split(".");
const decoded = JSON.parse(atob(payload));
console.log(decoded.sub); // usr_123
console.log(decoded.name); // Aaron
console.log(new Date(decoded.exp * 1000)); // Expiration date

Python:

import base64
import json

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfMTIzIiwiY25hbWUiOiJhcm9vbiJ9.SflKxwR..."

# JWT uses "URL-safe" Base64 variant: replace - with + and _ with /
payload = token.split(".")[1]
payload += "=" * (4 - len(payload) % 4)
decoded = json.loads(base64.urlsafe_b64decode(payload))

Note: You can decode a JWT payload instantly in the browser with the Toolblip JWT Decoder - no library, no install, entirely client-side.

Base64 in Configuration Files

Many config formats (Docker, Docker Compose, .env files, SSH keys) use Base64 to store binary data as text.

Dockerfile - encode a file into an ENV variable:

# Build args come in as strings; encode for safe transport
ARG SSL_CERT
ENV SSL_CERT_DATA=$(echo -n "$SSL_CERT" | base64)

docker-compose.yml - storing credentials:

secrets:
  api_key:
    file: ./api_key.txt   # The raw key file on disk

# Or inline (for non-sensitive dev values):
environment:
  - CERT_DATA=dGVzdC1rZXktaGVyZQ==

.env files and binary values:

# .env
SERVICE_ACCOUNT_CREDENTIALS={"type":"service_account",...}
# This JSON string gets Base64-encoded when passed through certain CI systems.
# Decode with: echo "$SERVICE_ACCOUNT_CREDENTIALS" | base64 -d

Common Errors and How to Fix Them

InvalidCharacterError in JavaScript

This fires when atob() or btoa() hits a character outside the Latin1 range. Fix:

// WRONG - fails on non-ASCII
btoa("café"); // Error

// RIGHT
btoa(unescape(encodeURIComponent("café")));
atob(decodeURIComponent(escape(atob(encoded))));

Or use the native TextEncoder and TextDecoder:

const encoder = new TextEncoder();
const decoder = new TextDecoder();

const encoded = btoa(String.fromCharCode(...new Uint8Array(encoder.encode("café"))));
const decoded = decoder.decode(Uint8Array.from(atob(encoded), c => c.charCodeAt(0)));

Wrong Padding

Base64 strings should end with = or == for padding. If you're dealing with a server that strips padding:

import base64

# Add padding if missing
def pad(s):
    return s + "=" * (4 - len(s) % 4)

decoded = base64.b64decode(pad(encoded))

URL-Safe Base64 vs. Standard Base64

Standard Base64 uses + and /. URL-safe Base64 replaces them with - and _ and strips padding. This variant is used in JWTs, OAuth tokens, and some API keys.

// Standard Base64
const standard = btoa("hello?world"); // "aGVsbG8/d29ybGQ="

// URL-safe Base64
const urlSafe = standard.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
// "aGVsbG8_d29ybGQ"

The Quick Reference

Operation JavaScript Python Node.js
Encode text btoa(str) base64.b64encode(str) Buffer.from(str).toString("base64")
Decode text atob(str) base64.b64decode(str) Buffer.from(str, "base64").toString()
Encode bytes btoa(String.fromCharCode(...bytes)) base64.b64encode(bytes) Buffer.from(bytes).toString("base64")
Decode to bytes Uint8Array.from(atob(str), c => c.charCodeAt(0)) base64.b64decode(str) Buffer.from(str, "base64")

Try It in Your Browser

Everything in this guide - text encoding, image conversion, data URL generation - works entirely in your browser with Toolblip Base64 Encoder/Decoder. No upload. No server call. No account.

Open a tab, paste, and you're done.


Related tools on Toolblip:

Related reading:


Part of the Toolblip Developer Tools series - free, no-signup browser tools for developers.

More in Developer Tools
Why Browser-Based Tools Are the Future
4 min read
How to Optimize Images Without Uploading
4 min read
Top 5 Developer Tools You Should Bookmark
5 min read