Skip to content

Instantly share code, notes, and snippets.

@yano3nora
Last active February 25, 2026 02:02
Show Gist options
  • Select an option

  • Save yano3nora/d7289659a8ec8e3878356bbdd961a381 to your computer and use it in GitHub Desktop.

Select an option

Save yano3nora/d7289659a8ec8e3878356bbdd961a381 to your computer and use it in GitHub Desktop.
ULID - Universally Unique Lexicographically Sortable Identifier

ulid

Getting Started

$ npm i ulid
import { ulid, isValid, decodeTime } from 'ulid'

ulid() // 01ARZ3NDEKTSV4RRFFQ69G5FAV

// timestamp seeding
ulid(1469918176385) // 01ARYZ6S41TSV4RRFFQ69G5FAV

// validation
isValid('01ARYZ6S41TSV4RRFFQ69G5FAV') // true
isValid('01ARYZ6S41TSV4RRFFQ69G5FA')  // false

// decode time
decodeTime('01ARYZ6S41TSV4RRFFQ69G5FAV') // 1469918176385

monotonicFactory

https://github.com/ulid/spec?tab=readme-ov-file#monotonicity

  • 同じミリ秒内では「ソート順序」が崩れてしまう
  • 同じミリ秒内にソート順序を保証したい場合は monotonic で対応できる
  • 極めて稀なケースで、生成失敗する
    • 同一ミリ秒に 2^80 以上の生成をするなど
    • ↑ 実際には js の仕様上 2^80 より少ない数で失敗する可能性もあるが、一般的なアプリで利用する場合はほぼ起こらないと考えてよさそう
import { monotonicFactory } from 'ulid'

const ulid = monotonicFactory()

// Assume that these calls occur within the same millisecond
ulid() // 01BX5ZZKBKACTAV9WEVGEMMVRY
ulid() // 01BX5ZZKBKACTAV9WEVGEMMVRZ
ulid() // 01BX5ZZKBKACTAV9WEVGEMMVS0
ulid() // 01BX5ZZKBKACTAV9WEVGEMMVS1
       // ...
ulid() // 01BX5ZZKBKZZZZZZZZZZZZZZZX
ulid() // 01BX5ZZKBKZZZZZZZZZZZZZZZY
ulid() // 01BX5ZZKBKZZZZZZZZZZZZZZZZ
ulid() // throw new Error()!

Custom PRNG

https://github.com/ulid/javascript?tab=readme-ov-file#pseudo-random-number-generators

  • デフォルトでは、内部の擬似乱数生成器は環境に応じて適切なものが利用される
    • ブラウザ:crypto.getRandomValues
    • Node:crypto.randomBytes
  • PRNG についてカスタムもできる
    • 以下の例は Math.random を利用してるが、insecure なのであくまで例として
import { ulid } from 'ulid'

const ulid = monotonicFactory(() => Math.random())

ulid() // 01BXAVRG61YJ5YSBRM51702F6M

Example

自分用。

import { decodeTime, monotonicFactory, ulid as u } from 'ulid'

const m = monotonicFactory()

export const ulid = () => {
  try {
    return m()
  } catch (e) {
    /**
     * throw はループで高速に生成するなどでしか起こり得ないが、
     * 発生時は sortable を捨てて動作させることを優先する、みたいな
     */
    console.warn(e)
    return u()
  }
}

export const ulid2Timestamp = decodeTime
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment