Let’s get this out of the way early. Moving from a Rails monolith to microservices is like trading in a bike for a unicycle and a skateboard. Yes, you can still get where you’re going, but you’ve made the journey harder in the name of imagined flexibility. Of course, these aren’t the only two architectural options out there. But for many teams, the conversation often centres on this particular shift. And when it does, it’s worth asking: is this a step forward or sideways?
Yet here you are. The team is grumbling about boundaries. Deployments feel heavy. Someone read a post, went to that conference talk, or copy-pasted the Spotify org chart into Notion. And now, as CTO, you’re asking, “Should we break up the monolith?”
As a consultancy that’s seen both sides, here’s our take: it’s usually best to start with a monolith. For many teams, the added complexity of microservices doesn’t pay off. There are cases where it does. For example, when a system needs different architectural characteristics or needs to scale. Martin Fowler suggests that a monolith gives you the fastest path to understanding. You should consider breaking things apart only once you’ve hit real friction. Fundamentals of Software Architecture by Mark Richards and Neal Ford echoes this idea. The authors emphasise evaluating tradeoffs based on system needs, not hype.
Rails Is a Monolith Friendly Framework
Rails shines brightest when you embrace its opinionated nature. Convention over configuration, batteries included, everything close to hand. It optimises for velocity, cohesion, and simplicity. These qualities are compelling for small teams moving fast. Of course, those strengths come with tradeoffs. As a monolith grows, complexity and coupling can increase. You may sacrifice scalability, elasticity, and fault tolerance compared to a distributed architecture. Rails’ advantages outweigh its constraints for teams in the early to mid stages.
The Rails monolith is not a flaw. It’s a feature. It allows a small team to ship and scale. Most performance issues don’t come from monolithic architecture. They come from premature optimisation, unindexed columns, and complicated abstractions.
So, if you’re looking to split the app for speed, ask yourself: “Is the app’s size the problem, or are we misusing our tools?”
Microservices Multiply Everything
In a monolith, a change is a git diff
. In microservices, a change can become a
coordinated dance between distributed systems. For example, when the services
are too granular, they cannot do meaningful work. Testing gets harder.
Deployments become orchestrated events. Local dev environments turn into
part-time jobs. When microservices aren’t independent, you’re not gaining
autonomy. Instead, you’re adding network latency and operational overhead.
You’re not adding services. You’re adding surfaces for failure. You’ve gone from method calls to network calls. You will track bugs across services, syncing schemas, and untangling observability spaghetti.
That is the real cost of microservices, and if you don’t have a specific, urgent reason to bear it, don’t.
Okay, But You’re Doing It Anyway
We get it. Sometimes, organisational reality trumps architectural purity. But it’s not only politics or team structure. There are also genuine architectural needs that can make microservices the right choice. Parts of your system need to scale. Fault isolation is critical. Different components have very different lifecycle needs or languages. These aren’t edge cases. They’re valid reasons to reach for a distributed architecture. The key is to make sure the benefits outweigh the costs.
You’ve hit team size limits, where working in the same codebase is a liability. Regulatory needs demand strict service boundaries. Parts of your system do scale, which is fair enough.
If you’re going to break things apart, do it with care:
Start with clear boundaries
Don’t split by model. Split by domain. Think in vertical slices: product search, billing, and notifications, not horizontal layers. Use the language of DDD if you must. Avoid building “microservices” that are “tiny Rails apps talking to the same Postgres.”
Treat your monolith as the first service
Don’t kill the monolith. Refactor it into a platform. Let it expose clear interfaces. Avoid creating the dreaded distributed monolith. You don’t want services coupled with implicit contracts and lousy documentation.
You’ll need infrastructure maturity
Docker, CI/CD, service discovery, logging, tracing, API management. These aren’t nice-to-haves anymore. If you don’t already have a DevOps culture (or team), you’re about to grow one, whether you like it or not.
So What’s the Alternative?
Before you jump to microservices, consider the following:
Modular monoliths: Break your app into engines or namespaces. Enforce boundaries in code, not on the network. It sets the stage for approaches like the citadel model. As complexity grows, a “majestic monolith” develops to have more defined internal walls.
Service objects and interactor patterns: You can isolate responsibilities without reaching for a queuing solution.
Extract read-heavy endpoints first: A read-only API service (for reporting or public data) is a safe, low-risk place to practice.
Final Thought
Monoliths aren’t only for MVPs. They’re for products that value maintainability, quick iteration, and developer happiness. That’s where Rails came from. Of course, a sprawling monolith can slow you down as much as it once helped you move fast. For example, if it slips into “ball of mud” territory. But the solution isn’t always to reach for microservices. Rails gives you the tools to keep things clean and cohesive. Please don’t throw away your most significant advantage by chasing architecture.
But if you’re going down this road. Do it with eyes wide open and build escape hatches. You might want to come back.