Rails::Snowflake
A Rails plugin that provides Snowflake-like IDs for your ActiveRecord models with minimal configuration.
Snowflake IDs are 64-bit integers that contain:
- 48 bits for millisecond-level timestamp
- 16 bits for sequence data (includes hashed table name + secret salt + sequence number)
This ensures globally unique, time-sortable IDs that don't reveal the total count of records in your database.
Features
-
Transparent - Just use
t.snowflake
and it works automatically -
Automatic database setup - Hooks into
db:migrate
anddb:prepare
tasks to ensure everything is set up.
Installation
Add this line to your application's Gemfile:
gem "rails-snowflake"
And then execute the installer (note the underscore):
rails generate rails_snowflake:install
Quick Start
That's it! Just use t.snowflake
in your migrations and everything works automatically.
For Snowflake ID as primary key:
class CreateUsers < ActiveRecord::Migration[8.0]
def change
create_table :users, id: false do |t|
t.snowflake :id, primary_key: true # Snowflake primary key
t.string :name
t.timestamps
end
end
end
Note: When using t.snowflake :id
directly, Rails will complain about redefining the primary key. Always use create_table :table_name, id: false
when you want a snowflake primary key.
For additional snowflake columns (non-primary key):
class CreatePosts < ActiveRecord::Migration[8.0]
def change
create_table :posts do |t|
t.string :title
t.text :content
t.snowflake :uid # Additional snowflake column
t.timestamps
end
end
end
Generator Support
You can also use Snowflake helper in Rails generators:
# Generate a model with a snowflake field
rails generate model Post title:string uid:snowflake
# This will create a migration like:
# create_table :posts do |t|
# t.string :title
# t.snowflake :uid
# t.timestamps
# end
Working with Snowflake IDs
There's nothing else to be done at this point. t.snowflake
columns will automatically get unique IDs on record creation, and they are just a :bigint
column in the database.
At this point, you can use them like any other integer ID.
user = User.create!(name: "Alice")
user.id # => 115198501587747344
# Convert ID back to timestamp
Rails::Snowflake::Id.to_time(user.id)
# => 2024-12-25 10:15:42 UTC
# Generate ID for specific timestamp
Rails::Snowflake::Id.at(1.hour.ago)
# => 1766651542000012345
Database Integration
The gem automatically hooks into these Rails tasks:
db:migrate
db:schema:load
db:structure:load
db:seed
Migration from Standard IDs
If you have existing models with standard Rails IDs, you'll need to run a migration to convert them to Snowflake IDs.
execute("ALTER TABLE table_name ALTER COLUMN id SET DEFAULT timestamp_id('table_name')")
⚠️ Warning: This is a complex operation that may require downtime and careful planning.
Requirements
- Database: PostgreSQL >= 15
- Rails: 7.1+
- Ruby: 3.2+
How it Works
-
Function Creation: Creates a PostgreSQL
timestamp_id()
function -
Sequence Management: Auto-creates sequences for each table (
table_name_id_seq
) - ID Generation: Uses timestamp + hashed sequence for uniqueness
- Rails Integration: Hooks into model lifecycle and database tasks
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/my-new-feature
) - Add tests for your changes
- Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin feature/my-new-feature
) - Create a Pull Request
License
The gem is available as open source under the terms of the MIT License.
Acknowledgements
The implementation of Snowflake-like ids was initially done by Mastodon