Rando
Rando is a library for generating identifiers. IDs are random and universally unique by default. Options can be modified to fit a wide variety of requirements. In a node environment, randomness is provided by the node:crypto module. In a browser environment, randomness is provided by the Web Crypto API.
Install
npm i @balancer-team/rando
Usage
Import the rando class and create an instance. The instance generates IDs with the generate() method.
import { Rando } from '@balancer-team/rando'
const rando = new Rando()
rando.generate() // => "Jb46bM8xM3mhDLnpQrwNvN"
Customizing the Length
If you want a longer random string, for example if you want extra security for an API key, it's easy to modify the length. The example below generates a 46-character ID with over 256 bits of entropy:
const rando = new Rando({ length: 46 })
rando.generate() //=> "X5533mwXPH6V2nMN5548t1vkFVN4RTJqM89JNQcbVjmt1G"
Sortable IDs
Rando can generate sortable IDs where the beginning of the ID is an encoded timestamp using the given alphabet. Rando will evaluate the alphabet length and automatically determine how many characters are required to encode a timestamp at millisecond precision. The length must be sufficient for millisecond precision. Refer to the table below for guidance on the length needed to support a given year with a given alphabet base.
const rando = new Rando({ sortable: true })
rando.generate()
// Output:
//
// "13DNYFr2DBJvhWfWCs58Nb"
// |------||------------|
// Sortable Random
// Segment Segment
Sortable IDs can be decoded to return a date. Note that the instance doing the decoding must have the same options as the instance that generated it.
rando.getDate('13DNYFr2DBJvhWfWCs58Nb').toISOString() //=> "2025-02-25T13:11:45.061Z"
All Options
Rando instances can be extensively customized to generate the perfect identifier for your requirements. Here's the type definition of all available options, with details below:
type RandoOptions = {
alphabet?: string
length?: number
sortable?: boolean
supportDate?: Date
}
| Property | Default | Description |
|---|---|---|
alphabet | BASE_50 | A string of characters to use to generate your IDs. Each character must be unique. The default base 50 alphabet excludes vowels and ambiguous characters. |
length | 22 | The length of the ID. By default, the length is 22 which provides 124 bits of entropy, slightly more than a UUIDv4. |
sortable | false | Makes the ID sortable when set to true. The leading characters encode a timestamp at millisecond precision. |
supportDate | '4000' | Allows you to specify a target date for the sortable segment. See below for additional details. |
Special Considerations for Sortable IDs
The length and base of the alphabet together determine how long the sortable segment must be for millisecond precision. If the length is too short, Rando will throw an error when instantiated. The supportDate property allows you to specify a target date for the sortable segment to support. The sortable segment will be left-padded to support the target date with a consistent overall length.
Note that making an ID sortable will reduce the number of random characters in the ID. If you console.log the instance, you will see several helpful properties such as randomBits that can help you determine whether or not the ID meets your requirements.
const rando = new Rando({ sortable: true })
// Output:
//
// Rando {
// alphabet: '123456789BCDFGHJKLMNPQRSTVWXYZbcdfghjkmnpqrstvwxyz',
// length: 22,
// randomLength: 13,
// base: 50,
// randomBits: 73.37013046707142,
// randomLimit: 1.2207031249999986e+22,
// sortable: true,
// supportDate: 4000-01-01T00:00:00.000Z,
// sortableLength: 9,
// sortableLimit: +063862-01-25T10:13:20.000Z
// }
Presets
Rando comes with a few presets to make it easy to generate IDs for common use cases.
import { rando, sorto, locker, sesame, pinto } from '@balancer-team/rando/presets'
rando.generate() //=> "7kFD8XHYp1JdXXzYsxRvXT"
sorto.generate() //=> "13DNYDsRBvc6TQ2HwHh1GW"
locker.generate() //=> "5Myvnv4BQm7rDhz3zntYGMXf9Srr71z7wFwF1SSYMQVvQQ"
tribble.generate() //=> "C5W3C4FP14KSDXBJ"
sesame.generate() //=> "E@MvHJG4JbA$o8li"
pinto.generate() //=> "368230"
randoDefault, like a compact UUIDv4.sortoSortable string followed by a random string, like a compact UUIDv7.lockerLong string with over 256 bits of entropy, suitable for API keys.tribbleA trillion billion possible values. Easy to type.sesameSecure 16-character password.pintoNumerical 6-digit pin for verification codes.
Guidance for Sortable IDs
The following table is a guide for the length needed to support at least the year 3000 with a given alphabet base.
| Base | Length | Max Year |
|---|---|---|
| 2 | 46 | 4199 |
| 3 | 29 | 4144 |
| 4 | 23 | 4199 |
| 5 | 20 | 4992 |
| 6 | 18 | 5188 |
| 7 | 17 | 9341 |
| 8 | 16 | 10889 |
| 9 | 15 | 8494 |
| 10 | 14 | 5138 |
| 11 | 14 | 14003 |
| 12 | 13 | 5360 |
| 13 | 13 | 11567 |
| 14 | 13 | 27121 |
| 15 | 12 | 6081 |
| 16 | 12 | 10889 |
| 17 | 12 | 20432 |
| 18 | 11 | 4006 |
| 19 | 11 | 5661 |
| 20 | 11 | 8459 |
| 21 | 11 | 13069 |
| 22 | 11 | 20486 |
| 23 | 11 | 32163 |
| 24 | 11 | 50190 |
| 25 | 10 | 4992 |
| 26 | 10 | 6443 |
| 27 | 10 | 8494 |
| 28 | 10 | 11356 |
| 29 | 10 | 15301 |
| 30 | 10 | 20681 |
| 31 | 10 | 27942 |
| 32 | 10 | 37648 |
| 33 | 10 | 50503 |
| 34 | 10 | 67387 |
| 35 | 9 | 4467 |
| 36 | 9 | 5188 |
| 37 | 9 | 6088 |
| 38 | 9 | 7205 |
| 39 | 9 | 8584 |
| 40 | 9 | 10277 |
| 41 | 9 | 12344 |
| 42 | 9 | 14856 |
| 43 | 9 | 17896 |
| 44 | 9 | 21557 |
| 45 | 9 | 25948 |
| 46 | 9 | 31193 |
| 47 | 9 | 37433 |
| 48 | 9 | 44832 |
| 49 | 9 | 53572 |
| 50 | 9 | 63862 |
| 51 | 9 | 75936 |
| 52 | 9 | 90061 |
| 53 | 9 | 106535 |
| 54 | 8 | 4261 |
| 55 | 8 | 4623 |
| 56 | 8 | 5034 |
| 57 | 8 | 5501 |
| 58 | 8 | 6028 |
| 59 | 8 | 6622 |
| 60 | 8 | 7292 |
| 61 | 8 | 8044 |
| 62 | 8 | 8888 |
| 63 | 8 | 9833 |
| 64 | 8 | 10889 |