Back to Blog
Node.jsBufferBinaryBackend

Node.js Buffer Guide

Master Node.js Buffers for working with binary data and raw memory.

B
Bootspring Team
Engineering
September 21, 2018
6 min read

Buffers handle binary data in Node.js. Here's how to work with them effectively.

Creating Buffers#

1// Create empty buffer 2const buf1 = Buffer.alloc(10); // 10 bytes, filled with zeros 3 4// Create with fill value 5const buf2 = Buffer.alloc(10, 1); // 10 bytes, filled with 1 6 7// Create without initialization (faster but unsafe) 8const buf3 = Buffer.allocUnsafe(10); // May contain old data 9 10// Create from string 11const buf4 = Buffer.from('Hello, World!'); 12const buf5 = Buffer.from('Hello', 'utf8'); // Explicit encoding 13 14// Create from array 15const buf6 = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]); 16 17// Create from another buffer 18const buf7 = Buffer.from(buf4); 19 20// Create from ArrayBuffer 21const arrayBuffer = new ArrayBuffer(10); 22const buf8 = Buffer.from(arrayBuffer);

Encodings#

1const str = 'Hello, World!'; 2 3// UTF-8 (default) 4const utf8 = Buffer.from(str, 'utf8'); 5 6// Other encodings 7const utf16 = Buffer.from(str, 'utf16le'); 8const latin1 = Buffer.from(str, 'latin1'); 9const base64 = Buffer.from(str, 'base64'); 10const hex = Buffer.from(str, 'hex'); 11const ascii = Buffer.from(str, 'ascii'); 12 13// Convert back to string 14utf8.toString('utf8'); 15utf8.toString('base64'); 16utf8.toString('hex'); 17 18// Supported encodings: 19// utf8, utf16le, latin1, base64, base64url, hex, ascii, binary

Reading and Writing#

1const buf = Buffer.alloc(10); 2 3// Write string 4buf.write('Hello'); 5buf.write('World', 5); // Start at offset 5 6 7// Write with encoding 8buf.write('48656c6c6f', 0, 'hex'); 9 10// Read/write integers 11buf.writeUInt8(255, 0); // 1 byte unsigned 12buf.writeUInt16BE(65535, 1); // 2 bytes big-endian 13buf.writeUInt32LE(12345, 3); // 4 bytes little-endian 14buf.writeInt8(-128, 7); // 1 byte signed 15 16const val1 = buf.readUInt8(0); 17const val2 = buf.readUInt16BE(1); 18const val3 = buf.readUInt32LE(3); 19const val4 = buf.readInt8(7); 20 21// Write floats 22const floatBuf = Buffer.alloc(8); 23floatBuf.writeFloatLE(3.14, 0); 24floatBuf.writeDoubleLE(3.14159265359, 0); 25 26const float = floatBuf.readFloatLE(0); 27const double = floatBuf.readDoubleLE(0); 28 29// BigInt (64-bit) 30const bigBuf = Buffer.alloc(8); 31bigBuf.writeBigUInt64LE(BigInt('9007199254740993')); 32const big = bigBuf.readBigUInt64LE();

Slicing and Copying#

1const buf = Buffer.from('Hello, World!'); 2 3// Slice (shares memory!) 4const slice = buf.slice(0, 5); 5console.log(slice.toString()); // 'Hello' 6 7// Modifying slice affects original 8slice[0] = 0x4a; // 'J' 9console.log(buf.toString()); // 'Jello, World!' 10 11// subarray (alias for slice) 12const sub = buf.subarray(7, 12); 13 14// Copy (doesn't share memory) 15const copy = Buffer.alloc(5); 16buf.copy(copy, 0, 0, 5); 17 18// Copy to specific position 19const dest = Buffer.alloc(20); 20buf.copy(dest, 5); // Copy to position 5 21 22// Clone buffer 23const clone = Buffer.from(buf);

Concatenation#

1const buf1 = Buffer.from('Hello'); 2const buf2 = Buffer.from(' '); 3const buf3 = Buffer.from('World'); 4 5// Concatenate buffers 6const combined = Buffer.concat([buf1, buf2, buf3]); 7console.log(combined.toString()); // 'Hello World' 8 9// With total length 10const limited = Buffer.concat([buf1, buf2, buf3], 8); 11console.log(limited.toString()); // 'Hello Wo' 12 13// Efficient concatenation for many buffers 14function concatBuffers(buffers) { 15 const totalLength = buffers.reduce((sum, buf) => sum + buf.length, 0); 16 return Buffer.concat(buffers, totalLength); 17}

Comparison#

1const buf1 = Buffer.from('ABC'); 2const buf2 = Buffer.from('ABD'); 3const buf3 = Buffer.from('ABC'); 4 5// Compare 6buf1.compare(buf2); // -1 (buf1 < buf2) 7buf2.compare(buf1); // 1 (buf2 > buf1) 8buf1.compare(buf3); // 0 (equal) 9 10// Equality 11buf1.equals(buf3); // true 12buf1.equals(buf2); // false 13 14// Sort buffers 15const buffers = [buf2, buf1, buf3]; 16buffers.sort(Buffer.compare);

Searching#

1const buf = Buffer.from('Hello, World!'); 2 3// Find index 4buf.indexOf('o'); // 4 5buf.indexOf('o', 5); // 8 (start from index 5) 6buf.indexOf(Buffer.from('World')); // 7 7buf.indexOf(0x6f); // 4 (byte value) 8 9// Last index 10buf.lastIndexOf('o'); // 8 11 12// Includes 13buf.includes('World'); // true 14buf.includes('world'); // false 15buf.includes(Buffer.from([0x48, 0x65])); // true (He)

Iteration#

1const buf = Buffer.from('Hello'); 2 3// for...of 4for (const byte of buf) { 5 console.log(byte); // 72, 101, 108, 108, 111 6} 7 8// forEach 9buf.forEach((byte, index) => { 10 console.log(index, byte); 11}); 12 13// entries 14for (const [index, byte] of buf.entries()) { 15 console.log(index, byte); 16} 17 18// keys 19for (const index of buf.keys()) { 20 console.log(index); 21} 22 23// values 24for (const byte of buf.values()) { 25 console.log(byte); 26}

Conversion#

1const buf = Buffer.from('Hello'); 2 3// To string 4buf.toString(); // 'Hello' 5buf.toString('base64'); // 'SGVsbG8=' 6buf.toString('hex'); // '48656c6c6f' 7 8// To JSON 9buf.toJSON(); 10// { type: 'Buffer', data: [72, 101, 108, 108, 111] } 11 12JSON.stringify(buf); 13// '{"type":"Buffer","data":[72,101,108,108,111]}' 14 15// From JSON 16const json = buf.toJSON(); 17const restored = Buffer.from(json.data); 18 19// To ArrayBuffer 20const arrayBuffer = buf.buffer.slice( 21 buf.byteOffset, 22 buf.byteOffset + buf.byteLength 23); 24 25// To Uint8Array 26const uint8 = new Uint8Array(buf);

Base64 Encoding#

1// Encode to base64 2const text = 'Hello, World!'; 3const base64 = Buffer.from(text).toString('base64'); 4// 'SGVsbG8sIFdvcmxkIQ==' 5 6// Decode from base64 7const decoded = Buffer.from(base64, 'base64').toString(); 8// 'Hello, World!' 9 10// Base64url (URL-safe) 11const base64url = Buffer.from(text).toString('base64url'); 12// No + or / characters 13 14// Encode binary data 15import { readFileSync, writeFileSync } from 'fs'; 16 17const imageData = readFileSync('image.png'); 18const imageBase64 = imageData.toString('base64'); 19 20// Data URL 21const dataUrl = `data:image/png;base64,${imageBase64}`;

Working with Files#

1import { createReadStream, createWriteStream } from 'fs'; 2 3// Read file into buffer 4import { readFile } from 'fs/promises'; 5const fileBuffer = await readFile('file.bin'); 6 7// Process binary file 8const header = fileBuffer.slice(0, 4); 9const data = fileBuffer.slice(4); 10 11// Stream processing 12const readStream = createReadStream('large-file.bin'); 13 14readStream.on('data', (chunk) => { 15 // chunk is a Buffer 16 console.log('Received', chunk.length, 'bytes'); 17}); 18 19// Write buffer to file 20import { writeFile } from 'fs/promises'; 21const data = Buffer.from([0x00, 0x01, 0x02]); 22await writeFile('output.bin', data);

Network Operations#

1import { createServer } from 'net'; 2 3const server = createServer((socket) => { 4 socket.on('data', (data) => { 5 // data is a Buffer 6 console.log('Received:', data); 7 8 // Parse protocol 9 const messageType = data.readUInt8(0); 10 const messageLength = data.readUInt16BE(1); 11 const payload = data.slice(3, 3 + messageLength); 12 13 // Send response 14 const response = Buffer.alloc(10); 15 response.writeUInt8(1, 0); // Response type 16 response.write('OK', 1); 17 socket.write(response); 18 }); 19}); 20 21server.listen(3000);

TypedArray Interop#

1// Buffer is a Uint8Array subclass 2const buf = Buffer.from([1, 2, 3, 4]); 3 4console.log(buf instanceof Uint8Array); // true 5 6// Use TypedArray methods 7buf.map(x => x * 2); 8buf.filter(x => x > 2); 9buf.reduce((a, b) => a + b); 10 11// Create views 12const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); 13view.getInt16(0, true); // Little-endian 14 15// Share ArrayBuffer 16const arrayBuffer = new ArrayBuffer(8); 17const buf1 = Buffer.from(arrayBuffer, 0, 4); 18const buf2 = Buffer.from(arrayBuffer, 4, 4);

Best Practices#

Creation: ✓ Use Buffer.alloc for security ✓ Use Buffer.from for conversion ✓ Specify encoding explicitly ✓ Use allocUnsafe only when needed Memory: ✓ Reuse buffers when possible ✓ Use slice carefully (shares memory) ✓ Pool buffers for frequent allocation ✓ Watch for memory leaks Performance: ✓ Pre-allocate known sizes ✓ Use streams for large data ✓ Batch small writes ✓ Use TypedArrays when appropriate Avoid: ✗ new Buffer() (deprecated) ✗ allocUnsafe without filling ✗ Assuming encoding ✗ Ignoring byte order

Conclusion#

Buffers are essential for binary data handling in Node.js. Use them for file I/O, network protocols, cryptography, and any binary processing. Understand endianness for cross-platform compatibility, use appropriate encodings, and be mindful of memory sharing with slices. For large data, prefer streams over loading entire files into buffers.

Share this article

Help spread the word about Bootspring