Rails UUID Primary Key with PostgreSQL
- Enable the pgcrypto extension in PostgreSQL to use gen_random_uuid() natively.
- Set config.generators.orm :active_record, primary_key_type: :uuid in application.rb.
- Reference columns for belongs_to associations need foreign_key: {type: :uuid} in migrations.
- UUIDs in Rails are stored as native PostgreSQL UUID type — 16 bytes, properly indexed.
Table of Contents
Rails with PostgreSQL supports UUID primary keys through the pgcrypto extension, which provides the gen_random_uuid() database function. Once configured, Rails generates UUIDs at the database level — no Ruby code change needed per model. The main gotcha is association migrations, which need an explicit UUID type declaration. This guide walks through the complete setup.
Step 1 — Enable the pgcrypto Extension
Create a migration to enable the extension in your PostgreSQL database:
rails generate migration EnablePgcrypto
class EnablePgcrypto < ActiveRecord::Migration[7.1]
def change
enable_extension 'pgcrypto'
end
end
rails db:migrate
The pgcrypto extension adds gen_random_uuid() to PostgreSQL, which generates cryptographically random UUID v4 values. This is what Rails uses as the default value for UUID columns.
If you're on PostgreSQL 13+, you can also use the built-in gen_random_uuid() without the extension — but enabling pgcrypto is the conventional Rails approach and works on all supported PostgreSQL versions.
Step 2 — Configure UUID as Default Primary Key Type
In config/application.rb, tell Rails to use UUID for all generated migrations:
module MyApp
class Application < Rails::Application
config.generators do |g|
g.orm :active_record, primary_key_type: :uuid
end
end
end
After this change, every rails generate model command creates a migration with t.uuid :id, default: "gen_random_uuid()", primary_key: true instead of the default integer id. You don't need to repeat this in each migration.
Step 3 — Create a Model with UUID Primary Key
Generate a model normally:
rails generate model Order customer_email:string total:decimal
The generated migration (with the application.rb config above) will look like:
class CreateOrders < ActiveRecord::Migration[7.1]
def change
create_table :orders, id: :uuid do |t|
t.string :customer_email, null: false
t.decimal :total, precision: 10, scale: 2
t.timestamps
end
end
end
The id: :uuid option sets the column type to PostgreSQL's native UUID type with gen_random_uuid() as the default.
Association Gotcha: Foreign Keys Need UUID Type
This is the most common Rails UUID mistake. When you add a belongs_to reference in a migration, you must declare the foreign key type explicitly:
# WRONG — creates an integer foreign key
t.references :order, foreign_key: true
# CORRECT — creates a UUID foreign key
t.references :order, type: :uuid, foreign_key: true
Or when adding to an existing table:
class AddOrderToLineItems < ActiveRecord::Migration[7.1]
def change
add_reference :line_items, :order, type: :uuid, foreign_key: true
end
end
If you forget the type: :uuid, Rails creates an integer order_id column and the foreign key constraint will fail to link to the UUID primary key.
The Model and ActiveRecord Queries
The Order model needs no UUID-specific code — ActiveRecord handles everything:
class Order < ApplicationRecord
has_many :line_items
validates :customer_email, presence: true
end
# Create
order = Order.create!(customer_email: '[email protected]', total: 49.99)
order.id # => "550e8400-e29b-41d4-a716-446655440000"
# Find by UUID
Order.find('550e8400-e29b-41d4-a716-446655440000')
# In a controller (route: GET /orders/:id)
order = Order.find(params[:id])
Rails routes and controllers work identically whether the primary key is an integer or UUID — the only change is that params[:id] now contains a UUID string. Use the free UUID generator above to create test values for RSpec fixtures, FactoryBot factories, or Postman collections.
Generate Test UUIDs for Rails Fixtures and FactoryBot
The Cheetah UUID Generator produces RFC-compliant UUID v4 strings — copy them into RSpec fixtures, FactoryBot factories, or Rails console commands.
Open Free UUID GeneratorFrequently Asked Questions
Do I need to change my model files to use UUID primary keys?
No. Once the migration sets the UUID column as primary key, ActiveRecord reads the column type from the schema and handles everything automatically. No changes to model files are needed.
Does Rails UUID work with SQLite (for development)?
Not with gen_random_uuid() — that's PostgreSQL-specific. For SQLite in development, you'd need to generate the UUID in Ruby: before_create { self.id ||= SecureRandom.uuid }. Most teams just use PostgreSQL in development to match production.
Will existing Rails routes break when switching to UUIDs?
Routes use params[:id] regardless of type — no route changes needed. Any bookmarked or cached integer-based URLs will 404 after migration since the IDs no longer exist in that format.
How do I write FactoryBot factories with UUID primary keys?
FactoryBot respects the database default, so factories work without changes. For explicit IDs: factory :order do id { SecureRandom.uuid } end.

