
Why We Switched to a Monorepo
We just completed a major infrastructure upgrade: migrating from separate repositories to a unified monorepo structure.
Why the Change?
Brandmine consists of two major applications:
- Hugo static site (brandmine.ai) - Our public-facing content platform
- Hub internal app (hub.brandmine.ai) - CRM, deal pipeline, story management
Previously, these lived in separate repos. Every shared update meant duplicate work—copying TypeScript types, config files, syncing data structures.
The problem: Making a simple schema change required editing 6+ files across 2 repos, tracking 2 separate deployments, and hoping nothing fell out of sync.
What We Built
Our monorepo uses modern tooling designed for exactly this scenario:
1. Unified Workspace (pnpm)
Single pnpm install installs all dependencies for both apps. No more jumping between repos to run setup scripts.
2. Shared Packages
We created 4 internal packages that both apps consume:
@brandmine/shared-types- Single source of truth for TypeScript interfaces@brandmine/typescript-config- Consistent tsconfig across all projects@brandmine/prettier-config- Unified code formatting@brandmine/eslint-config- Shared linting rules
Result: Change a type definition once, both apps get it instantly.
3. Intelligent Build System (Turborepo)
Turborepo adds caching and dependency-aware task execution:
- First build: 11.4 seconds
- Cached build: 204ms (98% faster, 55x speedup)
- Parallel dev servers: Start both Hugo and Hub simultaneously
The “FULL TURBO” message when cache hits feels unreasonably satisfying.
Real-World Impact
Before Monorepo
# Terminal 1
cd brandmine-hugo
npm install
hugo server
# Terminal 2
cd brandmine-hub
npm install
npm run dev
# Make schema change
# → Edit hugo/data/schema.json
# → Copy to hub/src/types/schema.ts
# → Manually keep in sync
# → Hope you didn't miss anything
After Monorepo
# Single terminal
pnpm dev # Both apps running
pnpm build # Both apps built (with caching)
# Make schema change
# → Edit packages/shared-types/index.ts
# → Both apps auto-update
# → Type safety guaranteed
Technical Details
5-Phase Migration:
- ✅ Created shared types package
- ✅ Switched to pnpm workspaces
- ✅ Restructured to
apps/andpackages/layout - ✅ Built shared config packages
- ✅ Integrated Turborepo caching
Disk Space: Saved ~500MB (40-50% reduction) by eliminating duplicate dependencies.
Zero Downtime: All migrations happened without affecting production deployments. Cloudflare Pages builds adapted seamlessly.
What This Enables
Easier Hugo ↔ Hub Data Sync
Our sync scripts (sync-to-supabase.js, sync-from-supabase.js) now import shared types directly. No more brittle string-based validation.
Confident Refactoring
TypeScript knows about all usages across both apps. Rename a field? The compiler shows every place that needs updating.
Faster Onboarding
New developers clone one repo, run pnpm install, and they’re ready. No “which repo do I need?” confusion.
Lessons Learned
Filter Names Matter
Turborepo requires exact package names (@brandmine/hugo not hugo). We learned this the hard way when a Cloudflare build failed. Now we test filter names locally first.
Gitignore Patterns for Monorepos
Root-level patterns (/public/) don’t apply to subdirectories (apps/hugo/public/). We fixed this immediately and removed 1000+ accidentally-tracked build artifacts.
Version Syntax Changes
Turborepo v2.x uses tasks instead of deprecated pipeline key. Always check latest docs when implementing from older specs.
Why This Matters
Most monorepo migrations are about scale (Google, Meta managing thousands of services). Ours is about clarity.
When your CTO is Claude and your CEO is switching between business strategy and technical implementation, reducing cognitive overhead matters. One repo, one truth, one command to run everything.
The goal: Spend less time coordinating infrastructure, more time illuminating exceptional brands.
What’s Next
Immediate: Let the monorepo stabilize for 2-3 weeks. We’re not chasing theoretical optimizations.
Future (if needed):
- Remote caching (Turborepo Cloud)
- CI/CD optimization (affected task detection)
- Shared utility packages
For now? We’re building features, not infrastructure.
Full technical breakdown: See our dev journal entry for performance benchmarks, error resolution, and complete implementation details.