Announcing SeaORM 2.0 ๐
SeaORM 2.0 is now stable. It arrives after 43 release candidates, and it is the largest release in the project's history.
SeaORM was first introduced in 2021 as an async ORM for Rust, built on top of SeaQuery. 1.0 landed in 2024 and stabilized the core. 2.0 reshapes how you write entities and how you read and write related data, while keeping the 1.0 API available for a gradual migration.
| version | date | notes |
|---|---|---|
| 0.1.0 | 2021-09-20 | initial release |
| 1.0.0 | 2024-08-04 | first stable release |
| 2.0.0-rc.1 | 2025-07-05 | first release candidate |
| 2.0.0 | 2026-07-20 | this release |
A community releaseโ
2.0 was developed in the open, one release candidate at a time, with feedback and fixes from people running SeaORM in production. The numbers below are a snapshot at the time of writing.
| GitHub stars | ~9,800 |
| Downloads on crates.io | 22,000,000+ |
| Releases published | 138 |
| People who contributed to SeaORM | 278 |
| Release candidates for 2.0 | 43 |
| Issues closed | 900+ |
| Pull requests merged | 885 |
SeaORM is one project in a wider ecosystem. The libraries it builds on and the tools built around it have grown alongside it:
| project | what it is | stars |
|---|---|---|
| SeaQuery | the query builder underneath SeaORM (now 1.0) | 1,700+ |
| Seaography | GraphQL from your entities | 500+ |
Thank you to everyone who filed an issue, opened a pull request, answered a question, or sponsored the work. 2.0 is yours as much as ours.
What changed in 2.0โ
A short tour of the headline features. Each links to a dedicated post if you want the details.
A new entity formatโ
The 1.0 entity format is explicit but verbose. 2.0 adds a denser format where relations live on the Model as typed fields, generated with sea-orm-cli generate entity --entity-format dense.
#[sea_orm::model]
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "user")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
#[sea_orm(unique)]
pub email: String,
#[sea_orm(has_one)]
pub profile: HasOne<super::profile::Entity>,
#[sea_orm(has_many)]
pub posts: HasMany<super::post::Entity>,
}
The inverse side is declared with belongs_to. The field type now pairs with BelongsTo, which encodes the foreign key's cardinality in the type: BelongsTo<Entity> for a non-null key, BelongsTo<Option<Entity>> for a nullable one.
#[sea_orm::model]
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
#[sea_orm(table_name = "post")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub user_id: i32,
pub title: String,
#[sea_orm(belongs_to, from = "user_id", to = "id")]
pub author: BelongsTo<super::user::Entity>,
#[sea_orm(has_many)]
pub comments: HasMany<super::comment::Entity>,
}
Read the new entity format post, or the full walk-through that builds a small blogging platform end to end.
Entity-first workflowโ
Hand-write your entities and let SeaORM create the tables and foreign keys in the correct order. Call sync after connecting, and the schema converges to match your entities.
db.get_schema_registry("my_crate::entity::*").sync(db).await?;
Nested ActiveModelโ
Build a nested object and save it in one call. SeaORM walks the tree, works out what changed, and executes the inserts and updates in one transaction, in foreign-key order.
user::ActiveModel::builder()
.set_name("Bob")
.set_profile(profile::ActiveModel::builder().set_picture("tennis.jpg"))
.add_post(post::ActiveModel::builder().set_title("A sunny day"))
.save(db)
.await?;
See nested ActiveModel.
Strongly-typed columnsโ
Columns are now available as a COLUMN constant with type-aware methods, so a mismatched value is a compile error instead of a runtime surprise โ and you can drop the CamelCase.
// old: an enum variant
user::Entity::find().filter(user::Column::Name.contains("Bob"));
// new: a typed constant
user::Entity::find().filter(user::COLUMN.name.contains("Bob"));
More in 2.0โ
- Synchronous SeaORM โ the same API without
async, for embedded and blocking contexts. - Arrow & Parquet โ load query results into columnar formats for analytics.
- SQL Server support via SeaORM X.
- Seaography 2.0 โ a GraphQL API from your entities, no re-generation required.
- Role-based access control and an updated SeaORM Pro admin panel.
Upgrading from 1.0โ
The 1.0 API still works in 2.0, so you can upgrade incrementally. The main change to be aware of is the entity format: a belongs_to field now pairs with BelongsTo<Entity> (or BelongsTo<Option<Entity>>) rather than the older HasOne / Option types, which remain supported as a legacy path.
The SeaORM 2.0 Migration Guide walks through the upgrade step by step.
Visionโ
Our aim is simple to state and hard to earn: we want SeaORM to be the data layer a Rust developer reaches for by default, the Active Record of Rust. If you are coming from a dynamic language, SeaORM should feel right at home: the ergonomics you are used to, backed by the strong typing and performance of Rust.
That aim is not new. SeaORM has followed the Active Record pattern from the start, and ActiveModel is right there in the name. The question driving the project is whether Rust can have that productivity without giving up the guarantees that make it worth using. 2.0 is our clearest answer yet, and there is still a long way to go. We are glad to be walking it with you.
๐ Sponsorsโ
If you feel generous, a small donation will be greatly appreciated, and goes a long way towards sustaining the organization.
A big shout out to our GitHub sponsors:
๐ฆ Rustacean Sticker Packโ
The Rustacean Sticker Pack is the perfect way to express your passion for Rust. Our stickers are made with a premium water-resistant vinyl with a unique matte finish.
Sticker Pack Contents:
- Logo of SeaQL projects: SeaQL, SeaORM, SeaQuery, Seaography
- Mascots: Ferris the Crab x 3, Terres the Hermit Crab
- The Rustacean wordmark
Support SeaQL and get a Sticker Pack!

