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.Builder define __shortuuid__/0, an optional ShortUUID.Behaviour callback that returns the alphabet, base, encoded length and canonical: 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.Behaviour module is now a prefixed ID (usr_...) that wraps ShortUUID and 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.md covers prefixed IDs and when a hand-written module may report canonical: 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.Builder have documentation showing the encoded length and alphabet.
  • usage-rules.md with guidance for coding agents, and markdown docs with an llms.txt index on hexdocs.
  • ShortUUID.Behaviour documents 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.Builder no 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/1 only accepts integers in the 128-bit range, and ShortUUID.Core.encode_int/5 returns {: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

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.Builder module for creating custom ShortUUID modules

Changed

  • Moved core functionality to ShortUUID.Core
  • Simplified main ShortUUID module 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 specified
  • v3.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 ns
  • v2.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/op

    after:

    ## 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