How to Encode and Decode Base64 in JavaScript, Node.js, Python, Go, and Shell
Practical developer recipes for Base64 encoding and decoding: fixing Unicode UTF-8 character corruption in JavaScript, Node.js Buffers, Python, Go, and Linux CLI.
The JavaScript Unicode UTF-8 Trap
A classic bug in web development occurs when passing UTF-8 strings containing emojis, accented characters, or non-Latin scripts (e.g., "CoShareX 🚀") to the browser's legacy window.btoa() function. Because btoa() expects each string character to occupy a single byte within code points 0x00 to 0xFF, multi-byte Unicode sequences immediately throw an uncatchable InvalidCharacterError DOMException.
1. Modern Browser JavaScript (TextEncoder / TextDecoder)
The modern standard method to encode and decode arbitrary Unicode strings in browsers uses TextEncoder to convert the string to a Uint8Array, followed by binary string conversion:
// Universal Browser UTF-8 Base64 Encoder
export function encodeBase64Utf8(str: string): string {
const bytes = new TextEncoder().encode(str);
const binString = Array.from(bytes, (byte) => String.fromCharCode(byte)).join('');
return btoa(binString);
}
// Universal Browser UTF-8 Base64 Decoder
export function decodeBase64Utf8(base64: string): string {
const binString = atob(base64);
const bytes = Uint8Array.from(binString, (m) => m.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
// Example usage:
const encoded = encodeBase64Utf8("CoShareX 🚀 Fast & Secure");
console.log(encoded); // "Q29TaGFyZVgg8J+agCBGYXN0ICYgU2VjdXJl"
console.log(decodeBase64Utf8(encoded)); // "CoShareX 🚀 Fast & Secure"2. Node.js & TypeScript (Buffer API)
In Node.js, the native Buffer class provides instant, zero-copy encoding between UTF-8 and Base64:
// Node.js Base64 Encoding & Decoding
import { Buffer } from 'node:buffer';
const rawText = 'CoShareX Platform Engineering';
// Encode string to Base64
const base64Str = Buffer.from(rawText, 'utf-8').toString('base64');
console.log(base64Str); // "Q29TaGFyZVggUGxhdGZvcm0gRW5naW5lZXJpbmc="
// Decode Base64 back to UTF-8
const decodedText = Buffer.from(base64Str, 'base64').toString('utf-8');
console.log(decodedText); // "CoShareX Platform Engineering"
// URL-Safe Base64 in Node.js:
const urlSafeBase64 = Buffer.from(rawText).toString('base64url');3. Python 3 (base64 standard library)
import base64
raw_text = "CoShareX 🚀 Data Pipelines"
# Encode: Convert string to bytes, then base64 encode
encoded_bytes = base64.b64encode(raw_text.encode('utf-8'))
encoded_str = encoded_bytes.decode('ascii')
print("Encoded:", encoded_str)
# Decode: Decode base64 bytes, then decode utf-8
decoded_bytes = base64.b64decode(encoded_str)
decoded_text = decoded_bytes.decode('utf-8')
print("Decoded:", decoded_text)
# URL-Safe Base64 in Python:
url_safe_encoded = base64.urlsafe_b64encode(raw_text.encode('utf-8')).decode('ascii')4. Go (encoding/base64)
package main
import (
"encoding/base64"
"fmt"
)
func main() {
raw := "CoShareX High Throughput"
// Standard Encoding
encoded := base64.StdEncoding.EncodeToString([]byte(raw))
fmt.Println("Base64:", encoded)
// Decoding
decodedBytes, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
panic(err)
}
fmt.Println("Decoded:", string(decodedBytes))
// URL-Safe Encoding
urlSafe := base64.URLEncoding.EncodeToString([]byte(raw))
fmt.Println("URL Safe:", urlSafe)
}5. Linux & macOS Terminal CLI
# Linux / macOS: Encode text
echo -n "CoShareX Security" | base64
# Linux: Decode Base64 string
echo -n "Q29TaGFyZVggU2VjdXJpdHk=" | base64 -d
# macOS: Decode Base64 string (BSD syntax)
echo -n "Q29TaGFyZVggU2VjdXJpdHk=" | base64 -D
# Encode an image or binary file
base64 -i icon.png -o icon.b64Code Formatter & Converter Suite
Validate, format, minify, and convert JSON, SQL, YAML, XML, and code dialects directly on your local machine.
Frequently Asked Questions
Why does base64 output end with "=" or "=="?
The equal sign (=) is padding added when the input length is not divisible by 3 bytes. Two "=" characters indicate 1 remaining byte, while one "=" indicates 2 remaining bytes.
How do I handle large binary files without memory exhaustion?
Use streaming encoders (such as Node.js Transform streams or Python file chunks) to process binary data in 64KB blocks rather than loading multi-gigabyte files into RAM.
Conclusion
Use native platform byte buffers and Unicode-safe abstractions to guarantee error-free Base64 encoding across browsers, servers, and scripts.
Related Articles
Base64 Encode vs Decode: Binary Conversions, Error Handling & Performance Pitfalls
Understand the architectural differences between Base64 encoding and decoding: memory transformations, corrupt padding errors, and performance overhead.
Developer ToolsHow to Encode and Decode URLs: RFC 3986 Percent-Encoding, URLSearchParams & Polyglot Recipes
Complete guide to URL percent-encoding and decoding: RFC 3986 rules, query string construction, multi-byte UTF-8 handling, and code recipes in JS, Python, Go, and Shell.
ConvertersWhat is Base64? Binary-to-Text Encoding Explained from Bitwise Roots
A deep architectural guide to Base64 encoding: 6-bit binary chunking, ASCII translation tables, padding mathematics, and URL-safe variants.