case-study

Shopify: A Monolith That Scaled

also called Packwerk, Shopify Pods

Shopify kept its Rails monolith and invested in enforced internal boundaries and horizontal sharding, rather than decomposing into microservices.

shopifymodular-monolithboundariesscale

The problem

Shopify runs one of the largest Ruby on Rails applications in existence, serving a very large merchant base through extreme traffic peaks — flash sales and Black Friday produce load spikes that arrive in seconds.

The conventional prescription at that scale is microservices. Shopify publicly took a different route, and their reasoning is a useful counterweight to the default.

What they did

Enforced modularity inside the monolith. They built and open-sourced Packwerk, a tool that enforces boundaries between packages in a Ruby codebase — checking that a module only depends on what it is permitted to and only uses another module's public interface. That converts "we have a modular architecture" from an intention maintained by review into a check that fails the build.

Horizontal sharding by merchant. The platform is partitioned into independent units, each holding a subset of shops with its own datastore. A failure or a hot merchant affects one unit rather than the platform, and capacity scales by adding units.

Why this works

It separates two things that microservices bundle together: logical modularity, which is nearly always valuable, and physical distribution, which is expensive.

They get domain separation, clear ownership and enforced boundaries, while keeping one deployable, one test suite, local development, transactions where needed, and boundary changes as ordinary refactors rather than migrations. The isolation and scaling that motivates decomposition is provided by the sharding instead.

The trade-off

One deployable means one release cadence and one technology stack. Very large teams working in one codebase requires strong tooling — build times, test selection and merge queues become significant engineering investments in themselves.

The transferable lesson

Scale does not compel microservices. The question is which specific constraint you are trying to relieve. If it is blast radius and capacity, sharding addresses it directly. If it is team autonomy and independent deployment, decomposition addresses it. Those are different problems with different answers, and conflating them is how organisations buy distributed systems complexity for a problem sharding would have solved.

And the transferable mechanism regardless of style: automated boundary enforcement. A boundary maintained by convention erodes; one that fails the build does not.