Code Guide

How to Base64 Encode/Decode in JavaScript, Python, and the Command Line

πŸ“… September 2026⏱️ 5 min read
Every major language and OS has built-in Base64 support β€” no external library required in most cases. Here's the copy-paste snippet for each, including the Unicode gotcha that trips people up in JavaScript.

JavaScript (Browser)

Browsers have built-in btoa() (binary-to-ASCII, encode) and atob() (ASCII-to-binary, decode). They work great for plain ASCII text:

const encoded = btoa('Hello');   // "SGVsbG8="
const decoded = atob('SGVsbG8='); // "Hello"

The catch: btoa() only supports Latin1 characters (code points 0–255) and throws InvalidCharacterError on anything outside that range β€” which means emoji, Chinese, Japanese, and most non-English text will break it. The fix is to UTF-8 encode the string into bytes first, then Base64-encode those bytes:

function utf8ToB64(str) {
  const bytes = new TextEncoder().encode(str);
  let bin = '';
  bytes.forEach(b => bin += String.fromCharCode(b));
  return btoa(bin);
}
function b64ToUtf8(b64) {
  const bin = atob(b64);
  const bytes = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
  return new TextDecoder().decode(bytes);
}

utf8ToB64('Hello πŸ‘‹ δΈ–η•Œ'); // works fine, unlike plain btoa()

Node.js

Node's built-in Buffer class handles Base64 (and Unicode) natively β€” no workaround needed:

const encoded = Buffer.from('Hello πŸ‘‹ δΈ–η•Œ', 'utf-8').toString('base64');
console.log(encoded);

const decoded = Buffer.from(encoded, 'base64').toString('utf-8');
console.log(decoded); // "Hello πŸ‘‹ δΈ–η•Œ"

Python

Python's standard library base64 module works on bytes, so you need .encode() before encoding and .decode() after decoding:

import base64

# Encode
text = "Hello πŸ‘‹ δΈ–η•Œ"
encoded_bytes = base64.b64encode(text.encode('utf-8'))
encoded_str = encoded_bytes.decode('ascii')
print(encoded_str)

# Decode
decoded_bytes = base64.b64decode(encoded_str)
decoded_str = decoded_bytes.decode('utf-8')
print(decoded_str)  # "Hello πŸ‘‹ δΈ–η•Œ"

Command Line

Linux / macOS

Most Unix-like systems ship with a base64 command:

# Encode
echo -n "Hello" | base64
# SGVsbG8=

# Decode
echo -n "SGVsbG8=" | base64 --decode
# Hello (use -D instead of --decode on macOS/BSD)

Windows

Windows doesn't ship a plain base64 command, but certutil (built into every Windows install) can do it, or use PowerShell directly:

:: certutil (writes to/from a file)
certutil -encode input.txt output.b64
certutil -decode output.b64 decoded.txt

# PowerShell (in-memory, no temp file needed)
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("Hello"))
[Text.Encoding]::UTF8.GetString([Convert]::FromBase64String("SGVsbG8="))
πŸ’‘ Don't need to write code right now?

If you just need a one-off Base64 encode or decode, skip the code entirely β€” do it directly in your browser, with full Unicode support built in.

Try the Base64 Encoder/Decoder

Encode or decode Base64 instantly, free, no code required, with full Unicode support.

Open Base64 Tool β†’

Frequently Asked Questions

Why does btoa() throw an error on some strings?
btoa() only accepts characters in the Latin1 range (code points 0–255). Any character outside that range β€” emoji, Chinese, Japanese, Korean, Cyrillic, and more β€” causes it to throw InvalidCharacterError. Encode the string to UTF-8 bytes first (with TextEncoder) before passing it to btoa() to avoid this.
Why do I need .encode() and .decode() in Python but not in Node.js?
Python's base64 module operates strictly on bytes objects, not str, so you must explicitly convert your string to bytes with .encode('utf-8') before encoding, and convert the decoded bytes back to a string with .decode('utf-8') afterward. Node's Buffer class handles this string-to-bytes conversion internally when you pass an encoding argument, so it feels more automatic.
Is there a difference between standard Base64 and the Base64 used in JWTs?
Yes β€” JWTs use "Base64URL," a URL-safe variant that replaces + with -, / with _, and typically omits the trailing = padding. If you're decoding a JWT segment with a standard Base64 library, you may need to substitute those characters back and re-add padding first, or use a library function specifically meant for Base64URL.