UXID
User eXperience focused IDentifiers (UXIDs) are prefixed, K-sortable,
Stripe-style identifiers like usr_01epey2p06tr1rtv07xa82zgjj. They are:
- Descriptive — the prefix names the resource on sight (aids debugging and investigation)
- Copy/paste friendly — double-clicking selects the entire ID
- Tunable in size — shortened for low-cardinality resources
- Secure against enumeration attacks
- Application-generated — not tied to the datastore
- K-sortable — lexicographically sortable by time, so they index well
- Coordination-free — no startup or generation-time coordination required
- Unlikely to collide — more randomness, lower odds
- Human-transmissible — easy to read out accurately over the phone
- Optionally monotonic — a burst within one millisecond stays unique and strictly ordered
- Optionally governed by a registry — one module keeps every prefix unique and maps an ID back to its resource
Many of the concepts of Stripe IDs have been used in this library.
Installation
Add uxid to your dependencies in mix.exs:
def deps do
[
{:uxid, "~> 2.6"}
]
end
Ecto is an optional dependency — UXID only pulls it in if your app already uses it.
Quick start
# No options generates a plain ULID
UXID.generate!() # "01emdgjf0dqxqj8fm78xe97y3h"
# Add a prefix to name the resource
UXID.generate!(prefix: "cus") # "cus_01emdgjf0dqxqj8fm78xe97y3h"
# Shrink the random part for low-cardinality resources
# T-shirt sizes: :xs :s :m :l :xl (or :xsmall :small :medium :large :xlarge)
UXID.generate!(prefix: "cus", size: :small) # "cus_01eqrh884aqyy1"
# Uppercase to match earlier UXID versions
UXID.generate!(case: :upper) # "01EMDGJF0DQXQJ8FM78XE97Y3H"
Ecto in 30 seconds
UXIDs work as Ecto fields, including primary keys — set the field type to UXID
and pass the same options you'd pass to generate!/1:
defmodule YourApp.User do
use Ecto.Schema
@primary_key {:id, UXID, autogenerate: true, prefix: "usr", size: :medium}
schema "users" do
field :api_key, UXID, autogenerate: true, prefix: "apikey", size: :small
end
end
See the Ecto Integration guide for foreign keys, strict
validation, and migrating a uuid column to UXIDs.
Guides
The five-minute path is above; each area has a dedicated guide:
- Sizes & Encoding — the t-shirt sizes, how much randomness each carries, and compact-time mode for extra collision resistance.
- Ecto Integration — primary/foreign keys, strict
validate:casting,allow_uuidcoexistence, andUXID.valid?/2. - Monotonic IDs — guaranteed same-millisecond uniqueness and ordering, the security tradeoff, and when to use it.
- Prefix Registry — a compile-time DSL that keeps every prefix unique, routes an ID back to its schema, works in layered/umbrella apps, and exports a cross-source JSON manifest.
- Configuration — every
config :uxidkey in one place, with per-call vs. global precedence.
Documentation
Full API docs are on HexDocs. The registry and routing patterns are drawn from Adam Kirk's ElixirConf US 2025 talk, UXIDs in Elixir/Ecto.
License
UXID is released under the MIT License.