JavaScript
Base64 Encoding
String Manipulation
Web Development
Coding Techniques

How can you encode/decode a string to Base64 in JavaScript?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Base64 encoding in JavaScript is easy for simple text, but the correct approach depends on two things: whether the input is really text or raw bytes, and whether the code runs in a browser or in Node.js. Most mistakes happen when code assumes all JavaScript strings are safe input for btoa, which is not true for arbitrary Unicode.

Browser API: btoa and atob

In browser environments, the classic functions are:

javascript
1const encoded = btoa("Hello, world!");
2console.log(encoded); // SGVsbG8sIHdvcmxkIQ==
3
4const decoded = atob(encoded);
5console.log(decoded); // Hello, world!

This works for text that fits the Latin1-style expectations of btoa and atob.

The Unicode Problem

The biggest surprise is that btoa does not accept arbitrary Unicode text safely.

javascript
btoa("こんにちは");

That usually throws because btoa expects a binary string, not a full UTF-16 JavaScript string with arbitrary characters.

For Unicode-safe handling in browsers, encode the text to bytes first with TextEncoder, then convert those bytes to Base64.

Unicode-Safe Browser Helpers

javascript
1function encodeBase64Utf8(text) {
2  const bytes = new TextEncoder().encode(text);
3  let binary = "";
4
5  for (const byte of bytes) {
6    binary += String.fromCharCode(byte);
7  }
8
9  return btoa(binary);
10}
11
12function decodeBase64Utf8(base64) {
13  const binary = atob(base64);
14  const bytes = Uint8Array.from(binary, char => char.charCodeAt(0));
15  return new TextDecoder().decode(bytes);
16}
17
18const encoded = encodeBase64Utf8("こんにちは世界");
19console.log(encoded);
20console.log(decodeBase64Utf8(encoded));

This is a much safer browser pattern than older escape or encodeURIComponent workarounds.

Node.js: Use Buffer

In Node.js, Buffer is the standard solution and handles UTF-8 naturally:

javascript
1const encoded = Buffer.from("こんにちは世界", "utf8").toString("base64");
2console.log(encoded);
3
4const decoded = Buffer.from(encoded, "base64").toString("utf8");
5console.log(decoded);

For server-side JavaScript, this is usually the simplest and most reliable approach.

URL-Safe Base64

Some systems use a URL-safe Base64 variant that replaces + and / and may omit padding. JavaScript does not switch to that form automatically, so if an API expects URL-safe output you need to transform it deliberately after encoding.

Base64 Is Encoding, Not Encryption

It is important to remember what Base64 is for. It does not secure data. It only converts bytes into a text-safe representation.

Examples of valid uses:

  • embedding binary content in text formats
  • basic transport through systems expecting text
  • data URLs or serialized payloads

Examples of invalid expectations:

  • hiding secrets
  • protecting passwords
  • treating Base64 as cryptography

Anyone can decode Base64 immediately if they have the string.

Working with JSON Payloads

A common pattern is encoding a JSON string before transport or storage:

javascript
1const payload = { userId: 42, role: "admin" };
2const json = JSON.stringify(payload);
3
4const encoded = btoa(json);
5const decoded = JSON.parse(atob(encoded));
6
7console.log(decoded.role); // admin

This works in the browser only if the JSON string stays within the character constraints of btoa. For arbitrary Unicode content, use the UTF-8-safe helper shown earlier.

Binary Data Versus Text

Another common confusion is mixing text encoding and binary encoding. If you are dealing with files, image bytes, or arbitrary binary blobs, treat the data as bytes first rather than as a JavaScript text string.

For example, in Node:

javascript
1const fs = require("fs");
2
3const fileBytes = fs.readFileSync("logo.png");
4const base64 = fileBytes.toString("base64");
5console.log(base64.slice(0, 40));

That is different from Base64-encoding human-readable text.

Common Pitfalls

The biggest mistake is using btoa directly on Unicode text. It may work for simple English strings and then break the moment accented or non-Latin characters appear.

Another issue is forgetting whether the code is running in the browser or in Node.js. Buffer is the natural Node solution, while btoa and atob are browser-oriented APIs.

Another common issue is confusing standard Base64 and URL-safe Base64. Two strings can look almost identical and still be invalid for the target API if the alphabet or padding rule is different.

Finally, do not treat Base64 as a security measure. If the problem is confidentiality, you need encryption, not encoding.

Summary

  • In browsers, btoa and atob work for simple Base64 tasks.
  • For Unicode-safe browser code, use TextEncoder and TextDecoder.
  • In Node.js, prefer Buffer.from(...).toString("base64") and the reverse operation.
  • Base64 is encoding, not encryption.
  • Keep text encoding and binary-byte handling separate so the conversion stays correct.

Course illustration
Course illustration

All Rights Reserved.