We’ve been running an Nx monorepo with 12 apps and 40+ libraries for over a year now. Here’s what works, what hurts, and what I wish I’d known from day one.
Why Monorepo?
The pitch is simple: shared code without the npm publish dance. When your Angular frontend and NestJS backend share TypeScript interfaces, a monorepo eliminates an entire class of bugs.
apps/
web-app/ # Angular frontend
admin-panel/ # Angular admin
api/ # NestJS backend
worker/ # Background jobs
libs/
shared/dto/ # Shared interfaces
shared/utils/ # Common utilities
ui/components/ # Angular component library
api/auth/ # Auth module
api/database/ # Database module
The Module Boundary Rules
This is the single most important Nx feature. Without it, monorepos become spaghetti repos.
// .eslintrc.json
{
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{
"depConstraints": [
{ "sourceTag": "type:app", "onlyDependOnLibsWithTags": ["type:lib", "type:util"] },
{ "sourceTag": "type:api", "onlyDependOnLibsWithTags": ["type:lib", "scope:api"] },
{ "sourceTag": "scope:web", "onlyDependOnLibsWithTags": ["scope:web", "scope:shared"] }
]
}
]
}
}
These rules saved us from circular dependencies at least a dozen times.
Caching is Everything
Nx’s computation caching is the difference between a 20-minute CI pipeline and a 3-minute one.
# Local cache hit
nx build web-app # 1.2s (cached)
# Remote cache with Nx Cloud
nx affected --target=test # Only tests what changed
Enable Nx Cloud early. The free tier is generous and the speed improvement is transformative.
Code Generation
Don’t hand-write boilerplate. Custom generators are a game-changer:
nx generate @nx/angular:component --name=feature-card --project=ui-components
nx generate @nx/nest:resource --name=products --project=api
We wrote custom generators for our common patterns — new feature modules, API resources with full CRUD, shared DTOs. New features now take minutes to scaffold instead of hours.
Pain Points
Not everything is sunshine:
- IDE performance degrades with 50+ projects. VS Code needs
"typescript.tsserver.maxTsServerMemory": 4096 - Dependency updates are all-or-nothing. When you bump Angular, every app gets it
- New developer onboarding takes longer — there’s more to understand upfront
- The Nx daemon occasionally gets confused.
nx resetis your friend
The Verdict
Despite the pain points, I’d choose Nx monorepo again in a heartbeat. The consistency, code sharing, and affected commands make it worthwhile. Just invest in module boundaries and caching from day one.