Skip to main content
The primary focus of moon is a task runner. In moon, a task is a binary or system command that is run as a child process within the context of a project. Tasks are defined per project with moon.yml, or inherited by many projects with .moon/tasks/**/*.

Configuring a Task

Most projects utilize the same core tasks: linting, testing, code formatting, typechecking, and building. Let’s implement a build task within a project. Begin by creating the moon.yml file at the root of a project and add build to the tasks field with a command parameter:
moon.yml
language: 'javascript'

tasks:
  build:
    command: 'webpack build'

Adding Arguments

Arguments can be defined with the args setting or directly in the command:
moon.yml
language: 'javascript'

tasks:
  build:
    command: 'webpack build --mode production --no-stats'
Now you can run the task from the command line:
moon run app:build

Inputs

Our task above works, but isn’t very efficient as it always runs, regardless of what has changed since the last time it ran. This becomes problematic in CI environments and locally. To mitigate this, moon provides inputs - file paths, globs, and environment variables that are used by the task. Moon will compare these inputs to calculate whether to run or return the previous run state from cache. Let’s expand the task with the inputs setting:
moon.yml
language: 'javascript'

tasks:
  build:
    command: 'webpack build --mode production --no-stats'
    inputs:
      - 'src/**/*'
      - 'webpack.config.js'
      - '/webpack-shared.config.js'
This list of inputs are run checks. The task will run when moon detects a change in:
  • Any files within the src folder (relative from the project’s root)
  • The webpack.config.js file in the project’s root
  • The webpack-shared.config.js file in the workspace root (denoted by the leading /)
If the change occurs outside of the project or outside the list of inputs, the task will not run.
Inputs are a powerful feature that can be fine-tuned to your project’s needs. Be as granular or open as you want!

Environment Variable Inputs

You can also include environment variables as inputs:
moon.yml
tasks:
  build:
    command: 'webpack build'
    inputs:
      - 'src/**/*'
      - '$NODE_ENV'
      - '$BUILD_TARGET'

Outputs

Outputs are the opposite of inputs - they are files and folders created as a result of running the task. Outputs are optional, as not all tasks require them, and the ones that do are typically build-related. Declaring outputs is important for incremental builds and smart caching! When moon encounters a build that has already been built, it hydrates all necessary outputs from the cache, then immediately exits. No more waiting for long builds! Let’s expand our task with the outputs setting:
moon.yml
language: 'javascript'

tasks:
  build:
    command: 'webpack build --mode production --no-stats --output-path @out(0)'
    inputs:
      - 'src/**/*'
      - 'webpack.config.js'
      - '/webpack-shared.config.js'
    outputs:
      - 'build'
The @out(0) token references the first output directory, ensuring the build goes to the correct location.

Task Dependencies

For scenarios where you need to run a task before another task, use the deps setting with targets:
  • <project>:<task> - Full canonical target
  • ~:<task> or <task> - A task within the current project
  • ^:<task> - A task from all depended on projects
moon.yml
dependsOn:
  - 'ui-library'

tasks:
  build:
    command: 'webpack build'
    deps:
      # Run the ui-library build before this build
      - '^:build'
  
  start:
    command: 'node server.js'
    deps:
      # Run the build task in this project first
      - 'build'

Using File Groups

Once you’re familiar with configuring tasks, you may notice certain inputs being repeated. To reduce boilerplate, moon provides file groups, which enable grouping of similar file types:
moon.yml
fileGroups:
  configs:
    - '*.config.js'
  sources:
    - 'src/**/*'
    - 'types/**/*'
  tests:
    - 'tests/**/*'

tasks:
  build:
    command: 'webpack build'
    inputs:
      - '@globs(sources)'
      - '@globs(configs)'
    outputs:
      - 'build'
The @globs(sources) and @globs(configs) tokens expand to all files matching those file groups.

Common Task Patterns

Here are some common task configurations:
moon.yml
tasks:
  build:
    command: 'vite build'
    inputs:
      - 'src/**/*'
      - 'index.html'
      - 'vite.config.js'
      - 'package.json'
    outputs:
      - 'dist'
    deps:
      - '^:build'

Task Options

Here are some useful task options:
moon.yml
tasks:
  build:
    command: 'webpack build'
    inputs: ['src/**/*']
    outputs: ['dist']
    
    # Task options
    local: false          # Run in CI (default: false)
    persistent: false     # Long-running process (default: false)
    interactive: false    # Requires user input (default: false)
    cache: true          # Enable caching (default: true)
    runInCI: true        # Explicitly run in CI (default: true)
    
    # Execution options
    retryCount: 2        # Retry failed tasks
    timeout: '30m'       # Task timeout
    
    # Environment variables
    env:
      NODE_ENV: 'production'
      BUILD_ID: '@task(id)'

Global Task Configuration

To avoid repeating the same tasks across multiple projects, create global task configurations in .moon/tasks/:
.moon/tasks/node.yml
# Inherited by all projects with language: 'javascript' or 'typescript'
tasks:
  format:
    command: 'prettier --check .'
    inputs:
      - 'src/**/*'
  
  lint:
    command: 'eslint .'
    inputs:
      - 'src/**/*'
      - '.eslintrc.js'
  
  test:
    command: 'jest --passWithNoTests'
    inputs:
      - 'src/**/*'
      - 'tests/**/*'
  
  typecheck:
    command: 'tsc --build --pretty'
    inputs:
      - 'src/**/*'
      - 'tsconfig.json'
All projects will automatically inherit these tasks based on their language setting!

Example: Complete Task Configuration

Here’s a complete example:
moon.yml
$schema: 'https://moonrepo.dev/schemas/project.json'

language: 'typescript'

fileGroups:
  sources:
    - 'src/**/*'
  tests:
    - 'tests/**/*'
    - '**/*.test.ts'
  configs:
    - '*.config.{js,ts}'
    - 'tsconfig.json'

tasks:
  build:
    command: 'vite build'
    inputs:
      - '@globs(sources)'
      - '@globs(configs)'
    outputs:
      - 'dist'
    deps:
      - '^:build'
  
  test:
    command: 'vitest run'
    inputs:
      - '@globs(sources)'
      - '@globs(tests)'
      - 'vitest.config.ts'
  
  dev:
    command: 'vite dev'
    local: true
    persistent: true
  
  preview:
    command: 'vite preview'
    deps:
      - 'build'

Next Steps

Run a Task

Learn how to run tasks with moon

Task Configuration Reference

View all available task configuration options

Build docs developers (and LLMs) love