Loading…
Topic
Monoliths
11 posts about Monoliths. Every summary links to the original.
- 11 posts
- 5 companies
The Good Stuff
Paid picks we use ourselves. Links carry a referral code — a subscription through one earns us a commission at no extra cost to you.
Newest first
Posts
Migrating a Large Flow Monorepo to TypeScript
Yelp migrated a 1.4-million-line JavaScript monorepo from Flow to TypeScript after community support and package ecosystem tooling shifted toward TypeScript. To maintain continuous type safety without code freezes, engineers converted the codebase package by package starting at the deepest internal dependencies. The toolchain used flowts for code conversion and flowgen to turn generated TypeScript declaration files back into Flow-compatible headers for downstream consumers. Webcore dogfooded the tooling across 90 packages, automated tracking through internal metrics, and assisted feature teams with bottleneck conversions. Completed in February 2026, the migration increased overall type coverage from 83.15% to 96.44% and unlocked TypeScript-only tooling.
Reducing our monorepo size to improve developer velocity
Dropbox reduced its core server monorepo size from 87GB to 20GB after approaching GitHub's 100GB limit and suffering from hour-long clone times. The excessive bloat was traced to Git's delta compression heuristics interacting poorly with internationalization directory paths, generating inefficient diffs across different languages. By collaborating with GitHub to run an aggressive server-side repack with tuned window and depth settings, Dropbox cut clone times to under 15 minutes.
How We Decomposed Tinder’s Monolith
Tinder faced significant agility and build performance challenges caused by an iOS codebase monolith containing over 1,000 files and 150,000 lines of code. Manual extraction efforts risked creating massive, unmanageable pull requests that would require constant rebasing against the main branch. To systematically decompose the target into Swift sub-modules, the team mapped declarations and references via the Swift compiler into a directed graph. They iteratively extracted leaf nodes with an in-degree of zero across sequential phases and automated common code adjustments, including module dependencies, imports, access control levels, and dependency injection. The automated decomposition completed in under six months with zero P0 incidents, reducing monolith build times by 78% and disallowing future additions to the monolith target.
A Packwerk Retrospective
Shopify’s retrospective examines Packwerk, a Ruby gem released in September 2020 to enforce package boundaries and help modularize Rails applications. It describes the tool as static analysis that checks constant references against a declared, non-circular dependency graph, with todo files allowing existing violations to be recorded while new ones are blocked. The authors recount how privacy checks shifted attention toward API design, introduced awkward file organization, and were removed in version 3.0. They also explain that Packwerk cannot determine whether package boundaries or violation fixes reflect runtime coupling, so semantic grouping can mislead developers and add harmful indirection. Shopify ultimately treats running code as the strongest progress signal and retains Packwerk mainly to prevent new dependencies at the application’s base layer.
Spin Cycle: Shopify’s SFN Team Overcomes a Cloud-Development Spiral
Shopify’s Fulfillment Network (SFN) worked to run its monolithic Rails application in Spin, a cloud-based development tool that provides on-demand Kubernetes containers instead of local service environments. Because SFN glues together Shopify and many external services, the team had to decide whether to run, mock, or share each dependency, while frequent changes to SFN, Spin, and those dependencies created regressions. The three-engineer team identified a human feedback dynamic: painful Spin experiences discouraged adoption, which allowed more Spin-specific breakage, while regular use could expose regressions before merge. To break that spiral, the team prioritized basic functionality for common validation flows, fixed disruptions there, and asked developers to use Spin daily and add missing capabilities; the intended outcome was a self-reinforcing “Loop of Happy Equilibrium,” though the transition is described as a hypothesis.
App Modularisation at Scale
Grab transitioned its monolithic mobile application into a modular architecture to resolve increasing code conflicts, slow releases, and difficult team collaboration. The team decomposed the single module by establishing base infrastructure modules, shared UI and utility libraries, discrete feature modules, and bridge kit modules for inter-module communication. Dependency injection using Dagger ties these components together in the main app module while preventing feature modules from directly depending on one another. The architecture spans over 1,000 modules across the app, with more than 200 modules in the Grab Financial Group payments domain where over 95% of modules build in under 15 seconds. This approach accelerated Gradle CI and local builds through parallel compilation and caching, though it increased Gradle sync times, IDE memory usage, and configuration maintenance overhead.
Our Journey to Continuous Delivery at Grab (Part 1)
Around the end of 2018, Grab's backend architecture consisted of roughly 270 services managed through fragmented, manual deployment workflows. Engineers copied release parameters between build logs, wiki pages, Slack bots, and multiple Jenkins jobs, leading to high operational friction and an average of 10 business days between production updates for a service. To streamline delivery, Grab built Conveyor, an internal automation platform built on top of open-source Spinnaker. Conveyor introduced a custom user interface focused on pipeline visibility and a pipeline-as-code DSL called Artificer using Jsonnet files in the monorepository. The platform automatically registers build artifacts with commit metadata to eliminate manual parameter entry and automatically provisions integration, staging, and production pipelines.
Go Modules- A Guide for monorepos (Part 1)
Grab transitioned its large Go monorepo dependency management from Glide to Go modules while retaining an existing vendor directory structure. The team generated root go.mod configurations from glide.yaml and used go mod vendor without directly enabling module-mode builds. Incompatible nested sub-vendor paths were excluded by placing empty go.mod files, relying on the rule that modules cannot contain other modules. Post-migration maintenance revealed challenges with dependency inheritance and implicit go.mod updates during builds, which engineers investigated using go mod graph and digraph to trace dependency paths.
How Shopify Manages API Versioning and Breaking Changes
Shopify describes how it versions APIs and manages breaking changes for an ecosystem of tens of thousands of partners. It releases date-based API versions every three months, with changes introduced in an unstable version and represented in the monolith through frozen records and a change file. Teams classify changes by whether third-party developers must migrate, use impact analysis and forward-compatibility testing, and protect uncertain changes with beta flags. For necessary breaking changes, tooling marks breaking or possibly breaking request paths, sends metadata through Monorail to a data warehouse, and produces reports on affected calls. Runtime conditionals then help teams manage old and new behavior, measure adoption, identify remaining risk, and communicate with developers.
Successfully Merging the Work of 1000+ Developers
Shopify’s single monolith supports changes 40 times a day and roughly 400 commits to master daily, making safe trunk-based development difficult at the scale of 1,000+ developers. Its first Merge Queue limited deployment drift and batch size, but queued pull requests did not receive CI, soft conflicts could break master, and a browser extension enabled accidental direct merges. Merge Queue v2 replaces that workflow with GitHub comments and webhooks, programmatic branch protection, an emergency /shipit --emergency path, and a predictive branch where queued changes receive CI before merging. A reconciliation algorithm synchronizes that branch through GitHub’s GraphQL API, while failure-tolerance thresholds handle flaky tests and remove repeatedly failing pull requests. CI starts when requests enter the queue; batches of eight and three concurrently tested batches balance throughput, risk, and resource use, while the changes improved user experience, deployment safety, and deploy throughput.
Deconstructing the Monolith - Shopify
Shopify describes why its decade-old Ruby on Rails monolith became difficult to change as the codebase and development organization grew. High coupling and absent boundaries made innocuous changes trigger unrelated test failures, slowed CI, and forced developers to absorb excessive domain context, while microservices would add deployment, infrastructure, network, and coordination costs. The chosen path was a modular monolith: retain one codebase and deployment unit while separating domains through strictly enforced component boundaries. Shopify’s Componentization effort was informed by a developer survey and uses Wedge to score components and report violations, including cross-component associations and calls that bypass explicitly public interfaces. Boundary enforcement at runtime remains a future goal, but dependency isolation has already enabled replacing a legacy tax engine with a new tax calculation system.
Related topics
All topics →Weekly digest
The best engineering reads, once a week.