Migration Guide (1.0 to 2.0)
Relevant source files
The following files were used as context for generating this wiki page:
SeaORM 2.0 introduces significant architectural enhancements and ergonomic improvements over the 1.0 series. This guide outlines the major breaking changes, new entity formats, and updated APIs required to transition your project to the 2.0 ecosystem.
The primary focus of SeaORM 2.0 is improving developer experience through more concise entity definitions, compile-time type safety via strongly-typed columns, and a simplified workflow for persisting nested object graphs. Sources: CLAUDE.md:3-8, src/lib.rs:720-730
New Entity Format (Dense Format)
One of the most visible changes in 2.0 is the "Dense" entity format. Unlike 1.0, where relations were defined via a separate Relation enum and Related trait implementations, 2.0 uses the #[sea_orm::model] macro to define relations directly within the Model struct.
2.0 Entity Definition Example
mod user {
use sea_orm::entity::prelude::*;
#[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(has_one)]
pub profile: HasOne<super::profile::Entity>,
#[sea_orm(has_many)]
pub posts: HasMany<super::post::Entity>,
}
impl ActiveModelBehavior for ActiveModel {}
}
Sources: CLAUDE.md:10-25, src/lib.rs:88-112
Key Changes in Relation Attributes
The transition from 1.0 to 2.0 involves moving from trait-based relations to attribute-based relations on the struct fields.
| Relation Type | 1.0 Pattern | 2.0 Attribute |
|---|---|---|
| Has One | impl Related<T> for Entity | #[sea_orm(has_one)] |
| Has Many | impl Related<T> for Entity | #[sea_orm(has_many)] |
| Belongs To | Relation::Entity.def() | #[sea_orm(belongs_to, from = "f_id", to = "id")] |
| Many to Many | impl Related<T> for Entity | #[sea_orm(has_many, via = "junction")] |
Sources: CLAUDE.md:28-44, src/lib.rs:135-144
Strongly-Typed Columns
In SeaORM 2.0, the COLUMN constant provides compile-time type safety for query filtering. This replaces the untyped Column enum used in 1.0.
// 2.0 (Preferred) - Compile-time type safety
user::Entity::find().filter(user::COLUMN.name.contains("Bob"))
// 1.0 (Outdated) - Still works but lacks advanced type checking
user::Entity::find().filter(user::Column::Name.contains("Bob"))
Sources: CLAUDE.md:60-66, src/lib.rs:163-165
API Changes and Removals
Several APIs have been renamed or removed to improve consistency and safety.
Renamed APIs
| 1.0 API | 2.0 API |
|---|---|
.into_condition() | .into() |
db.execute(Statement) | db.execute_raw(Statement) |
db.query_all(backend.build(&query)) | db.query_all(&query) |
Alias::new("col") | Expr::col("col") |
Sources: CLAUDE.md:126-132
Database Specific Changes
- PostgreSQL: The
serialtype is no longer the default for auto-increment columns. It now usesGENERATED BY DEFAULT AS IDENTITY. To restore legacy behavior, use theoption-postgres-use-serialfeature. - SQLite: Both
IntegerandBigIntegernow map to the sameintegertype in 2.0. The generator producesi64by default. - MySQL/MSSQL: String fields now default to
VARCHAR(255). For longer content, use#[sea_orm(column_type = "Text")]orStringLen::Max.
Sources: CLAUDE.md:136-155
ActiveModel Builder and Eager Loading
2.0 introduces a fluent builder API for ActiveModel that supports nested persistence. This allows saving a parent and all its children in a single transaction.
Persisting Nested Graphs
let user = user::ActiveModel::builder()
.set_name("Bob")
.set_profile(profile::ActiveModel::builder().set_picture("Tennis"))
.add_post(post::ActiveModel::builder().set_title("First Post"))
.save(db)
.await?;
Sources: CLAUDE.md:68-87, src/lib.rs:215-225
Smart Entity Loader
The new Entity::load() API replaces manual join management for common relational queries. It intelligently chooses between JOIN (for 1-1) and a Data Loader (for 1-N) to prevent N+1 issues.
The diagram shows how the Entity Loader splits requests into optimized queries based on relationship cardinality. Sources: src/lib.rs:160-185, README.md:95-120
Migrator System
The migration system remains compatible but adds support for the new "Entity-First" workflow.
This flowchart illustrates the migration lifecycle. The "Entity First" workflow uses the Schema Registry to automatically synchronize entity definitions to the database schema. Sources: sea-orm-cli/src/commands/migrate.rs:23-55, sea-orm-migration/src/migrator.rs:150-180, src/lib.rs:242-250
New Migration CLI Usage
Users should update their sea-orm-cli to use the 2.0 features.
| Command | Action |
|---|---|
sea-orm-cli generate entity | Use --entity-format dense for 2.0 style |
migrate fresh | Drop everything and re-run all migrations |
migrate status | Check which migrations are Pending vs Applied |
Sources: sea-orm-cli/src/commands/migrate.rs:88-110, sea-orm-migration/src/migrator.rs:14-23
Summary
Migrating to SeaORM 2.0 involves updating entity definitions to the dense format, adopting the COLUMN constant for type-safe queries, and utilizing the new ActiveModel builder for complex data structures. While breaking changes exist in string handling (MySQL/MSSQL) and ID generation (PostgreSQL), the new APIs significantly reduce boilerplate and runtime errors. Sources: CLAUDE.md:115-155, src/lib.rs:720-740