ui7
A small UUIDv7 generator, targeting the latest draft update to RFC 4122. v7 UUID’s are lexically sortable by their included timestamp.
import uuid, { timestamp } from "ui7";
const id = uuid();
console.log(new Date(timestamp(id)));
Installation
ui7 is available on NPM and deno.land:
npm
npm install --save ui7
Node.js versions 12.0 and up are supported, and ui7 includes an ESM build. It has no runtime dependencies.
deno
import uuid from "https://deno.land/x/ui7@v0.1.0/mod.ts";
Usage
Default generator
The default UUIDv7 generator is available as both a default export and a named v7
function:
import uuid from "ui7";
console.log(uuid());
import { v7 } from "ui7";
console.log(v7());
Monotonic generators
Version 7 UUID’s include a millisecond-precision timestamp part and a random part. By default, ui7 will fully populate the random part with random bits. This means that ID’s generated during the same millisecond will sort in an arbitrary order:
import uuid from "ui7";
const ids = [uuid(), uuid(), uuid()];
[...ids].sort().map(id => ids.indexOf(id))
If you want UUID’s generated in the same process to sort in the order they were generated, you can instead create a monotonic generator:
import { generator } from "ui7";
const uuid = generator();
const ids = [uuid(), uuid(), uuid()];
[...ids].sort().map(id => ids.indexOf(id))
This uses the 12-bit rand_a
field of UUIDv7 as a counter. For the first timestamp generated in a particular millisecond, the high bit is set to 0, so that there are always at least 2¹¹ (2,048) sequential counter values available before the field overflows (and wraps back to 0).
Retrieving the timestamp
Use the timestamp
function to read the timestamp field of a UUIDv7:
import { timestamp } from "u7";
const time = timestamp("01836db9-3d80-7df2-9c5e-d66442a3cf21");
console.log(new Date(time));
If the input to timestamp
is not a UUIDv7, it throws a ParseError
exception.
Customizing generation
The default uuid
function, the generator
factory function, and the functions returned by generator
all accept some options to customize their behavior.
Setting the time
You can pass a numeric timestamp, Date
object, or custom clock function to a UUID generator or factory:
import uuid from "ui7";
const id1 = uuid(0);
const id2 = uuid(new Date("2009-08-23T03:58:16.491Z"));
const id3 = uuid(() => Date.now() * 2);
const id4 = uuid({ time: 1663993200000 });
Controlling the format
You can omit dashes from the generated UUID’s, or use upper-case hex characters:
import uuid from "ui7";
const id1 = uuid({ dashes: false });
const id2 = uuid({ upper: true });
const id3 = uuid({ dashes: false, upper: true });
Using a different entropy source
By default, ui7 uses crypto.getRandomValues
to populate the random part of the UUID (or crypto.randomFillSync
on Node.js versions that don't support Web-compatible crypto).
You can override this by providing an entropy
function, which must return a Uint8Array
with a byteLength
of 10:
import uuid from "ui7";
const id1 = uuid({ entropy: () => new Uint8Array(10) });
const id2 = uuid({ entropy: () => new Uint8Array(10).map((_, i) => i) })
const id4 = uuid({
entropy(time) {
const b = new Uint8Array(10);
new DataView(b.buffer).setBigUint64(0, BigInt(time));
return b;
}
});
TypeScript
ui7 is written in TypeScript and ships with type definitions.
Should I use this?
UUID’s are currently defined by RFC 4122 (2005), which specifies three UUID versions in common use: 1, 4, and 5. The “UUIDv7” identifiers generated by this package conform to a candidate update to that RFC, and are not a generally-accepted standard.
UUIDv7 – a sortable UUID containing a UNIX timestamp – was first proposed in the second draft from April 2021, and simplified to always hold a millisecond-precision timestamp in the fourth draft from March 2022. The latest draft is from June 2022 and expires at the end of the year. It has not yet entered the formal process of advancing to a published RFC – UUIDv7 may never become standard.
There are advantages to the UUIDv7 format: they encode the time of their creation, and the fact that they naturally sort in order of creation is not only convenient for display, but efficient for being inserted into the B-tree structures that underlie many databases.
But you might reasonably decide to say “no” or “not yet” to UUIDv7, until it is specified in an accepted RFC, or to use a different unique identifier format like ULID.
Should I use this implementation?
ui7 is a compact, zero-dependency implementation of UUIDv7, using a cryptographic PRNG provided by its host environment. It is one of the simplest, but neither the fastest nor the slowest implementation; a few others can be found on NPM.