Part 3: Monorepo vs Polyrepo Strategies

Introduction

I'll never forget the frustration of managing shared TypeScript packages across five different microservices stored in separate repositories. Whenever I updated a shared authentication library, I had to:

  1. Publish the package to our private npm registry

  2. Update package.json in five different repositories

  3. Create five separate pull requests

  4. Wait for five separate CI/CD pipelines

  5. Deploy five services independently

This process took hours and was error-prone. Then I discovered monorepos and everything changed. But monorepos aren't always the answerβ€”I later worked on a project where a monorepo became a nightmare. In this part, I'll share my real-world experience with both approaches and help you choose what's right for your projects.

Understanding Repository Strategies

Before diving into pros and cons, let's define these terms clearly:

Polyrepo (Multiple Repositories)

Each project, service, or library lives in its own repository.

Example Structure:

GitHub Organization: my-company
β”œβ”€β”€ user-service (repo)
β”œβ”€β”€ payment-service (repo)
β”œβ”€β”€ inventory-service (repo)
β”œβ”€β”€ notification-service (repo)
└── shared-lib (repo)

Monorepo (Single Repository)

Multiple projects, services, or libraries live in one repository with a structured directory layout.

Example Structure:

Polyrepo: My First Approach

When I started building a multi-tenant POS system, I chose the polyrepo approach because it seemed simpler. Here's what I learned:

Real-World Polyrepo Structure

Managing Shared Code in Polyrepo

The Challenge: All services needed shared TypeScript types and utilities.

My Solution: Private npm Registry

1. Create Shared Package:

2. Publish to GitHub Packages:

3. Use in Other Services:

Polyrepo Workflow Example

Scenario: Add new field to User type

Advantages of Polyrepo

1. Clear Ownership and Boundaries

Each service has its own repository, making ownership obvious:

2. Independent CI/CD Pipelines

Each service deploys independentlyβ€”if user-service is broken, payment-service can still deploy.

3. Smaller Repository Size

4. Flexible Technology Choices

Different services can use different languages and frameworks.

Disadvantages of Polyrepo

1. Dependency Management Nightmare

The pain I felt most acutely:

2. Code Duplication

Even with shared packages, some duplication creeps in:

3. Difficult Refactoring Across Services

Refactoring that touches multiple services requires coordination:

4. Complex Cross-Service Changes

Monorepo: The Alternative Approach

After the polyrepo pain, I migrated one of my projects to a monorepo. Here's what I learned:

Real-World Monorepo Structure

Setting Up a Monorepo with pnpm

1. Initialize Monorepo:

2. Create Workspace Configuration:

3. Root package.json:

4. Create Shared Package:

5. Create Service:

6. Install Dependencies:

Monorepo Workflow Example

Scenario: Add multi-currency support (same feature as polyrepo example)

Advantages of Monorepo

1. Atomic Changes Across Multiple Services

2. Simplified Dependency Management

3. Code Sharing is Trivial

4. Easier Refactoring

5. Unified CI/CD with Smart Builds

Turbo/Nx only builds and tests what changed!

6. Consistent Tooling

Disadvantages of Monorepo

1. Large Repository Size

Mitigation: Use Git shallow clones in CI/CD:

2. Requires Tooling (Turbo, Nx, Rush)

3. All-or-Nothing Access Control

4. Risk of Tight Coupling

5. CI/CD Complexity

Monorepo Tools Comparison

Turbo (My Preferred Choice)

Pros:

  • Simple setup

  • Fast (caching and parallelization)

  • Great for TypeScript projects

  • Works with npm, yarn, pnpm

Cons:

  • Less features than Nx

  • Relatively new

Nx

Pros:

  • Powerful code generation

  • Advanced dependency graph

  • Plugin ecosystem

  • Great for large teams

Cons:

  • Steeper learning curve

  • More opinionated

  • Heavier setup

Lerna (Legacy)

Pros:

  • Battle-tested

  • Simple concepts

Cons:

  • Slower than modern tools

  • Less active development

  • No built-in caching

My Recommendation: Start with Turbo for simplicity, migrate to Nx if you need advanced features.

Hybrid Approach: The Best of Both Worlds

In my current project, I use a hybrid approach:

Structure

When to Separate

Keep in monorepo:

  • Services that change together frequently

  • Services sharing types and utilities

  • Services owned by same team

  • Services with similar tech stack

Separate repository:

  • Services with different tech stacks (Python vs Node.js)

  • Services owned by completely different teams

  • Services with different security/access requirements

  • Infrastructure code (Terraform, Kubernetes manifests)

Decision Framework: Choosing Your Strategy

Choose Monorepo When:

βœ… Team works on multiple related services βœ… Frequent changes span multiple services βœ… Sharing code between services is common βœ… Atomic cross-service changes are important βœ… Team size: small to medium (1-20 developers) βœ… Similar tech stack across services

Example: SaaS product with microservices (API, web, mobile)

Choose Polyrepo When:

βœ… Clear service boundaries and independence βœ… Services rarely change together βœ… Different teams own different services βœ… Different tech stacks per service βœ… Large organization (100+ developers) βœ… Services have different release schedules

Example: Large enterprise with many independent products

Choose Hybrid When:

βœ… Some services are tightly coupled, others independent βœ… Multiple tech stacks in use βœ… Different teams with different workflows βœ… Some services have different security requirements

Example: Platform with core services in monorepo + specialized services in separate repos

Migrating from Polyrepo to Monorepo

If you're considering migration, here's how I did it:

Conclusion

Both monorepo and polyrepo strategies have their place in modern software development. From my experience:

Monorepo Benefits:

  • Atomic cross-service changes

  • Simplified dependency management

  • Easy code sharing

  • Better refactoring capabilities

Polyrepo Benefits:

  • Clear ownership boundaries

  • Independent CI/CD pipelines

  • Smaller repository size

  • Flexible technology choices

My Recommendation:

  • Start with monorepo for new projects with related services

  • Use polyrepo for truly independent services or different teams

  • Consider hybrid for complex organizations

In Part 4, we'll explore GitHub best practices and collaboration patterns, including pull request workflows, code reviews, and GitHub Actions automation.


Key Takeaways:

  • Monorepo excels at coordinating changes across services

  • Polyrepo provides independence and clear boundaries

  • Hybrid approach combines benefits of both

  • Use tools like Turbo or Nx for monorepo management

  • Choose based on team structure and service coupling

Remember: You can always migrateβ€”start simple and evolve as needed!

Last updated