This post is part 2 of 2. In this one:
- Where monorepo shines
- Where it sucks
- My honest take: when you should and shouldn't do it
Introduction
In part one, I covered why we decided to move to a monorepo — and what pains we were trying to solve.
So now, the big question: was it worth it?
Spoiler: mostly yes - but not without surprises.
1. What are the benefits?
1.1 Code awareness went through the roof
Now, when I search for a function or a component, chances are it already exists - inside a feature package. I can just move it to a shared package and reuse instead of reimplementing everything from scratch.
I don't think that kind of visibility happens often in a polyrepo world...
Also, with a unified structure and shared configs, developers are on the same page. Even if you're changing someone else's code — you know exactly how to test it and where to look.
1.2 Refactoring became a walk in the park
Refactoring used to be tedious. So we outsourced it to AI 🤖
Imagine:
- You improve a component contract
- You update all its usages
- You double-check every edge case
Classic headache.
A while back, we shipped a feature behind a feature flag. It worked great - and when it was time to clean it up, we just asked Cursor:
"Hey, remove this flag and delete any leftover code."
It worked brilliantly.
Mostly because the AI had full visibility into the monorepo and could grep all flag usages, one file at a time. I just prompted, clicked continue
a few times when it hit operation limits - and spent ~20 minutes reviewing.
That's it.
1.3 Developer experience is just better
Day-to-day work became much smoother.
Want to run just the ui
package?
pnpm dev --filter=ui
Want to run everything? Go ahead.
You're no longer connecting the dots across 5 repos to debug a single change. You don't need to play "git archaeologist" to find where something came from.
And onboarding?
New devs can install and start coding in minutes:
pnpm install && pnpm dev
2. What are the pain points?
2.1 CI/CD pipelines
Yeah, that's a real one.
You go from having a few focused pipelines… to one giant spaghetti-pipeline that tries to handle everything at once.
For example, we run Playwright tests for application X
via currents.dev - but we absolutely don't want them triggered when someone changes application Y
.
Unfortunately, Turborepo doesn't give you that out of the box. Its caching model assumes that you run all affected commands and skip what's not changed - but coordinating that with external CI jobs like Currents is tricky.
Same goes for other per-app jobs.
To solve it, we had to build a custom GitHub Action that reads Turbo's output and determines which jobs should run - or be skipped - depending on which apps were actually touched.
Is it cool? - Yeah.
Is it plug-and-play? - Not even close.
2.2 Dependency management
pnpm
is blazing fast and works great for monorepos - no doubt. But it comes with gotchas.
Since pnpm
installs each dependency once at the top level and uses symlinks everywhere, transitive dependencies can cause headaches.
Let’s say:
- Your app depends on
A@2.3.0
- It also depends on
B@2.0.0
, andB
depends onA@1.4.0
pnpm
will only install one version of A
, and it might pick the wrong one for your use case.
That can break:
- types
- runtime behavior
- or both
You'll especially feel the pain when:
- One app uses a modern stack (e.g. latest React)
- Another app is stuck with legacy versions
...and they both depend on shared packages.
You either:
- start version pinning everything manually, or
- accept the chaos and debug weird mismatches
So yeah - fast install times come at a price.
3. When don't
and when do
?
We actually tried moving our API services into the same monorepo - aiming to have literally all code in one place.
Sounds neat.
But in practice? A total headache.
Even though our backend is built with Node + Express (so technically compatible with our frontend stack), the divergence in config, dependencies, CI jobs, and workflows made the whole thing a mess.
It wasn’t an outright failure - but it forced us to step back and ask:
Do we really need the API in the same repo?
Or is it enough to keep just the frontend there?
We haven't fully answered that yet. For now, we've paused the migration and kept our backend separate - and honestly, that feels okay. We'll probably revisit it when (or if) the benefits start outweighing the overhead.
When I would recommend monorepo:
✅ When your code shares the same stack (e.g., TS + React + tooling)
✅ For medium to large-scale apps (but not mega-enterprise)
✅ When you're trying to kill off submodules and avoid version juggling
When I wouldn't:
🚫 When teams work independently on fully untangled apps
🚫 For tiny projects — it's overkill
🚫 At massive scale (think 2k+ devs) - trying to keep everyone aligned gets absurd fast
There's no one-size-fits-all
, just like the classic articles said.
But for our stack, our scale, and our team - monorepo turned out to be the right move.
Will that still be true in five years? No idea.
But for now, it's a powerful tool - and we're glad we took the leap.
"(Choo|U)se wisely"!
Feel free to connect with me on LinkedIn
🚀 More content coming soon - stay tuned!