bgmlv
EN ES

Four frameworks through an agent's eyes

Somewhere this year the question “which framework should I use” quietly changed meaning for me. Most of the code in my projects is now written by agents. I describe, review and steer; they type. And a framework that is a joy for a person to type in is not necessarily one an agent can work in. An agent does not remember the docs from ten years of practice. It reads them, right now, page by page, and then it either gets the feature right or it does not.

So I ran a small experiment. One product, a platform for book clubs: accounts, clubs, meetings, discussions, email, a bit of live updating. One spec. Four frameworks: Ruby on Rails, Next.js, Go with Gin, and Django. Agents did the building. I sat next to them and wrote down where they got stuck.

Where the docs live

The first surprise came before a line of code. For a person, documentation is a website. For an agent, a website is a series of network requests, each one a page that may or may not describe the version actually installed.

Next.js turned out to be the only one that ships its documentation with the package: several hundred Markdown pages inside node_modules, the exact version, plus an AGENTS.md, an llms.txt and an MCP server inside the dev server. The agent opened the folder and read. No guessing which release the page was written for.

Django has the biggest reference of the four by a wide margin, but it hides in the source tarball on PyPI. A normal install does not bring it, so the agent has to know to go and fetch it. Rails has fifty-odd guides, all on the website, nothing in the gem. Gin has a small site, partly stale, and an llms.txt link that returns 404. What go doc gives you locally is the API, not how the pieces fit together.

What is in the box

Then the building started, and a second pattern appeared: how much of the product the framework already contains.

Watching the Rails agent was almost boring. Database, migrations, forms, sessions, background jobs, email in both directions, WebSockets, encrypted fields: every server-side thing the product needed was already there, and the agent guessed the right place for each piece before reading anything. It pulled two third-party libraries for the whole backend.

The Django agent had a similar time on the server side, until it reached the interface. There is no Turbo in Django, so partial page updates and anything interactive had to be written by hand.

The Next.js agent lived the mirror image. The frontend tooling is the best of the four, from images and fonts to optimistic updates and modals addressed by URL. The backend, though, was assembled from a dozen libraries, each with its own docs, each a separate thing to get slightly wrong.

The Go agent wrote the most code of anyone. Gin is an HTTP router; CSRF, sessions, flash messages and layout templates all had to be written from scratch. The standard library covers a lot on its own, crypto, mail, templates, but in pieces, without the glue.

How fast you learn you were wrong

The third thing I watched was the loop: change something, run the checks, see the result. For an agent this loop is everything, because the agent does not get a feeling that something is off. It only gets a test result.

Rails and Django run their whole test suite in about three seconds, straight against the server code, no browser. Go takes seven, or seventy if you ask it to check for data races. Next.js takes twenty-five, because server actions and server components cannot be executed outside a browser, so what remains is end-to-end tests. Ten times slower, and far fewer of them. For an agent that is the difference between checking every change and checking every tenth.

The traps

Every framework had a couple of places where the documentation and reality disagree, and an agent trusts documentation more than a person would.

A Rails guide example calls a method that does not exist. Rails generators silently overwrite files when there is no terminal attached, which is exactly how an agent runs them. In Next.js, a streamed response comes back as 200 where it should have been 401 or a redirect, and the CSP example from the guide breaks the production build. Gin’s streaming falls over in the tests its own docs recommend, and a template error is served as a blank page with status 200. In Django, the limits of the new DB_CASCADE only show up in system checks, and serialized_rollback quietly breaks neighbouring tests.

The Go agent spent every fifth minute on this kind of thing: undocumented behaviour of Gin and the libraries around it. The Django agent, half that, and only on the newest features, because the reference describes behaviour precisely enough that you rarely have to find out by running it.

The scoreboard

I scored each framework on ten things an agent cares about: where the docs are and whether the examples work, how complete and predictable the framework is, what is built in, tooling, error messages, testability, upgrades and hidden traps. Out of ten, Django came out at 8.0, Rails at 7.8, Next.js at 6.1 and Go with Gin at 6.05.

The gap between Django and Rails is noise. The gap between those two and the other two is not. Django wins on accuracy and tooling; the examples work as written, and check --deploy catches configuration mistakes before production does. Rails wins on built-ins and predictability. Next.js has the best documentation delivery and the weakest everything else once you leave the browser.

The picture I keep coming back to is this one.

Scatter plot of backend score against frontend score: Rails at 9 and 6, Django at 8 and 4, Go + Gin at 6 and 3, Next.js at 4 and 8

Backend against frontend. Rails is the only one in the top-right corner. Django is almost Rails on the server with nothing like Turbo. Next.js is the best frontend with a backend built from other people’s libraries. Gin is a strict, fast router with nothing for the interface.

What I would pick

If an agent is doing the work, the choice is not about taste anymore.

  • A rich backend with a simple UI: Django. Precise documentation, three-second checks.
  • A full-stack product with an interactive interface: Rails. Everything built in on both sides, and the agent always knows where things go.
  • A complex interface over an existing API: Next.js. Nothing else comes close on the frontend.
  • A heavily loaded API service: Go with Gin. Strict types and a single binary, but be ready to write the application layer yourself.

My own default stays Rails, and this experiment made me more comfortable with that than less. But Django earned a lot of respect, and the next time a product is mostly server and barely interface, I will probably let an agent build it there.

The full report with all the charts is at pages.bgmlv.com/rails-vs-nextjs, in Russian. Versions, for the record: Rails 8.1, Next.js 16, Gin 1.12 on Go 1.27, Django 6.1, PostgreSQL underneath all four.