Next.js vs Ruby on Rails


Why I Migrated from Next.js to Ruby on Rails

Next.js has dominated the React ecosystem for years. With over 5 million weekly downloads on npm and backing from Vercel, it became the de facto standard for React applications. The value proposition seemed compelling: deploy serverless applications globally on the edge, starting with a free tier and scaling to $20/month for the Pro plan.
Next.js has evolved beyond frontend-only applications. With API routes and server components, combined with an ORM like Prisma, you can build full-stack applications. This makes comparisons to monolithic frameworks like Ruby on Rails less absurd than they might initially appear.
Yet after years of building with Next.js, I've migrated my projects to Ruby on Rails—a framework that turned 20 in 2024. Here's why I made that decision.

Security by Default

Rails was built with security as a core principle, not an afterthought. Out of the box, Rails provides:
  • CSRF protection: Automatic token generation and validation for all forms
  • SQL injection prevention: Active Record parameterizes queries by default
  • XSS protection: Output escaping is automatic in views
  • Secure headers: Content Security Policy, X-Frame-Options, and other headers configured by default
  • Encrypted credentials: Built-in secrets management with encrypted files
In Next.js, developers must implement many of these protections manually or rely on third-party packages. The Node.js ecosystem itself presents challenges—with hundreds of transitive dependencies in a typical project, the attack surface expands significantly. The npm supply chain has experienced notable security incidents, including the event-stream compromise in 2018 and the ua-parser-js malware injection in 2021.

Convention Over Configuration

Ruby on Rails was designed and is still actively maintained by David Heinemeier Hansson (DHH) and a core team with strong opinions about software architecture. While you may disagree with some of those opinions, the "convention over configuration" philosophy delivers tangible benefits.
In Rails, there's typically one established way to accomplish a task. File structures are predictable. Naming conventions are enforced. This consistency means any Rails developer can navigate any Rails codebase with minimal orientation.
Next.js offers flexibility—App Router or Pages Router, various data fetching patterns, multiple state management approaches, different styling solutions. This flexibility comes at a cost: codebases diverge significantly, and the "right" approach often changes between major versions.

AI-Assisted Development

Rails' conventions create an unexpected advantage with AI coding tools. When using tools like Cursor or Claude, the predictable structure of Rails applications produces more consistent, maintainable code. The AI can reliably follow established patterns because those patterns are well-documented and uniform across the Rails ecosystem.
With Next.js, AI tools remain capable, but the variety of valid architectural approaches can result in inconsistent suggestions. The generated code may work, but it often lacks the coherence that comes from following a single, opinionated framework's conventions.

Batteries Included

Rails provides components that would require significant integration work in Next.js:
  • Active Record: An ORM that makes encryption at rest straightforward with built-in encrypted attributes
  • Action Text: Rich text editing with the Trix editor, working out of the box. The team at 37signals has also announced Lexxy as a next-generation option
  • Action Mailer: Email handling integrated into the framework
  • Active Job: Background job processing with a unified API
  • Active Storage: File uploads with cloud storage integration
Having worked with Django's admin interface, which is excellent but lacks built-in rich text support, the contrast with Rails' integrated approach is notable. These aren't revolutionary features individually, but having them work together without configuration saves substantial development time.

Modern Frontend Without the Complexity

Hotwire—comprising Turbo and Stimulus—delivers single-page application responsiveness without JavaScript framework complexity. Pages feel instant. Forms submit without full page reloads. Dynamic updates happen over WebSockets when needed.
For native mobile development, Turbo Native allows the same server-rendered HTML to power iOS and Android applications, with native navigation and the ability to drop into fully native screens where appropriate.
This approach won't suit every application. Complex interactive UIs may still benefit from React or Vue. But for the substantial category of applications that are fundamentally CRUD operations with some real-time features, Hotwire delivers results with far less code.

Ruby: A Language Designed for Developer Happiness

Ruby's syntax prioritizes readability and expressiveness. Code reads closer to English than to most programming languages. Compare iterating over a collection in Ruby versus the ceremony required in TypeScript with explicit type annotations, arrow functions, and semicolons.
DHH has written extensively about his concerns with TypeScript's approach, arguing that the type system's benefits don't justify its costs for many web applications—particularly those that interact primarily with dynamically-typed data from databases and APIs. Rails 7 notably removed TypeScript from its default setup for the Importmap-based JavaScript approach.

Production-Proven at Scale

Ruby on Rails powers applications handling significant traffic:
  • Shopify: One of the largest Rails applications, processing substantial e-commerce volume
  • GitHub: Built on Rails since its founding
  • 37signals: The creators of Rails run Basecamp, HEY, and other products on the framework
  • Airbnb: Built their platform initially on Rails
The framework has two decades of production hardening. Edge cases have been discovered and addressed. Documentation is extensive. The community has answered most questions you'll encounter.

Predictable Builds and Deployments

Rails applications compile and deploy predictably. The asset pipeline is mature. Dependencies are managed through Bundler, which has proven stable over many years.
Next.js builds can be less predictable, particularly as applications grow. Dependency conflicts, build-time memory issues, and configuration complexity tend to increase with application size. The rapidly evolving nature of the ecosystem means build processes that worked six months ago may require updates.

When Next.js Still Makes Sense

This isn't a categorical dismissal of Next.js. It remains a strong choice for:
  • Applications requiring tight integration with the React ecosystem
  • Teams with deep JavaScript/TypeScript expertise
  • Projects requiring extensive client-side interactivity
  • Static site generation at scale
  • Edge computing requirements that benefit from Vercel's infrastructure

Conclusion

After years of building with Next.js, returning to Rails has simplified my development workflow. The framework handles security, provides sensible defaults, and produces maintainable code. Ruby's syntax makes the work more pleasant. Hotwire delivers modern user experiences without JavaScript framework overhead.
For applications centered on CRUD operations—which describes most web applications—Rails offers a mature, secure, and productive environment. Twenty years of development haven't made it obsolete; they've made it refined.
The migration has made maintaining my applications a more straightforward experience, with fewer dependencies to manage and more predictable behavior. Sometimes the established solution is established for good reasons.
10 claps
← Back to Blog