What it is
Diesel is a safe, extensible ORM and query builder for Rust that catches invalid queries at compile time through its type-level schema representation.
diesel_cli generates a schema module from migrations. Queries are built from those generated table types, so column names and types are checked by the compiler.
Installation
cargo add diesel --features postgres,chronoGetting started
The smallest useful thing you can do with it, and what each part means.
// @generated by diesel_cli into src/schema.rs
diesel::table! {
books (id) {
id -> Int4,
title -> Varchar,
year -> Int4,
}
}
#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::schema::books)]
struct Book { id: i32, title: String, year: i32 }
use crate::schema::books::dsl::*;
let results = books
.filter(year.gt(1990))
.order(year.desc())
.limit(10)
.select(Book::as_select())
.load(conn)?;
// books.filter(titel.eq("x")) // compile error: no such columnAdvanced usage
Where the library earns its place over a simpler alternative.
#[derive(Insertable)]
#[diesel(table_name = books)]
struct NewBook<'a> { title: &'a str, year: i32 }
conn.transaction(|conn| {
let book: Book = diesel::insert_into(books)
.values(&NewBook { title: "Dune", year: 1965 })
.returning(Book::as_returning())
.get_result(conn)?;
diesel::update(stock.filter(sku.eq(&book.title)))
.set(quantity.eq(quantity - 1))
.execute(conn)?;
diesel::QueryResult::Ok(book)
})?;Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- the trait bound is not satisfied on a query
- Diesel's errors are notoriously long. Read the first line only: it usually names a column or type mismatch between the struct and the schema.
- Column does not exist at runtime
- schema.rs is out of date. Re-run diesel migration run and regenerate.
Best practices
- Regenerate schema.rs with diesel_cli after every migration; a stale schema compiles but lies.
- Use Selectable and as_select() so struct fields and selected columns cannot drift apart.
- Prefer SQLx or SeaORM if you need async; Diesel's async story is a separate crate and less mature.
- Keep migrations in version control and run them in CI against a scratch database.
Background
Why it exists, and what it was reacting to.
Diesel predates async Rust and takes a different approach from SQLx: instead of checking SQL strings against a live database, it represents the schema in the type system, so an impossible join simply does not compile.
