This project is part of the @thi.ng/umbrella monorepo.
Configurable K-sortable unique IDs, ULIDs, binary & base-N encoded, 32/48/64bit time resolutions.
Idea based on segmentio/ksuid, though the added flexibility in terms of configuration & implementation also enables the creation of ULIDs:
Feature | KSUID default | ULID default |
---|---|---|
Configurable bit size | 160 bits | 128 bits |
Base-N encoding scheme | base62(1) | base32 (Crockford) |
Timestamp resolution | seconds (32 bits) | milliseconds (48 bits) |
milliseconds (64 bits) | ||
Epoch start time offset | approx. 2020-09-13 | none |
Time-only base ID generation | ✅ | ✅ |
ID parsing / decomposition | ✅ | ✅ |
Configurable RNG source(2) | ✅ | ✅ |
- (1) See @thi.ng/base-n for alternatives
- (2) Default:
window.crypto
,Math.random
as fallback
IDs generated w/ this package are composed of a 32, 48 or 64 bit Unix epochs (by
default time shifted to free up bits for future timestamps) and N additional
bits of a random payload (from a configurable source). IDs can be generated as
byte arrays or base-N encoded strings. For the latter, the JS runtime MUST
support
BigInt
.
STABLE - used in production
Search or submit any issues for this package
- @thi.ng/base-n - Arbitrary base-n conversions w/ presets for base16/32/36/58/62/64/85, support for arrays & bigints
- @thi.ng/idgen - Generator of opaque numeric identifiers with optional support for ID versioning and efficient re-use
- @thi.ng/random - Pseudo-random number generators w/ unified API, distributions, weighted choices, ID generation
yarn add @thi.ng/ksuid
ES module import:
<script type="module" src="https://cdn.skypack.dev/@thi.ng/ksuid"></script>
For Node.js REPL:
# with flag only for < v16
node --experimental-repl-await
> const ksuid = await import("@thi.ng/ksuid");
Package sizes (gzipped, pre-treeshake): ESM: 846 bytes
import { defKSUID32, defKSUID64, defULID } from "@thi.ng/ksuid";
// init 32bit epoch (resolution: seconds) w/ defaults
const id = defKSUID32();
// init 64bit epoch (resolution: milliseconds), same API
const id = defKSUID64();
// init 48bit epoch (resolution: milliseconds), same API
const id = defULID();
id.next();
// '05XCWbXa3akRqLDBUw4ogCVKGkd'
const a = id.nextBinary()
// Uint8Array(20) [
// 0, 160, 48, 77, 101, 251,
// 244, 17, 155, 97, 24, 101,
// 70, 71, 207, 23, 32, 21,
// 244, 116
// ]
// format a binary KSUID
id.format(a);
// '05XCZ32AaDZfZt0SWE2C22o6cqK'
id.parse("05XCZ32AaDZfZt0SWE2C22o6cqK")
// {
// epoch: 1610498125000,
// id: Uint8Array(16) [
// 101, 251, 244, 17, 155, 97,
// 24, 101, 70, 71, 207, 23,
// 32, 21, 244, 116
// ]
// }
new Date(1610498125000).toISOString()
// '2021-01-13T00:35:25.000Z'
Creating custom IDs:
import { BASE36 } from "@thi.ng/base-n";
// no time shift, 64bit random
const id36 = defKSUID32({ base: BASE36, epoch: 0, bytes: 8 });
// '2VOUKH4K59AG0RXR4XH'
yarn bench
benchmarking: b62, 128bit, n=10000
warmup... 659.22ms (10 runs)
executing...
total: 6402.18ms, runs: 100
mean: 64.02ms, median: 63.50ms, range: [59.98..96.15]
q1: 62.64ms, q3: 64.41ms
sd: 6.93%
benchmarking: b62, 64bit, n=10000
warmup... 363.35ms (10 runs)
executing...
total: 3469.28ms, runs: 100
mean: 34.69ms, median: 34.41ms, range: [32.61..56.58]
q1: 33.35ms, q3: 35.41ms
sd: 7.47%
benchmarking: b62, 32bit, n=10000
warmup... 218.78ms (10 runs)
executing...
total: 2118.93ms, runs: 100
mean: 21.19ms, median: 20.95ms, range: [20.20..25.74]
q1: 20.71ms, q3: 21.30ms
sd: 4.14%
Karsten Schmidt
If this project contributes to an academic publication, please cite it as:
@misc{thing-ksuid,
title = "@thi.ng/ksuid",
author = "Karsten Schmidt",
note = "https://thi.ng/ksuid",
year = 2020
}
© 2020 - 2021 Karsten Schmidt // Apache Software License 2.0