All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
v4.3.0 (10.11.2026)
Added
- Modules created with
ShortUUID.Builderdefine__shortuuid__/0, an optionalShortUUID.Behaviourcallback that returns the alphabet, base, encoded length andcanonical: true. Libraries such as ecto_shortuuid can use it to skip re-encoding decoded IDs to check them.
Changed
- Faster decoding for alphabets made only of ASCII characters, including all predefined alphabets: they decode with a byte lookup table, about 25-30% faster than in 4.2.0. Input with the wrong length is rejected about 2.5x faster. Other alphabets are unchanged.
- The README's example of a hand-written
ShortUUID.Behaviourmodule is now a prefixed ID (usr_...) that wrapsShortUUIDand accepts only the IDs it produces. The previous example decoded anything after its prefix. A test compiles the example from the README to keep it working. usage-rules.mdcovers prefixed IDs and when a hand-written module may reportcanonical: true.
v4.2.0 (09.11.2026)
Added
- UUIDs can be given as URNs (
urn:uuid:550e8400-e29b-41d4-a716-446655440000). - Functions generated by
ShortUUID.Builderhave documentation showing the encoded length and alphabet. usage-rules.mdwith guidance for coding agents, and markdown docs with anllms.txtindex on hexdocs.ShortUUID.Behaviourdocuments the contract implementations must meet.
Fixed
- Custom alphabets with characters that merge when concatenated (combining marks, regional indicators, emoji modifiers, ZWJ, CR/LF, Hangul jamo) failed to encode or decode many UUIDs. Encoded strings are now matched by codepoint instead of grapheme.
Changed
- Requires Elixir 1.8 or later. CI now checks this by compiling the library and running smoke tests on Elixir 1.8 to 1.13; the full test suite runs on 1.14 and later.
- Custom alphabets are now rejected at compile time if a character is a prefix of another one, a character is not in Unicode NFC form, or Unicode normalization could make an encoded ID decode to a different UUID.
use ShortUUID.Builderno longer adds aliases, imports or module attributes (@alphabet,@base, ...) to the calling module, so it no longer overrides the caller's own attributes.ShortUUID.Core.format_uuid/1only accepts integers in the 128-bit range, andShortUUID.Core.encode_int/5returns{:error, "Invalid UUID"}for other input instead of raising.- Faster decoding.
- Clarified in the docs that alphabets are not required to be URL-safe, that only UUID input is case-insensitive, and which predefined alphabets are compatible with the Python and JavaScript implementations. Compatibility is now tested against fixtures generated with both libraries.
- The changelog is included in the Hex package.
v4.1.0 (08.04.2025)
Added
ShortUUID.Behaviourfor implementing ShortUUID-compatible modules- Modules created with
ShortUUID.Builderdeclare@behaviour ShortUUID.Behaviour
v4.0.0 (25.12.2024)
Breaking changes:
- Dropped support for binary UUID input
Added
- Support for custom alphabets
- Predefined alphabets (base32, base58, base62, base64, etc.)
ShortUUID.Buildermodule for creating custom ShortUUID modules
Changed
- Moved core functionality to
ShortUUID.Core - Simplified main
ShortUUIDmodule interface - Improved error messages and validation
# Old v3.x code still works, the ShortUUID module uses the same alphabet as in V3
# If you just want to keep using ShortUUID no changes are required
ShortUUID.encode(uuid)
# New in v4.x you can use one of the predefined alphabets or define your own
defmodule MyUUID do
use ShortUUID.Builder, alphabet: :base58
end
MyUUID.encode(uuid)
defmodule MyCustomUUID do
use ShortUUID.Builder, alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
end
MyCustomUUID.encode(uuid)v3.0.0 (15.07.2023)
Breaking change, ShortUUIDs created by < v3.0.0 will produce bad results when decoded.
The new output of encode is the reverse of the previous output.
This follows a change in other languages ShortUUID libraries.
To migrate ShortUUIDs created by < v3.0.0 reverse them before passing to decode.
# UUID "00000001-0001-0001-0001-000000000001" encoded using v2.1.2 to "UD6ibhr3V4YXvriP822222"
# reversing the encoded string before decode with v3.0.0 will produce the correct result
iex> "UD6ibhr3V4YXvriP822222" |> String.reverse() |> ShortUUID.decode!()
"00000001-0001-0001-0001-000000000001"Changed
- move most significant bit to the beginning of the encoded result similar to libraries in other languages (most importantly python shortuuid)
- drop support for decoding of un-padded ShortUUIDs
- drop support for formats other than regular hyphenated and unhyphenated UUIDs, MS format and binary UUIDs like are stored in PostgreSQL uuid type
- refactor code for better readability
- improve encode and decode performance
Benchmarks
Results are not comparable to previous benchmarks due to them being run on a different system
Operating System: macOS
CPU Information: Apple M2 Max
Number of Available Cores: 12
Available memory: 32 GB
Elixir 1.15.2
Erlang 25.3.2.3
Benchmark suite executing with the following configuration:
warmup: 2 s
time: 5 s
memory time: 0 ns
parallel: 1
inputs: none specifiedv3.0.0
Name ips average deviation median 99th % encode/1 binary uuid 1212.57 K 0.82 μs ±1995.67% 0.75 μs 1.00 μs encode/1 unhyphenated uuid string 788.79 K 1.27 μs ±984.70% 1.13 μs 1.63 μs encode/1 hyphenated uuid string 753.56 K 1.33 μs ±1106.96% 1.17 μs 1.67 μs encode/1 uuid string with braces 722.36 K 1.38 μs ±1188.51% 1.21 μs 1.83 μs decode/1 1.15 M 868.43 ns ±1506.27% 751 ns 1334 nsv2.1.1
Name ips average deviation median 99th % encode/1 binary uuid 1018.43 K 0.98 μs ±1224.91% 0.88 μs 1.25 μs encode/1 unhyphenated uuid string 849.67 K 1.18 μs ±1171.07% 1.08 μs 1.42 μs encode/1 hyphenated uuid string 731.91 K 1.37 μs ±691.40% 1.29 μs 1.63 μs encode/1 uuid string with braces 569.16 K 1.76 μs ±833.41% 1.63 μs 2.17 μs decode/1 1.00 M 996.37 ns ±781.87% 918 ns 1376 ns
v2.1.2 (2020-04-25)
- fix endless loop when decoding strings whose value does not fit in 128 bits
v2.1.1 (2019-02-18)
speed improvements
Benchmarked on 2018 Macbook Pro 13 (non-touch), results are just a snapshot and not averaged.
before:
## ShortUUIDBench benchmark name iterations average time encode/1 uuid binary 500000 5.93 µs/op encode/1 uuid string not hyphenated 100000 10.71 µs/op encode/1 uuid string 100000 15.35 µs/op encode/1 uuid string with braces 100000 17.22 µs/op decode/1 100000 15.05 µs/opafter:
## ShortUUIDBench benchmark name iterations average time encode/1 uuid binary 500000 3.54 µs/op encode/1 uuid string not hyphenated 500000 4.12 µs/op encode/1 uuid string 500000 4.54 µs/op encode/1 uuid string with braces 500000 5.84 µs/op decode/1 500000 7.97 µs/op
v2.1.0 (2019-02-08)
- support directly encoding binary UUID
v2.0.1 (2019-01-31)
- add error fallbacks for encode/decode for the case where input is not string
- update test cases
- update docs
v2.0.0 (2019-01-29)
- drop support for custom alphabets
- use fixed alphabet 23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz as it seems to be by far the most widely used shortuuid alphabet