Buffer.allocUnsafe()
Allocates a Buffer without zeroing it, trading initialised memory for allocation speed.
Buffer.allocUnsafe(size[, alignment])- Added in Node.js v5.10.0
Parameters
| Parameter | Type | Description |
|---|---|---|
$size | integer | The desired length of the new Buffer. |
$alignmentoptional | integer | If given, the memory backing the new Buffer will start at an address that is a multiple of alignment. Must be a power of two no larger than 2 ** 30. |
Return value
BufferA new Buffer of size bytes whose contents are undefined until written.
Errors
Throws ERR_OUT_OF_RANGE if size is negative or greater than buffer.constants.MAX_LENGTH, and ERR_INVALID_ARG_TYPE if size is not a number.
Changelog
- PHP v26.8.0Added the alignment argument; on earlier releases a second argument is ignored.
- PHP v20.0.0Invalid arguments now throw ERR_INVALID_ARG_TYPE or ERR_OUT_OF_RANGE instead of ERR_INVALID_ARG_VALUE.
- PHP v7.0.0Passing a negative size now throws instead of returning an empty buffer.
Buffer.allocUnsafe() skips the zeroing pass that Buffer.alloc() performs. The returned buffer contains whatever those bytes held previously — often the remains of an earlier buffer from the same process, which may be a password, a session token or another user's request body.
The contract you are accepting
You must write every byte you will later read or send. If you allocate 64 bytes, write 40 and hand the whole buffer onward, the last 24 bytes are leaked memory. The safe pattern is to allocate, fill immediately, and pass a subarray of only the region you actually wrote.
Why it is faster
Allocations smaller than Buffer.poolSize >> 1 (2 KiB by default) are carved out of a shared pre-allocated pool, so there is no per-call allocation at all. Larger requests bypass the pool. The win is real only in hot paths that allocate constantly; for a handful of buffers, the difference is unmeasurable and the risk is not worth it.
Buffer.allocUnsafeSlow() does the same thing but never uses the pool, which matters when you intend to retain a small buffer for a long time and do not want it pinning an 8 KiB chunk.
Example
When to use it
- Allocate a read target in a hot loop where fs.read overwrites the whole block.
- Build a fixed-size binary frame whose every field is written immediately.
- Avoid the zero-fill cost when generating large buffers filled from a source.
- Use allocUnsafeSlow for a small buffer you will retain, to keep it off the shared pool.
Frequently asked questions
Why does Buffer.allocUnsafe contain random garbage?
Because it returns memory without clearing it, so you see whatever the previous owner of those bytes left behind. That content is not random in the cryptographic sense; it can be recognisable data from elsewhere in your process.
Is Buffer.allocUnsafe actually faster than Buffer.alloc?
Yes, because it skips the zero fill and, for sizes below Buffer.poolSize >> 1, carves the buffer out of an existing pool instead of allocating. The gap only shows up in code that allocates in a tight loop.
When should I use allocUnsafeSlow instead of allocUnsafe?
Use allocUnsafeSlow for a small buffer you will keep for a long time, because allocUnsafe would take it from the shared 8 KiB pool and keep that entire slab alive. For short-lived buffers the pooled version is the better choice.
More examples
The leak this causes
This is the failure mode that made the old new Buffer(size) constructor a security problem. The fix is not to inspect the buffer but to bound it: keep the byte count buf.write returned and pass only that region onward.
// Something earlier in the process used this memory.
Buffer.from('password=hunter2&session=abc123').fill(0x41); // pretend it was freed
const buf = Buffer.allocUnsafe(32);
buf.write('OK'); // only 2 bytes written
// Sending the whole buffer sends 30 bytes you never set.
socket.write(buf); // WRONG
// Send only what you wrote.
const written = buf.write('OK');
socket.write(buf.subarray(0, written)); // rightA read loop where it is justified
One buffer is allocated once and reused, and every iteration only touches the prefix that readSync actually filled. The zero fill would be pure waste here because the kernel overwrites the region anyway.
const fs = require('node:fs');
const fd = fs.openSync('data.bin', 'r');
const chunk = Buffer.allocUnsafe(64 * 1024);
let total = 0;
for (;;) {
// read() overwrites bytes 0..bytesRead, and we never look past that.
const bytesRead = fs.readSync(fd, chunk, 0, chunk.length, null);
if (bytesRead === 0) break;
total += bytesRead;
process.stdout.write(chunk.subarray(0, bytesRead));
}
fs.closeSync(fd);
console.log('bytes copied:', total);Pooling, and when to use allocUnsafeSlow
Buffers under half of Buffer.poolSize share one backing ArrayBuffer, which is why small.buffer.byteLength reports 8192 rather than 16. If you cache such a buffer for the life of the process, allocUnsafeSlow gives it a private allocation so the shared slab can be collected.
console.log('poolSize:', Buffer.poolSize); // 8192
const small = Buffer.allocUnsafe(16);
console.log('pooled :', small.buffer.byteLength === Buffer.poolSize); // true
const big = Buffer.allocUnsafe(Buffer.poolSize);
console.log('unpooled:', big.buffer.byteLength === big.length); // true
// A retained small buffer keeps the whole 8 KiB slab alive.
const retained = Buffer.allocUnsafeSlow(16);
console.log('own slab:', retained.buffer.byteLength); // 16
Discussion