Tame your monorepo scripts
Every package has its own build, lint, and dev commands, and the root package.json has thirty scripts nobody can keep straight. Give the monorepo one entry point with per-package tasks and task calls.
blog/monorepo-tasksOpen the root package.json of any monorepo that's been alive for a year. There are thirty scripts: build:web, build:ui, build:api, dev:web, test:ui, lint:all, and a build that's just npm run build:ui && npm run build:web && npm run build:api with the order memorized by exactly one person. New teammates run the wrong one, forget the build order, and learn the dependency graph by breaking it.
The scripts aren't the problem. The problem is that the relationships between them — this builds before that, this is the one you actually run — live in a flat list of strings with no structure.
OrchStep gives you per-package tasks and lets one task call another. The build order stops being tribal knowledge and becomes the workflow.
One entry point, tasks underneath
Each package gets a task. One top-level build task calls them in the right order. That's the whole pattern:
name: monorepo
defaults:
mode: dev
tasks:
# `orchstep run ui`
ui:
steps:
- name: build-ui
func: shell
do: echo "pnpm --filter ui build"
# `orchstep run web`
web:
steps:
- name: build-web
func: shell
do: echo "pnpm --filter web build"
# `orchstep run api`
api:
steps:
- name: build-api
func: shell
do: echo "pnpm --filter api build"
# `orchstep run build` — the single entry point newcomers learn.
build:
steps:
- name: shared-ui
task: ui
- name: frontend
task: web
- name: backend
task: api
- name: done
func: shell
do: echo "all packages built ({{ vars.mode }})"The task: field is the key move. build doesn't repeat the ui commands — it calls the ui task. The shared library builds before the apps because the steps are ordered, not because someone remembered. Need to build just one package? Run it directly. Need everything? Run build.
Run it
orchstep run buildOne command, the right order, every time. The shared ui package builds first, then web and api. When ui changes its build command, you change it in one place — web and api keep calling the same task.
Don't remember the task name?
Thirty scripts in a package.json means npm run and squinting. Here you press a key:
orchstep menuA fuzzy task picker with single-key hotkeys lists every package task. New teammates discover the whole build surface without reading a wiki — and because the picker refuses to hang in a pipeline, the same tasks are safe to call from CI.
What you actually gained
| Concern | thirty package.json scripts | OrchStep |
|---|---|---|
| Build order | memorized && chain | ordered task: calls |
| Reuse | copy the command string | call the package task |
| One entry point | a build script that lists all | a build task that calls each |
| Discoverability | npm run and guess | orchstep menu |
| Per-package run | npm run build:web | orchstep run web |
This doesn't replace pnpm, turbo, or your bundler — they still do the building. OrchStep gives the orchestration a shape, so the build graph is something you read instead of something you memorize. If turbo run build with a tuned pipeline already does this for you, keep it. When your orchestration is a wall of &&, this is the upgrade.
Where to go next
- Quick Start — your first workflow in two minutes
- Variables & Outputs — sharing data across tasks
- Error Handling — what happens when one package fails
Got a package.json with thirty scripts and a memorized build order? Give the monorepo one entry point and let the task calls hold the graph.
curl -fsSL https://orchstep.dev/install.sh | sh