Pilum vs. CI/CD Pipelines
The most common misreading of Pilum is “a niche alternative to GitHub Actions.” It isn’t one. CI/CD platforms and Pilum answer different questions:
- CI/CD answers: when should things happen (on push, on merge, on tag), with what secrets, recorded where.
- Pilum answers: what does “deploy” actually mean for these fifteen services — in what order, in parallel with what, to which providers.
You keep your CI. Pilum replaces the part of it you were maintaining by hand.
The glue-code problem
Most pipelines that deploy containers contain a stretch of bash that everyone is afraid of: build the image, compute the tag, push it, then thread that tag into whatever deploys — sed into a manifest, -var into Terraform, an output variable into the next job. Multiply by every service, times every environment.
That stretch of bash is what Pilum replaces:
- name: Deploy all changed services run: pilum deploy --tag=${{ github.sha }} --only-changed --since=${{ github.event.before }} --github-status env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}One step. Pilum discovers services via pilum.yaml files, validates them against recipes, fills shared build caches once, builds in parallel waves that respect depends_on, pushes, deploys each service to its provider, and (with --github-status) posts a commit status back to GitHub. The recipe is declarative YAML — there is no per-service pipeline to copy-paste and drift.
A full GitHub Actions workflow, including the official SID-Technologies/pilum-action, credentials and cache restore, is in Environments & CI.
What about reusable workflows?
GitHub Actions reusable workflows and GitLab CI templates are the right way to standardize pipeline structure — and if yours already pass image tags into your IaC cleanly, you may not need Pilum at all (we say so plainly in When to Use Pilum).
The differences that matter when you’re deciding:
| Reusable workflows / CI templates | Pilum | |
|---|---|---|
| Runs locally, identically to CI | No — pipelines run on the platform | Yes — same recipe, same command, laptop or runner |
| Multi-provider in one pass (Cloud Run + Lambda + Pages + npm + Homebrew) | One job per target, wired manually | Service discovery + parallel waves, one command |
| Cross-service dependency ordering | Job needs: graphs, maintained by hand | Declared per service via depends_on |
| Deploy only what changed in a monorepo | Path filters per pipeline, kept in sync with imports by hand | Git-aware filtering built in (--only-changed): follows Go imports, lockfiles, Dockerfile templates and depends_on |
| Undo a bad deploy | Re-run an old pipeline, or provider console | pilum rollback (GCP Cloud Run, jobs, MIGs), same command locally or in CI |
| Platform lock-in | Tied to GitHub/GitLab syntax | Portable CLI; --dry-run shows the exact commands |
| Scheduling, secrets, audit history | Yes — this is what CI is for | No — bring your CI |
The local-parity row is the one teams feel daily: with Pilum, “test the deploy” doesn’t require pushing a commit and watching a runner. The exact production deploy loop runs from your machine with --dry-run to preview and without it to ship.
Where the boundary sits
Keep in CI: triggers, secrets management, approvals, audit history, notifications.
Move into Pilum: build → push → deploy orchestration, service discovery, ordering, provider specifics, environment overrides (--env), rollback.
Pilum’s deployment lock (.pilum/deploy.lock) only guards a single checkout, so keep using your CI’s concurrency controls (for example a GitHub Actions concurrency group) to stop two runners deploying at once.
If you’re evaluating whether that trade is worth a new tool in your stack, start with the decision test in When to Use Pilum — it includes the cases where the answer is no.