Skip to main content
info

Documentation is currently for moon v2 and latest proto. Documentation for moon v1 has been frozen and can be found here.

Project graph

The project graph is a representation of all configured projects in the workspace and their relationships between each other, and is represented internally as a directed acyclic graph (DAG). Below is a visual representation of a project graph, composed of multiple applications and libraries, where both project types depend on libraries.

info

The moon project-graph command can be used to view the structure of your workspace.

Relationships

A relationship is between a dependent (downstream project) and a dependency/requirement (upstream project). Relationships are derived from source code and configuration files within the repository, and fall into 1 of 2 categories:

Explicit

These are dependencies that are explicitly defined in a project's moon.* config file, using the dependsOn setting.

moon.yml
dependsOn:
- 'components'
- id: 'utils'
scope: 'peer'

Implicit

These are dependencies that are implicitly discovered by moon when scanning the repository. How an implicit dependency is discovered is based on a language's platform integration, and how that language's ecosystem functions.

package.json
{
// ...
"dependencies": {
"@company/components": "workspace:*"
},
"peerDependencies": {
"@company/utils": "workspace:*"
}
}
caution

If a language is not officially supported by moon, then implicit dependencies will not be resolved. For unsupported languages, you must explicitly configure dependencies.

Scopes

Every relationship is categorized into a scope that describes the type of relationship between the parent and child. Scopes are currently used for project syncing and deep Docker integration.

  • Production - Dependency is required in production, will not be pruned in production environments, and will sync as a production dependency.
  • Development - Dependency is required in development and production, will be pruned from production environments, and will sync as a development-only dependency.
  • Build - Dependency is required for building only, and will sync as a build dependency.
  • Peer - Dependency is a peer requirement, with language specific semantics. Will sync as a peer dependency when applicable.
  • Root - Special scope applied when depending on the root-level project. Treated as a development dependency.

Scope partitionsv2.5.0

Internally, relationships are partitioned into 2 graphs based on their scope: production (production, peer) and development (development, build, root). Each partition enforces its own acyclicity, so a dependency cycle is only an error when it exists entirely within a single partition.

Relationships that cross the production/development boundary are valid, and no longer fail with a cycle error (nor silently drop dependency edges). A common example from the Go ecosystem: a package is depended on in production, while its tests depend on a test-utility package that imports the original package right back.

What is the graph used for?

Great question, the project graph is used throughout the codebase to accomplish a variety of functions, but mainly:

  • Is fed into the task graph to determine relationships of tasks between other tasks, and across projects.
  • Powers our Docker layer caching and scaffolding implementations.
  • Utilized for project syncing to ensure a healthy repository state.
  • Determines affected projects in continuous integration workflows.