DEV Community

Cover image for Husky vs Jenkins vs Ansible: When to Use Which for CI/CD?
Dinesh Wijethunga
Dinesh Wijethunga

Posted on Originally published at dineshstack.com

Husky vs Jenkins vs Ansible: When to Use Which for CI/CD?

In this guide, we will cover everything you need to know about choosing between Husky, Jenkins and Ansible for a Laravel CI/CD pipeline — and why the real answer is a layered setup, not a single winner.

I recently built the full pipeline for a production Laravel 12 + React (Inertia) multi-tenant SaaS running on a single Ubuntu VPS. This series documents that build step by step, including everything that broke along the way. But before touching a terminal, we had to answer the question every team hits: which tool?

The trap: these are not competing tools

The comparison is a category error, and understanding why is the whole decision:

Tool Where it runs What it's for When it fires
Husky Developer's machine Git-hook checks (lint, quick tests) Before commit / push
Jenkins Your server Pipelines: test → build → deploy After push
Ansible Your machine → many servers Server configuration management When you provision servers

Husky cannot deploy. Jenkins cannot stop a bad commit from being created. Ansible does neither — it makes servers identical.

The layered architecture we chose

Developer Mac
 ├─ pre-commit (Husky): Laravel Pint on staged files only  → ~1s
 ├─ pre-push  (Husky): JS test suite + pint --test         → ~5s
 ▼ git push
Jenkins on the VPS
 ├─ Lint → PHP tests (full suite) → Vite build → JS tests
 ├─ Package artifact → deploy to STAGING → smoke test
 ├─ Manual approval gate
 └─ Deploy to PRODUCTION → health check → auto-rollback on failure

Two principles drive this:

  1. Fast checks live locally, slow checks live on the server. A pre-commit hook that takes 30 seconds gets bypassed with --no-verify within a week — I've watched it happen on every team. Pint on staged files takes about a second; the full PHPUnit suite (340+ tests against MySQL) belongs in Jenkins where nobody is waiting with their fingers on the keyboard.
  2. The server is the source of truth. Husky is a courtesy that keeps embarrassing commits out of history. Jenkins is the enforcement layer — it runs the suite you can't skip.

Why Jenkins over GitHub Actions?

Fair question, and for many teams Actions is the right call. We picked Jenkins because:

  • The VPS had spare capacity (31 GB RAM) — self-hosted CI costs nothing extra, and there are no per-minute charges for a 340-test suite that runs on every push.
  • The deploy target is the CI machine. No SSH-from-cloud-runner complexity, no secrets leaving the box.
  • Existing Jenkins experience on the team. The best tool is frequently the one you already know how to debug at 1 a.m.

Why we skipped Ansible

One VPS. Ansible's payoff is "make 10 servers identical" — with a single server, a version-controlled runbook (every command we ran, committed to the repo in docs/) gives the reproducibility without the abstraction tax. If we grow to multiple app servers, that runbook becomes the Ansible playbook spec.

Decision rule you can steal: Husky always (it's a 10-minute setup, post #2). Jenkins or Actions for CI — Jenkins if you own idle hardware, Actions if you don't. Ansible only at 3+ servers.

What's next in the series

Post #2 sets up Husky properly for a Laravel + React repo — including the trick that runs Pint only on staged files and re-stages the fixes automatically, and why the full PHP suite deliberately stays out of the hooks.

This series documents a real production build. The domains and IPs are anonymised; the mistakes are not.


Originally published at dineshstack.com — read the full version with code samples and updates there.

Top comments (0)