Ruby on Rails has supported UUID primary keys since Rails 4, but the defaults still favour auto-increment integers. Rails 7.2 tightened the UUID integration — the uuid generator option now sets up PostgreSQL uuid columns correctly without extra configuration. Migrating to UUID v7 requires one additional step: swapping Rails’ built-in SecureRandom.uuid (which generates v4) for a v7 source. The uuidv7 gem provides a drop-in replacement that follows RFC 9562 and keeps B-tree indexes sequential on PostgreSQL and MySQL.

Enabling UUID primary keys in Rails

Set the default primary key type in config/application.rb:

config.generators do |g|
  g.orm :active_record, primary_key_type: :uuid
end

Generate a migration for an existing table:

class AddUuidToPosts < ActiveRecord::Migration[7.2]
  def change
    add_column :posts, :uuid_id, :uuid, default: -> { "gen_random_uuid()" }, null: false
    # After backfilling, swap to UUID v7 default via PostgreSQL 18:
    # change_column_default :posts, :uuid_id, from: nil, to: -> { "uuidv7()" }
  end
end

Switching from UUID v4 to UUID v7

Add the gem:

# Gemfile
gem 'uuidv7'

Configure the model to use v7:

class ApplicationRecord < ActiveRecord::Base
  before_create :set_uuid_v7

  private

  def set_uuid_v7
    self.id ||= UUIDv7.generate
  end
end

Alternatively, use a PostgreSQL 18 database default so the ID is assigned at the database layer — this keeps UUID generation consistent for bulk inserts via INSERT INTO ... SELECT that bypass Rails callbacks.

PostgreSQL 18 database default

ALTER TABLE posts
  ALTER COLUMN id SET DEFAULT uuidv7();

This ensures every row inserted — from Rails, from a database migration, or from a direct SQL script — gets a time-ordered UUID v7 primary key. The PostgreSQL 18 UUID functions documentation covers uuidv7(), uuid_extract_timestamp(), and the related helper functions.

Index performance comparison

Primary key typeInsert patternIndex fragmentationCache hit rate
SERIAL / BIGSERIALSequentialMinimalHigh
UUID v4RandomHigh after ~100K rowsLow
UUID v7Near-sequentialMinimalHigh

UUID v7 matches auto-increment performance on B-tree indexes because new values always land near the end of the index. The PostgreSQL B-tree implementation guide explains why sequential inserts minimise page splits.

Stimulus and Hotwire patterns

When generating UUIDs client-side in Stimulus controllers (for optimistic UI updates), use the browser’s crypto.randomUUID() for v4, or the uuid npm package for v7. The client-generated UUID is sent to Rails, which validates format before inserting:

# Controller
def create
  @post = Post.new(post_params)
  raise ArgumentError, "Invalid UUID" unless @post.id.match?(/\A[0-9a-f-]{36}\z/i)
  @post.save!
end

Further reading

External references

Frequently asked questions

How do I enable UUID primary keys in Rails?

Add config.generators.orm :active_record, primary_key_type: :uuid to application.rb, then run rails generate model Post — Rails creates a uuid column as the primary key automatically. For UUID v7, use the activeuuid gem or generate v7 values from PostgreSQL 18's uuidv7() function via a database default.

Does Rails support UUID v7 natively?

Rails itself uses UUID v4 via SecureRandom.uuid. For UUID v7 you need either the uuidv7 gem (Ruby implementation of RFC 9562) or a database-side default on PostgreSQL 18. The database-default approach keeps ID generation consistent regardless of which application server creates the record.

Will UUID primary keys break ActiveRecord associations?

No. ActiveRecord handles UUID primary keys and foreign keys transparently — belongs_to, has_many, and has_and_belongs_to_many all work as long as foreign key columns are also declared as :uuid type. The Rails ActiveRecord guides document the :id option for migrations and the primary_key option for models.