Base64 in Node.js
Node.js Buffer is the idiomatic way to handle Base64. It works with strings, binary data, and files out of the box — no extra packages needed. Node.js 16+ also added global btoa() and atob() for browser compatibility.
Encoding and Decoding Strings
// Encode a string to Base64
const encoded = Buffer.from('Hello, world!').toString('base64');
console.log(encoded); // "SGVsbG8sIHdvcmxkIQ=="
// Decode Base64 back to a string
const decoded = Buffer.from('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('utf8');
console.log(decoded); // "Hello, world!"
No Unicode issues: Unlike browser btoa(), Buffer.from(str) defaults to UTF-8, so emoji and non-ASCII characters work correctly without extra steps.
URL-Safe Base64 (Node 16+)
// base64url encoding — no +, /, or = characters
const encoded = Buffer.from('Hello, world!').toString('base64url');
console.log(encoded); // "SGVsbG8sIHdvcmxkIQ"
// Decode base64url
const decoded = Buffer.from(encoded, 'base64url').toString('utf8');
console.log(decoded); // "Hello, world!"
For older Node versions, implement it manually:
function toBase64URL(str) {
return Buffer.from(str).toString('base64')
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
function fromBase64URL(b64url) {
let b64 = b64url.replace(/-/g, '+').replace(/_/g, '/');
while (b64.length % 4) b64 += '=';
return Buffer.from(b64, 'base64').toString('utf8');
}
Encoding Files
const fs = require('fs');
// Encode a file to Base64 string
const fileBuffer = fs.readFileSync('image.png');
const encoded = fileBuffer.toString('base64');
console.log(`Encoded size: ${encoded.length} chars`);
// Decode Base64 back to a file
const decoded = Buffer.from(encoded, 'base64');
fs.writeFileSync('output.png', decoded);
Streaming Large Files
const fs = require('fs');
const { pipeline } = require('stream/promises');
// Encode large file using streams
async function encodeFileStream(input, output) {
const readable = fs.createReadStream(input);
const writeable = fs.createWriteStream(output, { encoding: 'ascii' });
let buffer = Buffer.alloc(0);
for await (const chunk of readable) {
buffer = Buffer.concat([buffer, chunk]);
// Process in 3-byte aligned chunks
const aligned = Math.floor(buffer.length / 3) * 3;
if (aligned > 0) {
writeable.write(buffer.slice(0, aligned).toString('base64'));
buffer = buffer.slice(aligned);
}
}
// Flush remaining bytes
if (buffer.length > 0) writeable.write(buffer.toString('base64'));
writeable.end();
}
HTTP Responses — Sending Binary as Base64
const http = require('http');
const fs = require('fs');
const server = http.createServer((req, res) => {
if (req.url === '/image-base64') {
const imageBuffer = fs.readFileSync('logo.png');
const base64 = imageBuffer.toString('base64');
const dataUri = `data:image/png;base64,${base64}`;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ image: base64, dataUri }));
}
});
server.listen(3000);
btoa() and atob() in Node.js 16+
// Available globally in Node 16+ for browser compatibility
const encoded = btoa('Hello'); // "SGVsbG8="
const decoded = atob('SGVsbG8='); // "Hello"
// Note: btoa/atob still have the same Unicode limitation as browsers.
// For Unicode strings, Buffer is the better choice in Node.js.
Working with Streams and Base64 Transform
const { Transform } = require('stream');
class Base64Encode extends Transform {
constructor() {
super();
this._buffer = Buffer.alloc(0);
}
_transform(chunk, enc, cb) {
this._buffer = Buffer.concat([this._buffer, chunk]);
const aligned = Math.floor(this._buffer.length / 3) * 3;
if (aligned > 0) {
this.push(this._buffer.slice(0, aligned).toString('base64'));
this._buffer = this._buffer.slice(aligned);
}
cb();
}
_flush(cb) {
if (this._buffer.length) this.push(this._buffer.toString('base64'));
cb();
}
}
// Usage
fs.createReadStream('input.bin')
.pipe(new Base64Encode())
.pipe(fs.createWriteStream('output.b64'));
Inspect your Node.js Base64 output
Paste the encoded string from your Node.js script into base64.dev to decode and verify it instantly.
Open base64.dev →