Skip to main content
Affected is a term to describe when a project or task is affected by a change in the environment (workspace). This is a core concept in moon, and is the basis for many of our features, such as task running, incremental builds, and more.

Overview

Affected detection analyzes your workspace to determine:
  • Which files have changed
  • Which projects are impacted by those changes
  • Which tasks need to re-run
  • Which projects depend on affected projects
Affected detection helps you run only what’s necessary, dramatically speeding up CI/CD and local development.

Change Types

To start, there are 3 types of “sources” that can trigger an affected state: files, environment variables, and graph relations.

Files

A file is considered changed if it has been added, modified, deleted, renamed, moved, copied, so on and so forth. This state is determined by the version control system (VCS) in use, such as Git, Mercurial, or Subversion. For Git, this is determined by the git status command. For a project, any changed file that is within the project folder (starts with the project source) triggers affected.
# Changes in these files affect the 'api' project
packages/api/src/index.ts          # ✓ Affected
packages/api/tests/api.test.ts     # ✓ Affected
packages/api/package.json          # ✓ Affected

# Changes here don't affect 'api'
packages/web/src/app.tsx           # ✗ Not affected
For a task, any changed file that is configured within the task’s inputs triggers affected.
packages/api/moon.yml
tasks:
  build:
    command: 'tsc'
    inputs:
      - 'src/**/*.ts'      # Changes here trigger affected
      - 'tsconfig.json'    # Changes here trigger affected
      - 'package.json'     # Changes here trigger affected

Environment Variables

An environment variable is considered changed if it exists and is non-empty. This is determined by the presence of the variable in the environment, and its value. For projects, they are not affected by environment variables. For a task, any changed environment variable that is configured within the task’s env triggers affected.
moon.yml
tasks:
  build:
    command: 'webpack'
    env:
      NODE_ENV: 'production'  # If this var changes, task is affected
      API_URL: '$API_URL'     # If this var changes, task is affected

Graph Relations

A relation is considered changed if a project or task that is depended on, or depends on, is affected by a changed file or environment variable. This is determined by the project and task graph, which is built from the workspace configuration. For a project, affected dependency/dependent projects of the project (via dependsOn), or affected tasks within the project, triggers affected.
packages/web/moon.yml
language: typescript

dependsOn:
  - 'ui'      # If 'ui' is affected, 'web' is affected
  - 'utils'   # If 'utils' is affected, 'web' is affected
For a task, affected dependency/dependent tasks of the task (via deps) triggers affected.
moon.yml
tasks:
  build:
    command: 'webpack'
    deps:
      - '~:typecheck'  # If typecheck is affected, build is affected
      - '^:build'      # If any dep's build is affected, this is affected
This check is conditionally enabled. For moon query, it is always enabled. For exec-based commands, it is not enabled by default and the --include-relations flag must be passed.

Graph Depth

When determining affected state based on graph relations, the depth of traversal can be configured with the --upstream (--dependencies) and --downstream (--dependents) options. These options can be set to one of the following values:
  • none - Do not include any relations
  • direct - Include only direct relations
  • deep - Include all relations
For exec-based commands, the default is --upstream=deep and --downstream=none, meaning all dependencies are included, but no dependents are included. For query and other commands, the default is none for both.

Upstream (Dependencies)

# Run build for project and all dependencies
moon run app:build --upstream=deep

# Run build for project and direct dependencies only
moon run app:build --upstream=direct

# Run build for project only, no dependencies
moon run app:build --upstream=none

Downstream (Dependents)

# If 'utils' changes, rebuild it and all projects that depend on it
moon run utils:build --downstream=deep

# Rebuild 'utils' and direct dependents only
moon run utils:build --downstream=direct

Usage Examples

Running Affected Tasks

# Run tests only in affected projects
moon run :test --affected

# Run build only in affected projects
moon run :build --affected

# Run lint in affected projects, including dependents
moon run :lint --affected --downstream=deep

Querying Affected Projects

# List affected projects
moon query projects --affected

# Show affected projects with details
moon query projects --affected --json

# Query affected projects by tag
moon query projects --affected --tags frontend

CI/CD with Affected

Optimize CI by running only affected tasks:
.github/workflows/ci.yml
name: CI

on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0  # Important: fetch full history
      
      - name: Setup moon
        run: |
          npm install -g @moonrepo/cli
      
      - name: Run affected tests
        run: |
          moon run :test --affected
      
      - name: Build affected projects
        run: |
          moon run :build --affected

Change Detection

Git-based Detection

Moon uses Git to detect changes:
# Compare current branch to main
moon run :test --affected

# Compare specific commits
moon run :test --affected --remote origin/main

# Compare specific refs
moon run :test --affected --base HEAD~1 --head HEAD

Local Changes

# Include uncommitted changes
moon run :build --affected --local

# Only committed changes (default)
moon run :build --affected

Real-World Scenarios

Scenario 1: Library Change

# Workspace structure
packages/
├── utils/          # Shared utilities
├── ui/             # UI components (depends on utils)
└── app/            # Application (depends on ui and utils)

# Change a file in utils
$ git diff
diff --git a/packages/utils/src/helpers.ts b/packages/utils/src/helpers.ts

# Run affected tests
$ moon run :test --affected --downstream=deep

# Runs tests for:
# - utils (directly affected)
# - ui (depends on utils)
# - app (depends on utils)

Scenario 2: Feature Branch

# On feature branch with changes to 'api' package
$ git diff origin/main...HEAD

# Run build for affected projects
$ moon run :build --affected

# Only builds 'api' and projects depending on it

Scenario 3: Multiple Projects

packages/web/moon.yml
dependsOn:
  - 'ui'
  - 'api-client'
  - 'utils'

tasks:
  build:
    command: 'vite build'
    deps:
      - '^:build'  # Build all dependencies
# Change files in 'ui' package
$ git status
modified: packages/ui/src/Button.tsx

# Run affected builds
$ moon run :build --affected

# Executes:
# 1. utils:build (dependency of ui)
# 2. ui:build (directly affected)
# 3. web:build (depends on ui)

Configuration

Base Branch Configuration

.moon/workspace.yml
vcs:
  defaultBranch: 'main'  # Base branch for affected detection
  provider: 'git'

Task Input Configuration

Configure inputs to control affected detection:
moon.yml
tasks:
  build:
    command: 'tsc'
    inputs:
      - 'src/**/*.ts'      # Source files
      - 'tsconfig.json'    # Config files
      - 'package.json'     # Dependencies
      # Exclude test files from build affected detection
      - '!tests/**/*'

Advanced Patterns

Matrix Testing

.github/workflows/test-matrix.yml
jobs:
  detect:
    runs-on: ubuntu-latest
    outputs:
      projects: ${{ steps.projects.outputs.projects }}
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      
      - name: Get affected projects
        id: projects
        run: |
          PROJECTS=$(moon query projects --affected --json | jq -c '[.[].id]')
          echo "projects=$PROJECTS" >> $GITHUB_OUTPUT
  
  test:
    needs: detect
    runs-on: ubuntu-latest
    strategy:
      matrix:
        project: ${{ fromJson(needs.detect.outputs.projects) }}
    steps:
      - name: Test ${{ matrix.project }}
        run: moon run ${{ matrix.project }}:test

Selective Deployment

# Deploy only affected applications
moon query projects --affected --tags app | while read project; do
  moon run $project:deploy
done

Troubleshooting

Everything is Affected

Causes:
  • Root-level configuration changed (.moon/workspace.yml)
  • Global task configuration changed (.moon/tasks/**/*)
  • Package manager lockfile changed
  • Toolchain versions changed
Solution: This is expected behavior. Configuration changes affect all projects.

Nothing is Affected

Causes:
  • No changes detected by Git
  • Incorrect base branch
  • Changes in ignored files only
Solution:
# Check Git status
git status

# Verify base branch
git branch --show-current

# Check affected with verbose logging
moon run :test --affected --log trace

Unexpected Affected Projects

Causes:
  • Implicit dependencies via package.json
  • File groups including more than expected
  • VCS ignore patterns
Solution:
# Inspect project dependencies
moon project <project> --json | jq .dependencies

# Check task inputs
moon task <project>:<task> --json | jq .inputs

Best Practices

Always use --affected in CI to run only necessary tasks. This dramatically reduces CI times and costs.
moon run :test --affected
moon run :build --affected
Set the correct default branch in .moon/workspace.yml to ensure accurate affected detection.
vcs:
  defaultBranch: 'main'  # or 'master', 'develop', etc.
Define explicit task inputs to control affected detection precisely. Avoid relying on defaults.
Before pushing, test affected detection locally to ensure the right tasks run.
moon query projects --affected
moon run :test --affected --log debug
  • Cache - Affected detection works with caching
  • Tasks - Configure task inputs for affected detection
  • Targets - Run affected targets
  • Action Graph - Visualize affected dependencies

Configuration Reference

For detailed configuration options, see:

Build docs developers (and LLMs) love