Por que a escolha de acesso a banco importa tanto em Rust
Rust não traz um ORM padrão embutido. Ao contrário de linguagens com ecossistema muito opinionado, o desenvolvedor Rust precisa decidir explicitamente como vai falar com o banco de dados. Essa escolha afeta performance, segurança de tipos, ergonomia, manutenção e até o formato dos erros que chegam nos logs.
Em 2026, três crates dominam a conversa: SQLx, Diesel e SeaORM. Cada uma representa uma filosofia diferente de acesso a dados. Entender essa diferença ajuda a desenhar serviços com Axum e Tokio que são previsíveis em produção, e também prepara melhor para vagas Rust e carreira backend, onde essa decisão aparece em entrevistas técnicas.
O erro comum é escolher pela popularidade do momento. A decisão certa depende do tipo de aplicação, do tamanho da equipe, do formato do schema, da necessidade de migrations e do quanto você quer que o compilador valide suas queries.
SQLx: queries verificadas em tempo de compilação
SQLx é hoje a escolha mais comum para serviços assíncronos em Rust. A grande ideia é a macro sqlx::query!: ela envia a query para o banco (ou para um cache offline) durante o build e valida tipos, nomes de coluna e compatibilidade antes do binário existir.
use sqlx::postgres::PgPool;
pub struct Usuario {
pub id: i64,
pub nome: String,
pub email: String,
}
pub async fn buscar_usuario(
pool: &PgPool,
id: i64,
) -> Result<Option<Usuario>, sqlx::Error> {
let usuario = sqlx::query_as!(
Usuario,
r#"SELECT id, nome, email FROM usuarios WHERE id = $1"#,
id
)
.fetch_optional(pool)
.await?;
Ok(usuario)
}
A vantagem é enorme: se a coluna email virar email_principal, o build quebra em vez de falhar em produção. O custo é que o build precisa de banco acessível ou de um cache offline gerado com cargo sqlx prepare.
SQLx funciona muito bem com Axum, suporta PostgreSQL, MySQL, SQLite e MSSQL, e tem sistema próprio de migrations. É a base sobre a qual o SeaORM é construído.
Diesel: type safety com schema gerado
Diesel é o ORM mais maduro do ecossistema Rust. Usa código gerado a partir do schema (diesel print-schema) e uma DSL fortemente tipada que impede grande parte dos erros de SQL antes do runtime.
use diesel::prelude::*;
use diesel::sql_types::{BigInt, Text};
sql_function!(fn lower(x: Text) -> Text);
let conexao = &mut establish_connection();
let usuarios = usuarios::table
.filter(usuarios::ativo.eq(true))
.order(usuarios::nome.asc())
.limit(20)
.load::<Usuario>(conexao)?;
O ponto forte é a robustez: refatorar queries grandes é seguro porque o compilador acompanha. O ponto fraco histórico é que Diesel é síncrono por padrão. Existe uma feature async experimental, mas serviços totalmente async ainda ficam mais naturais com SQLx.
Diesel brilha em projetos que valorizam estabilidade, schemas bem definidos e times que aceitam a verbosidade em troca de garantias. Para quem já domina PostgreSQL ou vem de ecossistemas com ORMs sólidos, a curva costuma valer a pena.
SeaORM: ORM dinâmico e async
SeaORM é um ORM mais novo, assíncrono, construído sobre SQLx. A proposta é ergonomia: entidades derivadas, API fluente, relacionamentos declarados em código e uma sensação mais próxima de frameworks web de outras linguagens.
use sea_orm::*;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "usuarios")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub nome: String,
pub email: String,
pub ativo: bool,
}
pub async fn ativos(db: &DatabaseConnection) -> Result<Vec<Model>, DbErr> {
Entity::find()
.filter(Column::Ativo.eq(true))
.all(db)
.await
}
SeaORM é uma boa escolha para times que prezam legibilidade e vêm de ORMs dinâmicos como Prisma, TypeORM ou Django ORM. Funciona em produção, mas a camada extra pode esconder custos de performance (especialmente N+1) se usada sem cuidado. Para serviços de alta carga, vale medir antes de assumir como padrão.
Comparação direta
| Critério | SQLx | Diesel | SeaORM |
|---|---|---|---|
| Estilo | Query com validação compile-time | DSL tipada com schema gerado | ORM dinâmico fluente |
| Async | Nativo (Tokio) | Experimental | Nativo (sobre SQLx) |
| Validação de tipos | Forte (macro query!) | Muito forte (DSL) | Média (entidades) |
| Curva de aprendizado | Média | Alta | Baixa-média |
| Migrações | Inclusas | Inclusas (CLI própria) | Via migration crate |
| Ideal para | APIs async, microserviços | Projetos maduros, schemas estáveis | Times que querem ergonomia ORM |
Quando escolher cada um
Não existe vencedor absoluto. A decisão depende de contexto:
- Começando uma API Axum nova: SQLx costuma ser o caminho mais direto. É async, valida queries e se integra bem com o resto do stack Rust moderno.
- Projeto grande com schema estável e time experiente: Diesel oferece garantias fortes e é difícil de errar queries grandes.
- Time vindo de frameworks web com ORM: SeaORM reduz fricção inicial e mantém produtividade alta, desde que o time cuide de performance.
Em todos os casos, vale manter a camada de acesso a dados isolada em um módulo de repositório, em vez de espalhar queries por handlers. Isso facilita testes, troca de biblioteca no futuro e revisão de performance.
Erros comuns e boas práticas
Independente da escolha, alguns problemas se repetem:
- N+1: carregar uma lista e depois buscar relacionamentos um a um. Use
JOIN, batch ou DataLoader (como no caso de GraphQL com async-graphql). - Pool subdimensionado: o pool de conexões precisa acompanhar a carga real do serviço. Monitore uso e latência.
- Migrations fora de ordem: mantenha migrations versionadas, testadas e aplicadas de forma determinística em CI.
- Erros genéricos: não vaze
sqlx::Erroroudiesel::Errordireto para o cliente. Converta em erros de domínio com mensagens em português, como discutido no artigo sobre tratamento de erros com thiserror e anyhow. - Transações esquecidas: operações que alteram várias tabelas precisam de transação explícita. Sem isso, um falha no meio deixa o banco inconsistente.
Conexão com carreira e portfólio
Saber justificar a escolha entre SQLx, Diesel e SeaORM é um diferencial real em entrevistas. Mostra que o candidato entende trade-offs, não apenas sintaxe. Para quem busca vagas remotas ou posições sênior, uma API pequena bem desenhada com migrations, transações, erros estruturados e cobertura de testes vale mais do que um projeto enorme sem clareza.
Para comparar abordagens entre linguagens, vale estudar como Go resolve acesso a dados com database/sql e ORMs no ecossistema do Golang Brasil. A diferença de filosofia ajuda a explicar por que Rust prioriza validação em compile-time enquanto Go depende mais de checagens em runtime.
Conclusão
SQLx, Diesel e SeaORM resolvem o mesmo problema de formas diferentes. SQLx aposta em validação de query em compile-time com async nativo. Diesel oferece o tipo de segurança mais profundo, com custo de verbosidade. SeaORM traz ergonomia de ORM moderno sobre uma base sólida.
A escolha não é definitiva nem precisa ser global. Muitos projetos saudáveis misturam abordagens conforme a complexidade da query. O mais importante é tomar a decisão com consciência dos trade-offs, manter o acesso a dados isolado e testar o caminho crítico de produção. Para quem cresce em Rust em 2026, essa maturidade de decisão vale tanto quanto dominar a linguagem.