← All articles
BUILD TOOLS Moon: Task Runner and Build System for Monorepos 2026-03-04 · 3 min read · moon · monorepo · build system

Moon: Task Runner and Build System for Monorepos

Build Tools 2026-03-04 · 3 min read moon monorepo build system task runner turborepo typescript ci/cd developer tools

Managing a monorepo with multiple packages requires a build system that understands dependencies between them, runs only what changed, and caches results. Moon is a task runner and build system that provides dependency graphs, change detection, remote caching, and toolchain management — without being tied to a specific package manager or language.

Install

# Install moon globally
curl -fsSL https://moonrepo.dev/install/moon.sh | bash

# or
npm install --save-dev @moonrepo/cli

Workspace Setup

Initialize moon in a monorepo:

moon init

This creates:

.moon/
  workspace.yml     # Workspace configuration
  toolchain.yml     # Toolchain versions
  tasks.yml         # Inherited tasks

workspace.yml

# .moon/workspace.yml
$schema: "https://moonrepo.dev/schemas/workspace.json"

projects:
  # Explicitly list projects
  - web
  - api
  - packages/ui
  - packages/utils

  # Or use a glob
  # projects:
  #   - "apps/*"
  #   - "packages/*"

vcs:
  defaultBranch: main
  manager: git

toolchain.yml

Moon manages language/tool versions for consistency across the team:

# .moon/toolchain.yml
$schema: "https://moonrepo.dev/schemas/toolchain.json"

node:
  version: "22.0.0"
  packageManager: pnpm
  addEnginesConstraint: true

typescript:
  version: "5.4.0"

When developers run moon commands, it installs and uses the exact toolchain versions — no more "works on my machine" from different Node versions.

Project Configuration

Each project has a moon.yml:

# web/moon.yml
$schema: "https://moonrepo.dev/schemas/project.json"

language: typescript
type: application

# Tags for grouping
tags:
  - frontend
  - react

# Project dependencies
dependsOn:
  - packages/ui
  - packages/utils

tasks:
  dev:
    command: vite dev
    local: true  # Don't run in CI

  build:
    command: vite build
    inputs:
      - "src/**/*"
      - "public/**/*"
    outputs:
      - "dist"
    deps:
      - packages/ui:build
      - packages/utils:build

  test:
    command: vitest run
    inputs:
      - "src/**/*.test.*"
      - "src/**/*"

Running Tasks

# Run a task in a specific project
moon run web:build

# Run a task across all projects
moon run :build

# Run multiple tasks
moon run web:build api:build

# Run for a project and its dependencies
moon run web:build --dependents

Affected Detection

Moon tracks which files changed and runs only affected projects:

# Run build only for changed projects (since main branch)
moon run :build --affected

# Against a specific branch
moon run :test --affected --base main --head HEAD

This is the key CI optimization — a PR changing only packages/utils triggers builds only for utils and projects that depend on it.

Task Inheritance

Define tasks once in .moon/tasks.yml and inherit them across projects:

# .moon/tasks.yml
tasks:
  format:
    command: biome format --write .
    inputs:
      - "@globs(sources)"

  lint:
    command: biome lint .
    inputs:
      - "@globs(sources)"

  typecheck:
    command: tsc --noEmit
    inputs:
      - "@globs(sources)"
      - "tsconfig.json"

Any project inherits these tasks unless it overrides them in its own moon.yml.

Dependency Graph

Visualize the dependency graph:

moon graph
moon graph web  # Just one project's graph

Opens an interactive graph in your browser showing which projects depend on which.

Remote Caching

Moon supports remote caching to share build artifacts across CI jobs and machines:

# .moon/workspace.yml
runner:
  cacheLifetime: "7 days"
  inheritColorsForPipedTasks: true

With moonbase (Moon's cloud cache) or self-hosted S3-compatible storage:

runner:
  archivableTargets:
    - ":build"
    - ":typecheck"

Once cached, identical tasks across CI runs use the cache without recomputing.

Proto: Toolchain Manager

Moon's companion tool proto manages multiple language versions:

# Install proto
curl -fsSL https://moonrepo.dev/install/proto.sh | bash

# Use .prototools file in repo root
node = "22.0.0"
pnpm = "9.0.0"
bun = "1.1.0"

# proto installs and activates the right version automatically
proto use

Proto replaces nvm, fnm, and similar tools with a unified manager for Node, Bun, Deno, Python, Go, and more.

Moon vs Turborepo

Feature Moon Turborepo
Language agnostic Yes Node-focused
Toolchain management Built-in (proto) No
Remote caching moonbase / self-hosted Vercel (free tier)
Configuration YAML JSON
Project detection Manual + glob package.json-based
Docker integration moon docker scaffold Manual
Affected detection Git-aware Basic

Moon is better for polyglot repos or when you want more control. Turborepo is simpler for pure Node/TypeScript monorepos already using npm/pnpm workspaces.

CI Integration

# .github/workflows/ci.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for affected detection

      - uses: moonrepo/setup-moon-action@v1

      - name: Run affected tasks
        run: |
          moon run :build --affected --base ${{ github.base_ref }}
          moon run :test --affected --base ${{ github.base_ref }}

Docker Support

Moon generates optimized Dockerfiles for projects:

moon docker scaffold web
moon docker build web

This creates a Docker build that only copies relevant workspace files for the target project, using layer caching effectively.

Moon's documentation is at moonrepo.dev. For monorepos with multiple languages or projects, or where Turborepo's Node-centric model is limiting, Moon provides a more flexible and feature-complete alternative.