Primeiros passos com o Loco, a resposta do Rust ao Rails
Crie uma aplicação web em Rust com Loco, o framework inspirado no Rails. Instale a CLI, gere uma API CRUD e adicione um worker em segundo plano com Loco 1.2.
O Loco é um framework web em Rust inspirado no Rails. Ele reúne o roteamento do Axum, os models e as migrations do Sea-ORM, workers em segundo plano e geradores de código por trás de um único comando cargo loco.
Se você já passou um fim de semana integrando Axum, um ORM, um executor de migrations e uma fila de jobs antes de escrever qualquer regra de negócio, o Loco foi pensado para poupar esse trabalho. Neste guia, você vai instalar o Loco, criar uma aplicação de API, gerar o scaffold de um recurso e adicionar um job em segundo plano. Muitos tutoriais mais antigos são voltados para versões anteriores à 1.0, por isso todos os comandos abaixo usam a CLI 1.x do Loco 1.2.0. Se você ainda está começando na linguagem, veja primeiro os fundamentos de Rust.
Principais pontos
- O Loco é um framework web em Rust inspirado no Ruby on Rails. Ele usa o Axum para o roteamento e o Sea-ORM 2.0 para models e migrations.
- Instale a CLI com
cargo install loco. Você também precisa executarcargo install sea-orm-cli, mas apenas se a sua aplicação usar banco de dados. - No Loco 1.2, o
cargo loco generate scaffoldgera uma migration, um model, uma entity, DTOs e um controller CRUD e, em seguida, aplica a migration. Não há uma etapa de migrate separada. - O servidor de desenvolvimento de uma nova aplicação Loco escuta na porta 5150.
- Em desenvolvimento, os jobs em segundo plano são executados no mesmo processo, no modo
BackgroundAsync. Em produção, normalmente eles são movidos para uma fila no Redis, Postgres ou SQLite, processada pelocargo loco start --worker.
O que é o Loco em Rust?
O Loco é um framework full-stack e opinativo para Rust. Ele resolve as decisões de stack que um projeto Axum puro deixa por sua conta. A página oficial do Loco indica o Axum como camada HTTP e o Sea-ORM 2.0 como ORM. Workers, scheduler, mailers, armazenamento e cache também vêm integrados. Você tem uma única estrutura de projeto, um único sistema de configuração e uma única CLI, sem precisar escolher cinco crates e escrever o código que as conecta. O código-fonte está no GitHub. O Loco chegou à sua primeira versão estável, a 1.0, em julho de 2026.
Quais ideias do Rails o Loco aproveita?
O Loco adota quatro práticas do Rails. Todo projeto segue a mesma estrutura previsível, geradores escrevem o boilerplate, as alterações de schema passam por migrations versionadas e o trabalho demorado vai para jobs em segundo plano. Se você conhece Django ou Laravel, já viu essas mesmas ideias com outros nomes.
| Conceito | O que significa | Comando ou local no Loco 1.2 |
|---|---|---|
| Convenção sobre configuração | Os arquivos ficam onde o framework espera encontrá-los | Estrutura gerada em src/ e config/ |
| Geradores | A CLI escreve o código boilerplate | cargo loco generate scaffold, model, controller, worker |
| Migrations | Alterações de schema versionadas | migration/src/, aplicadas automaticamente ao gerar |
| Jobs em segundo plano | O trabalho é executado fora do ciclo da requisição | cargo loco generate worker, perform_later |
Como instalar o Loco e criar uma aplicação?
A instalação do Loco exige dois comandos do cargo, e a criação de uma aplicação, mais um. Como indica o README do Loco, a instalação do sea-orm-cli só é necessária quando a aplicação usa banco de dados. Este exemplo usa SQLite, então você vai precisar dele:
cargo install loco
cargo install sea-orm-cli
Em seguida, gere a aplicação. Se você passar as quatro flags, o assistente pula as perguntas interativas. Assim, o comando pode ser usado em scripts e sempre produz o mesmo resultado:
loco new --name tour_app --db sqlite --bg async --assets none
cd tour_app
cargo loco start
De acordo com o tutorial oficial da primeira aplicação, --db sqlite define o SQLite como banco de dados, --bg async executa os jobs em segundo plano no mesmo processo e --assets none dispensa o scaffolding de views, de modo que a aplicação serve apenas JSON. A última linha da saída do start confirma que o servidor está no ar:
listening on port 5150
Por padrão, o servidor de desenvolvimento escuta na porta 5150. Os arquivos de configuração definem a porta por meio de uma chamada get_env, que lê a variável de ambiente PORT, como mostra a referência de configuração. É por ali que você pode alterá-la. Como você escolheu um banco de dados, a aplicação também já vem com rotas de autenticação em /api/auth/*.
Tutoriais mais antigos instalam uma crate chamada loco-cli. O Loco 1.0 removeu essa crate, e a CLI agora é instalada como loco.
Como gerar um recurso com scaffold?
Um scaffold do Loco gera, com um único comando, uma API CRUD funcional e integrada ao banco de dados:
cargo loco generate scaffold posts title:string! content:text --no-auth
No Loco 1.2, o cargo loco generate scaffold gera uma migration, um model e uma entity do Sea-ORM, DTOs tipados de requisição e resposta e um controller CRUD. Em seguida, aplica a migration e regenera as entities, então você nunca precisa executar um comando de migrate separado.
A sintaxe dos campos vem do guia Add a model. Um tipo terminado em !, como title:string!, gera uma coluna obrigatória. Um tipo sem sufixo, como content:text, gera uma coluna anulável, e ^ marca o campo como único. As rotas geradas pelo scaffold exigem um JWT por padrão, então uma requisição anônima retorna 401. A flag --no-auth torna as rotas públicas, o que simplifica esta demonstração.
As partes do projeto gerado usadas neste guia (visão parcial):
tour_app/
├── config/development.yaml
├── migration/src/
└── src/
├── app.rs
├── controllers/posts.rs
├── dtos/
├── models/_entities/
└── workers/
Para testar o novo endpoint, reinicie o servidor e envie uma requisição POST:
curl -X POST -H "Content-Type: application/json" \
-d '{"title":"Tour post","content":"hi"}' localhost:5150/api/posts
A resposta JSON começa com {"id":1, e, em seguida, devolve o post armazenado.
Como adicionar um job em segundo plano no Loco?
Um job em segundo plano no Loco é um módulo de worker com uma struct de argumentos tipada. Você o coloca na fila com perform_later. Gere um worker:
cargo loco generate worker notifier
added: "src/workers/notifier.rs"
injected: "src/workers/mod.rs"
injected: "src/app.rs"
Como explica o guia de background workers, o gerador sempre nomeia a struct como Worker e a coloca em um módulo próprio, ao lado de uma struct WorkerArgs vazia que você deve preencher. Ou seja, o worker notifier gerado é workers::notifier::Worker. Em src/workers/notifier.rs, adicione um campo a WorkerArgs e substitua o corpo de perform. Mantenha o build e o restante do arquivo gerado como estão:
#[derive(Deserialize, Debug, Serialize)]
pub struct WorkerArgs {
pub post_id: i64,
}
// inside the generated `impl BackgroundWorker<WorkerArgs> for Worker`
async fn perform(&self, args: WorkerArgs) -> Result<()> {
println!("new post created: {}", args.post_id);
Ok(())
}
Depois, abra src/controllers/posts.rs e adicione as linhas abaixo ao handler create gerado pelo scaffold, logo após a linha que insere o novo post (let item = item.insert(&ctx.db).await?;). Desde o Loco 1.0, as chaves primárias geradas são i64, então item.id é compatível com post_id sem nenhuma conversão:
crate::workers::notifier::Worker::perform_later(
&ctx,
crate::workers::notifier::WorkerArgs { post_id: item.id },
)
.await?;
Desde o Loco 1.0, perform_later() retorna o ID do job como Result<String>, conforme as notas de versão do Loco 1.0. Você pode registrá-lo em log se quiser rastrear os jobs depois.
O seu config/development.yaml define workers.mode como BackgroundAsync, que executa os jobs como tasks do Tokio no mesmo processo. O modo BackgroundAsync não precisa de nenhum backend de fila. Em produção, altere workers.mode para BackgroundQueue, configure uma fila no Redis, Postgres ou SQLite e processe os jobs em um processo separado com cargo loco start --worker. As filas no Postgres e no SQLite funcionam com a feature padrão worker, enquanto uma fila no Redis exige a feature worker_redis. O backend é selecionado na configuração por meio de queue.kind. O código do worker e do controller não muda com a troca.
Para quem o Loco é indicado?
O Loco torna a configuração de um backend em Rust muito mais rápida, mas não elimina os custos de programar em Rust:
- Tempo de compilação. Toda alteração passa pelo
rustc, então o ciclo de editar e recarregar é mais lento do que em frameworks de Ruby, Python ou PHP. - Ecossistema. Há muito menos integrações de terceiros, plugins e perguntas respondidas do que o acumulado por Rails ou Django.
- Curva de aprendizado. O código gerado ainda pressupõe que você domine ownership, async e traits, e os erros de compilação nos handlers pressupõem que você saiba interpretá-los.
O Loco é uma boa escolha para quem já conhece Rust e quer a agilidade de configuração do Rails, assim como para desenvolvedores Rails, Django ou Laravel que estão migrando para Rust de forma deliberada. Não é uma boa escolha para o primeiro backend de quem está aprendendo servidores web e Rust ao mesmo tempo. Se você ainda está decidindo se vale a pena aprender Rust para desenvolvimento web, leia sobre se desenvolvedores web precisam de Rust.
Conclusão
O Loco oferece aos desenvolvedores Rust o que o Rails oferece aos desenvolvedores Ruby: uma única CLI, uma estrutura previsível e migrations e jobs integrados, tudo sobre o Axum e o Sea-ORM. Use os comandos 1.x deste guia em vez dos comandos anteriores à 1.0 presentes em tutoriais mais antigos. O próximo passo é adicionar um segundo recurso com cargo loco generate model e depois seguir o guia de background workers para migrar sua fila do BackgroundAsync para um backend persistente.
Perguntas frequentes
Posso usar middlewares e extractors existentes do Axum em uma aplicação Loco?
Sim. O Loco é basicamente uma camada de integração em torno do Axum, então extractors personalizados que implementam FromRequestParts funcionam nos controllers do Loco. Para adicionar layers do Tower, como um timeout do tower-http ou uma layer de sessão, implemente Hooks::after_routes em src/app.rs, que recebe o router do Axum já construído pelo Loco.
Como migrar uma aplicação Loco do SQLite para o Postgres?
Defina database.uri em config/development.yaml ou config/production.yaml com uma connection string postgres://. A configuração gerada lê esse valor por meio de get_env com a variável DATABASE_URL, então definir essa variável de ambiente também funciona. Os padrões do Loco esperam o usuário loco, a senha loco e um banco de dados com o nome da aplicação e do ambiente, como myapp_development. Adicionar sslmode=require à URI ativa o TLS do Postgres, sem necessidade de nenhuma feature extra do Cargo.
Como fazer o deploy de uma aplicação Loco em produção?
Gere um binário de release com cargo build --release e copie-o para o servidor junto com a pasta config/. A máquina de destino não precisa de toolchain do Rust nem do cargo. Para empacotamento, o cargo loco generate deployment oferece três opções: docker, nginx e lambda. A opção docker gera um Dockerfile e um .dockerignore, a nginx gera uma configuração de proxy reverso e a lambda gera um entrypoint para AWS Lambda e adiciona a dependência lambda_http. As configurações de produção ficam em config/production.yaml.
Qual é a diferença entre o scheduler e os background workers do Loco?
Os workers executam jobs que o seu código coloca na fila com perform_later, enquanto o scheduler executa jobs de acordo com uma programação de horários. Os jobs do scheduler são declarados no YAML de configuração, cada um com uma expressão cron ou uma programação em inglês simples. O valor de run indica uma task registrada no Loco ou um comando de shell, quando shell é true. A flag --scheduler executa o scheduler junto com o servidor, sem um processo de worker.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k