Context
I need a Continuous Integration and Continuous Deployment (CI/CD) system to automate testing, linting, and deployment. For a personal project, the priority is zero-maintenance, zero-cost (for public repos), and tight integration.
I have previous experience with several alternatives:
- Semaphore CI: Found it functional but often too restrictive and opinionated in its pipeline definition compared to modern flexible workflows
- Bitbucket Pipelines: I liked the "Docker-container-per-step" model, which ensured a clean environment for every command. However, it is vendor-locked to Bitbucket, and this project is hosted on GitHub to maximize visibility ("Build in Public")
Other potential alternatives include CircleCI, which is a robust option but requires setting up a separate platform and managing separate users/billing.
I need a solution that minimizes administrative overhead ("Minimize Platforms") while maintaining local reproducibility.
Decision
I decided to use GitHub Actions.
This aligns with:
- Minimize Platforms: The CI is the platform. Code, issues, PRs, and builds live in a single URL namespace. There is no "go to the CI dashboard" step—the logs are right in the Pull Request
- Mise Integration: Instead of relying on a complex web of third-party Actions (vendor lock-in), I use Mise to strictly define the toolchain. The CI workflow becomes a thin wrapper:
mise install && mise run ci. This ensures that what runs in CI is exactly what runs on my laptop - Cost Efficiency: It is completely free for public repositories
- Escape Hatches: The workflow syntax allows for plugging in alternative runners. If I encounter performance bottlenecks or cost issues (on private repos), I can swap the default runners for Blacksmith (faster/cheaper runners) or offload Docker builds to Depot without rewriting the pipeline logic
- Good Enough: It is not the most powerful CI in the world, but it is "good enough" for the current scale. The investment in
miseensures that if I hit the scaling limits, migrating to CircleCI or others is trivial
Consequences
Pros
- Identity Federation: supports OIDC (OpenID Connect) natively, allowing me to authenticate with AWS/GCP/Cloudflare without managing long-lived static secret keys
- Community Support: Every issue I encounter has likely been solved and documented widely due to the massive user base
Cons
- Debuggability: Logic in YAML is brittle. Tools like
actclaim to allow local testing of workflows, but in practice, they often fail to reproduce complex environment or networking issues. By leaning onmise, I mitigate this—if a script fails in CI, I can run the script locally, but debugging the workflow YAML itself remains a slow "commit-push-fail-repeat" cycle - Scalability & Analysis: GitHub Actions lacks deep insights into test flakiness or historical run times compared to dedicated platforms like CircleCI. It creates a "wall of text" logs that are hard to search
- Vendor Lock-in: The workflow syntax (
.github/workflows/*.yml) is proprietary. Migrating to GitLab CI would require a rewrite of the pipeline wrapper (though the underlyingmisetasks would remain portable) - Docker Handling: While robust, it doesn't default to the "clean container per step" model as aggressively as Bitbucket Pipelines, sometimes leading to state pollution in the runner workspace if not careful