Buffers Basics
7 examples to get you started with Buffers - 5 basic and 2 intermediate.
Prerequisites
- Node.js 24.18.0 -
Bufferis global; also available vianode:buffer. - Understand when to use Streams instead of loading entire files.
Basic Examples
1. Allocate a Buffer
Create fixed-size binary storage with known encoding upfront.
import { Buffer } from 'node:buffer';
const buf = Buffer.alloc(8); // zero-filled
buf.write('hello', 0, 'utf8');
console.log(buf.toString('utf8')); // hello with null paddingBuffer.alloc(n)zero-fills - safe for crypto and secrets.Buffer.allocUnsafe(n)is faster but may contain old memory - overwrite fully before use.Buffer.byteLength(str, 'utf8')sizes UTF-8 without allocating.
Related: Buffer Security - zero-fill and leaks
2. Create from String
Encode text into bytes with an explicit encoding.
const text = 'Node.js 24';
const buf = Buffer.from(text, 'utf8');
console.log(buf.length, Buffer.byteLength(text, 'utf8'));- Default encoding is
utf8- specify explicitly in security-sensitive code. - Invalid sequences for the encoding throw
TypeErrorin strict conversions. buf.toString('hex')dumps bytes for debugging protocols.
Related: Text Encodings - UTF-8 and malformed input
3. Slice Without Copying
slice returns a view sharing the same underlying memory.
const original = Buffer.from('abcdef', 'utf8');
const slice = original.subarray(2, 5); // 'cde'
slice[0] = 67; // 0x43 'C'
console.log(original.toString()); // abCdefsubarrayis the modern alias - same behavior asslicefor Buffers.- Mutating a slice affects the parent - copy with
Buffer.from(slice)when isolating. - Useful for parsing length-prefixed frames without allocations.
4. Compare and Concatenate
Binary equality and joining chunks from network reads.
const a = Buffer.from('abc');
const b = Buffer.from('abc');
console.log(a.equals(b)); // true
const combined = Buffer.concat([Buffer.from('hel'), Buffer.from('lo')]);equalsis timing-safe enough for length-matched buffers - usecrypto.timingSafeEqualfor secrets.Buffer.concat(list, totalLength)pre-size when you know final length to avoid realloc.- Avoid massive
concatin loops - use a list then one concat or a stream.
5. Read File into Buffer (Small Files)
Fine for config and keys; use streams for large assets.
import { readFile } from 'node:fs/promises';
const buf = await readFile('logo.png');
console.log(buf.length, buf[0], buf[1]); // PNG magic bytes- Entire file loads into memory - cap file size for untrusted uploads.
buf.subarray(0, 8)inspects magic numbers for type sniffing.- For user uploads, prefer streaming to object storage.
Related: fs and fs/promises - async file I/O
Intermediate Examples
6. Uint8Array Interop
Web APIs and fetch bodies use Uint8Array - Buffers are Uint8Array subclasses.
const buf = Buffer.from([1, 2, 3]);
const view: Uint8Array = buf;
console.log(view instanceof Uint8Array); // true
const copy = Buffer.from(view); // copies when isolation neededArrayBufferviews from WASM or Web Crypto interoperate via.buffer,.byteOffset,.byteLength.- Be careful with shared memory views - copy before async handoff if mutating.
Buffer.from(arrayBuffer, byteOffset, length)creates a view-backed Buffer.
7. Length-Prefixed Message
Common binary framing pattern for TCP protocols.
function encodeFrame(payload: Buffer): Buffer {
const header = Buffer.alloc(4);
header.writeUInt32BE(payload.length);
return Buffer.concat([header, payload]);
}
function decodeFrame(data: Buffer): { frame: Buffer; rest: Buffer } {
const len = data.readUInt32BE(0);
return { frame: data.subarray(4, 4 + len), rest: data.subarray(4 + len) };
}- Use big-endian (
BE) network byte order by convention. - TCP may deliver partial frames - accumulate in a Buffer list until complete.
- See Binary Protocols for production parsers.
Related: Streams Basics - large payload handling
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.