process.hrtime.bigint()

Returns a monotonic high-resolution timestamp in nanoseconds as a BigInt, for measuring elapsed time.

Signature
process.hrtime.bigint()
  • Added in Node.js v10.7.0

Return value

bigintThe current high-resolution real time in nanoseconds as a bigint, relative to an arbitrary past origin.

Errors

Mixing the returned bigint with a Number in an arithmetic expression throws a TypeError.

process.hrtime.bigint() reads a monotonic clock and returns nanoseconds as a bigint. The absolute value is meaningless — it counts from an arbitrary origin — so it is only ever useful as a difference between two readings.

When to reach for it

Any time you measure a duration. Because the clock is monotonic it cannot go backwards when NTP adjusts the system time or when daylight saving changes, which is exactly the failure that makes Date.now() produce negative or wildly wrong durations in production. It also has nanosecond resolution, where Date.now() has milliseconds.

What trips people up

  • BigInt does not mix with Number. end - start is fine, but elapsed / 1000 throws Cannot mix BigInt and other types. Divide by a BigInt literal — elapsed / 1_000_000n for whole milliseconds — or convert first with Number(elapsed) / 1e6 when you want a fraction.
  • BigInt division truncates. 1_999_999n / 1_000_000n is 1n, not 2n.
  • It does not measure async work by itself. Reading before and after an await measures wall time including everything else the event loop ran in between.
  • It is not a timestamp. Never store it as a date or send it to another process.

Prefer it over the legacy array-returning process.hrtime(), and consider perf_hooks for structured measurements.

Example

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

When to use it

  • Time a hot function during optimisation work with sub-millisecond resolution.
  • Record request handling duration for a latency histogram.
  • Measure a startup phase without a clock adjustment corrupting the number.
  • Compare two implementations of an algorithm inside a benchmark script.

Frequently asked questions

How do I convert process.hrtime.bigint() to milliseconds?

Divide by 1000000n for whole milliseconds, or convert first with `Number(end - start) / 1e6` when you want a fraction. BigInt division truncates, so the first form discards everything below a millisecond.

Why do I get "Cannot mix BigInt and other types"?

Because process.hrtime.bigint() returns a BigInt and JavaScript refuses to combine BigInt and Number in one arithmetic expression. Either make the other operand a BigInt literal ending in n, or wrap the BigInt in Number() before dividing.

Should I use process.hrtime.bigint() or performance.now()?

Both read a monotonic clock, so either is correct for durations; hrtime.bigint() gives integer nanoseconds while performance.now() gives fractional milliseconds as a Number and is portable to browsers. Avoid the legacy process.hrtime(), which returns a [seconds, nanoseconds] array and is documented as Legacy.

More examples

A reusable benchmark helper

The output shows per-call cost in nanoseconds, a resolution Date.now() cannot reach — at roughly 600 ns per call, a millisecond clock would report 0 for hundreds of iterations. The warm-up call is what makes the numbers comparable: without it the first measured iteration also pays for V8 compiling the function, which can dominate a short benchmark.

Example · javascript
function bench(label, fn, iterations = 1000) {
  fn(); // warm up so JIT compilation is not counted

  const start = process.hrtime.bigint();
  for (let i = 0; i < iterations; i++) fn();
  const elapsed = process.hrtime.bigint() - start;

  const perCallNs = Number(elapsed) / iterations;
  console.log(
    `${label.padEnd(16)} total ${(Number(elapsed) / 1e6).toFixed(2)} ms  ` +
    `per call ${perCallNs.toFixed(0)} ns`
  );
}

const words = ['delta', 'alpha', 'charlie', 'bravo'];

bench('sort copy', () => [...words].sort());
bench('toSorted', () => words.toSorted());
// sort copy        total 0.62 ms  per call 620 ns
// toSorted         total 0.55 ms  per call 549 ns

Why the monotonic clock beats Date.now()

The output shows the failure mode this API exists to prevent: a backwards system-clock adjustment during the measurement makes the Date.now() difference negative, while the monotonic reading stays correct. This is not hypothetical — NTP corrections, VM snapshot restores and daylight-saving changes all move the wall clock, and negative durations in a latency histogram are the usual first symptom.

Example · javascript
const wallStart = Date.now();
const monoStart = process.hrtime.bigint();

await new Promise((resolve) => setTimeout(resolve, 250));

// If NTP or an operator moved the system clock back 2 seconds during that wait:
const wallElapsed = Date.now() - wallStart;              // can be negative
const monoElapsed = Number(process.hrtime.bigint() - monoStart) / 1e6;

console.log('wall clock  :', wallElapsed, 'ms');
console.log('monotonic   :', monoElapsed.toFixed(1), 'ms');
console.log('wall clock plausible:', wallElapsed >= 0);
// wall clock  : -1750 ms
// monotonic   : 251.4 ms
// wall clock plausible: false

Discussion

  • Be the first to comment on this lesson.