How I Migrated to a Monorepo in 3 Days
(Without writing much code. Or crying.)
Let’s be honest. Migrating a live production app to a monorepo is usually the software engineering equivalent of root canal surgery.
You start with high hopes of "shared packages" and "better DX".
Three weeks later it’s 2 AM, Metro hates symlinks, Jest can’t find your tokens, and node_modules has eaten itself.
It’s the classic rewrite-from-scratch trap, just with more config files.
Yet, last week, I migrated my entire React Native app (Expo, NativeWind, 20+ screens) into a Turborepo setup.
It took 3 days. It works. I barely wrote a line of code.
Here is how I cheated. Spoiler: I didn’t make the AI smarter. I made the constraints boringly clear.
The "Vibes" Approach (Don't Do This)
If I had done this the "modern AI way", I would have opened Cursor and typed:
"Hey Claude, migrate my app to a monorepo structure please."
And Claude would have tried. Oh, it would have tried so hard.
It would have moved files around randomly. It would have hallucinated 5 different tsconfig.json files. It would have broken every single import path.
And I would have spent the next month fixing it.
Because AI doesn't know architecture. It knows patterns. If you ask it to "build a house", it will give you a pile of bricks that looks vaguely house-shaped but collapses if you lean on it.
The Boring Way: Architecture First
Instead, I treated the AI like a junior developer on their first day: Zero trust, infinite patience, and a very, very clear spec.
Before I let the AI touch a single file, I wrote this.
packages/design-system/srcpackages/design-system/tokensconfig.resolver.disableHierarchicalLookup = trueI wrote a 1300-line migration plan.
It detailed the folder structure. The exact package.json exports. The specific Metro config flags we needed to avoid the symlink hell.
I defined the contract. This is GS-TDD in disguise: architecture and tests first, implementation second.
The Execution: AI as the Grunt
Then, the work began. But instead of "make it work", the prompts were:
"Execute Step 3.1 from MONOREPO-MIGRATION-PLAN.md. Move the files. Do not change the code."
And then:
"Execute Step 3.2. Update imports to use the new package alias. Run
yarn testto verify."
The AI was fantastic at this. It moved files, renamed imports, updated 50 test files in seconds. It did the grunt work that usually makes developers lose their minds.
But here is the kicker: I had a safety net.
2300+ Tests Don't Lie
My design system has over 2300 behavioral tests. My UI renderer has 200+ specifications. Every time the AI touched something, I ran the tests.
- AI: "I have updated the imports."
- Me:
yarn test-> 💥 FAIL (Can't resolve module) - Me: "You broke the imports. Revert and try again, respecting the
tsconfig.paths."
Without those tests, I would have been flying blind. With them, I had a feedback loop of seconds.
Where AI Tried to Kill Me (and Tests Saved Me)
It wasn't all smooth sailing. The AI tried to "help" in ways that would have been disastrous:
- The "Helpful" Refactor: While moving components, it decided to "clean up" some complex TypeScript types. Tests failed. I reverted immediately.
- The Configuration Hallucination: It tried to invent a
turbo.jsonconfig that looked plausible but did absolutely nothing. Because the plan already included the real config, the fake one didn’t stand a chance. - The NativeWind Nightmare: Monorepos and Tailwind/NativeWind are notoriously tricky. The AI confidently suggested a config that would have broken production builds. Because I had a
buildstep in my plan, we caught it before merge.
The Lesson
If I hadn't had the plan and the tests, I would have accepted the AI's "fixes". And three weeks later, I would be debugging why the app crashes on Android but only in release mode.
The Result
Three days. One massive PR. Green tests across the board.
I now have:
@company/design-system(fully isolated, versioned)@company/ui-renderer(clean separation of concerns)apps/enterprise-app(thin consumer app)apps/showcase(documentation app)
And I sleep well at night because I know it works.
What actually made 3 days possible
- A detailed migration plan (architecture first, no vibes)
- 2300+ design-system tests and 200+ UI renderer specs
- Build and CI steps baked into the plan (not an afterthought)
- AI doing the boring file moving, not the creative decision making
GS-TDD (Gold Standard TDD) isn't just about writing tests. It's about flipping the dynamic with AI:
- Human: Architect, Reviewer, Test-Writer.
- AI: Builder, Mover, Syntax-Generator.
If you let the AI be the architect, you get a shantytown. If you make it the bricklayer, you get a fortress.
Want to see the actual plan? Or the test setup?
I’m turning the migration plan + test adapters into open source examples – they’ll land here on the blog first.
This entire blog is built using the same principles. Boring is beautiful.