buf.fill()

Overwrites a buffer, or a range within it, with a repeated value and returns the same buffer.

Signature
buf.fill(value[, offset[, end]][, encoding])
  • Added in Node.js v0.5.0

Parameters

ParameterTypeDescription
$valuestring | Buffer | Uint8Array | integerThe value with which to fill buf. An empty value (string, Uint8Array, or Buffer) is coerced to 0.
$offsetoptionalinteger= 0Number of bytes to skip before starting to fill buf.
$endoptionalinteger= buf.lengthWhere to stop filling buf (not inclusive).
$encodingoptionalstring= 'utf8'The encoding for value if value is a string.

Return value

BufferA reference to buf — the same buffer, mutated in place, not a copy.

Errors

Throws ERR_OUT_OF_RANGE when offset or end fall outside the buffer, and ERR_INVALID_ARG_VALUE when value is a zero-length Buffer or Uint8Array.

Changelog

  • PHP v11.0.0Throws ERR_OUT_OF_RANGE instead of ERR_INDEX_OUT_OF_RANGE.
  • PHP v10.0.0Negative end values throw an ERR_INDEX_OUT_OF_RANGE error.
  • PHP v10.0.0Filling a non-zero length buffer with a zero length buffer now throws instead of silently doing nothing.
  • PHP v10.0.0Specifying an invalid string for value now throws instead of being ignored.
  • PHP v5.7.0The encoding parameter is supported.

buf.fill() writes a repeating value over a buffer in place and hands the same buffer back, which makes it chain neatly off an allocation. Its two main jobs are initialising memory from Buffer.allocUnsafe() — which hands you whatever bytes were previously in the pool — and wiping data you no longer want sitting in the heap.

The value repeats and truncates

A multi-byte value is written over and over until the range is full, and the final repetition is cut mid-pattern rather than left out. Filling five bytes with the two-byte character 'Ȣ' gives c8 a2 c8 a2 c8, ending on half a character. Anything you decode back may therefore be invalid text.

Integers wrap, they do not throw

A numeric value is masked to one byte with value & 255. That means fill(256) writes zeros and fill(321) writes 0x41, silently, with no warning that your number did not fit.

Wiping is best effort

Filling a buffer with 0 clears that allocation, but it cannot clear copies. Every toString(), JSON.stringify(), or string concatenation you performed earlier left an immutable string the garbage collector owns and you cannot overwrite. Keep secrets in buffers from creation if you intend to wipe them.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Zero the garbage bytes that Buffer.allocUnsafe() returns before writing structured data into them.
  • Overwrite a decryption key or password buffer once you are finished with it.
  • Pad a fixed-width binary record with spaces or null bytes to the field length.
  • Reset a reusable scratch buffer between iterations of a parsing loop.

Frequently asked questions

Does buf.fill() return a new buffer or modify the original?

It modifies the original in place and returns a reference to that same buffer, so `const b = a.fill(0)` leaves a and b pointing at one object. The return value exists for chaining, as in Buffer.allocUnsafe(16).fill(0). If the buffer is a view created by subarray() or slice(), the fill writes through to the parent buffer's memory as well.

How do I zero out a buffer containing a password or key?

Call buf.fill(0) on it as soon as you are done, which overwrites that allocation immediately. This only clears that one buffer, though — any string you produced from it with toString() or template interpolation is immutable and stays in memory until the garbage collector reclaims it. Keep the secret in a Buffer from the moment it is created and never convert it to a string.

Why does buf.fill() with a number over 255 not throw?

Because a numeric value is masked with value & 255 to fit in a single byte, so fill(256) writes 0x00 and fill(321) writes 0x41. There is no warning. Validate the number yourself before calling, or pass a Buffer or Uint8Array when the value is meant to be more than one byte wide.

More examples

Padding fixed-width binary records

Fill first, write second: the fill establishes the padding byte across the whole field and write() overwrites only the prefix it needs, leaving the remainder padded. Without the fill, allocUnsafe would leave whatever bytes the pool last held after the written text, which would end up in the serialised record.

Example · javascript
const { Buffer } = require('node:buffer');

const NAME_WIDTH = 12;

// Space-pad the field, then write the text over the top of it.
function nameField(name) {
  const field = Buffer.allocUnsafe(NAME_WIDTH).fill(0x20); // ASCII space
  field.write(name.slice(0, NAME_WIDTH), 'ascii');
  return field;
}

const record = Buffer.concat([nameField('node'), nameField('buffer')]);
console.log(record.toString('ascii'));
// node        buffer
console.log(record.length);
// 24

// Null-padding instead, for formats that expect it.
const nulPadded = Buffer.allocUnsafe(8).fill(0);
nulPadded.write('id', 'ascii');
console.log(nulPadded);
// <Buffer 69 64 00 00 00 00 00 00>

Range fills mutate shared memory

subarray() and the deprecated slice() return views over the same underlying memory, so filling the view silently rewrites the region of the parent it covers. This is the most common surprise with fill(): code that meant to scrub a temporary corrupts a buffer someone else still holds. Copy with Buffer.from(view) when you need an independent buffer.

Example · javascript
const { Buffer } = require('node:buffer');

const parent = Buffer.from('AAAABBBBCCCC');
const middle = parent.subarray(4, 8);

// subarray() is a view, not a copy — filling it writes through to the parent.
middle.fill(0x2d); // '-'
console.log(middle.toString());
// ----
console.log(parent.toString());
// AAAA----CCCC

// Buffer.from(buf) copies, so the parent is untouched.
const copy = Buffer.from(parent.subarray(0, 4));
copy.fill(0x21); // '!'
console.log(copy.toString());
// !!!!
console.log(parent.toString());
// AAAA----CCCC

Values that throw and values that wrap

Out-of-range integers are the dangerous case, because they fail silently: fill(256) produces zeros and fill(321) produces the letter A, with no error to tell you the value did not fit in a byte. Bad offsets and empty Buffer values do throw, and have since Node.js 10 — before that some of these cases were quietly ignored.

Example · javascript
const { Buffer } = require('node:buffer');

// Integers are masked to one byte rather than rejected.
console.log(Buffer.alloc(4).fill(256));
// <Buffer 00 00 00 00>   (256 & 255 === 0)
console.log(Buffer.alloc(4).fill(321));
// <Buffer 41 41 41 41>   (321 & 255 === 65, 'A')

// An empty string is coerced to 0.
console.log(Buffer.alloc(4).fill(''));
// <Buffer 00 00 00 00>

// An empty Buffer is not: it throws.
try {
  Buffer.alloc(4).fill(Buffer.alloc(0));
} catch (err) {
  console.log(err.code);
  // ERR_INVALID_ARG_VALUE
}

// An out-of-bounds end throws.
try {
  Buffer.alloc(4).fill('a', 0, 9);
} catch (err) {
  console.log(err.code);
  // ERR_OUT_OF_RANGE
}

Discussion

  • Be the first to comment on this lesson.