Migrating Astro.js Monorepo From Nx to Moonrepo
بِسْمِ اللَّهِ الرَّحْمَٰنِ الرَّحِيمِ
Several days ago, I decided to migrate from Nx to Moonrepo for managing my Astro.js monorepo. Maybe the first question that comes to your mind is:
Why Migrate to Moonrepo?
Several factors drove this decision:
Simpler Configuration — Moonrepo uses declarative YAML that’s easy to read. No need for separate
nx.json,project.json, andworkspace.jsonfiles.Faster Task Runner — Moonrepo is built with Rust and offers faster task execution and efficient caching.
Native Astro Support — Moonrepo provides official moon-configs for Astro.js, so you can extend the setup without writing configuration from scratch.
Clear Dependency Graph — Dependencies between tasks and projects are explicit via the
depsdeclaration in YAML.Less Overhead — Compared to Nx with its many plugins and concepts like “affected”, Moonrepo focuses on task running and caching without extra complexity for simple monorepo use cases like mine.
My Monorepo Structure, Before and After Migration
Well, the monorepo structure keeps the apps/* and packages/* pattern:
ikuyo/
├── apps/
│ └── web/ # Astro.js app
├── packages/
│ ├── biome/ # Shared Biome config
│ └── typescript/ # Shared TypeScript config
├── .moon/
│ ├── workspace.yml
│ └── tasks/
│ └── tag-astro.yml
└── package.jsonMigration Steps
1. Remove Nx Dependencies and Configuration
First, remove all Nx-related dependencies from the project. Also, delete Nx configuration files:
nx.jsonworkspace.jsonornx.json(depending on version)- All
project.jsonfiles in each app/package
2. Install Moonrepo
bun add -D @moonrepo/cli3. Create Workspace Configuration
Create .moon/workspace.yml:
projects:
- "apps/*"
- "packages/*"
vcs:
defaultBranch: "master" # or "main", "develop", etc.
provider: "github" # or "gitlab", "bitbucket", etc.Moonrepo automatically detects projects based on folder structure. Project names are derived from folder names (e.g. apps/web → project web).
4. Setup Astro Tasks
Create .moon/tasks/tag-astro.yml that extends the official Astro config:
$schema: "https://moonrepo.dev/schemas/tasks.json"
extends: "https://raw.githubusercontent.com/moonrepo/moon-configs/master/javascript/astro/tasks.yml"This file is applied to projects with the astro tag. The extended config provides tasks: build, dev, check, preview, and astro.
See all available tasks in the moon-configs repository.
5. Configure the Astro Project
In apps/web/moon.yml:
$schema: "https://moonrepo.dev/schemas/project.json"
tags: ["astro"]
tasks:
build:
deps: ["check"]With tags: ['astro'], this project inherits all tasks from tag-astro.yml. I added deps: ['check'] to the build task so type-checking runs before build (matching the astro check && astro build script in package.json).
6. Configure Shared Packages
For packages like Biome and TypeScript config, set the language:
packages/biome/moon.yml:
$schema: "https://moonrepo.dev/schemas/project.json"
language: "javascript"packages/typescript/moon.yml:
$schema: "https://moonrepo.dev/schemas/project.json"
language: "typescript"7. Update Scripts in Root package.json
Replace Nx scripts with Moonrepo. In my case:
// Nx scripts
{
"scripts": {
"build:web": "nx build web",
"build:web:prod": "nx build web --prod",
"dev:web": "nx dev web",
"test:web": "nx test web"
}
}// Moonrepo scripts
{
"scripts": {
"build:web": "moon run web:build",
"build:web:prod": "moon run web:build",
"dev:web": "moon run web:dev",
"test:web": "moon run web:test"
}
}Moonrepo command format: moon run <project>:<task>.
Configuration Comparison
Nx (Before)
Nx typically requires multiple files:
nx.json— workspace config, cache, etc.workspace.jsonorproject.json— project and target definitions@nrwl/workspaceor@nx/workspaceplugin for integration
Moonrepo (After)
One YAML file per project, extending the official config:
tags: ["astro"]
tasks:
build:
deps: ["check"]Tasks build, dev, and check are defined in moon-configs. We only override what we need.
Available Tasks
After migration, these tasks are available for the web project:
| Task | Command | Description |
|---|---|---|
build | astro build | Production build (after check) |
dev | astro dev | Development server |
check | astro check | Type-check .astro files |
preview | astro preview | Preview build (deps: build) |
astro | astro | Catch-all for astro commands |
Running tasks:
moon run web:build
moon run web:dev
moon run web:checkLessons Learned
Tag-based Inheritance — Moonrepo’s tag system is very practical. One task file can be shared across many projects with the same tag, reducing duplication.
File Groups for Caching — Moonrepo defines
fileGroups(astro, sources, tests) for input hashing. Changes outside those groups won’t invalidate the cache.Keep Using npm/pnpm/bun Workspaces — Moonrepo doesn’t replace the package manager. The
workspacesfield inpackage.jsonis still used for dependency resolution.Schema Validation — The
$schemain YAML enables IDE autocomplete and validation, reducing typos.