Lire en français

Is Rails really done?

DHH is rebuilding HEY without Rails, and Lucas Dohmen says Rails is done. I think there's still plenty left to do.

rails, ai

At Rails World last week, DHH explained that 37signals barely writes code by hand anymore, and that HEY is being rewritten as native apps with a Rust backend, which means no Rails.

Six weeks earlier, Lucas Dohmen published Rails is done: in his view, the core of Rails has barely moved since 2019, and that’s fine. (His post is mostly about governance; I’ll come back to that.)

Fine, it doesn’t move. Whether that’s a good thing is another matter. I’ve been doing Rails since 2008, and on every new project I still hand-build things the framework could handle.


Rails has moved, though. Rails 8 added an authentication generator; Solid Queue, Solid Cache and Solid Cable to drop Redis; SQLite in production to drop Postgres or MySQL; and Kamal to deploy on your own servers.

Not all of it is to my taste. Take the SQLite default: a database in a file fits poorly with disposable compute that scales on demand. 37signals doesn’t have that problem, because they’ve hosted everything on their own servers since their cloud exit. Luckily, it’s only a default: rails new -d postgresql, and the Solid gems run on Postgres.

Rails 8.1, released in October 2025, kept going: jobs that resume where they stopped, structured events for observability, local CI with bin/ci, and the ability to respond directly in Markdown, since Markdown has apparently become the lingua franca of AI.

So Rails can do it. Why stop there?


Front end and assets: a needless isolation

Why close the door on popular JS frameworks? With rails new, it’s Hotwire or you’re on your own. Laravel offers React, Vue and Svelte starter kits. Symfony has React and Vue integrations. Inertia Rails exists; it’s just not an option at setup.

Why ignore Vite? Laravel ships an official Vite integration and uses it by default. Vite Ruby bridges the gap, but rails new still doesn’t offer it.

Why nothing for fonts, and so little for images? Next.js and Astro self-host fonts, and their image components can generate srcset, modern formats and lazy loading from a single source image. Active Storage can resize and convert, but the srcset is still on you.

AI and DX: behind on the new standards

Why no Active LLM? RubyLLM does the job, but Laravel shipped its own AI SDK (integrated with queues and the ORM), and Symfony has Symfony AI.

Why no AGENTS.md file at setup? Phoenix and Next.js generate one when you create a project, to guide coding agents from the start.

Why no built-in docs for LLMs? Apple ships skills with Xcode to help developers and agents modernize their code, and Next.js bundles its up-to-date docs with the package.

Backend architecture: reinventing the wheel, again and again

Why does every team reinvent form objects? Hanami has its schemas, Phoenix its changesets, Django its Forms. We’re still waiting for a standard way to validate params per use case.

Why no pagination in Active Record? We still pick from Kaminari, Pagy or will_paginate. In Laravel, ->paginate() is part of the ORM, and Django has its Paginator.

Why add a gem for soft deletes? We still install Discard, or the older Paranoia, while Eloquent has its SoftDeletes trait and Hibernate its @SoftDelete.

Why nothing for REST and GraphQL APIs? Nothing that turns one API contract into validation and OpenAPI docs an LLM can use, the way FastAPI does.

Product building blocks: what we rebuild on every project

Why no notification system? Sending a message by email, SMS, Slack or in-app means writing a class per channel. Laravel and Symfony have a multi-channel system out of the box.

Why no native feature flags or search? Laravel has Pennant and Scout. With Rails, we always fall back on a third-party gem (pg_search, Searchkick) or a homegrown integration.

Why skip SEO and GEO? No SEO metadata API, sitemap or llms.txt out of the box. Next.js has its Metadata API and file conventions for sitemaps and robots files, and Django has its sitemaps framework.

All of this is up for debate. The list is surely incomplete, and some points are probably off the mark. But for problems almost every project runs into, why reinvent the wheel every time?


Rails has always sold itself as the one-person framework, and its Rails is built for AI page goes further: its conventions and very concise Ruby let an agent find its way around quickly. In Pencils Down, Notation Up, Sam Ruby compares two versions of Campfire: the original Rails app and a version compiled to C. In Rails, the app is around 60,000 tokens, small enough for an agent to read in one go. In C, framework included, it’s around 4 million. His point: even if we end up compiling our apps to Rust for performance, the Rails code is what the agent should edit. (I wrote roughly the same thing in February, in French.)

The problem is everything Rails doesn’t cover. There, the agent picks a random gem or writes the thing itself, with its own structure. For one feature, that’s fine. For ten generated in a week, you get what DHH described in his keynote about Basecamp 5: pull requests that are fine one by one, and an architecture full of holes at the end.

I’m not asking Rails to ship everything. But some building blocks need the rest of the framework to work well: an Active LLM that runs its calls in Active Job, stores its files in Active Storage and streams its responses with Turbo, or feature flags that know about Current.user. These could ship as generators, like the authentication one in Rails 8, which put the code in your app and let you change it.


Why not open a pull request? Because opening the door to React or adding an LLM building block isn’t something you settle in a PR; it’s a choice of direction. And Rails is omakase, as DHH wrote in 2012: at the restaurant, you let the chef pick the menu. What goes into the framework mostly reflects the needs of the people who maintain it, like the structured events in Rails 8.1, led by Shopify.


Rails isn’t dead or done, so it’s up to us to decide what to make of it. I’d like a framework that keeps taking us from idea to production, with fewer tokens and less sloppy vibe code.

But omakase means the chef decides. And in that same post, DHH described himself as the head chef. Today, 37signals is betting on Rust for HEY, and DHH openly shares far-right, racist and transphobic views.

So when the chef decides everything and you no longer trust the chef, what do you do?