How to use Sea-ORM

Sea-ORM is an async Rust ORM that uses a code-first approach where you define your database schema in Rust structs, then generate migration files and query builders automatically.

Sea-ORM is an async Rust ORM that uses a code-first approach where you define your database schema in Rust structs, then generate migration files and query builders automatically. You start by defining your entity models with the sea_orm::EntityTrait and sea_orm::ActiveModelTrait, then use the generated query builder to perform type-safe database operations.

First, add the dependencies to your Cargo.toml. You need the core library, the runtime (like tokio), and the migration generator.

[dependencies]
sea-orm = { version = "1", features = ["sqlx-postgres", "runtime-tokio-rustls"] }
sea-orm-migration = { version = "1", features = ["sqlx-postgres"] }

Define your entity in src/entity.rs using the derive macros. This single definition generates the migration SQL, the query builder methods, and the active model for inserts/updates.

use sea_orm::entity::prelude::*;

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "user")]
pub struct Model {
    #[sea_orm(primary_key)]
    pub id: i32,
    pub name: String,
    pub email: String,
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

impl ActiveModelBehavior for ActiveModel {}

To generate the initial migration, run the CLI tool. This creates a migrations folder with the SQL needed to create the user table based on your Rust struct.

cargo sea-orm-cli generate migration --name init

In your application logic, connect to the database and use the generated Entity to query or insert data. The query builder is fluent and type-safe, preventing SQL injection and compile-time errors.

use sea_orm::{Database, DbConn, EntityTrait, QueryFilter};

#[tokio::main]
async fn main() -> Result<(), sea_orm::DbErr> {
    let db = Database::connect("postgres://user:pass@localhost/dbname").await?;

    // Insert a new user
    let user = user::ActiveModel {
        name: Set("Alice".to_owned()),
        email: Set("alice@example.com".to_owned()),
        ..Default::default()
    };
    let inserted = user.insert(&db).await?;

    // Query users by name
    let users = User::find()
        .filter(user::Column::Name.eq("Alice"))
        .all(&db)
        .await?;

    println!("Found {} users", users.len());
    Ok(())
}

Sea-ORM handles the heavy lifting of mapping Rust types to SQL types, managing connections asynchronously, and providing a consistent API across different database backends like PostgreSQL, MySQL, and SQLite.