How to Base64 Encode and Decode in JavaScript
JavaScript has built-in Base64 functions, but they have a famous UTF-8 trap. Here's how to encode and decode correctly.
The basics: btoa and atob
btoa('Hello'); // "SGVsbG8=" (encode)
atob('SGVsbG8='); // "Hello" (decode)
These work for plain ASCII. The names come from "binary to ASCII" and "ASCII to binary."
The UTF-8 problem
btoa throws on characters outside Latin-1 (like emoji or many accented letters):
btoa('café'); // ❌ throws or corrupts
The UTF-8-safe way
Encode through TextEncoder first:
function toBase64(str) {
const bytes = new TextEncoder().encode(str);
let bin = '';
bytes.forEach(b => bin += String.fromCharCode(b));
return btoa(bin);
}
function fromBase64(b64) {
const bin = atob(b64);
const bytes = Uint8Array.from(bin, c => c.charCodeAt(0));
return new TextDecoder().decode(bytes);
}
This round-trips emoji, accents, and any Unicode correctly.
In Node.js
Node uses Buffer, which handles UTF-8 natively:
Buffer.from('café').toString('base64'); // encode
Buffer.from(b64, 'base64').toString('utf-8'); // decode
URL-safe Base64
For tokens and URLs, swap the characters and strip padding:
b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
More on that in URL-safe Base64 encoding.
Test it
Verify your output against the Base64 tool — paste text to encode or a string to decode and compare.
Got a config file to check?
Open the config toolkit →