Skip to content

Why zorb?

A short, honest comparison with the things zorb usually replaces. If you're trying to decide whether zorb is worth adding to your project — or whether to leave whatever you've got in place — read this first.

What zorb is

A declarative local workflow runner. You write tasks in zorb.yml. You call them from the CLI. Tasks can shell out, invoke containers, or run JavaScript/TypeScript/Python actions. The same zorb run build runs locally and in CI.

That's it. No event triggers, no remote runners, no marketplace, no DAG, no parallel execution. The scope is deliberately small.

vs. Makefiles

Make is forty years old, ubiquitous, and good at one thing: incremental builds where a file is the unit of work. Pretty much everything else people use it for is a stretch.

ConcernMakezorb
Tab-indentation gotchasYes, eternallyNo — YAML
Shell quoting via $$VARYesNo — env vars are first-class
Typed inputsPositional args, manually parsedinputs: with string/number/boolean
Discoverabilitymake help requires custom wiringzorb list is built in
Cross-platformGNU Make vs BSD Make vs Windows headachesPOSIX-only today, Windows planned
File-based incremental buildsExcellentNot the goal
Calling codeShell onlyShell, Docker, or JS/TS/Python actions

Stick with Make when: the workflow really is "rebuild X when Y is newer than Z." That's what Make was designed for, and it's still better at it than anything else.

Switch to zorb when: the Makefile has grown .PHONY: for half its targets, has stopped using file-mtime tracking in favour of always running, and the team can't remember which underscores are which.

vs. npm scripts (package.json)

The de facto Node project task runner. Cheap to start with, painful at scale.

Concernnpm scriptszorb
Single-line shell stringsYes — and rapidly unreadableBlock scalars (run: |) keep scripts legible
Inputs / parametersPositional CLI args, manually parsedTyped inputs: with defaults
Conditional logicCross-platform pain (sh syntax in cmd.exe)Same pain, but isolated to one step
Compositionnpm run a && npm run buses: ./zorb.a as a step
Cross-language workAwkward (shell out, parse strings)First-class actions
Discoverabilitynpm run lists scriptszorb list lists tasks + required inputs
SpeedNode startup overhead per scriptSingle Bun binary, no per-task startup tax
Dependency on NodeRequires Node on the runnerSelf-contained binary; Node not needed

Stick with npm scripts when: the whole project is one Node package, the scripts fit on one line each, and there are fewer than five of them.

Switch to zorb when: scripts are routinely multi-line, the same shell snippet appears in three places, or a contributor has to read package.json to remember which env var goes with which command.

vs. Just / Justfile

Just is the closest spiritual neighbour to zorb. Both are declarative task runners aimed at replacing Make. Real differences:

ConcernJustzorb
File formatCustom justfile syntaxYAML
Editor supportPlugin-dependentJSON Schema → autocomplete in any LSP-aware editor
Code actionsShell onlyShell, Docker, JS/TS, Python
Cross-file compositionImportsuses: ./other/zorb.<task>
Env isolationInherits caller envStrict, declaration-only
Secret maskingNoneFirst-class (setSecret, *** in output)
Step outputsCapture via shellNative — $ZORB_OUTPUT for shell, return for actions
DistributionStandalone binary, CargoStandalone binary, NPM

Stick with Just when: the team prefers a custom DSL over YAML, the workflow is shell-only, and you don't need typed inputs or code actions.

Switch to zorb when: the workflow needs to call into TypeScript or Python; secrets are part of the picture; or you'd benefit from schema-driven editor autocomplete in zorb.yml.

vs. taskfile.dev (Taskfile.yml)

Taskfile is the other YAML-based task runner in this space. The biggest single difference is scope:

ConcernTask (taskfile.dev)zorb
File formatYAMLYAML
File-based dependenciessources: / generates: with mtime checksNot the goal
Parallel executionYes (deps: runs in parallel)No — sequential, by design
Includesincludes: for namespaced sub-taskfilesuses: ./other/zorb.<task> for call-style refs
Code actionsShell onlyShell, Docker, JS/TS, Python
Env isolationInherits caller envStrict, declaration-only
InputsVariables, untypedTyped inputs: (string/number/boolean)
Step outputsVariable interpolation between tasks$ZORB_OUTPUT (shell) / return value (actions)

Stick with Task when: you want Make-style file-based incremental builds in a YAML wrapper, or you need parallel task execution.

Switch to zorb when: the workflow is more about "named tasks I run from CLI" than "rebuild graph of files"; you want typed inputs; or you want first-class code actions.

vs. GitHub Actions (the awkward conversation)

zorb's syntax is openly cribbed from GitHub Actions — inputs:, ${{ }}, with:, env:, step outputs, the uses: ref pattern. So why isn't zorb just a GitHub Actions local-runner shim?

Because they solve different problems.

ConcernGitHub Actionszorb
Where it runsGitHub-hosted or self-hosted runnersLocal machine
Trigger modelEvents (on: push, on: schedule, etc.)CLI invocation (zorb run <task>)
ParallelismJobs run in parallel; matrix strategiesSequential steps
DAGneeds: between jobsCall-style only (uses: ./zorb.<task>)
MarketplaceHuge action ecosystemSmall (@zorb/* is just emerging)
CostFree tier + paid minutesFree; you own the machine
Speed on a fresh runner10–30s cold startSub-second (single binary)
Iteration loopPush, wait, observeEdit, zorb run, observe
Authoring familiarityIndustry-standardAlmost identical

Use GitHub Actions when: the work is event-driven (PR, push, cron), needs to run on hosted infra, or you want the marketplace + observability stack.

Use zorb when: the work runs on a developer machine or inside a CI job. The signature win is that the same zorb run build you call locally is what CI calls — no two-spec drift, no "works on my machine."

In practice, the pairing is: small .github/workflows/ci.yml that installs zorb and calls zorb run ci. zorb owns the workflow logic. GH Actions owns the trigger and the runner. See Running zorb in CI for the wiring.

When zorb is the wrong tool

Be honest about the cases where you should pick something else:

  • You only have two shell commands. A two-line shell script doesn't need a workflow runner.
  • You need file-based incremental rebuilds. Use Make, Ninja, Bazel, or the build tool your language ecosystem already provides. zorb's "always run" model isn't the right shape.
  • You need to run on Windows today. Windows support is planned but not implemented.
  • You need parallel step execution within a task. zorb steps are sequential by design. If you need fan-out, invoke multiple zorb run from a wrapper script — or use a tool built for parallel execution.
  • You need a DAG with needs:. Same answer. Composition is call-style only.
  • You want a marketplace of off-the-shelf actions. The @zorb/* ecosystem is small. If you'd be pulling from five different community actions tomorrow, that ecosystem isn't there yet.

If two or more of those apply, zorb probably isn't the right tool today.

The short version

Pick zorb when:

  • You have more than three tasks and you'd like them documented as code rather than as a wiki page.
  • Your workflow is mostly shell, mostly Docker, or mostly small bits of TypeScript/Python glue — and you want one declarative file describing all of it.
  • You want CI and local dev to call the same commands. Drift between package.json scripts: and .github/workflows is the problem you're tired of.
  • You want typed inputs, schema-driven editor support, and secret masking out of the box.

Stick with what you have when:

  • Your workflow is genuinely a build graph (file-based, incremental). Make is better.
  • Your workflow is genuinely event-driven (push, schedule, webhook). GH Actions is better.
  • Your workflow is two lines of shell. ./scripts/build.sh is better.

Next steps

MIT licensed