A Real GitLab + Runner

The thorough approach to local CI is to stop faking anything: run GitLab in Docker, register a runner against it, push your project to it, and watch real pipelines. Some teams already have a staging instance and use it this way.

It is not a bad instinct, and it gives you both kinds of fidelity, real execution and a real server, which is what glci is chasing too. The catch is the cost, and that most of what it buys is what you already had.

You still have to push#

This is the part that decides the comparison, and it is easy to miss while planning the setup. A local GitLab reproduces the platform. It does nothing about the loop. To run a job you still commit, still push to a remote, still wait for pipeline creation, runner pickup, container provisioning, image pull, and clone. You have removed queue time and network latency and kept everything else.

The workflow properties that make local CI worth having are absent too:

A warm glci daemon does the opposite: glci run test:unit --watch re-runs one job against a working tree you have not committed, and glci show --context tag=v1.0 answers the tag question without a tag existing.

The instance is heavy#

GitLab’s own installation requirements put the baseline for a single-node install at 8 vCPU and 16 GB of RAM, with 8 GB described as the memory-constrained floor. That is Puma, Sidekiq, Gitaly, PostgreSQL, Redis, Workhorse, and Registry, all running so that you can find out whether your before_script has a typo. Boot is minutes rather than seconds, and it competes for RAM with the containers your jobs need.

glci’s resident footprint is a mock server container and one runner container, and its cold start is dominated by pulling the runner image once.

It drifts from your real instance anyway#

The less obvious failure is that a local GitLab is not your GitLab. To make pipelines behave the same you would have to mirror, and keep mirroring:

Every one of those is a drift source that produces false confidence, which is worse than no local testing because you will trust it. glci instead reads your real project’s variables from your real instance over the API, with no mirroring, and resolves variable precedence the way GitLab resolves it.

If you already maintain a staging instance for other reasons, this calculus is friendlier: the drift is someone’s job and the cost is already sunk. If you were about to stand one up for CI testing, you are taking on an ongoing maintenance obligation to shorten a loop it does not shorten.

Where a real instance is the right answer#

Some questions genuinely require one, and glci will not pretend otherwise:

These two tools are not really competing. A staging instance answers questions about your platform; glci answers questions about your pipeline. Most days the question is about the pipeline, and it is worth being able to ask it in a second rather than an afternoon.

Esc