● Batteries-included Rust · v1.0

The one-person
framework for Rust.

Everything you need to take a side-project or startup from an idea to production — models, controllers, jobs, mailers, auth — generated and wired together.

Start building →
$ cargo install loco⧉ copy
1.0 Sea-ORM 2.0 · edition 2024
6.9k ★ on GitHub
0 → prod in one command
Loco illustration
// all aboard
terminal
 
batteries-included·Rails, in Rust·SeaORM·Axum·background jobs·test-driven

Empower the one-person team.

Loco follows Rails — carefully adapted to modern Rust. The heavy lifting is tucked away so you can move fast, and pulled back out the moment you need to scale.

🔋

Batteries included

Service, data, emails, background jobs, tasks, and a CLI to drive it all — in the box from day one.

Rails is great

Loco follows Rails. There, we said it — its concepts, carefully adapted to idiomatic Rust.

Deliver with confidence

Unapologetically optimized for the solo developer. Complexity and heavy lifting tucked away.

Scale when needed

Split, reconfigure, or use only the parts of Loco you need. Grow without a rewrite.

Build incrementally

Just a service. Or with a database. Or a background worker. Or a task. Use what you need.

Test-driven everything

Models, controllers, jobs — test the whole app with very little effort. Ship fast, stay safe.

One feature, a few small files.

Handle the request.

  • No macros, no magic. Plain async fn returning Result<Response>.
  • Wired with Routes. The app context — db, config, workers — is handed to you.
  • Typed both ways. Extractors in, serialized responses out.
01 / 06
src/controllers/articles.rs
// src/controllers/articles.rs
use loco_rs::prelude::*;
use crate::models::_entities::articles;
use crate::views::article::ArticleResponse;

pub async fn list(State(ctx): State<AppContext>) -> Result<Response> {
    let items = articles::Model::latest(&ctx.db).await?;
    let res: Vec<_> = items.iter().map(ArticleResponse::new).collect();
    format::json(res)
}

pub fn routes() -> Routes {
    Routes::new()
        .prefix("articles")
        .add("/", get(list))
}