Portable UUIDv7 generator for Clojure, ClojureScript, Babashka, nbb, and scittle.
Implements RFC 9562 Section 6.2 Method 3 (monotonic random):
Usage: (require '[com.github.franks42.uuidv7.core :as uuidv7]) (uuidv7/uuidv7) ;=> #uuid "0195xxxx-xxxx-7xxx-xxxx-xxxxxxxxxxxx"
;; Extract embedded data: (uuidv7/extract-ts u) ;=> 1738934578991 (ms since epoch) (uuidv7/extract-inst u) ;=> #inst "2025-02-07..." (as Date) (uuidv7/extract-key u) ;=> [ts a bh bl] (sortable composite key)
The 74-bit counter space (~1.9 * 10^22 values per millisecond) is effectively inexhaustible. On each new millisecond the counter reseeds with fresh random bits. Within the same millisecond it increments by a random amount (1 to 2^31), preserving both monotonicity and unpredictability.
The extraction functions (extract-ts, extract-counter, extract-key,
extract-inst) require a UUIDv7. Use uuidv7? to validate first:
(when (uuidv7/uuidv7? u) (uuidv7/extract-ts u)) ;=> Safe to call after validation
Passing anything else to an extraction function throws an ex-info
with {:type ::not-uuidv7} in its ex-data.
Portable UUIDv7 generator for Clojure, ClojureScript, Babashka, nbb, and scittle.
Implements RFC 9562 Section 6.2 Method 3 (monotonic random):
- 48-bit millisecond Unix timestamp
- 74-bit monotonically increasing random counter
- Sub-millisecond ordering guaranteed from a single generator
- No blocking, no spinning, no overflow in practice
Usage:
(require '[com.github.franks42.uuidv7.core :as uuidv7])
(uuidv7/uuidv7) ;=> #uuid "0195xxxx-xxxx-7xxx-xxxx-xxxxxxxxxxxx"
;; Extract embedded data:
(uuidv7/extract-ts u) ;=> 1738934578991 (ms since epoch)
(uuidv7/extract-inst u) ;=> #inst "2025-02-07..." (as Date)
(uuidv7/extract-key u) ;=> [ts a bh bl] (sortable composite key)
The 74-bit counter space (~1.9 * 10^22 values per millisecond)
is effectively inexhaustible. On each new millisecond the counter
reseeds with fresh random bits. Within the same millisecond it
increments by a random amount (1 to 2^31), preserving both
monotonicity and unpredictability.
## UUID Validation
The extraction functions (`extract-ts`, `extract-counter`, `extract-key`,
`extract-inst`) require a UUIDv7. Use `uuidv7?` to validate first:
(when (uuidv7/uuidv7? u)
(uuidv7/extract-ts u)) ;=> Safe to call after validation
Passing anything else to an extraction function throws an ex-info
with `{:type ::not-uuidv7}` in its ex-data.(extract-counter uuid)Extract the 74-bit monotonic counter from a UUIDv7 as a three-element vector [rand-a rand-b-hi rand-b-lo] (12 + 30 + 32 bits).
The vector compares lexicographically, preserving the same total order as the original UUID. Suitable as a composite key component: [(extract-ts u) (extract-counter u)]
Consistent shape on all platforms (JVM and JS).
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.
Extract the 74-bit monotonic counter from a UUIDv7 as a three-element
vector [rand-a rand-b-hi rand-b-lo] (12 + 30 + 32 bits).
The vector compares lexicographically, preserving the same total order
as the original UUID. Suitable as a composite key component:
[(extract-ts u) (extract-counter u)]
Consistent shape on all platforms (JVM and JS).
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.(extract-inst uuid)Extract the creation timestamp from a UUIDv7 as a Date/inst. Useful for logging, auditing, and debugging.
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.
Extract the creation timestamp from a UUIDv7 as a Date/inst.
Useful for logging, auditing, and debugging.
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.(extract-key uuid)Extract a sortable composite key [ts rand-a rand-b-hi rand-b-lo] from a UUIDv7.
The four-element vector compares lexicographically with the same total order as the original UUID. Useful when you want the (timestamp, counter) tuple as a map key or sort key without carrying the UUID itself.
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.
Extract a sortable composite key [ts rand-a rand-b-hi rand-b-lo]
from a UUIDv7.
The four-element vector compares lexicographically with the same
total order as the original UUID. Useful when you want the
(timestamp, counter) tuple as a map key or sort key without
carrying the UUID itself.
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.(extract-ts uuid)Extract the Unix epoch timestamp (milliseconds) from a UUIDv7. Works with any UUID type or UUID string.
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.
Extract the Unix epoch timestamp (milliseconds) from a UUIDv7.
Works with any UUID type or UUID string.
Throws ex-info {:type ::not-uuidv7} if the UUID is not version 7.(make-generator)Create an independent UUIDv7 generator with its own monotonic state. Returns a zero-argument function that produces UUIDv7s.
The returned function is impure in the same way as uuidv7: clock, CSPRNG, and its own state.
Useful when you need multiple independent monotonic sequences, e.g. per-subsystem or per-thread dedicated generators.
Create an independent UUIDv7 generator with its own monotonic state. Returns a zero-argument function that produces UUIDv7s. The returned function is impure in the same way as uuidv7: clock, CSPRNG, and its own state. Useful when you need multiple independent monotonic sequences, e.g. per-subsystem or per-thread dedicated generators.
(random-bytes n)Impure: draws from the platform's CSPRNG.
Returns n bytes from the platform's cryptographically secure generator: a byte[] from java.security.SecureRandom on the JVM and bb, a Uint8Array from crypto.getRandomValues on ClojureScript, nbb and Scittle.
Fails closed: throws if no secure generator is available, rather than falling back to Math.random.
Impure: draws from the platform's CSPRNG. Returns n bytes from the platform's cryptographically secure generator: a byte[] from java.security.SecureRandom on the JVM and bb, a Uint8Array from crypto.getRandomValues on ClojureScript, nbb and Scittle. Fails closed: throws if no secure generator is available, rather than falling back to Math.random.
(uuidv7)Generate a UUIDv7 with monotonic sub-millisecond ordering.
Impure: reads the clock and the CSPRNG, and advances the default generator's state.
Returns java.util.UUID on JVM/BB, cljs.core/UUID on CLJS/nbb/scittle.
Successive calls from the same generator are guaranteed to produce strictly increasing UUIDs, even within the same millisecond. Under concurrency the order is the order in which calls update the state: two threads may receive their UUIDs in the opposite order, so sort by value, not by arrival.
Generate a UUIDv7 with monotonic sub-millisecond ordering. Impure: reads the clock and the CSPRNG, and advances the default generator's state. Returns java.util.UUID on JVM/BB, cljs.core/UUID on CLJS/nbb/scittle. Successive calls from the same generator are guaranteed to produce strictly increasing UUIDs, even within the same millisecond. Under concurrency the order is the order in which calls update the state: two threads may *receive* their UUIDs in the opposite order, so sort by value, not by arrival.
(uuidv7? uuid)True if uuid is a version 7, variant 10xx UUID.
Accepts UUID objects and strings in the canonical 8-4-4-4-12 hex form,
in either case. Anything else — nil, other types, other string forms
such as urn:uuid:... or braces — returns false; never throws.
True if `uuid` is a version 7, variant 10xx UUID. Accepts UUID objects and strings in the canonical 8-4-4-4-12 hex form, in either case. Anything else — nil, other types, other string forms such as `urn:uuid:...` or braces — returns false; never throws.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |