January 1st, 2026
The day we finally understood our monorepo instead of just working inside it blindly.The Day We Settled the Commit Monorepo Today wasn’t about adding features. It was about stopping and asking uncomfortable questions about the structure we’ve already built. The repo looked clean from the outside. Inside, it felt massive, confusing, and slightly scary. This document captures the exact thought process — confusion first, clarity later.
The First Question I Asked Myself
Q: What is a monorepo, really? My first explanation sounded like this:A monorepo is one giant folder where all apps and servers live together.That answer is not fully correct.
Correcting the Definition (Properly)
Q: So what is a monorepo? A monorepo is:- One Git repository
- Containing multiple independent projects
- Managed under a shared workspace
- With explicit sharing, not accidental coupling
A monorepo is not one project split into folders. It is many projects that agree on rules.
The First Dangerous Misunderstanding
Q: Does monorepo mean everything can import everything? At first, I thought yes. That idea sounds powerful. It’s also how monorepos collapse.What “Sharing Everything Freely” Actually Means (and Why It’s Bad)
If sharing was unrestricted, this would be possible:- Backend internals leak into frontend
- Refactors become impossible
- Build order becomes fragile
- No ownership boundaries
The Correct Sharing Model
Q: Then how does sharing work safely? By using explicit packages. Example structure:packages/ are meant to be reused — and only through public APIs.
Workspace Packages in Action
Q: How does one package get used by another? Example:packages/config/package.json
apps/native/package.json:
What workspace:* actually means
“Use the version of this package that exists inside this monorepo, not from npm.”So:
- No publishing
- No version mismatch
- Always local
The TypeScript Confusion
Q: What ispackages/config/tsconfig.base.json even doing?
Here’s the file:
apps/native/tsconfig.json:
Learning TypeScript Rules Through Code (Not Docs)
Let’s use the exact example we discussed.Base Code
What If This Were ES5?
Iftarget was ES5, TypeScript would compile this down:
TypeScript doesn’t run in production. It enforces rules and then disappears.
Strict Mode Screaming at You (Red Lines)
Q: What happens if I write bad code? Example:noUnusedLocals: true and strict: true:
- Red underline
- Editor warning
- CI failure (if enforced)
- Function returns nothing
- Might be unintended
- Easy bug
Another Example: noUncheckedIndexedAccess
Object is possibly undefined.Without this rule:
- Runtime crash
- Production bug
- Forced to handle edge cases
Do Engineers Memorize All These Rules?
Q: Do real engineers remember every TS compiler option? No. Here’s the real workflow:- Senior engineers define the baseline
- Rules are enforced automatically
- Developers learn by writing code
- Red lines appear
- Code gets fixed
- Standards slowly become instinct
So Is This Config “A Lot”?
Q: Is this too much for a project? No. This is:- one-time setup
- years of safety
- zero runtime cost
Understanding Bun’s Role
Q: Why are we using Bun? Because Bun provides:- Fast installs (parallel)
- Built-in runtime
- Native workspace support
catalog:dependency pinning
package.json:
- same React
- same TypeScript
- no version drift
TurboRepo — The Missing Mental Model
Q: Is Turbo just about running things in order? Partially. Turbo’s real job is task graph orchestration. Exampleturbo.json:
“Before building this project, build all its dependencies first.”Turbo:
- understands dependency graphs
- caches intelligently
- avoids unnecessary work
The Kotlin Reality Check
Q: Can I write Kotlin inpackages/ and import it into Android?
No.
Android builds only care about:
So What Are All Those Other Packages For?
Examples:packages/backend→ Convex backend (Node runtime)packages/config→ shared rulespackages/monitoring-extension→ JS tooling / extensionspackages/docs/fumadocs→ documentation systems
Final Mental Model (The One That Actually Works)
One-Line Takeaway
A monorepo doesn’t remove boundaries. It forces you to define them clearly.Honest Reflection
I wasn’t wrong to feel confused. The structure is complex. But now the complexity is named, bounded, and intentional. That’s the difference between chaos and architecture.Metro + Uniwind (Expo) — Q&A Deep Understanding Doc
Q1: What is Metro?
Answer: Metro is a development-time software that:- Reads your React Native / Expo code
- Bundles it into one executable JS file
- Sends that bundle to the running app (Expo Go / dev build)
Q2: What does “bundling” mean exactly?
Answer: Bundling means:Taking many JS/TS files and merging them into ONE ordered JS fileExample: Before:
- Android / iOS want one entry JS program
- They cannot follow imports like Node.js
- Merging
- Ordering
- Not compression
- Not minification (that’s production)
Q3: Why does metro.config.js exist?
Answer:
Metro by default understands only basic JS/TS.
It does NOT understand:
- CSS files
- Tailwind / Uniwind classes
- custom asset behavior
metro.config.js exists to:
Teach Metro how to understand extra things
Q4: Does Expo require metro.config.js?
Answer:
No — only if you use advanced tools.
If you use:
- plain Expo
- no CSS
- no Uniwind
- you use Uniwind
- you use global.css
Q5: What is getDefaultConfig(__dirname)?
“Expo, give me your already-working Metro configuration.”Why this matters:
- Metro config is huge and complex
- Writing from scratch = easy to break everything
- Expo’s default config already handles:
- platforms (android / ios / web)
- assets
- transformers
- caching
- Not replacing Metro
- Extending a safe base
Q6: Does the variable name config matter?
Answer:
No. Metro does NOT care about variable names.
Metro only cares about:
Q7: What is withUniwindConfig(...)?
“Take Expo’s default Metro config, and ADD Uniwind support to it.”It does not replace the config. It wraps it.
Q8: What problem does Uniwind solve?
Without Uniwind, Metro sees this and gets confused:“What is bg-black? What is p-4?”Uniwind solves this by:
- reading Tailwind-like classes
- converting them into React Native style objects
Q9: What does Uniwind ACTUALLY do under the hood?
Conceptually: You write:- These are native styles
- No runtime CSS
- No DOM
- High performance
- JS logic
- converted styles together into the final bundle
Q10: What is cssEntryFile?
“This is the root CSS file where Tailwind utilities are defined.”It includes:
- Tailwind base
- components
- utilities
- custom styles (if any)
- Uniwind doesn’t know what classes exist
Q11: What is dtsFile?
- generates typings for
className - helps autocomplete
- prevents TS errors
Q12: Final mental model (MOST IMPORTANT)
One sentence to remember forever:
Metro bundles your app, and Uniwind teaches Metro how to understand Tailwind-style classes and CSS so they become native styles.