Roux is a web platform for Roc that includes everything you need to deploy.
![]()
Fast, and raced every night against Go, Rust's axum, and basic-webserver. Rendering a template, roux serves about 1.9× axum's requests and 7.5× Go's, within 6% of fourneau, the raw Zig server it's built on:
![]()
Over TLS it serves 168,700 requests/s, to axum's 80,700.
The latest results: https://fourneau.y2kbugger.com/
Try it in a minute. The tutorial is itself a roux app, and that live reload timing is its first page: https://github.com/Eldhus/roux-tutor
Couldn't help myself ... had to make a click bait post on Reddit :grinning_face_with_smiling_eyes:
https://www.reddit.com/r/roc_lang/comments/1x74nx2/how_is_this_new_web_framework_so_fast/
The answer is some combination of: io_uring+shards, lack of features, and deceiving myself somehow.
I really appreciate the effort you have put into making it polished and sharing it. Looks really nice.
Definitely be sure to checkout the "dragrace" site its pretty fun to click through and compare. I'm sure the other platforms have a bunch of low hanging fruit to compete better too (looking at basic-webserver).
https://fourneau.y2kbugger.com
![]()
this is really exciting! The hot loading with errors in the browser looks awesome, and the benchmarks are really impressive :rocket: :rocket: :rocket:
Update!
Two new features
{{...}})## A price in hundredths: `12.05`, written as a stress test/poc
kr : U32 -> Str
kr = |hundredths| {
cents = hundredths % 100
pad = if cents < 10 "0" else ""
"${(hundredths // 100).to_str()}.${pad}${cents.to_str()}"
}
expect Fmt.kr(1205) == "12.05"
{{#dishes |dish|}}<li>{{ dish.name }}: {{ Fmt.kr(dish.price) }}</li>{{/dishes}}
Fragments are inline partials that can be rendered on their own, and have their own inferrered or hinted context type.
Before, to swap one row over Datastar or htmx, you moved it to its own partial file:
Row.rocstache
<li id="dish-{{ dish.id.to_str() }}">{{ dish.name }}: {{ Fmt.kr(dish.price) }}</li>
Page.rocstache
{{#dishes}}{{> Row .}}{{/dishes}}
Now it stays where it is and renders alone too:
Page.rocstache
{{#dishes |dish|}}
{{$Row}}<li id="dish-{{ dish.id.to_str() }}">{{ dish.name }}: {{ Fmt.kr(dish.price) }}</li>{{/Row}}
{{/dishes}}
"/row" => Ok(Rocstache.html(Menu.Row.template(dish)))
Menu.Row.Ctx is just what it reads: { id : U64, name : Str, price : U32 }.
Docs: https://github.com/Eldhus/roux/blob/master/docs/templates.md
The downside is that we are now losing to Axum in the dragrace for the most intesive template test, but I have two small-string PRs on built-ins that close that gap. https://github.com/roc-lang/roc/issues/12824
I also mention that that string interpolation has a lot left on the table perf-wise, but I'm sure this is known and rightfully deffered to a later time.
I haven't really looked into string interpolation perf - do you know offhand what's inefficient about it at the moment?
I'm doing perf stuff now but plan to stop that in favor of bugfixes only pretty soon, so now's the time for fixes like that :smile:
17 messages were moved from this topic to #show and tell > Rocstache: small string concat perf by Zak Kohler.
Last updated: Nov 04 2026 at 18:54 UTC