Ruby on Rails vs Spring Boot — How I Choose for a New Project

by Arif Ikhsanudin, Backend Developer

The decision nobody wants to make twice

Your CTO has handed you a greenfield service and a six-week runway to first deployment. The team has two senior engineers — one who has spent the last four years in Java microservices land, one who came up through Rails startups. You are about to have the framework argument. Skip it. Here is how I actually make this call.

What Rails gets right that Spring Boot does not

Rails wins on time-to-first-feature. Convention over configuration means a new resource — model, controller, serializer, migration — is four files and one generator command. There is no XML, no annotation soup, no context configuration class. Active Record makes join-heavy queries readable without a query builder library. For a domain that is mostly CRUD with some business logic layered on top, Rails will put you in production faster than Spring Boot by a factor of two or three in my experience.

The other thing Rails gets right is the default stack coherence. Action Mailer, Active Job, Action Cable, Turbo — these are not third-party integrations. They are first-class citizens with shared conventions. When your service needs background jobs, you reach for Sidekiq backed by Redis. The integration is documented, battle-tested, and works identically across every Rails app I have built.

# A typical Rails service object — no ceremony
class ProcessPayment
  def initialize(order:, payment_method:)
    @order = order
    @payment_method = payment_method
  end

  def call
    ActiveRecord::Base.transaction do
      charge = @payment_method.charge(@order.total)
      @order.update!(status: :paid, charge_id: charge.id)
      OrderMailer.confirmation(@order).deliver_later
    end
  end
end

That is the whole thing. No dependency injection container. No interface declaration. No bean lifecycle.

What Spring Boot gets right that Rails does not

Concurrency is where Spring Boot earns its place. Rails is single-threaded per Puma worker by default. You can tune it, but the GIL (Global Interpreter Lock) in MRI Ruby means true parallelism requires multiple OS processes, not threads. A Spring Boot service running on the virtual thread model introduced in Java 21 (Project Loom) can handle tens of thousands of concurrent connections with a modest heap. If your service sits on a high-throughput messaging pipeline — say, 5,000 requests per second sustained — Rails will require significantly more horizontal scaling to match the same throughput.

Spring Boot also wins when the domain model is genuinely complex. Hibernate's type system, Spring Data's repository abstractions, and the Java type checker catch a category of bugs at compile time that Rails will only surface in production or in tests if you wrote them. When you have a payment processing service with 15 entity types, 40 business rules, and regulatory compliance requirements, that type safety is not pedantry — it is incident prevention.

@Service
@Transactional
public class PaymentService {

    public PaymentResult process(Order order, PaymentMethod method) {
        // The compiler tells you if order or method is nullable
        // before this ships — Rails won't
        var charge = method.charge(order.getTotal());
        order.setStatus(OrderStatus.PAID);
        order.setChargeId(charge.getId());
        orderRepository.save(order);
        eventPublisher.publish(new OrderPaidEvent(order.getId()));
        return PaymentResult.success(charge);
    }
}

The actual decision criteria

Choose Rails when:

  • Your team has strong Ruby experience or is small and needs to move fast
  • The domain is CRUD-heavy with moderate business logic
  • You need to validate product-market fit and expect the schema to evolve rapidly
  • You are building an internal tool, admin dashboard, or API that serves a single frontend

Choose Spring Boot when:

  • You need sustained high throughput (>1,000 RPS per instance) or low-latency SLAs (< 50ms P99)
  • The domain is complex, with strict type contracts between services
  • Your team is Java/Kotlin-native and you cannot afford a ramp-up cost
  • You are operating in a regulated industry where auditability and compile-time correctness matter

The cases where I have been wrong: I once pushed Rails on a team of three Java engineers because I estimated the delivery speed gain would outweigh the learning curve. It did not. The team wrote defensive, un-idiomatic Ruby that performed worse than equivalent Java would have, because they were fighting the language instead of using it. Team composition overrides everything else on this list.

What to do this week

If you are stuck in this decision right now: build the same endpoint in both frameworks with your actual team. Time it — not the runtime performance, the development time. Whichever takes fewer hours to produce a tested, deployed endpoint wins, because that ratio holds for the rest of the project. The performance gap between Rails and Spring Boot is real but rarely the bottleneck. The productivity gap between a team using its native stack versus a foreign one almost always is.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

How to Undo Almost Anything in Git Without Panicking

Git is one of the most forgiving version control systems ever built — but only if you know where to look. Most "I ruined everything" moments are recoverable in under five minutes.

Read more

Bind Mounts vs Volumes in Docker: Which One Should You Use

Bind mounts and named volumes both attach external storage to containers, but they solve different problems. Choosing the wrong one leads to permission issues, performance problems, and data in the wrong place.

Read more

GROUP BY Is More Powerful Than Most Developers Use It For

Most developers use GROUP BY only for basic aggregations — but combined with HAVING, ROLLUP, CUBE, GROUPING SETS, and conditional aggregation, it can replace entire reporting pipelines that currently require multiple queries and post-processing.

Read more

CI/CD Is Not a Tool. It Is a Practice.

Most teams install a CI/CD tool and call it done. But running a pipeline is not the same as practicing continuous delivery — and confusing the two is why deployments are still painful.

Read more