I built the same shop app twice: once with Loco, once with Sofie, a Rust web framework I've been working on. Both have sign-up, orders with status transitions, an HTML page and a JSON API, a background audit job and an hourly expiry job. The Loco version is 1,834 lines of app code. The Sofie version is 365.
Part of that gap is accounts. Loco generates its auth system into the app (889 lines), while Sofie ships it as a crate. Without accounts, it's 365 vs ~945, still about 2.5×.
The rest comes from one idea: if every app follows the same fixed structure, the framework can read the whole app at build time and derive what you'd normally write by hand.
• The aggregate struct is the schema. Columns, validation, input types, form fields and table columns all derive from it. Change a field once, and everything built on it follows.
• Wiring is generated, not hidden. There's no DI container and no reflection. sofie gen writes the wiring into a plain Rust file that you commit and can read.
• Architecture rules fail the build. A module can import only another module's contract. Cross-module SQL joins are an error, and the check runs during cargo build, not in code review.
• Modules are split-ready. They never share transactions, so sofie split can move one into its own app later without rewriting its queries.
The price is the structure itself: the folder layout isn't yours to choose, and code that doesn't fit a role gets no help from the framework.
On the same machine, Sofie also built faster (20s vs 81s clean) and served more (~24k vs ~5.9k req/s on the JSON list). This is one small app on one machine, and the docs list everywhere the comparison is uneven.
Sofie is a proof of concept, built with heavy use of Claude Code, and the APIs will change. I'd like feedback on the structure itself: which rules would you want enforced, and which would make you walk away?
GitHub: https://github.com/sofie-rs/sofie
Docs and benchmark details: https://sofie.rs/
Top comments (0)