11 minutes
glci vs gitlab-ci-local: Which Tool Should You Use?
GitLab CI pipelines usually run on a remote GitLab instance. However, a local tool can give faster feedback during development. Two tools are available for this task: glci and gitlab-ci-local.
The tools have a similar purpose, but they use different designs. This difference affects what each tool can verify. In this article, I compare the tools, explain their limitations, and recommend where to use each one.
Versions checked
This comparison uses the latest releases that were available on 15 October 2026. In this article, glci means the experimental project in GitLab’s gitlab-org/ci-cd/runner-tools namespace. It does not mean the older, unrelated project with the same name. See the glci README.
| Tool | Latest release | Release date |
|---|---|---|
glci |
v0.8.0 | 15 September 2026. See the GitLab releases API. |
gitlab-ci-local |
4.76.1 | 7 October 2026. See the GitHub release. |
glci v0.8.0 adds several important functions. These functions include the glci merged command, structured JSON output, more mock Git and submodule support, infrastructure-image overrides, and fixes for rules and the parser. gitlab-ci-local 4.76.1 is mainly a maintenance release. It fixes variable-file validation and nested !reference and extends resolution. See the glci v0.8.0 change log.
This comparison uses the documentation and the released source code. It does not use performance benchmarks or execution tests.
1. The primary difference
glci uses the actual GitLab Runner with a local mock GitLab service. It starts containers that supply the APIs and services that the runner needs. The runner uses its Docker executor to run the jobs. You do not have to install GitLab Runner on the host. See the glci architecture documentation.
gitlab-ci-local implements pipeline parsing, scheduling, and job execution. It does not use GitLab Runner. It can run a job in a container or directly in a local shell. See the gitlab-ci-local job source.
This design difference gives each tool a different advantage:
| What you must verify | Tool with an advantage |
|---|---|
| Does this build or test script work? | Either tool. gitlab-ci-local also supplies direct shell execution. |
| Does this job operate correctly in GitLab Runner? | glci, because the actual runner runs the job. |
| Will GitLab create exactly this pipeline with these rules, permissions, and variables? | Neither tool is authoritative. Both tools replace some GitLab server functions. |
The last point is important. The use of the actual runner does not make glci a local GitLab installation. The glci documentation describes differences in configuration, variable precedence, and simulated contexts. See the glci variables documentation.
2. Capability comparison
Both tools do more than run the script: section of a job. For example, gitlab-ci-local supports component and project includes, inputs, and parallel or matrix jobs. Thus, it is not only a basic script runner. See the gitlab-ci-local include parser.
| Area | glci v0.8.0 |
gitlab-ci-local 4.76.1 |
|---|---|---|
| Execution environments | It uses the Docker executor through the actual GitLab Runner. Docker or Podman can supply the container engine. It does not support a host-shell or Kubernetes executor. See the glci prerequisites. |
It uses its own container execution with Docker or Podman. It also supports direct shell execution. |
| Selected work | It can run complete pipelines, selected jobs, or selected stages. It can also reuse artifacts between runs. See the glci pipeline documentation. |
It can run complete pipelines, selected jobs, or selected stages. Options such as --needs and --only-needs select dependencies. |
| Developer interface | It supplies a terminal user interface, pipeline visualisation, watch mode, run history, and rerun workflows. See the glci README. |
It is mainly a command-line tool. It supplies job lists, expanded YAML through --preview, logs, and execution summaries. |
| Machine-readable output | It supplies structured execution and state data in JSON. It also supplies JUnit reports. See the glci structured-output documentation. |
It supplies job lists in JSON or CSV. These lists are not equal to the structured run events and JUnit run reports from glci. |
| Child and cross-project pipelines | It supports local child pipelines, child configurations from artifacts, and cross-project pipelines. It can map a project to a local repository. See the glci cross-project documentation. |
Child and downstream pipeline support is experimental. Important trigger-include types are not implemented. |
| Container registry workflows | It has an integrated registry with persistent storage, pull-through caching, and optional upstream push-through. See the glci registry documentation. |
It has a --registry option and a Docker-in-Docker build and push example. Registry support is not exclusive to glci. |
| Variables and secrets | It can get instance, group, and project CI variables through the GitLab API. It can also show the origin of a variable. See the glci variables documentation. |
It uses command-line variables and local or scoped variable files. These files can come from Git. It does not automatically import variables from the GitLab API. |
| Uncommitted files | By default, it includes modified files and untracked files that Git does not ignore. The --no-dirty option disables this behaviour. See the glci pipeline documentation. |
Isolated workspaces synchronise tracked files and their local changes. Usually, you must use git add for a new file. You do not have to commit the file. |
Installation and platform support
glci supplies Linux and macOS binaries for AMD64 and ARM64. The v0.8 documentation lists Windows with Podman as a source-build option only. It does not supply a Windows binary. You need Go to build glci from source, but you do not need Go to use a prebuilt binary. See the GitLab releases API.
gitlab-ci-local supplies installation methods for npm or Bun, Homebrew, and standalone binaries. On Windows, its instructions use Git Bash and rsync. On macOS, it requires Bash 4 or later. Node.js is not always necessary because standalone binaries are available. See the gitlab-ci-local README.
3. When to use gitlab-ci-local
Routine local development
I recommend gitlab-ci-local for routine lint, test, build, and job-debug tasks. Its choice of shell or container execution is useful. You can use a container when a job needs isolation. You can use the local shell when the development environment already has the necessary tools.
You can also select one job and its dependencies. Thus, you do not have to run the complete pipeline. See the gitlab-ci-local command source.
A pipeline can contain a build job, unit tests, and a database service for integration tests. This pipeline does not always need glci. gitlab-ci-local supports containers, services, artifacts, and dependency scheduling. First, decide if you must test the exact runner implementation. Do not select a tool only because the pipeline uses Docker. See the gitlab-ci-local job source.
CI jobs as local commands
Direct shell execution is useful when .gitlab-ci.yml also defines local development tasks. However, the host tools, file system, and isolation can differ from the CI environment. The --shell-isolation option gives each job a separate workspace. See the gitlab-ci-local README.
4. Limitations of gitlab-ci-local
It does not use GitLab Runner
A successful local run does not prove that runner-specific behaviour is correct. Open compatibility issues include GIT_STRATEGY, cache:untracked, and the runner’s FF_ENABLE_BASH_EXIT_CODE_CHECK behaviour. I did not reproduce these problems in version 4.76.1. They are findings from the issue tracker. See GitHub issue 1819.
This limitation is important when a failure depends on checkout behaviour, runner-generated shell code, or a runner feature flag. It is less important when you only must test the business logic in a script.
workflow:rules does not give full pipeline-creation fidelity
In the source for version 4.76.1, the parser evaluates workflow:rules. It also merges variables from the matching rule. However, it does not use the result to reject pipeline creation. The execution path then filters jobs with each job-level when value.
From this source, I conclude that the tool supports workflow variables. However, whole-pipeline gating is not equal to GitLab behaviour. Thus, do not use this tool alone to prove that GitLab will never create a pipeline for an event. See the gitlab-ci-local parser source.
Downstream pipelines are incomplete
The current implementation identifies downstream pipelines as experimental. It supports child configurations from local files and generated artifacts. It does not implement trigger:include:project or trigger:include:template, and it gives a warning for these types.
This limitation does not apply to ordinary top-level include:project and include:template entries. The include parser supports those entries. For a large multi-project pipeline, this limitation is a good reason to select glci. See the gitlab-ci-local job source.
Workspace and include caches can cause incorrect conclusions
An isolated job cannot usually see a new untracked file until you add it to Git. A non-isolated shell job can see shared host-workspace data. Also, the tool caches external includes. Use --fetch-includes when you must get new upstream configuration. See the gitlab-ci-local README.
These defaults can cause a difference between a local run and a remote run. The job scripts can be the same while the input files are different.
5. When to use glci
Runner-specific behaviour
I recommend glci when you must investigate GitLab Runner behaviour. The actual runner gets jobs from the mock service. Thus, glci is a better architectural match for problems in runner script handling, services, artifacts, or cache endpoints. You must still use the correct runner version and configuration. See the glci architecture documentation.
Integrated pipeline development
glci is also the better option when you need a terminal user interface, watch mode, saved run history, reusable artifacts, or structured output. Its JSON and JUnit outputs are useful when another program must examine local run results. See the glci pipeline documentation.
Child pipelines and related repositories
glci supports generated child configurations and cross-project pipelines. It can also map another project to a local checkout. This function is useful when you develop related changes in multiple repositories.
This feature is a more important difference than basic Docker builds or registry pushes. Both tools can do those tasks. See the glci cross-project documentation.
Cross-project behaviour still has local-resolution limitations. For example, glci can skip a project include when it does not have a usable token. The remaining configuration can continue without an error. As a result, jobs can be absent without an obvious configuration failure. Check the resolved configuration before you run the pipeline.
6. Limitations of glci
It is experimental and uses more local infrastructure
The project identifies itself as experimental. It needs containers for the runner and mock services. It does not have a simple host-shell mode. Podman is supported, but it must supply a Docker-compatible API socket. This design gives more integrated behaviour, but it also gives you more components to configure and diagnose. See the glci README.
Rule evaluation and job execution can use different variable values
The v0.8 documentation describes an important variable-precedence limitation. During rule evaluation, a supplied high-priority variable can override a job YAML variable. During job execution, the job YAML variable has the final override.
Thus, a rule can use one value while the job script receives a different value. Also, static commands such as glci show, glci jobs, and glci variables do not get API variables. Their results can differ from an actual run. See the glci variables documentation.
A run is not a lint check
The v0.8 documentation gives an important example. glci lint finds invalid non-string entries in a script. glci run does not enforce this diagnostic. It can remove the invalid entry and report a successful job. GitLab rejects this configuration.
Always lint an edited CI configuration before you run it. See the glci troubleshooting documentation.
Simulated contexts and Git history are not exact
By default, glci simulates a merge-request pipeline. It does not simulate a push pipeline by default. Rules and repository history can differ from the data in GitLab. For example, the mock default branch can point to the same synthetic commit as HEAD. This condition gives an empty comparison with the default branch.
Select the correct context when you test context-sensitive rules. See the glci troubleshooting documentation.
Local secrets do not keep all GitLab protection rules
glci can get protected variables without regard to branch protection. Also, the forwarded CI_JOB_TOKEN uses a host token. Its permissions can differ from the permissions of an actual job token.
Use --secrets none when you do not want remote variables. Use --no-token when you do not want token forwarding. See the glci troubleshooting documentation.
7. Performance
There is no universal performance winner. You must measure the tools with your pipeline before you make a speed claim.
The shell mode in gitlab-ci-local does not start a container for a suitable job. This can reduce start time. glci starts more infrastructure, but its daemon and saved state support repeated runs. It does not have to create all components again for each run.
For a pipeline that uses many containers, other factors can have a larger effect. These factors include local images, service start time, build caches, and the set of selected jobs. The difference between shell mode and daemon mode is useful information. It is not proof that one tool is always faster. See the gitlab-ci-local command source.
Summary: which tool is better?
For routine local CI development, I recommend gitlab-ci-local. For runner-specific diagnosis and integrated pipeline orchestration, I recommend glci.
| Primary requirement | Recommended tool |
|---|---|
| Run lint, test, and build jobs with shell or container execution | gitlab-ci-local |
| Use CI jobs as local development commands without containers | gitlab-ci-local |
| Investigate behaviour in the GitLab Runner Docker executor | glci |
| Develop cross-project pipelines | glci |
| Use a terminal user interface, watch mode, or structured run reports | glci |
| Prove exact GitLab pipeline creation, credentials, or deployment behaviour | Neither tool alone |
Start with gitlab-ci-local when you need a flexible tool for routine development. It uses less infrastructure, and it can run jobs in a shell or a container. This recommendation does not mean that it reproduces all GitLab behaviour.
Select glci when actual GitLab Runner execution is a requirement. Its design is a better match for runner-specific problems. However, it is experimental, and its documented configuration and variable differences prevent it from being a complete GitLab replacement.
The final rule is simple: use gitlab-ci-local to run CI work locally, and use glci to investigate how that work operates in GitLab Runner. In both cases, use real GitLab CI for the final validation.