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, binaryReading 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.