Simple configuration for UUID primary keys in Ecto
Using UUID’s as primary keys can have many benefits, and if you’re using PostgreSQL you have the advantage of solid performance and efficient storage of those UUIDs leading to good scalability even compared to bigint
.
With Ecto, using UUID primary keys is very easy, however most guides out there are still written for Ecto 1.x or 2.x – in modern times using UUIDs is even easier with Ecto 3+.
In your config.exs
, simply configure your repo to use the :binary_id
by default for primary keys and foreign keys:
config :my_app, MyApp.Repo,
migration_primary_key: [name: :id, type: :binary_id],
migration_foreign_key: [column: :id, type: :binary_id]
You don’t have to modify your migrations at all; Ecto will use UUIDs for keys unless you tell it otherwise, just as it was previously with bigint
keys.
The only other required step is to annotate your schemas so they use :binary_id
as well. You can do this on each individually, but I generally prefer to do this in a behaviour that wraps Ecto.Schema
. For example,
defmodule MyApp.Schema do
@moduledoc """
Behaviour to replace `Ecto.Schema` to set some defaults across all schemas in
the codebase -- namely, UUID primary keys.
"""
defmacro __using__(_opts) do
quote do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
end
end
end
Then you can use this in your schemas:
defmodule MyApp.User do
use MyApp.Schema
...
end
And that’s all there is to it! I hope this helped you avoid setting primary_key: false
in every migration you write.