UUIDv7 for Elixir and (optionally) Ecto, using always-increasing clock-precision for monotonicity.
Uses suggestions described in Section 6.2 from RFC 9562 to add additional sort precision to a version 7 UUID.
- You want sequential, time-based, ordered IDs (per-node).
- You are willing to trade a small amount of raw performance for these guarantees.
NOTE: In this library, sequential UUIDs and ordering are more important than time precision and performance. We take a slight hit in both of those areas to ensure that the UUIDs are in order. For example, in the case of a backwards time leap, or even concurrent requests at the same time, we continue with the previously used timestamp and increment the clock precision by a minimum step.
- You don't care about sort/order precision beyond milliseconds.
There are other UUID packages, that only have millisecond precision, for example:
The package can be installed by adding uuid_v7
to your list of dependencies in mix.exs
:
def deps do
[
{:uuid_v7, "~> 0.6.0"}
]
end
iex> UUIDv7.generate()
"018e90d8-06e8-7f9f-bfd7-6730ba98a51b"
iex> UUIDv7.bingenerate()
<<1, 142, 144, 216, 124, 16, 127, 196, 158, 92, 92, 74, 83, 46, 116, 173>>
Use this the same way you would use Ecto.UUID
. For example:
defmodule MyApp.Blog.Post do
use Ecto.Schema
@primary_key {:id, UUIDv7.Type, autogenerate: true}
@foreign_key_type UUIDv7.Type
schema "blog_posts" do
field :text, :string
# etc.
end
end
To use UUIDs for everything in your migrations, it's easiest to just add that as the default type in your config. e.g.:
# config/config.exs
config :app, App.Repo,
migration_primary_key: [type: :binary_id],
migration_foreign_key: [type: :binary_id]
If you need to generate UUIDs in migrations (e.g. inserting or seeding data), then also add this to your Repo config as well:
# config/config.exs
config :app, App.Repo,
start_apps_before_migration: [:uuid_v7]
Run benchmarks with
MIX_ENV=bench mix run bench/filename.exs
Where filename.exs
is the name of one of the benchmark files in the bench
directory.
(which has no extra clock precision, only millisecond precision.)
Name ips average deviation median 99th %
uniq v7 string 2.13 M 468.64 ns ±4155.60% 417 ns 584 ns
uuid_v7 string 1.98 M 504.57 ns ±3338.92% 458 ns 667 ns
Comparison:
uniq v7 string 2.13 M
uuid_v7 string 1.98 M - 1.08x slower +35.93 ns
Name ips average deviation median 99th %
uniq v7 raw 3.14 M 318.58 ns ±8234.89% 250 ns 417 ns
uuid_v7 raw 2.85 M 351.26 ns ±4999.60% 292 ns 459 ns
Comparison:
uniq v7 raw 3.14 M
uuid_v7 raw 2.85 M - 1.10x slower +32.69 ns