Monotonic UUIDv7 Generator in Pure JS

Generate time-ordered UUIDv7 identifiers with a 48-bit millisecond prefix and a 12-bit counter that keeps values increasing.

JavascriptData Integrity

Code

snippet
let lastTimestamp = -1;
let counter = 0;

export function uuidv7() {
  if (typeof globalThis.crypto?.getRandomValues !== "function") {
    throw new Error("crypto.getRandomValues is required to generate UUIDv7");
  }
  let timestamp = Date.now();
  if (timestamp < lastTimestamp) timestamp = lastTimestamp;
  if (timestamp === lastTimestamp) {
    counter += 1;
    if (counter > 0x0fff) {
      timestamp = lastTimestamp + 1;
      counter = 0;
    }
  } else {
    counter = 0;
  }
  lastTimestamp = timestamp;
  const bytes = new Uint8Array(16);
  globalThis.crypto.getRandomValues(bytes);
  bytes[0] = Math.floor(timestamp / 2 ** 40) & 0xff;
  bytes[1] = Math.floor(timestamp / 2 ** 32) & 0xff;
  bytes[2] = Math.floor(timestamp / 2 ** 24) & 0xff;
  bytes[3] = Math.floor(timestamp / 2 ** 16) & 0xff;
  bytes[4] = Math.floor(timestamp / 2 ** 8) & 0xff;
  bytes[5] = timestamp & 0xff;
  bytes[6] = 0x70 | ((counter >> 8) & 0x0f);
  bytes[7] = counter & 0xff;
  bytes[8] = (bytes[8] & 0x3f) | 0x80;
  const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
  return [
    hex.slice(0, 4).join(""),
    hex.slice(4, 6).join(""),
    hex.slice(6, 8).join(""),
    hex.slice(8, 10).join(""),
    hex.slice(10, 16).join(""),
  ].join("-");
}

const first = uuidv7();
const second = uuidv7();
console.log(first);
console.log(second);
console.log(first < second);