Graphite Reviewer is now Diamond

Common pitfalls when adopting a monorepo (and how to avoid them)

Greg Foster
Greg Foster
Graphite software engineer
Try Graphite

Adopting a monorepo—a single repository that houses multiple projects—can offer significant benefits, including streamlined dependency management and improved collaboration. However, without proper planning and tooling, teams may encounter several challenges. This guide outlines common monorepo pitfalls and provides actionable strategies to address them, incorporating tools like Graphite to enhance monorepo workflows.

Problem: In a monorepo, the lack of clear separation between projects can lead to confusion over code ownership and responsibilities.

Solution: Establish clear project boundaries by organizing the repository into well-defined directories and assigning ownership using tools like Git's CODEOWNERS file. This ensures accountability and simplifies code reviews.

Example:

Terminal
/services
/auth
/payment
/libraries
/utils
/validators

Assign teams to specific directories and enforce review policies accordingly.

Problem: A broken main branch can halt development across all projects in the monorepo, causing significant delays.

Solution: Adopt trunk-based development practices to maintain a stable and deployable main branch.

Strategies:

  • Short-lived feature branches: Develop features on brief branches that are merged back into the main branch frequently, often multiple times a day.

  • Feature flags: Integrate incomplete features into the main branch by wrapping them in feature flags, allowing code to be merged without affecting production behavior.

  • Comprehensive automated testing: Implement automated tests that run on every commit to the main branch, ensuring that new changes do not break existing functionality.

  • Merge queues: Utilize merge queue systems, like Graphite's Merge Queue, to automate and serialize the merging of pull requests, ensuring that each change passes all tests before being integrated into the main branch.

Problem: Managing a monorepo without appropriate tools can lead to inefficiencies in dependency management, builds, and releases.

Solution: Adopt monorepo-specific tools to streamline workflows.

Tools:

  • Graphite: Enhances code review processes and manages stacked diffs, facilitating efficient collaboration in monorepos.
    • Stacked PRs workflow: Graphite introduces a stacked diffs workflow, allowing developers to break down large changes into smaller, manageable pull requests (PRs). This approach improves code review efficiency and reduces merge conflicts. ​
    • Graphite Merge Queue: Graphite's merge queue automates the rebase process during merges, preventing semantic merge conflicts and ensuring that the main branch remains stable. It is stack-aware, allowing for efficient merging of stacked PRs. ​
  • Bazel: Optimizes build and test performance through incremental builds and caching.
  • Nx: Provides advanced support for building, testing, and sharing libraries in JavaScript/TypeScript monorepos.

Problem: As the monorepo grows, operations like cloning and building can become time-consuming, affecting developer productivity.

Solution: Implement strategies to manage repository size and build times.

Strategies:

  • Sparse checkouts: Use Git's sparse checkout feature to clone only necessary parts of the repository.
  • Incremental builds: Employ build tools that support incremental builds to avoid rebuilding unaffected projects.
  • Git LFS: Utilize Git Large File Storage to handle large files efficiently.

Example:

Terminal
git clone --filter=blob:none --no-checkout https://your-repo-url.git
cd your-repo
git sparse-checkout init --cone
git sparse-checkout set services/auth
git checkout main

This approach reduces the amount of data cloned, speeding up the setup process.

Problem: Manual processes for tasks like project setup and dependency updates can lead to inconsistencies and increased overhead.

Solution: Automate repetitive tasks to ensure consistency and efficiency.

Automation Areas:

  • Project scaffolding: Use generators to create standardized project structures.
  • Dependency management: Automate dependency updates to maintain consistency across projects.
  • CI/CD pipelines: Set up automated pipelines for building, testing, and deploying code changes.

Example:

Implementing a script to scaffold new services with predefined templates and configurations can reduce setup time and errors.

Problem: Managing access permissions in a monorepo can be challenging, potentially exposing sensitive code to unauthorized users.

Solution: Utilize tools that support granular access controls.

Strategies:

  • Path-based permissions: Configure access controls based on directory paths to restrict access to specific projects.
  • Submodules or subtrees: Use Git submodules or subtrees to separate sensitive components, applying different access controls as needed.

Note: While tools like GitHub and Azure DevOps offer path-based permissions, careful configuration is required to maintain security.

Transitioning to a monorepo structure offers numerous advantages but comes with its own set of challenges. By proactively addressing common pitfalls—such as unclear project boundaries, broken main branches, lack of specialized tooling, scalability issues, insufficient automation, and complex access control—teams can fully leverage the benefits of a monorepo. Incorporating tools like Graphite can further streamline workflows, enhance collaboration, and maintain code quality across projects.

Built for the world's fastest engineering teams, now available for everyone