Video summary
Why Shopify Rejected Microservices (And What They Did Instead)
Main summary
Key takeaways
Main ideas, concepts, and lessons
Why Shopify matters
- Shopify is described as a high-scale e-commerce platform, with:
- millions of lines of code,
- billions in sales,
- extremely high request rates.
- Even with this success, Shopify’s original architecture evolved over time due to maintainability and delivery speed problems.
Shopify’s architectural evolution
- Started with a layered monolith (Rails/MVC style).
- Over time, code for major business domains (billing, shipping, checkout, orders, taxes, etc.) became tightly intertwined.
- This is framed as technical debt and the result of no clear domain boundaries.
- Consequences included:
- fragile code
- slow, friction-filled changes
Core architecture lesson: “Monoliths fail in two ways”
Monoliths typically end up as one of two patterns:
- a “majestic monolith” (well-structured), or
- a “big ball of mud” (high coupling, unclear boundaries).
Key lesson:
- The problem isn’t coupling itself—it’s uncontrolled coupling caused by missing/weak boundaries, leading to:
- side effects across domains/components,
- brittle behavior (one change breaks another area),
- reduced ability to ship features quickly.
Pain points Shopify experienced
- Fragile code: changing one domain (e.g., tax) could break shipping logic or related tests.
- No enforced boundaries: internal component/domain calls were not restricted.
- High onboarding cost: new teammates needed to understand many moving parts.
- Very large test suite (>100,000 tests): tests existed, but slow execution and architectural friction prevented improvement.
Decision: Modular monolith over microservices
Shopify surveyed developers and chose to change direction.
Options considered:
- Do nothing (stay with the existing monolith)
- Migrate to a modular monolith (chosen)
- Adopt microservices (considered but rejected due to trade-offs)
Why microservices weren’t chosen:
- multiple deployment pipelines (one per service),
- network overhead/latency for cross-service calls,
- database isolation per service complicating cross-domain querying,
- refactors being riskier and often requiring coordinated multi-service deploys,
- API versioning complexity (version drift vs coordinated versioning),
- observation that Big Tech has sometimes shifted away from microservices as the default and become more open to monoliths.
What a modular monolith is (as explained)
Goal
- Maintain logical boundaries while keeping one deployment unit.
How it works
- Boundaries are enforced inside a single codebase/deployment.
- Each module exposes a public API, while keeping the module’s internals encapsulated.
Conceptual comparison
- Microservices: boundaries are physically enforced via separate deployment units; communication usually involves network calls.
- Big ball of mud monolith: boundaries are not enforced; bounded contexts mix together.
- Modular monolith: “monolith done right”—more modularity, controlled coupling, and no network overhead.
Methodology / steps described for Shopify’s modular monolith migration (detailed)
Stage 1: Componentization (reorganize by business domain)
- Initial state: code organized by technical capability (e.g., controllers/models/data access), resulting in low cohesion and weak boundaries.
- Action:
- reorganize into a structure grouped by business domain rather than technical folders.
- example domain components mentioned: apps, billing, checkouts, taxes, orders, shipping.
- How Shopify performed the refactor:
- listed ~6,000 classes,
- manually labeled each class into a domain (with stakeholder input),
- created an automated script to move files into the appropriate domain/component folders,
- used their full test suite to verify correctness after the move.
Stage 2: Enforce boundaries via module public APIs
- Action:
- each component/module exposes a public API that other modules can call,
- module internals remain hidden via encapsulation:
- e.g., using C#
internalfor implementation details, - placing each module in its own C# project so internals remain isolated.
- e.g., using C#
- Why this matters:
- without a defined public API, any module could depend on another module’s internal details,
- with a public API + encapsulation, boundaries become enforceable at the code level.
Optional / further tightening: enforce boundaries at the database level
- Action:
- create separate database schemas per component/module,
- store each module’s tables in its own schema,
- create a dedicated database user per schema,
- configure access so only the owning module can access its tables.
- Optional exception:
- extra permissions/views may be allowed for cross-module needs,
- but the preferred approach is routing access through the module’s public API and application code, not broad database access.
Additional architectural guidance / principles emphasized
- The primary design target is to improve cohesion and control coupling, increasing change locality (things that change together should live together).
- Vertical slice architecture is referenced as a pattern that helps enforce functional grouping/cohesion.
- Clean architecture is also referenced as compatible with grouping around use cases and dependency direction.
- Warning sign: if a small feature change unintentionally impacts multiple modules, boundaries are likely wrong.
- Practical benefit: unlike microservices, correcting boundaries in a modular monolith is “only refactoring” and preserves one deployment unit.
Speakers / sources featured
- Speaker/creator of the video: unnamed (the transcript uses “we” and “I”, but no name is provided).
- Referenced sources:
- Shopify (including a Shopify tech blog article referenced in the transcript).
- Books/frameworks mentioned:
- Clean Architecture
- Vertical Slice Architecture
Rate this summary
Your feedback will help improve summaries.
Improve this summary
Reprocess with a stronger model when the summary feels incomplete or inaccurate.
Translate summary in another language
Ask questions to this video
Chat for follow-up questions, clarifications, and source-backed answers.