PackageTrack
Sign in Get early access

sea-orm-cli

Command line utility for SeaORM

2.0.2 11M downloads/mo #2919 most downloaded on crates.io SeaQL/sea-orm

What this package is like to depend on

Last release 11 days ago

12 Aug 2026

Ships fairly regularly

a new release about every 2 weeks

Nearly every release is documented

notes for 67 of 73 stable releases

5 versions withdrawn

withdrawn after publishing

5 years old

138 releases · first in 2021

47 releases in the last 12 months

see the full history below

Release timeline

138 releases · Aug 2021 to Aug 2026
2022 2023 2024 2025 2026
Release Pre-release Withdrawn

Releases

latest 60 of 138
  1. 2.0.2 12 Aug 2026
    Release notes

    SeaORM 2.0.2

    Enhancements

    • Add require_one to fetch exactly one row, erroring if none: a non-optional counterpart to one() that returns the item directly and yields DbErr::RecordNotFound when no row matches, so call sites can use ? instead of unwrapping an Option. Available on Selector / SelectorRaw and the Select, SelectTwo, and SelectTwoRequired wrappers #3164
    • Add date_time_default_now schema helper — a column defaulting to Expr::current_timestamp() #3159
    • Add timestamp_default_now and timestamp_with_time_zone_default_now schema helpers, mirroring date_time_default_now for the timestamp family #3165

    Bug Fixes

    • CLI: deduplicate grouped vs individual imports when regenerating entities with --preserve-user-modifications, so a user-grouped use foo::{A, B} is recognised as equivalent to the freshly generated use foo::A; use foo::B; and no longer emitted twice #3163
    Open source →
    Release notes

    Add changelog for 2.0.2

    Open source →
    Release notes

    require_one query helper, date_time_default_now / timestamp_default_now schema helpers, entity-merge duplicate-import fix

    Open source →
  2. 2.0.1 02 Aug 2026
    Release notes

    SeaORM 2.0.1

    Enhancements

    • Add set_page to Paginator to set the current page #2963
    • Add as_option / into_option to ActiveValue<Option<V>>, flattening the outer active-value state and the inner option #3155
    • Add set_unset and friends to ActiveValue: set the value only when currently NotSet #3083
    • Add is_set_and / is_unchanged_and to ActiveValue #3125
    • Add ConnectOptions::test_before_acquire_if_idle_for(Duration) — ping a pooled connection before it is handed out only once it has been idle for at least the given duration, instead of on every acquire; setting it disables test_before_acquire. Also map_sqlx_postgres_before_acquire / map_sqlx_mysql_before_acquire / map_sqlx_sqlite_before_acquire to install a per-backend SQLx before_acquire callback (composes with the idle-ping shorthand: idle-ping first, then the callback), plus the corresponding getters #3143
    • Add MigratorTrait::get_pending_migrations_read_only / get_applied_migrations_read_only / get_migration_with_status_read_only (and the with-self equivalents) — query migration status without running CREATE TABLE, so a database user without DDL privileges can check pending migrations; if the migration table does not exist, all migrations are reported as pending #3144

    Bug Fixes

    • Require TransactionTrait::Transaction to be a fixed point, fixing nested-transaction recursion (E0275 / future_not_send) in #[sea_orm::model] generated save methods #3153

      Compatibility note: if you implement TransactionTrait yourself, Self must be Sync, and your Transaction type must be Send and its own transaction type (Transaction::Transaction = Transaction). Implementations delegating to DatabaseConnection / DatabaseTransaction, and virtually all #[async_trait] implementations, already satisfy this. Callers are unaffected.

    Upgrades

    • Loco examples upgraded to loco-rs 1.0 (which runs on SeaORM 2.0 stable) #3152
    Open source →
    Release notes

    Tag seaography example sea-orm version for bump.sh; tolerate taplo padding

    Open source →
    Release notes

    ActiveValue helpers (set_unset, is_set_and, as_option), Paginator::set_page, before_acquire pool hooks, read-only migration status queries, nested-transaction recursion fix

    Open source →
  3. 2.0.0 19 Jul 2026
    Release notes

    Reformat example manifests with taplo after 2.0.0 bump

    Open source →
    Release notes

    SeaORM 2.0.0

    SeaORM 2.0 is the first stable release of the 2.x line. It reworks how entities,
    relations, and ActiveModels are defined and used, adds an entity-first workflow,
    introduces role-based access control, and brings the library onto SeaQuery 1.0 and
    SQLx 0.9.

    The full, itemized changelog for the 2.0 series (all release candidates included)
    is in CHANGELOG.md.

    Highlights

    New entity format

    Relations are now declared directly on the Model struct with #[sea_orm::model],
    replacing the separate Relation enum and Related impls.

    #[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>,
    }

    See the new entity format walk-through.

    BelongsTo relation type with compile-time cardinality

    A belongs_to relation can be typed BelongsTo<Entity> (required) or
    BelongsTo<Option<Entity>> (optional), encoding the foreign-key cardinality in the
    type and paired with the write-side ActiveBelongsTo. The macro validates the type
    against the nullability of the from columns at compile time. BelongsTo is the
    recommended type for belongs_to; the legacy HasOne<Entity> field type remains
    supported for backward compatibility. (#3118)

    Strongly-typed columns

    Filter with the typed COLUMN constant for compile-time type safety, alongside the
    existing Column enum.

    user::Entity::find().filter(user::COLUMN.name.contains("Bob"))

    See strongly-typed columns.

    Nested ActiveModel

    Build and persist an entity together with its related rows in one expression, and
    push has-many children onto a loaded model.

    let bob = user::ActiveModel::builder()
        .set_name("Bob")
        .set_email("[email protected]")
        .set_profile(profile::ActiveModel::builder().set_picture("Tennis"))
        .insert(db)
        .await?;

    See nested ActiveModel.

    Entity Loader

    Load an entity together with its relations, including nested relations, in a single
    call.

    let user = user::Entity::load()
        .filter_by_id(12)
        .with(profile::Entity)
        .with((post::Entity, comment::Entity))
        .one(db)
        .await?;

    Entity-first workflow

    Create tables directly from entity definitions via the schema registry, without
    writing a migration first.

    db.get_schema_registry("my_crate::*").sync(db).await?;

    See the entity-first workflow.

    Role-Based Access Control

    A table-scoped, hierarchical RBAC engine with a query auditor and a
    RestrictedConnection that implements ConnectionTrait and enforces permissions on
    all Entity operations (including complex joins, insert-select, and CTE queries).
    (#2683)

    Overhauled insert_many

    insert_many no longer shares a helper struct with single insert. Panic-prone APIs
    were removed, empty input returns None / vec![] on exec, and the new InsertMany
    helper exposes last_insert_id: Option<Value>. (#2628)

    Synchronous SeaORM

    The sea-orm-sync crate provides a synchronous SeaORM backed by rusqlite, mirroring
    the async API with async/await stripped away.

    Upgrading from 1.x

    Follow the 1.0 to 2.0 migration guide
    and the 2.0 walk-through.

    Notable breaking changes to be aware of:

    • Expression methods like .eq(), .like(), .contains() now require
      use sea_orm::ExprTrait; in scope. Also read
      SeaQuery's breaking changes.
    • execute / query_one / query_all / stream now take a SeaQuery statement; the
      raw-SQL variants are execute_raw / query_one_raw / query_all_raw / stream_raw.
    • PostgreSQL auto-increment columns now use GENERATED BY DEFAULT AS IDENTITY instead
      of serial; opt back in with option-postgres-use-serial if needed.
    • SQLite maps both Integer and BigInteger to integer.
    • DeriveValueType now also derives NotU8, IntoActiveValue, and TryFromU64;
      remove any manual implementations to avoid conflicts.
    • Removed the runtime-actix feature alias (use runtime-tokio); removed
      DeriveCustomColumn and default_as_str.

    Dependencies

    • SeaQuery 1.0
    • SQLx 0.9
    • sea-schema 0.18
    Open source →
    Release notes

    Release Candidates

    • 2.0.0-rc.43BelongsTo relation type (opt-in, compile-time FK cardinality), CLI generation-option errors, has_related Condition::any() & PG enum-array codegen fixes
    • 2.0.0-rc.42 — typed value arrays, HasOne replace/delete, ActiveHasOne/ActiveHasMany rename, codegen ColumnType fixes
    • 2.0.0-rc.41SelectFourMany, update_without_returning, cargo binstall sea-orm-cli, junction ActiveModelBehavior & schema-sync PG-schema fixes
    • 2.0.0-rc.40 - Restore pgvector binding with SQLx 0.9
    • 2.0.0-rc.39 - SeaQuery 1.0, SQLx 0.9, async transaction helpers
    • 2.0.0-rc.38find_both_related, set_ne, pool options, schema sync fixes
    • 2.0.0-rc.37 — ER Diagram Generation
    • 2.0.0-rc.36 — Per-migration transaction control
    • 2.0.0-rc.35 — SQLite transaction modes, DeriveIntoActiveModel extensions, Decimal64/Bytes, schema sync fix
    • 2.0.0-rc.34 — Arrow/Parquet support, try_from_u64 for DeriveValueType
    • 2.0.0-rc.32MigratorTrait with self, PostgreSQL application_name
    • 2.0.0-rc.31ne_all, typed TextUuid, COUNT overflow fix
    • 2.0.0-rc.30 — Maintenance release, sea-query bump
    • 2.0.0-rc.29 — Tracing spans, UUID-as-TEXT, relation filtering, LEFT JOIN fix
    • 2.0.0-rc.28sqlx-all in migration, set_if_not_equals_and, auto_increment for String/Uuid PKs
    • 2.0.0-rc.27DeriveValueType implements NotU8 for PostgreSQL arrays
    • 2.0.0-rc.26postgres-use-serial-pk feature for legacy serial PKs
    • 2.0.0-rc.25 — Value system restoration, sea-query bump
    • 2.0.0-rc.24sea-query bump to rc.27
    • 2.0.0-rc.23DeriveValueType implements IntoActiveValue, remove NotU8
    • 2.0.0-rc.22DatabaseExecutor unified type, value array refactor
    • 2.0.0-rc.21 — Rusqlite / sea-orm-sync crate, exists on PaginatorTrait
    • 2.0.0-rc.20 — Stringy newtypes, M2M self-ref, nullable columns, bug fixes

    New Features

    • Split belongs_to from has_one with a new BelongsTo relation type https://github.com/SeaQL/sea-orm/pull/3118

      A belongs_to relation can now be typed BelongsTo<Entity> (required) or BelongsTo<Option<Entity>> (optional), encoding the foreign-key cardinality in the type, paired with the write-side companion ActiveBelongsTo. BelongsTo is the recommended type for belongs_to; the legacy HasOne<Entity> field type remains supported for backward compatibility.

    • Role Based Access Control https://github.com/SeaQL/sea-orm/pull/2683

      1. a hierarchical RBAC engine that is table scoped
        • a user has 1 (and only 1) role
        • a role has a set of permissions on a set of resources
          • permissions here are CRUD operations and resources are tables
          • but the engine is generic so can be used for other things
        • roles have hierarchy, and so can inherit permissions
        • there is a wildcard * to grant all permissions or resources
        • individual users can have rules override
      2. a set of Entities to load / store the access control rules to / from database
      3. a query auditor that dissect queries for necessary permissions (implemented in SeaQuery)
      4. integration of RBAC into SeaORM in form of RestrictedConnection. it implements ConnectionTrait, and will audit all queries and perform permission check, and reject them accordingly. all Entity operations except raw SQL are supported. complex joins, insert select from, and even CTE queries are supported.
    // load rules from database
    db_conn.load_rbac().await?;
    
    // admin can create bakery
    let db = db_conn.restricted_for(admin)?;
    let seaside_bakery = bakery::ActiveModel {
        name: Set("SeaSide Bakery".to_owned()),
        ..Default::default()
    };
    assert!(Bakery::insert(seaside_bakery).exec(&db).await.is_ok());
    
    // public cannot create bakery
    let db = db_conn.restricted_for(public)?;
    assert!(matches!(
        Bakery::insert(bakery::ActiveModel::default())
            .exec(&db)
            .await,
        Err(DbErr::AccessDenied { .. })
    ));
    
    • Overhauled Entity::insert_many. We've made a number of changes https://github.com/SeaQL/sea-orm/pull/2628
      1. removed APIs that can panic
      2. new helper struct InsertMany, last_insert_id is now Option<Value>
      3. on empty iterator, None or vec![] is returned on exec operations
      4. TryInsert API is unchanged

    Previously, insert_many shares the same helper struct with insert_one, which led to an awkard API.

    let res = Bakery::insert_many(std::iter::empty())
        .on_empty_do_nothing() // <- you need to add this
        .exec(db)
        .await;
    
    assert!(matches!(res, Ok(TryInsertResult::Empty)));
    

    last_insert_id is now Option<Value>:

    struct InsertManyResult<A: ActiveModelTrait>
    {
        pub last_insert_id: Option<<PrimaryKey<A> as PrimaryKeyTrait>::ValueType>,
    }
    

    Which means the awkardness is removed:

    let res = Entity::insert_many::<ActiveModel, _>([]).exec(db).await;
    
    assert_eq!(res?.last_insert_id, None); // insert nothing return None
    
    let res = Entity::insert_many([ActiveModel { id: Set(1) }, ActiveModel { id: Set(2) }])
        .exec(db)
        .await;
    
    assert_eq!(res?.last_insert_id, Some(2)); // insert something return Some
    

    Same on conflict API as before:

    let res = Entity::insert_many([ActiveModel { id: Set(3) }, ActiveModel { id: Set(4) }])
        .on_conflict_do_nothing()
        .exec(db)
        .await;
    
    assert!(matches!(conflict_insert, Ok(TryInsertResult::Conflicted)));
    

    Exec with returning now returns a Vec<Model>, so it feels intuitive:

    assert!(
        Entity::insert_many::<ActiveModel, _>([])
            .exec_with_returning(db)
            .await?
            .is_empty() // no footgun, nice
    );
    
    assert_eq!(
        Entity::insert_many([
            ActiveModel {
                id: NotSet,
                value: Set("two".into()),
            }
        ])
        .exec_with_returning(db)
        .await
        .unwrap(),
        [
            Model {
                id: 2,
                value: "two".into(),
            }
        ]
    );
    
    • Improved utility of ActiveModel::from_json. Consider the following Entity https://github.com/SeaQL/sea-orm/pull/2599
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel, Serialize, Deserialize)]
    #[sea_orm(table_name = "cake")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: i32,      // <- not nullable
        pub name: String,
    }
    

    Previously, the following would result in error "missing field id":

    assert!(
        cake::ActiveModel::from_json(json!({
            "name": "Apple Pie",
        })).is_err();
    );
    

    Now, the ActiveModel will be partially filled:

    assert_eq!(
        cake::ActiveModel::from_json(json!({
            "name": "Apple Pie",
        }))
        .unwrap(),
        cake::ActiveModel {
            id: NotSet,
            name: Set("Apple Pie".to_owned()),
        }
    );
    
    • A full Model can now be used as PartialModel in nested query https://github.com/SeaQL/sea-orm/pull/2642
    #[derive(DerivePartialModel)]
    #[sea_orm(entity = "cake::Entity")]
    struct Cake {
        id: i32,
        name: String,
        #[sea_orm(nested)]
        bakery: Option<bakery::Model>,
    }
    
    let cake: Cake = cake::Entity::find()
        .left_join(bakery::Entity)
        .order_by_asc(cake::Column::Id)
        .into_partial_model()
        .one(&ctx.db)
        .await?
        .unwrap();
    
    assert_eq!(cake.id, 13);
    assert_eq!(cake.name, "Cheesecake");
    assert_eq!(
        cake.bakery.unwrap(),
        bakery::Model {
            id: 42,
            name: "cool little bakery".to_string(),
        }
    );
    
    • Wrapper type derived with DeriveValueType can now be used as primary key https://github.com/SeaQL/sea-orm/pull/2643
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "my_value_type")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: MyInteger,
    }
    
    #[derive(Clone, Debug, PartialEq, Eq, DeriveValueType)]
    pub struct MyInteger(pub i32);
    // only for i8 | i16 | i32 | i64 | u8 | u16 | u32 | u64
    
    • You can now define unique keys that span multiple columns in Entity https://github.com/SeaQL/sea-orm/pull/2651
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "lineitem")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: i32,
        #[sea_orm(unique_key = "item")]
        pub order_id: i32,
        #[sea_orm(unique_key = "item")]
        pub cake_id: i32,
    }
    
    let stmts = Schema::new(backend).create_index_from_entity(lineitem::Entity);
    
    assert_eq!(
        stmts[0],
        Index::create()
            .name("idx-lineitem-item")
            .table(lineitem::Entity)
            .col(lineitem::Column::OrderId)
            .col(lineitem::Column::CakeId)
            .unique()
            .take()
    );
    
    assert_eq!(
        backend.build(stmts[0]),
        r#"CREATE UNIQUE INDEX "idx-lineitem-item" ON "lineitem" ("order_id", "cake_id")"#
    );
    
    • Overhauled ConnectionTrait API: execute, query_one, query_all, stream now takes in SeaQuery statement instead of raw SQL statement https://github.com/SeaQL/sea-orm/pull/2657
    // old
    let query: SelectStatement = Entity::find().filter(..).into_query();
    let backend = self.db.get_database_backend();
    let stmt = backend.build(&query);
    let rows = self.db.query_all(stmt).await?;
    
    // new
    let query: SelectStatement = Entity::find().filter(..).into_query();
    let rows = self.db.query_all(&query).await?;
    
    • Added raw_sql macro for ergonomic parameter injection
    #[derive(FromQueryResult)]
    struct Cake {
        name: String,
        #[sea_orm(nested)]
        bakery: Option<Bakery>,
    }
    
    #[derive(FromQueryResult)]
    struct Bakery {
        #[sea_orm(alias = "bakery_name")]
        name: String,
    }
    
    let cake_ids = [2, 3, 4]; // expanded by the `..` operator
    
    let cake: Option<Cake> = Cake::find_by_statement(raw_sql!(
        Sqlite,
        r#"SELECT "cake"."name", "bakery"."name" AS "bakery_name"
           FROM "cake"
           LEFT JOIN "bakery" ON "cake"."bakery_id" = "bakery"."id"
           WHERE "cake"."id" IN ({..cake_ids})"#
    ))
    .one(db)
    .await?;
    
    • Added consolidate method to SelectThree. This output has different shape depending on the topology of the join.
    // Order -> Customer
    //       -> Lineitem
    
    let items: Vec<(order::Model, Option<customer::Model>, Option<lineitem::Model>)> =
        order::Entity::find()
            .find_also_related(customer::Entity)
            .find_also_related(lineitem::Entity)
            .order_by_asc(order::Column::Id)
            .order_by_asc(lineitem::Column::Id)
            .all(&ctx.db)
            .await?;
    
    // flat result
    assert_eq!(
        items,
        vec![
            (order, Some(customer), Some(line_1)),
            (order, Some(customer), Some(line_2)),
        ]
    );
    
    let items: Vec<(order::Model, Vec<customer::Model>, Vec<lineitem::Model>)> =
        order::Entity::find()
            .find_also_related(customer::Entity)
            .find_also_related(lineitem::Entity)
            .order_by_asc(order::Column::Id)
            .order_by_asc(lineitem::Column::Id)
            .consolidate() // <-
            .all(&ctx.db)
            .await?;
    
    // consolidated by order
    assert_eq!(
        items,
        vec![(
            order,
            vec![customer],
            vec![line_1, line_2]
        )]
    );
    
    // Order -> Lineitem -> Cake
    let items: Vec<(order::Model, Option<lineitem::Model>, Option<cake::Model>)> =
        order::Entity::find()
            .find_also_related(lineitem::Entity)
            .and_also_related(cake::Entity)
            .order_by_asc(order::Column::Id)
            .order_by_asc(lineitem::Column::Id)
            .all(&ctx.db)
            .await?;
    
    // flat result
    assert_eq!(
        items,
        vec![
            (order, Some(line_1), Some(cake_1)),
            (order, Some(line_2), Some(cake_2)),
        ]
    );
    
    let items: Vec<(order::Model, Vec<(lineitem::Model, Vec<cake::Model>)>)> =
        order::Entity::find()
            .find_also_related(lineitem::Entity)
            .and_also_related(cake::Entity)
            .order_by_asc(order::Column::Id)
            .order_by_asc(lineitem::Column::Id)
            .consolidate() // <-
            .all(&ctx.db)
            .await?;
    
    // consolidated by order first, then by line
    assert_eq!(
        items,
        vec![(
            order,
            vec![(line_1, vec![cake_1]), (line_2, vec![cake_2])]
        )]
    );
    
    • Added Select::has_related
    // cake -> fruit: find all cakes containing mango
    assert_eq!(
        cake::Entity::find()
            .has_related(fruit::Entity, fruit::Column::Name.eq("Mango"))
            .build(DbBackend::Sqlite)
            .to_string(),
        [
            r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
            r#"WHERE EXISTS(SELECT 1 FROM "fruit""#,
            r#"WHERE "fruit"."name" = 'Mango'"#,
            r#"AND "cake"."id" = "fruit"."cake_id")"#,
        ]
        .join(" ")
    );
    // cake -> cake_filling -> filling: find all cakes with orange fillings
    assert_eq!(
        cake::Entity::find()
            .has_related(filling::Entity, filling::Column::Name.eq("Marmalade"))
            .build(DbBackend::Sqlite)
            .to_string(),
        [
            r#"SELECT "cake"."id", "cake"."name" FROM "cake""#,
            r#"WHERE EXISTS(SELECT 1 FROM "filling""#,
            r#"INNER JOIN "cake_filling" ON "cake_filling"."filling_id" = "filling"."id""#,
            r#"WHERE "filling"."name" = 'Marmalade'"#,
            r#"AND "cake"."id" = "cake_filling"."cake_id")"#,
        ]
        .join(" ")
    );
    
    • Support self-referencing relations in loader
    #[sea_orm::model]
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
    #[sea_orm(table_name = "staff")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: i32,
        pub name: String,
        pub reports_to_id: Option<i32>,
        #[sea_orm(self_ref, relation_enum = "ReportsTo", from = "reports_to_id", to = "id")]
        pub reports_to: HasOne<Entity>,
    }
    
    // Entity Loader
    let staff = staff::Entity::load()
        .with(staff::Relation::ReportsTo)
        .all(db)
        .await?;
    
    assert_eq!(staff[0].name, "Alan");
    assert_eq!(staff[0].reports_to, None);
    
    assert_eq!(staff[1].name, "Ben");
    assert_eq!(staff[1].reports_to.as_ref().unwrap().name, "Alan");
    
    assert_eq!(staff[2].name, "Alice");
    assert_eq!(staff[2].reports_to.as_ref().unwrap().name, "Alan");
    
    // Model Loader
    let staff = staff::Entity::find().all(db).await?;
    
    let reports_to = staff
        .load_self(staff::Entity, staff::Relation::ReportsTo, db)
        .await?;
    
    assert_eq!(staff[0].name, "Alan");
    assert_eq!(reports_to[0], None);
    
    assert_eq!(staff[1].name, "Ben");
    assert_eq!(reports_to[1].unwrap().name, "Alan");
    
    assert_eq!(staff[2].name, "Alice");
    assert_eq!(reports_to[2].unwrap().name, "Alan");
    
    • Strongly-typed column https://github.com/SeaQL/sea-orm/pull/2794
    // old
    user::Entity::find().filter(user::Column::Name.contains("Bob"))
    
    // new
    user::Entity::find().filter(user::COLUMN.name.contains("Bob"))
    
    // compile error: the trait `From<{integer}>` is not implemented for `String`
    user::Entity::find().filter(user::COLUMN.name.like(2))
    
    • Unix timestamp column type that will be mapped to big integer in database
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "access_log")]
    pub struct Model {
        .. // with `chrono` crate
        pub ts: ChronoUnixTimestamp,
        pub ms: ChronoUnixTimestampMillis,
        .. // with `time` crate
        pub ts: TimeUnixTimestamp,
        pub ms: TimeUnixTimestampMillis,
    }
    
    • Nested ActiveModel (ActiveModelEx) and cascade operations https://github.com/SeaQL/sea-orm/pull/2818

      The following operation saves a new set of user + profile + post + tag + post_tag into the database atomically:

    let user = user::ActiveModel::builder()
        .set_name("Bob")
        .set_email("[email protected]")
        .set_profile(profile::ActiveModel::builder().set_picture("image.jpg"))
        .add_post(
            post::ActiveModel::builder()
                .set_title("Nice weather")
                .add_tag(tag::ActiveModel::builder().set_tag("sunny")),
        )
        .save(db)
        .await?;
    

    Enhancements

    • Added serde feature
    • TextUuid now derives Serialize and Deserialize when the serde feature is enabled
    • [sea-orm-cli] Added --column-extra-derives https://github.com/SeaQL/sea-orm/pull/2212
    • [sea-orm-cli] Added --big-integer-type=i32 to use i32 for bigint (for SQLite)
    • [sea-orm-cli] Fix codegen to not generate relations to filtered entities https://github.com/SeaQL/sea-orm/pull/2913
    • [sea-orm-cli] Added --experimental-preserve-user-modifications https://github.com/SeaQL/sea-orm/pull/2755 https://github.com/SeaQL/sea-orm/pull/2964
    • [sea-orm-migration] Add custom connection entrypoint to migration CLI https://github.com/SeaQL/sea-orm/pull/3035
    • Added Model::try_set
    • Added new error variant BackendNotSupported. Previously, it panics with e.g. "Database backend doesn't support RETURNING" https://github.com/SeaQL/sea-orm/pull/2630
    let result = cake::Entity::insert_many([])
        .exec_with_returning_keys(db)
        .await;
    
    if db.support_returning() {
        // Postgres and SQLite
        assert_eq!(result.unwrap(), []);
    } else {
        // MySQL
        assert!(matches!(result, Err(DbErr::BackendNotSupported { .. })));
    }
    
    • Added new error variant PrimaryKeyNotSet. Previously, it panics with "PrimaryKey is not set" https://github.com/SeaQL/sea-orm/pull/2627
    assert!(matches!(
        Update::one(cake::ActiveModel {
            ..Default::default()
        })
        .exec(&db)
        .await,
        Err(DbErr::PrimaryKeyNotSet { .. })
    ));
    
    • Remove panics in Schema::create_enum_from_active_enum https://github.com/SeaQL/sea-orm/pull/2634
    fn create_enum_from_active_enum<A>(&self) -> Option<TypeCreateStatement>
    // method can now return None
    
    • Added ColumnTrait::eq_any as a shorthand for the = ANY operator. Postgres only.
    assert_eq!(
        cake::Entity::find()
            .filter(cake::Column::Id.eq_any(vec![4, 5]))
            .build(DbBackend::Postgres)
            .to_string(),
        r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = ANY(ARRAY [4,5])"#
    );
    
    • Added ActiveModelTrait::try_set
    pub trait ActiveModelTrait {
        /// old: set the Value of a ActiveModel field, panic if failed
        fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) {
            self.try_set(c, v).unwrap_or_else(|e| panic!(..))
        }
    
        /// new: same as above but non-panicking
        fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
    }
    
    • Linked can now be used in partial select, in case Related cannot be defined
    pub struct ToBakery;
    impl Linked for ToBakery {
        type FromEntity = super::cake::Entity;
        type ToEntity = super::bakery::Entity;
    
        fn link(&self) -> Vec<RelationDef> {
            vec![Relation::Bakery.def()]
        }
    }
    
    #[derive(Debug, DerivePartialModel)]
    #[sea_orm(entity = "cake::Entity", into_active_model)]
    struct Cake2 {
        id: i32,
        name: String,
        #[sea_orm(nested, alias = "r0")]
        bakery: Option<Bakery>,
        #[sea_orm(skip)]
        ignore: Ignore,
    }
    
    let cake2: Cake2 = cake::Entity::find()
        .left_join_linked(ToBakery)
        .order_by_asc(cake::Column::Id)
        .into_partial_model()
        .one(&ctx.db)
        .await?
        .unwrap();
    
    • RelationDef now implements Clone. on_condition is changed to Arc but this is a minor breaking change.
    • Added extra on column attribute:
    #[cfg(feature = "with-rust_decimal")]
    #[sea_orm(extra = "CHECK (price > 0)")]
    pub price: Decimal,
    
    // results in:
    ColumnDef::new("price")
        .decimal()
        .not_null()
        .extra("CHECK (price > 0)"),
    
    • Added ColumnTrait::avg, in addition to sum, min, max etc
    let average: Decimal = order::Entity::find()
        .select_only()
        .column_as(order::Column::Total.avg(), "avg")
        .into_tuple()
        .one(&ctx.db)
        .await?
        .unwrap();
    
    • SchemaBuilder::sync can now be used in migrations
    #[async_trait::async_trait]
    impl MigrationTrait for Migration {
        async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
            let db = manager.get_connection();
    
            db.get_schema_builder()
                .register(note::Entity)
                .sync(db)
                .await
        }
    }
    
    • Allowed None for max_lifetime and idle_timeout Parameters https://github.com/SeaQL/sea-orm/pull/2748
    • Try to parse u32 in Postgres as i32 https://github.com/SeaQL/sea-orm/pull/2753
    • DeriveActiveEnum now also impl IntoActiveValue https://github.com/SeaQL/sea-orm/issues/1972
    • DeriveValueType now also supports any structs that can be converted to / from string https://github.com/SeaQL/sea-orm/issues/2811
    #[derive(Copy, Clone, Debug, PartialEq, Eq, DeriveValueType)]
    #[sea_orm(value_type = "String")]
    pub struct Tag3 {
        pub i: i64,
    }
    
    impl std::fmt::Display for Tag3 {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            write!(f, "{}", self.i)
        }
    }
    
    impl std::str::FromStr for Tag3 {
        type Err = std::num::ParseIntError;
    
        fn from_str(s: &str) -> Result<Self, Self::Err> {
            let i: i64 = s.parse()?;
            Ok(Self { i })
        }
    }
    
    • Fix DeriveIntoActiveModel on Option<T> fields https://github.com/SeaQL/sea-orm/pull/2926
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "fruit")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: i32,
        pub name: String,
        pub cake_id: Option<i32>,
    }
    
    #[derive(DeriveIntoActiveModel)]
    #[sea_orm(active_model = "<fruit::Entity as EntityTrait>::ActiveModel")]
    struct PartialFruit {
        cake_id: Option<i32>,
    }
    
    assert_eq!(
        PartialFruit { cake_id: Some(1) }.into_active_model(),
        fruit::ActiveModel { id: NotSet, name: NotSet, cake_id: Set(Some(1)) }
    );
    
    assert_eq!(
        PartialFruit { cake_id: None }.into_active_model(),
        fruit::ActiveModel { id: NotSet, name: NotSet, cake_id: NotSet }
    );
    
    • FromQueryResult now supports nullable nested model https://github.com/SeaQL/sea-orm/pull/2845
    #[derive(FromQueryResult)]
    struct CakeWithOptionalBakeryModel {
        #[sea_orm(alias = "cake_id")]
        id: i32,
        #[sea_orm(alias = "cake_name")]
        name: String,
        #[sea_orm(nested)]
        bakery: Option<bakery::Model>, // can be null
    }
    
    • Added try_from_u64 to DeriveValueType https://github.com/SeaQL/sea-orm/pull/2958
    // Test for try_from_u64 attribute with type alias
    type UserId = i32;
    
    #[derive(Clone, Debug, PartialEq, Eq, DeriveValueType)]
    #[sea_orm(try_from_u64)]
    pub struct MyUserId(pub UserId);
    
    • Arrow / Parquet support https://github.com/SeaQL/sea-orm/pull/2957
      • Added ArrowSchema, DeriveArrowSchema
      • Support decimal with different formats
      • Support timestamp with different timezone / resolution
      • Added parquet example
    • Support HashMap and BTreeMap for JSON columns via TryGetableFromJson https://github.com/SeaQL/sea-orm/pull/3009
    • Derive macros now inherit the visibility of the input type for generated items such as Entity, Column, PrimaryKey, and ActiveModel https://github.com/SeaQL/sea-orm/pull/3029

    Bug Fixes

    • [sea-orm-migration] PostgreSQL drop_everything now drops custom types with CASCADE

    Breaking Changes

    Please read SeaQuery's breaking changes as well. But for most compile errors, you can simply add use sea_orm::ExprTrait; in scope.

    error[E0599]: no method named `like` found for enum `sea_query::Expr` in the current scope
        |
        |         Expr::col((self.entity_name(), *self)).like(s)
        |
        |     fn like<L>(self, like: L) -> Expr
        |        ---- the method is available for `sea_query::Expr` here
        |
        = help: items from traits can only be used if the trait is in scope
    help: trait `ExprTrait` which provides `like` is implemented but not in scope; perhaps you want to import it
        |
     -> + use sea_orm::ExprTrait;
    
    error[E0308]: mismatched types
      --> src/sqlite/discovery.rs:27:57
       |
       |             .and_where(Expr::col(Alias::new("type")).eq("table"))
       |                                                      -- ^^^^^^^ expected `&Expr`, found `&str`
       |                                                      |
       |                                                      arguments to this method are incorrect
       |
       = note: expected reference `&sea_query::Expr`
                  found reference `&'static str`
    
    error[E0308]: mismatched types
        |
    390 |             Some(Expr::col(Name).eq(PgFunc::any(query.symbol)))
        |                                  -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&Expr`, found `FunctionCall`
        |                                  |
        |                                  arguments to this method are incorrect
        |
    note: method defined here
       --> /rustc/6b00bc3880198600130e1cf62b8f8a93494488cc/library/core/src/cmp.rs:254:8
    
    error[E0277]: the trait bound `sea_orm::Condition: From<bool>` is not satisfied
        |
    367 |         .add_option(option)
        |          ---------- ^^^^^^ the trait `From<bool>` is not implemented for `sea_orm::Condition`
        |          |
        |          required by a bound introduced by this call
        |
        = note: required for `bool` to implement `Into<sea_orm::Condition>`
    
    • Removed runtime-actix feature flag. It's been an alias of runtime-tokio for more than a year, so there should be no impact.
    • Enabled sqlite-use-returning-for-3_35 by default. SQLite 3.35 was released in 2021, it should be the default by now.
    • Now implemented impl<T: ModelTrait + FromQueryResult> PartialModelTrait for T, there may be a potential conflict https://github.com/SeaQL/sea-orm/pull/2642
    • Now DeriveValueType will also TryFromU64 if applicable, there may be a potential conflict https://github.com/SeaQL/sea-orm/pull/2643
    • Now DeriveValueType also impl IntoActiveValue and NotU8, there may be a potential conflict
    • Added TryIntoModel and Serialize to trait bounds of ActiveModel::from_json. There should be no impact if your models are derived with DeriveEntityModel https://github.com/SeaQL/sea-orm/pull/2599
    fn from_json(mut json: serde_json::Value) -> Result<Self, DbErr>
    where
        Self: TryIntoModel<<Self::Entity as EntityTrait>::Model>,
        <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
        for<'de> <<Self as ActiveModelTrait>::Entity as EntityTrait>::Model:
            serde::de::Deserialize<'de> + serde::Serialize,
    
    • DerivePartialModel now implement FromQueryResult by default, so there may be a potential conflict. Remove FromQueryResult in these cases https://github.com/SeaQL/sea-orm/pull/2653
    error[E0119]: conflicting implementations of trait `sea_orm::FromQueryResult` for type `CakeWithFruit`
      |
    > | #[derive(DerivePartialModel, FromQueryResult)]
      |          ------------------  ^^^^^^^^^^^^^^^ conflicting implementation for `CakeWithFruit`
    
    • Changed IdenStatic and EntityName definition https://github.com/SeaQL/sea-orm/pull/2667
    trait IdenStatic {
        fn as_str(&self) -> &'static str; // added static lifetime
    }
    trait EntityName {
        fn table_name(&self) -> &'static str; // added static lifetime
    }
    
    • Removed DeriveCustomColumn and default_as_str https://github.com/SeaQL/sea-orm/pull/2667
    // This is no longer supported:
    #[derive(Copy, Clone, Debug, EnumIter, DeriveCustomColumn)]
    pub enum Column {
        Id,
        Name,
    }
    
    impl IdenStatic for Column {
        fn as_str(&self) -> &str {
            match self {
                Self::Name => "my_name",
                _ => self.default_as_str(),
            }
        }
    }
    
    // Do the following instead:
    #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
    pub enum Column {
        Id,
        #[sea_orm(column_name = "my_name")]
        Name,
    }
    
    • execute, query_one, query_all, stream now takes in SeaQuery statement instead of raw SQL statement. a new set of methods execute_raw, query_one_raw, query_all_raw, stream_raw is added https://github.com/SeaQL/sea-orm/pull/2657
      --> src/executor/paginator.rs:53:38
       |
    >  |         let rows = self.db.query_all(stmt).await?;
       |                            --------- ^^^^ expected `&_`, found `Statement`
       |                            |
       |                            arguments to this method are incorrect
       |
       = note: expected reference `&_`
                     found struct `statement::Statement`
    
    let backend = self.db.get_database_backend();
    let stmt = backend.build(&query);
    // change to:
    let rows = self.db.query_all_raw(stmt).await?;
    // if the query is a SeaQuery statement, then just do this:
    let rows = self.db.query_all(&query).await?; // no need to build query
    
    • DatabaseConnection is changed from enum to struct. The original enum is moved into DatabaseConnection::inner. The new enum is named DatabaseConnectionType https://github.com/SeaQL/sea-orm/pull/2671
    error[E0599]: no associated item named `Disconnected` found for struct `db_connection::DatabaseConnection` in the current scope
       --> src/database/db_connection.rs:137:33
        |
    >   | pub struct DatabaseConnection {
        | ----------------------------- associated item `Disconnected` not found for this struct
    ...
    >   |             DatabaseConnection::Disconnected => Err(conn_err("Disconnected")),
        |                                 ^^^^^^^^^^^^ associated item not found in `DatabaseConnection`
    
    match conn.inner {
        DatabaseConnectionType::Disconnected => (),
        _ => (),
    }
    
    • DeleteOne and UpdateOne no longer implement QueryFilter and QueryTrait directly. Those implementations could expose an incomplete SQL query with an incomplete condition that touches too many records. To generate the right condition, we must make sure that the primary key is set on the input ActiveModel. If you need to access the generated SQL query, convert into ValidatedDeleteOne/ValidatedUpdateOne first.
    error[E0599]: no method named `build` found for struct `query::update::UpdateOne` in the current scope
       --> src/entity/column.rs:607:22
        |
      > | /                 Update::one(active_model)
      > | |                     .build(DbBackend::Postgres)
        | |                     -^^^^^ method not found in `UpdateOne<A>`
        | |_____________________|
        |
    

    Call the validate() method:

    Update::one(active_model)
      + .validate()?
        .build(DbBackend::Postgres)
    
    • Removed DbBackend::get_query_builder() because QueryBuilder is not longer object safe.
      - fn get_query_builder(&self) -> Box<dyn QueryBuilder>
    
    • A number of methods has been removed from SelectTwoMany: into_partial_model, into_json, stream. These methods are same as those in SelectTwo. Please use Cake::find().find_also_related(Fruit).into_json() instead.
    • The delete_by_id method has changed to returning DeleteOne instead of DeleteMany. It doesn't change normal exec usage, but would change return type of exec_with_returning to Option<Model>
    fn delete_by_id<T>(values: T) -> DeleteMany<Self>         // old
    
    fn delete_by_id<T>(values: T) -> ValidatedDeleteOne<Self> // new
    
    • DeriveActiveEnum now also automatically impl IntoActiveValue, if you have a custom impl before, there would be a collision
    • with-bigdecimal is now removed from default features
    • RuntimeErr::SqlxError is now held in Arc to make DbErr clonable and smaller:
    pub enum RuntimeErr {
        SqlxError(Arc<sqlx::error::Error>),
    

    Upgrades

    • Upgraded Rust Edition to 2024 https://github.com/SeaQL/sea-orm/pull/2596
    • Upgraded strum to 0.27
    Open source →
  4. 2.0.0-rc.43 15 Jul 2026 pre-release
    Release notes

    sea-orm-cli 2.0.0-rc.43

    Open source →
    Release notes

    Release Notes: SeaORM 2.0.0-rc.43

    (since 2.0.0-rc.42)

    New Features

    BelongsTo relation type (#3118, #3133, #3134)

    A dedicated BelongsTo<E> / BelongsTo<Option<E>> type for belongs_to relations,
    alongside the existing HasOne. Cardinality lives in the type parameter, so the
    foreign-key nullability is expressed — and checked — at compile time:

    • BelongsTo<E> — the FK is NOT NULL; the relation cannot be detached (there is
      no way to set it to "none" on the active side), so orphaning a required parent is
      a compile error rather than a runtime constraint violation.
    • BelongsTo<Option<E>> — the FK is nullable; the relation can be detached, which
      nulls the FK on save.

    The cardinality is validated against the FK columns when the entity is derived:
    BelongsTo<Entity> requires every from column to be NOT NULL, and
    BelongsTo<Option<Entity>> requires at least one nullable from column — a mismatch
    is a compile error. Composite foreign keys with mixed nullability detach by nulling
    only their nullable columns.

    #[sea_orm(belongs_to, from = "user_id", to = "id")]
    pub author: BelongsTo<super::user::Entity>,          // required
    
    #[sea_orm(belongs_to, from = "bakery_id", to = "id")]
    pub bakery: BelongsTo<Option<super::bakery::Entity>>, // optional

    The active side is ActiveBelongsTo<..>, mirroring ActiveHasOne / ActiveHasMany.

    HasOne still works for belongs_to — no migration required (#3133)

    Adopting BelongsTo is opt-in. A belongs_to field may keep its existing
    HasOne<Entity> type; it continues to compile and behave as before. Use BelongsTo
    when you want the compile-time cardinality guarantee; otherwise nothing changes.

    Enhancements

    CLI lists valid options on generation error (#3131)

    sea-orm-cli generate entity now prints the valid choices when an invalid option
    value is supplied, instead of only reporting that the value was rejected.

    Bug Fixes

    has_related with a Condition::any() filter (#3126)

    has_related wrapped the caller's condition and then added the mandatory FK/join
    condition to it. When the caller passed a Condition::any() (an OR group), the
    join condition was folded into that disjunction, so the relation constraint was no
    longer guaranteed. The caller's condition is now wrapped in Condition::all() first,
    yielding (caller condition) AND (fk join) regardless of any() / all().

    Entity codegen for PostgreSQL enum array columns (#3120)

    Array-of-enum columns were generated as scalar active-enum fields because the type
    resolver unwrapped Array(Enum) to Enum. Array columns now route through the
    full type resolver, so enum[] columns generate Vec<Enum> fields.

    Compatibility Notes

    • belongs_to relations may now be typed BelongsTo<Entity> /
      BelongsTo<Option<Entity>>. This is opt-in — existing HasOne-typed belongs_to
      fields are unchanged and still supported. sea-orm-cli continues to generate the
      HasOne form.
    • The compile-time detach guarantee applies only to BelongsTo<Entity> (non-null);
      it is a property of the type, so it costs nothing at runtime.
    • A BelongsTo field's type parameter must match its FK nullability (checked when
      the entity is derived). This only affects code that opts into BelongsTo.
    • The nested-ActiveModel relation types remain semver-exempt (unstable): rc.43
      drops their PartialEq<Option<..>> impls, so compare an empty relation with
      is_unloaded_or_not_found() / is_not_found() / as_ref() rather than == None
      / == Some(..).
    Open source →
  5. 2.0.0-rc.42 04 Jul 2026 pre-release
    Release notes

    Release Notes: SeaORM 2.0.0-rc.42

    (since 2.0.0-rc.41)

    New Features

    Typed value arrays via try_getable_array (#3108, #2967)

    DeriveValueType wrappers backed by a Vec<_> now round-trip as native
    PostgreSQL arrays: the derive generates a try_getable_array implementation, so
    a newtype over Vec<i32> reads and writes as INTEGER[] without a manual
    TryGetable impl.

    #[derive(Clone, Debug, PartialEq, DeriveValueType)]
    pub struct Tags(Vec<String>);

    Replace and delete a nested HasOne (#3110, #3060, #3061)

    The active has-one type (ActiveHasOne) gains a Delete variant plus generated
    delete_<field> / set_<field>_option builders. Setting a populated has-one now
    replaces the existing linked record (deleting or orphaning the old one) instead
    of erroring, and Delete removes it on save.

    let mut user = user::Entity::load().filter_by_id(1).with(profile::Entity).one(db).await?.unwrap();
    user.delete_profile().save(db).await?; // remove the linked profile

    TryFrom<&str> for active enums (#3111)

    DeriveActiveEnum now generates a TryFrom<&str> implementation, so a string
    value can be parsed straight into the enum by its database string representation.

    let color = Color::try_from("Black")?;

    Enhancements

    ActiveHasOne / ActiveHasMany (renamed)

    The active/write-side companions to HasOne / HasMany are renamed from
    HasOneModel / HasManyModel to ActiveHasOne / ActiveHasMany, so the names
    read as active-model values rather than loaded models. The read-side HasOne /
    HasMany types are unchanged.

    Documented SqlErr and DbErr::sql_err() (#2940)

    DbErr::sql_err() and the SqlErr variants are documented, including how to reach
    the raw driver error for backend-specific handling.

    if let Some(SqlErr::UniqueConstraintViolation(_)) = err.sql_err() { /* ... */ }

    Schema sync warns on column-type divergence (#3106)

    SchemaBuilder::sync() logs a warning when a live column's type diverges from the
    entity definition instead of silently ignoring the difference.

    Bug Fixes

    Codegen ColumnType coverage (#3092)

    Entity generation emits compiling code for Year, Bit, VarBit, MacAddr,
    LTree, and Interval columns, and for Money columns carrying precision and
    scale — previously these produced non-compiling ColumnType expressions.

    Skip generated columns in entity generation (#3094)

    sea-orm-cli generate entity skips database-generated columns, which cannot be
    inserted or updated, instead of emitting them as ordinary fields.

    SchemaBuilder::sync() returns a Send future (#3100)

    Regression fix: sync() no longer returns a non-Send future, so it can be used
    across .await points on multi-threaded runtimes. Released together with
    sea-schema 0.18.1.

    sea-orm-sync generation fixes (#3112)

    The make-sync transform correctly handles futures_util usage in the mock
    driver, keeping the blocking sea-orm-sync crate in sync with the async source.

    Compatibility Notes

    • HasOneModel / HasManyModel are renamed to ActiveHasOne / ActiveHasMany.
      Update references; the read-side HasOne / HasMany are unaffected.
    • DbErr, UpdateResult, DeleteResult, ActiveHasOne, and ActiveHasMany are
      now #[non_exhaustive]; downstream matches need a wildcard arm.
    • Schema sync and nested-ActiveModel relation mutation are marked unstable
      (semver-exempt) while their APIs settle.
    • Prebuilt sea-orm-cli binaries no longer include the Intel macOS
      (x86_64-apple-darwin) target.
    Open source →
    Release notes

    sea-orm-cli 2.0.0-rc.42

    Open source →
  6. 2.0.0-rc.41 18 Jun 2026 pre-release

    Nothing published for this version

  7. 2.0.0-rc.40 30 May 2026 pre-release

    Nothing published for this version

  8. 2.0.0-rc.39 30 May 2026 pre-release

    Nothing published for this version

  9. 2.0.0-rc.38 09 Apr 2026 pre-release

    Nothing published for this version

  10. 2.0.0-rc.37 09 Mar 2026 pre-release

    Nothing published for this version

  11. 2.0.0-rc.36 04 Mar 2026 pre-release

    Nothing published for this version

  12. 2.0.0-rc.35 27 Feb 2026 pre-release

    Nothing published for this version

  13. 2.0.0-rc.34 21 Feb 2026 pre-release

    Nothing published for this version

  14. 2.0.0-rc.33 20 Feb 2026 pre-release

    Nothing published for this version

  15. 2.0.0-rc.32 11 Feb 2026 pre-release

    Nothing published for this version

  16. 2.0.0-rc.31 08 Feb 2026 pre-release

    Nothing published for this version

  17. 2.0.0-rc.30 26 Jan 2026 pre-release

    Nothing published for this version

  18. 2.0.0-rc.29 25 Jan 2026 pre-release

    Nothing published for this version

  19. 2.0.0-rc.28 11 Jan 2026 pre-release

    Nothing published for this version

  20. 2.0.0-rc.27 30 Dec 2025 pre-release

    Nothing published for this version

  21. 2.0.0-rc.26 29 Dec 2025 pre-release

    Nothing published for this version

  22. 2.0.0-rc.25 29 Dec 2025 pre-release

    Nothing published for this version

  23. 2.0.0-rc.24 29 Dec 2025 pre-release

    Nothing published for this version

  24. 2.0.0-rc.23 28 Dec 2025 pre-release

    Nothing published for this version

  25. 2.0.0-rc.22 21 Dec 2025 pre-release

    Nothing published for this version

  26. 2.0.0-rc.21 14 Dec 2025 pre-release

    Nothing published for this version

  27. 2.0.0-rc.20 01 Dec 2025 pre-release

    Nothing published for this version

  28. 2.0.0-rc.19 23 Nov 2025 pre-release

    Nothing published for this version

  29. 2.0.0-rc.18 08 Nov 2025 pre-release

    Nothing published for this version

  30. 2.0.0-rc.17 02 Nov 2025 pre-release

    Nothing published for this version

  31. 2.0.0-rc.16 28 Oct 2025 pre-release

    Nothing published for this version

  32. 2.0.0-rc.15 25 Oct 2025 pre-release

    Nothing published for this version

  33. 2.0.0-rc.14 24 Oct 2025 pre-release

    Nothing published for this version

  34. 2.0.0-rc.13 19 Oct 2025 pre-release

    Nothing published for this version

  35. 2.0.0-rc.12 19 Oct 2025 pre-release

    Nothing published for this version

  36. 2.0.0-rc.11 16 Oct 2025 pre-release

    Nothing published for this version

  37. 2.0.0-rc.10 11 Oct 2025 pre-release

    Nothing published for this version

  38. 2.0.0-rc.9 27 Sep 2025 pre-release

    Nothing published for this version

  39. 2.0.0-rc.8 23 Sep 2025 pre-release

    Nothing published for this version

  40. 2.0.0-rc.7 16 Sep 2025 pre-release

    Nothing published for this version

  41. 2.0.0-rc.6 31 Aug 2025 pre-release

    Nothing published for this version

  42. 2.0.0-rc.5 23 Aug 2025 pre-release

    Nothing published for this version

  43. 2.0.0-rc.4 21 Aug 2025 pre-release

    Nothing published for this version

  44. 2.0.0-rc.3 11 Aug 2025 pre-release

    Nothing published for this version

  45. 2.0.0-rc.2 11 Aug 2025 pre-release withdrawn

    Nothing published for this version

  46. 2.0.0-rc.1 05 Jul 2025 pre-release

    Nothing published for this version

  47. 1.2.0-rc.1 29 May 2025 pre-release

    Nothing published for this version

  48. 1.1.20 31 Mar 2026

    Nothing published for this version

  49. 1.1.19 11 Nov 2025
    Release notes

    Enhancements

    • Add find_linked_recursive method to ModelTrait https://github.com/SeaQL/sea-orm/pull/2480
    • Skip drop extension type in fresh https://github.com/SeaQL/sea-orm/pull/2716

    Bug Fixes

    • Handle null values in from_sqlx_*_row_to_proxy_row functions https://github.com/SeaQL/sea-orm/pull/2744
    Open source →
  50. 1.1.18 10 Nov 2025

    Nothing published for this version

  51. 1.1.17 09 Oct 2025
    Release notes

    New Features

    • Added map_sqlx_mysql_opts, map_sqlx_postgres_opts, map_sqlx_sqlite_opts to ConnectOptions https://github.com/SeaQL/sea-orm/pull/2731
    let mut opt = ConnectOptions::new(url);
    opt.map_sqlx_postgres_opts(|pg_opt: PgConnectOptions| {
        pg_opt.ssl_mode(PgSslMode::Require)
    });
    
    • Added mariadb-use-returning to use returning syntax for MariaDB https://github.com/SeaQL/sea-orm/pull/2710
    • Released sea-orm-rocket 0.6 https://github.com/SeaQL/sea-orm/pull/2732
    Open source →
  52. 1.1.16 11 Sep 2025
    Release notes

    Bug Fixes

    • Fix enum casting in DerivePartialModel https://github.com/SeaQL/sea-orm/pull/2719 https://github.com/SeaQL/sea-orm/pull/2720
    #[derive(DerivePartialModel)]
    #[sea_orm(entity = "active_enum::Entity", from_query_result, alias = "zzz")]
    struct PartialWithEnumAndAlias {
        #[sea_orm(from_col = "tea")]
        foo: Option<Tea>,
    }
    
    let sql = active_enum::Entity::find()
        .into_partial_model::<PartialWithEnumAndAlias>()
        .into_statement(DbBackend::Postgres)
        .sql;
    
    assert_eq!(
        sql,
        r#"SELECT CAST("zzz"."tea" AS "text") AS "foo" FROM "public"."active_enum""#,
    );
    

    Enhancements

    • [sea-orm-cli] Use tokio (optional) instead of async-std https://github.com/SeaQL/sea-orm/pull/2721
    Open source →
  53. 1.1.15 31 Aug 2025
    Release notes

    Enhancements

    • Allow DerivePartialModel to have nested aliases https://github.com/SeaQL/sea-orm/pull/2686
    #[derive(DerivePartialModel)]
    #[sea_orm(entity = "bakery::Entity", from_query_result)]
    struct Factory {
        id: i32,
        #[sea_orm(from_col = "name")]
        plant: String,
    }
    
    #[derive(DerivePartialModel)]
    #[sea_orm(entity = "cake::Entity", from_query_result)]
    struct CakeFactory {
        id: i32,
        name: String,
        #[sea_orm(nested, alias = "factory")] // <- new
        bakery: Option<Factory>,
    }
    
    • Add ActiveModelTrait::try_set https://github.com/SeaQL/sea-orm/pull/2706
    fn set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value);
    /// New: a non-panicking version of above
    fn try_set(&mut self, c: <Self::Entity as EntityTrait>::Column, v: Value) -> Result<(), DbErr>;
    

    Bug Fixes

    • [sea-orm-cli] Fix compilation issue https://github.com/SeaQL/sea-orm/pull/2713
    Open source →
  54. 1.1.14 21 Jul 2025
    Release notes

    Enhancements

    • [sea-orm-cli] Mask sensitive ENV values https://github.com/SeaQL/sea-orm/pull/2658

    Bug Fixes

    • FromJsonQueryResult: panic on serialization failures https://github.com/SeaQL/sea-orm/pull/2635
    #[derive(Clone, Debug, PartialEq, Deserialize, FromJsonQueryResult)]
    pub struct NonSerializableStruct;
    
    impl Serialize for NonSerializableStruct {
        fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
        {
            Err(serde::ser::Error::custom(
                "intentionally failing serialization",
            ))
        }
    }
    
    let model = Model {
        json: Some(NonSerializableStruct),
    };
    
    let _ = model.into_active_model().insert(&ctx.db).await; // panic here
    
    Open source →
  55. 1.1.13 29 Jun 2025
    Release notes

    New Features

    • [sea-orm-cli] New --frontend-format flag to generate entities in pure Rust https://github.com/SeaQL/sea-orm/pull/2631
    // for example, below is the normal (compact) Entity:
    use sea_orm::entity::prelude::*;
    use serde::{Deserialize, Serialize};
    
    #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
    #[sea_orm(table_name = "cake")]
    pub struct Model {
        #[sea_orm(primary_key)]
        #[serde(skip_deserializing)]
        pub id: i32,
        #[sea_orm(column_type = "Text", nullable)]
        pub name: Option<String> ,
    }
    // this is the generated frontend model, there is no SeaORM dependency:
    use serde::{Deserialize, Serialize};
    
    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
    pub struct Model {
        #[serde(skip_deserializing)]
        pub id: i32,
        pub name: Option<String> ,
    }
    

    Enhancements

    • Removed potential panics from Loader https://github.com/SeaQL/sea-orm/pull/2637
    Open source →
  56. 1.1.12 27 May 2025
    Release notes

    Enhancements

    • Make sea-orm-cli & sea-orm-migration dependencies optional https://github.com/SeaQL/sea-orm/pull/2367
    • Relax TransactionError's trait bound for errors to allow anyhow::Error https://github.com/SeaQL/sea-orm/pull/2602

    Bug Fixes

    • Include custom column_name in DeriveColumn Column::from_str impl https://github.com/SeaQL/sea-orm/pull/2603
    #[derive(DeriveEntityModel)]
    pub struct Model {
        #[sea_orm(column_name = "lAsTnAmE")]
        last_name: String,
    }
    
    assert!(matches!(Column::from_str("lAsTnAmE").unwrap(), Column::LastName));
    
    Open source →
  57. 1.1.11 07 May 2025
    Release notes

    Enhancements

    • Added ActiveModelTrait::default_values
    assert_eq!(
        fruit::ActiveModel::default_values(),
        fruit::ActiveModel {
            id: Set(0),
            name: Set("".into()),
            cake_id: Set(None),
            type_without_default: NotSet,
        },
    );
    
    • Impl IntoCondition for RelationDef https://github.com/SeaQL/sea-orm/pull/2587
    // This allows using `RelationDef` directly where sea-query expects an `IntoCondition`
    let query = Query::select()
        .from(fruit::Entity)
        .inner_join(cake::Entity, fruit::Relation::Cake.def())
        .to_owned();
    
    • Loader: retain only unique key values in the query condition https://github.com/SeaQL/sea-orm/pull/2569
    • Add proxy transaction impl https://github.com/SeaQL/sea-orm/pull/2573
    • [sea-orm-cli] Fix PgVector codegen https://github.com/SeaQL/sea-orm/pull/2589

    Bug fixes

    • Quote type properly in AsEnum casting https://github.com/SeaQL/sea-orm/pull/2570
    assert_eq!(
        lunch_set::Entity::find()
            .select_only()
            .column(lunch_set::Column::Tea)
            .build(DbBackend::Postgres)
            .to_string(),
        r#"SELECT CAST("lunch_set"."tea" AS "text") FROM "lunch_set""#
        // "text" is now quoted; will work for "text"[] as well
    );
    
    • Fix unicode string enum https://github.com/SeaQL/sea-orm/pull/2218

    Upgrades

    • Upgrade heck to 0.5 https://github.com/SeaQL/sea-orm/pull/2218
    • Upgrade sea-query to 0.32.5
    • Upgrade sea-schema to 0.16.2
    Open source →
  58. 1.1.10 14 Apr 2025
    Release notes

    Upgrades

    • Upgrade sqlx to 0.8.4 https://github.com/SeaQL/sea-orm/pull/2562
    Open source →
  59. 1.1.9 13 Apr 2025
    Release notes

    Enhancements

    • [sea-orm-macros] Use fully-qualified syntax for ActiveEnum associated type https://github.com/SeaQL/sea-orm/pull/2552
    • Accept LikeExpr in like and not_like https://github.com/SeaQL/sea-orm/pull/2549

    Bug fixes

    • Check if url is well-formed before parsing https://github.com/SeaQL/sea-orm/pull/2558
    • QuerySelect::column_as method cast ActiveEnum column https://github.com/SeaQL/sea-orm/pull/2551

    House keeping

    • Remove redundant Expr::expr from internal code https://github.com/SeaQL/sea-orm/pull/2554
    Open source →
  60. 1.1.8 30 Mar 2025
    Release notes

    New Features

    • Implement DeriveValueType for enum strings
    #[derive(DeriveValueType)]
    #[sea_orm(value_type = "String")]
    pub enum Tag {
        Hard,
        Soft,
    }
    
    // `from_str` defaults to `std::str::FromStr::from_str`
    impl std::str::FromStr for Tag {
        type Err = sea_orm::sea_query::ValueTypeErr;
        fn from_str(s: &str) -> Result<Self, Self::Err> { .. }
    }
    
    // `to_str` defaults to `std::string::ToString::to_string`.
    impl std::fmt::Display for Tag {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { .. }
    }
    
    // you can override from_str and to_str with custom functions
    #[derive(DeriveValueType)]
    #[sea_orm(value_type = "String", from_str = "Tag::from_str", to_str = "Tag::to_str")]
    pub enum Tag {
        Color,
        Grey,
    }
    
    impl Tag {
        fn from_str(s: &str) -> Result<Self, ValueTypeErr> { .. }
    
        fn to_str(&self) -> &'static str { .. }
    }
    
    • Support Postgres Ipnetwork (under feature flag with-ipnetwork) https://github.com/SeaQL/sea-orm/pull/2395
    // Model
    #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
    #[sea_orm(table_name = "host_network")]
    pub struct Model {
        #[sea_orm(primary_key)]
        pub id: i32,
        pub ipaddress: IpNetwork,
        #[sea_orm(column_type = "Cidr")]
        pub network: IpNetwork,
    }
    
    // Schema
    sea_query::Table::create()
        .table(host_network::Entity)
        .col(ColumnDef::new(host_network::Column::Id).integer().not_null().auto_increment().primary_key())
        .col(ColumnDef::new(host_network::Column::Ipaddress).inet().not_null())
        .col(ColumnDef::new(host_network::Column::Network).cidr().not_null())
        .to_owned();
    
    // CRUD
    host_network::ActiveModel {
        ipaddress: Set(IpNetwork::new(Ipv6Addr::new(..))),
        network: Set(IpNetwork::new(Ipv4Addr::new(..))),
        ..Default::default()
    }
    

    Enhancements

    • Added try_getable_postgres_array!(Vec<u8>) (to support bytea[]) https://github.com/SeaQL/sea-orm/pull/2503

    Bug fixes

    • [sea-orm-codegen] Support postgres array in expanded format https://github.com/SeaQL/sea-orm/pull/2545

    House keeping

    • Replace once_cell crate with std equivalent https://github.com/SeaQL/sea-orm/pull/2524 (available since rust 1.80)
    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive