
Three days ago, JetBrains published “Rust Web Development 2026: The Problems Nobody Talks About.” The number one complaint from the co-maintainers of cot.rs? The database layer. Specifically: “Rust ORMs require you to maintain the same schema in multiple places.” That is a precise description of Diesel’s three-schema problem, which developers have been tolerating for years. The Tokio team shipped Toasty on crates.io in April 2026 — the first Rust ORM designed around the idea that you should not have to think in SQL while writing Rust. If you have been living with Diesel’s macro soup or SQLx raw query strings, here is what changed.
Not Another Thin SQL Wrapper
Toasty is not a query builder. It is what the Tokio team calls an “application-level query engine.” The core design decision: the application schema and the database schema are fully decoupled. You model your data as a graph of entities and relationships. Toasty transforms your queries into whatever the target database actually needs — SQL JOINs for PostgreSQL, index-based access patterns for DynamoDB. You never write SQL syntax in Rust.
That single decision cascades into almost every ergonomic win Toasty offers. The same model code works against SQLite in development and DynamoDB in production. Toasty enforces at compile time that your DynamoDB queries only use indexed access patterns. And relationships are first-class Rust types, not foreign key integers scattered across your structs.
One Source of Truth, Not Three
If you have used Diesel in production, you know the drill: update a Rust struct, update the migration file, update schema.rs, and discover three months later that something drifted. Toasty uses the derive macro as the single source of truth:
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: u64,
name: String,
#[unique]
email: String,
#[has_many]
todos: toasty::Deferred<Vec<Todo>>,
}
#[derive(Debug, toasty::Model)]
struct Todo {
#[key]
#[auto]
id: u64,
title: String,
done: bool,
#[belongs_to(key = user_id, references = id)]
user: toasty::Deferred<User>,
}
One codegen step (cargo toasty generate) produces all query builders, relationship accessors, and schema output from this single definition. The generated code lives in a file you can open and read — not proc macros you decode through cargo expand.
Deferred<T> Solves N+1 at the API Level
The Deferred<T> wrapper on relationship fields is Toasty’s most immediately useful feature. Any relationship marked as Deferred is skipped by default when loading a model. You choose at the query site whether to load eagerly or lazily:
// Eager: loads user + todos in one query
let user = User::find_by_id(&db, user_id)
.include(User::todos())
.await?;
// Lazy: load todos only when you need them
let user = User::find_by_id(&db, user_id).await?;
let todos = user.todos.load(&db).await?;
// Selective field loading
let users = User::all()
.select(User::name().and(User::email()))
.await?;
This is the N+1 problem handled at the type level. Your code will not accidentally fire 100 individual queries to hydrate 100 users’ todo lists — the API forces you to be explicit. SeaORM has eager loading, but it requires careful documentation-reading to avoid N+1 traps. Toasty makes the safe path the default path.
Same Model, Different Database
Toasty currently supports SQLite, Turso, PostgreSQL, MySQL, and DynamoDB. The database is a config-level decision, not a code-level decision. The same User::find_by_id call generates a SQL SELECT against PostgreSQL and a GetItem API call against DynamoDB. When you target DynamoDB, Toasty only generates query methods that are legal for DynamoDB’s access patterns. You cannot build a full-table-scan query by accident — the compiler will not produce the method.
This is a real step beyond SeaORM’s approach, where you can write a query that is valid Rust but illegal for your database and only discover the problem at runtime. Toasty’s constraint awareness means fewer surprises in production.
What Is Missing
Toasty 0.6.0 has no migration tooling. Schema changes require manually written migration scripts. For greenfield projects, that is manageable. For teams with existing production databases and complex migration histories, this is a real gap. The Tokio team has flagged migrations as a priority for future releases, but future is not now. NoSQL support beyond DynamoDB is also limited — PostgreSQL JSONB document storage is planned but not shipped. This is 0.x software evolving quickly.
When to Use It Now
Toasty earns a green light for new Rust projects choosing a data layer from scratch. If you are already on Axum and Tokio, adding Toasty gives you the full Tokio team web stack: async runtime, HTTP framework, and data layer from the same maintainers sharing the same design philosophy.
For teams considering migration from Diesel or SeaORM in an existing production codebase: wait for migration tooling. The ergonomics win is real, but switching without migration support is unnecessary pain.
Getting started is three lines:
cargo add toasty
cargo add toasty-sqlite # or toasty-postgres, toasty-mysql, toasty-dynamodb
cargo toasty generate
The Toasty guide covers full model setup and relationship configuration. The tokio-rs/toasty repository has working examples for each supported database. For context on how Toasty fits the existing landscape, ByteIota’s Rust ORMs 2026 comparison covers Diesel, SQLx, and SeaORM — Toasty is the new arrival that changes the calculus.













