DHH's Campfire Benchmark Is Flawed, and Still Right
DHH had agents port Campfire to Elixir, Go and Rust. The Elixir numbers are wrong, the argument holds, and none of these languages is where this ends.
On 4 October DHH posted a table of five Campfire workloads across four languages, and the row everyone repeated was the room page: 244 requests a second on Rails, 722 on Elixir, 3,860 on Go and 36,260 on Rust. Agents wrote and optimised the three ports, and his point was that Ruby being the slowest never bothered him while the pay-off was productivity and developer joy, "but if you're no longer reading the code?"
Two weeks ago I wrote about his Rails World keynote and said the Rust figures in it were claims with no published benchmark behind them. Now there is one, with a public repo for every port, and within two days the Elixir community had shown that the Elixir column is wrong. I think they are right about the benchmark, and I think it changes nothing about the conclusion.
What the Campfire benchmark measured
The table from the Campfire README, in requests per second:
| Workload | Rails | Elixir | Go | Rust |
|---|---|---|---|---|
| Room page | 244 | 722 | 3,860 | 36,260 |
| Messages page | 424 | 1,053 | 5,573 | 40,872 |
| Sidebar | 556 | 1,275 | 19,753 | 34,672 |
| Search | 432 | 1,156 | 7,053 | 33,299 |
| Post a message | 258 | 801 | 4,767 | 6,896 |
It was measured with 16 concurrent clients on an AMD Ryzen AI MAX+ 395, with four hardware threads given to each app, and every port keeps Campfire's SQLite database and is checked against the Rails app's behaviour (the Elixir port reports 65 gates and 1,896 tests passing). These are 37signals' own measurements on one machine, none of the ports has replaced the Rails app in production, and no Campfire install needs 36,000 requests a second.
The Elixir column is not what Elixir can do
I have run Elixir and Phoenix in production for years, on a fostering profile platform and a judging app for a national schools competition, and the official port is not how anyone who works on the BEAM would build a chat app. It reproduces the structure of the Rails app instead: every database query goes through a single GenServer, Redis sits on the critical path, and Rack and Resque are emulated, so a runtime built for concurrency was benchmarked with its reads queued behind one process.
The fixes arrived quickly. Zach Daniel opened a pull request that pools SQLite connections, compiles the routes into pattern matches instead of walking a list of regexes, drops Redis, and stops WebSockets disconnecting every 60 seconds or so (an idle timeout in Bandit), and he reports the room page going from about 800 requests a second to between 2,600 and 4,100. His overload test is the part I found most interesting: with 64 clients posting at once the Elixir port delivered every message with no disconnects, while the Rust port delivered between 1% and 9% and dropped several hundred clients.
Kurt Melby went further with response caching and reports 12,130 requests a second on the room page, up from 1,226 on his machine, with peak memory down from 1,472 MiB to 369 MiB (an automated review flagged cache correctness problems and the parity gates have not been run against it, so I would not quote that number as settled). A separate idiomatic Phoenix rewrite gets roughly two and a half times the official port on its author's hardware, and its README notes that the Go port had its own optimisation pass and inherited work from the Rust one, which the Elixir port did not get.
Both pull requests were still open when I wrote this, and the published table still shows 722.
Needing an expert to fix it is the result
DHH answered the objection before most people had made it: "If your answer here is "frontier agents aren't good at writing Elixir or Go", then it only makes the argument worse. Any programming language that agents can't write well out of the box is going to have a hard time in the future."
I agree with him, and so does the most useful response I read from inside the Elixir community. Almir Sarajčić wrote that "explaining what an Elixir expert would have done doesn't remove the need for that expert", and that if agents consistently produce better software in Rust with the tokens he has, he would choose Rust.
The agents were given the same Rails app and the same brief in each language, and what came out was fast Rust and Elixir that needed two of the better-known Elixir developers to repair by hand. The flawed column measures what an agent produces in that language today without a specialist standing next to it, which is the number that matters once agents are doing the writing, and I say that as someone whose production Elixir is older than any of these agents.
I would not read it as permanent, though. The repairs took two days and are now public code, and agents get better at optimisation with every release while a language's design stays where it is.
The work is moving from syntax to managing agents
Most of the thread was an argument about idiom, and idiom is the part of this job that is going away. Whether the port should have used a connection pool or a GenServer is a question a developer used to carry in their head, and it is turning into a question the agent answers on the second pass when a benchmark tells it the first pass was slow.
What stays with us is deciding what to build, writing down the behaviour precisely enough to check, and running the agents that do the rest. The Campfire ports are a good example of the second one: they were possible in hours because the Rails app could be used as an executable specification, with checks that compare each port against it, which is the same idea as treating tests as contracts for AI agents. The people in that thread who were best at Elixir spent two days optimising code, and I expect that within a few model generations nobody will need to.
Choose the language by output per unit of cost
Once nobody reads the code, a language has two costs left: the tokens it takes to produce and change the software, and the infrastructure it takes to run it.
The token side has been measured. A July 2026 study ran coding agents on the same problems in Python, Java, Rust and OCaml, and on the two frontier models it tested Rust cost between 1.16 and 1.36 times the tokens of Python, mostly from agents fighting the compiler in languages they know less well. DHH's own follow-up names the other half of that cost, slow compile times, which an agent pays on every loop.
The infrastructure side is the table. On the room page the Rust port serves 149 times what Rails does on the same four threads, and even on the write path, where everything queues behind SQLite, it is 27 times. Paying a third more in tokens to need a fraction of the servers for the life of the product is an easy trade, and it is the trade I described when I said my own new work is moving to Rust and Elixir. Developer joy is not in that sum, because it was a cost of human attention, and human attention is going somewhere else. (What I work on now is on my CV.)
None of these languages is the end state
Every language in that table was designed for a person to type and a person to read. Ruby optimises for the pleasure of the author, Go for large teams reading each other's code, Elixir for humans reasoning about concurrent processes, and Rust for humans who need the compiler to stop them, and agents are using all four through an interface built for eyes and hands.
I do not expect any of today's programming languages to exist in ten years. I expect one language, or several, designed from the start for agents to write: cheap in tokens, strict enough that the toolchain rejects wrong code before a test runs, fast to compile because the loop runs thousands of times a day, and close enough to the machine that the hosting bill is small. Rust won this table because it is the nearest thing to that available this year.