DEV Community

fiker
fiker

Posted on

# I Built a Scalable Monorepo Boilerplate for Multi-Product Apps (Next.js + NestJS + Turbo)

Most monorepo setups fall into one of two traps:

  • ❌ Everything is duplicated per app → impossible to scale
  • ❌ Everything is centralized → turns into a “god app”

After hitting both problems, I built a boilerplate that actually scales cleanly across multiple products.


🧠 The Idea

Instead of thinking:

“Each product is its own app”

I flipped it to:

“Products are modules. Apps are just runtimes.”


🧱 The Architecture

apps/
  web/        → Next.js runtime
  api/        → NestJS runtime

packages/
  core/       → auth, db, logging, http
  products/   → all business domains
  shared/     → types, utils, validation
  ui/         → design system
Enter fullscreen mode Exit fullscreen mode

🔥 Key Concept

Each product looks like this:

packages/products/product-a/
  backend/
  frontend/
Enter fullscreen mode Exit fullscreen mode
  • backend/ → NestJS modules
  • frontend/ → UI + features

No duplication. No separate repos. No messy coupling.


⚙️ How It Works

Backend (NestJS)

Products plug into the API:

import { ProductAModule } from "@repo/products/product-a/backend";

@Module({
  imports: [ProductAModule]
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

Frontend (Next.js)

Products plug into the UI:

import { ProductAFeature } from "@repo/products/product-a/frontend";
Enter fullscreen mode Exit fullscreen mode

⚡ Why This Is Better

1. No duplication

Auth, DB, and config live in core/ once.


2. Real scalability

Adding a new product = new folder, not a new app.


3. Clean boundaries

  • products = business logic
  • core = infrastructure
  • apps = runtime only

4. Works with Turbo

  • fast builds
  • caching
  • parallel dev

🧠 What I Learned (the hard way)

1. NodeNext breaks monorepos if you’re not careful

Use:

"module": "commonjs",
"moduleResolution": "node"
Enter fullscreen mode Exit fullscreen mode

2. Every module needs an entry point

backend/index.ts
Enter fullscreen mode Exit fullscreen mode

Otherwise imports fail silently.


3. Path aliases must be correct

"paths": {
  "@repo/products/*": ["packages/products/*"]
}
Enter fullscreen mode Exit fullscreen mode

No leading /.


4. Never mix core and product logic

That’s how monorepos rot.


🚀 What You Can Build With This

  • SaaS platforms with multiple products
  • internal tools ecosystems
  • white-label systems
  • modular startups (build fast, scale later)

📦 Example Use Case

Instead of:

  • 10 repos
  • 10 APIs
  • 10 frontends

You get:

  • 1 system
  • shared infrastructure
  • isolated products

⚠️ What This Is NOT

  • Not microservices
  • Not a simple starter template
  • Not beginner-friendly (and that’s fine)

This is for when you actually care about scale and structure.


🧭 What’s Next

I’m planning to add:

  • automatic product generator CLI
  • dynamic module loading (no manual imports)
  • per-product database isolation
  • CI/CD pipelines per domain

💭 Final Thought

Most people scale by adding more apps.

That’s the wrong move.

Scale by composing systems, not duplicating them.


If you’re building something similar or thinking about monorepos, I’d like to hear how you’re structuring yours.

Top comments (0)