Beyond Moon's Defaults: Adding Explicit Multi-App Commands

monorepodeveloper-experienceproductivitymoonrepo

MoonRepo is exceptional at managing multiple applications. Running moon run :dev starts all your dev servers with colored output and intelligent parallelization. It just works. But as a monorepo grows, you might want more control over which apps start, clearer log prefixes, or structured production workflows. This article explores what Moon already provides and what convenience layers can add value.

What Moon Already Provides

Before adding anything, understand what MoonRepo gives you out of the box:

The Command:

moon run :dev

What It Does:

  • Starts all projects with a dev task defined
  • Executes them in parallel automatically
  • Provides colored output to differentiate apps
  • Handles process management and cleanup
  • Respects task dependencies

This is excellent. For many monorepos, moon run :dev is all you need. It's fast, reliable, and requires zero configuration beyond your existing moon.yml files.

Why Add More Commands?

As our monorepo grew, we identified three scenarios where additional control was valuable:

1. Explicit App Selection

The Problem: moon run :dev runs every project with a dev task. If you add a docs site, admin panel, or internal tools to your monorepo, they all start too.

The Solution: Explicit commands targeting specific apps:

pnpm dev:all  # Only api, astro-app, web

This prevents accidentally starting unwanted services and makes intentions clear.

2. Named Prefixes

Moon's Output: Colored logs (great!)
What We Added: Named prefixes like [api], [astro], [next]

Using concurrently, we added explicit labels:

[api]   Server listening on port 3001
[astro] Ready at http://localhost:4321  
[next]  Compiled successfully

Is this necessary? No. Moon's colors work fine. Is it clearer? Marginally. Some developers prefer explicit labels when debugging multi-app issues.

3. Production Orchestration

The Gap: Moon excels at development workflows, but production server orchestration needed structure.

What We Added:

pnpm start:all  # Builds first, then starts production servers

This command:

  • Ensures builds complete before starting servers
  • Uses moon task dependencies (deps: ['~:build'])
  • Provides consistent production workflow
  • Prevents "forgot to rebuild" errors

This is the biggest genuine improvement.

The Implementation

Here's what we added to package.json:

{
  "scripts": {
    "dev:all": "moon run api:dev astro-app:dev web:dev",
    "dev:all:parallel": "concurrently -n \"api,astro,next\" -c \"blue,magenta,cyan\" \"moon run api:dev\" \"moon run astro-app:dev\" \"moon run web:dev\"",
    "start:all": "moon run api:start astro-app:preview web:start",
    "build:all": "moon run :build"
  }
}

Plus moon task additions for production modes:

# apps/astro-app/moon.yml
tasks:
  preview:
    command: 'astro preview'
    local: true
    deps:
      - '~:build'

# apps/web/moon.yml  
tasks:
  start:
    command: 'next start'
    local: true
    deps:
      - '~:build'

The deps: ['~:build'] configuration is key—it ensures apps are built before production servers start.

Honest Assessment: Was It Worth It?

Time invested: ~30 minutes
Dependency added: concurrently (if using parallel mode)

Value delivered:

⭐⭐⭐ Production orchestration - The start:all command is genuinely useful for structured deployments.

⭐⭐ Explicit selection - Prevents accidentally starting all projects as your monorepo grows.

⭐⭐ Discoverability - New developers see commands in pnpm run listing, familiar Node.js pattern.

Named prefixes - Marginally clearer than Moon's colors alone.

Bottom line: If moon run :dev works for you, stick with it. Add these conveniences when your workflow outgrows Moon's defaults—particularly for production deployments.

When to Use Each Approach

Use Moon's native commands when:

  • You want all projects with dev tasks to start
  • Moon's colored output is sufficient
  • You prefer Moon's simplicity and zero configuration
  • You're comfortable with moon run :dev

Add convenience scripts when:

  • Your monorepo has 5+ projects and you only need specific apps
  • You want explicit named prefixes for debugging
  • You need structured production workflows
  • New developers find pnpm run more familiar than moon commands

The Bigger Picture

This article isn't about solving fundamental problems—Moon already handles multi-app development elegantly. It's about recognizing when a convenience layer adds value:

For small monorepos (2-4 apps): moon run :dev is perfect. Don't overcomplicate.

For growing monorepos (5+ projects): Explicit selection and production workflows become valuable.

For open-source projects: Documentation and familiar commands (pnpm run) lower the barrier to contribution.

Lessons Learned

The real insight here isn't technical—it's about honest assessment. We initially thought we were solving major problems. In reality, we added polish on top of already-excellent tooling.

Moon's defaults are strong. If you're adding layers, make sure they deliver genuine value. In our case:

  • Production orchestration: Yes
  • Explicit app selection: Yes, as we scale
  • Named prefixes: Nice-to-have, not need-to-have

Small improvements matter, but so does recognizing when the default is already excellent. Build on Moon's strengths rather than working around imagined weaknesses.