Create your FREE Codefresh account and start making pipelines fast. Create Account

Codefresh vs. GitlabCI

13 min read

If you have selected Gitlab as your git provider, you may automatically think about selecting GitlabCI as your CI/CD solution as well. Using the same vendor for source control and CI/CD might seem natural, but is not always the best combination. In fact, choosing a “good-enough” option just because it is part of the same solution is unwise in the long run if it doesn’t cover your needs.

Gitlab is one of the supported GIT providers in Codefresh, so another valid combination is using Gitlab for source control and Codefresh for CI/CD. In this article, we will look at the advantages of Codefresh compared to the GitlabCI platform.

Update: See Gitlab’s response to this comparison here

Content was updated as both products changed since initial writing

Table of contents

  1. Codefresh is GIT agnostic, GitlabCI has native support only for its own repos
  2. Codefresh allows you to create multiple pipelines per repo, while GitlabCI is constrained to just one
  3. Docker builds are much faster with Codefresh
  4. GitlabCI needs special configuration to share information between pipeline phases
  5. The Docker registry in Codefresh is fully automated
  6. The Docker registry in Codefresh is much more detailed
  7. Codefresh has explicit support for Kubernetes deployments
  8. Codefresh has explicit support for Helm deployments

Codefresh is GIT agnostic, GitlabCI is not

This is probably the biggest difference between Codefresh and GitlabCI. Codefresh has native support for all popular Git providers such as Github, Gitlab, Bitbucket, Azure Devops Git, Atlassian Stash and can work with both cloud and hosted variants of them. All Git providers enjoy equal support in Codefresh and all features (git triggers, monorepo changes, checkouts, webhooks etc) work in a similar manner.

Codefresh Git support
Codefresh Git support

GitlabCI has native support only for Gitlab repositories. If your source code is located somewhere else you need to import it into Gitlab, basically creating a second copy. Specifically for Github, there is also partial support for “mirroring” where a second clone of your git repository is placed into Gitlab and all upstream changes are automatically synced. But the communication is one way. If you make changes into Gitlab they won’t be synced back to Github. The process is very cumbersome as essentially you have two repos to manage and they can easily suffer from drift issues.

At the time of writing there is a whole epic open (with 10+ issues), so at least Gitlab is aware of this limitation. But until this epic is implemented Codefresh is the only viable solution if you work in an organization that is using multiple GIT providers.

We find that several companies want to use other Git providers apart from Gitlab, so Codefresh has a major advantage on the topic of GIT support.

Codefresh allows you to create multiple pipelines per repo, while GitlabCI is constrained to just one

This was another big revelation during my time with GitlabCI. In GitlabCI you can only define a single pipeline per project. That’s it! There is no way to add more pipelines. In the screenshot below, you can see there is really only one “Run Pipeline” button:

Only one pipeline
Only one pipeline

A nontrivial application will need more than one pipeline. A common set of pipelines would be:

  • A pipeline that runs on every commit that packages code and probably creates a Docker image.
  • A pipeline the deploys to an environment (e.g. prod or staging).
  • A pipeline that runs load testing against a specific environment.
  • A pipeline for pull requests that might run code quality or other security tools.
  • A weekly build for cleanups or maintenance actions.

GitlabCI offers the capability to have conditionals in a pipeline, so in theory, you could create a really huge pipeline that acts as a superset of all the things that you might ever need. But this is not ideal, and there is even an issue that has been open since 2016 for this particular problem.

Codefresh does not suffer from such limitations. Even though Codefresh also allows you to define pipeline conditionals, you are still free to define multiple pipelines for every workflow imaginable.

Multiple pipelines in Codefresh
Multiple pipelines in Codefresh

In a similar manner, the git trigger capabilities in Codefresh can cover all webhook events sent by the git provider resulting in pipelines that can run against specific git events. This can be done right from the GUI with no special configuration in the build yaml file.

Codefresh git triggers
Codefresh git triggers

This limitation of GitlabCI essentially forces you into having a huge gitab-ci.yml file with multiple conditional steps that select the “proper” workflow when an event is triggering the pipeline. For a really really complex workflow, this can quickly get out of hand.

Codefresh also supports parent/child relationships which GitlabCI currently does not.

Docker builds are much faster with Codefresh

Codefresh has several types of built-in caching and two of them are actually specific to Docker builds.

One of the most powerful Codefresh features is the zero-configuration distributed docker layer cache. All Codefresh build nodes share it which means that all subsequent builds will use the previously cached layers. It works exactly as you would expect from the Docker layer cache in your local workstation:

Docker cache in Codefresh
Docker cache in Codefresh

This cache is completely automatic. There is nothing to setup or configure. It works in all versions of Codefresh (even the SAAS one). GitlabCI has no such cache and no matter how many times you build a docker images, it will rebuild everything from scratch. This means that Docker builds are very slow in GitlabCI and depending on the size of your images (and number of layers) the amount of time you lose by waiting for builds can become a bottleneck.

Here is an actual example where the same project is packaged with Codefresh and GitlabCI without actually changing anything.

GitlabCI has no Docker cache
GitlabCI has no Docker cache

Codefresh is very fast because the second type of cache has kicked-in and has detected that this Docker image is already built.

Codefresh detects an existing Docker image
Codefresh detects an existing Docker image

At the time of writing there is an open issue for Docker cache in GitlabCI. But as things are now, just by building a project with Codefresh you will get much faster builds.

GitlabCI needs special configuration to share information between pipeline phases

The pipeline phases in GitlabCI are called “jobs” (in Codefresh they are called “steps”). These run in a completely independent manner so everything that needs to be shared between pipeline phases must be defined explicitly.

To accomplish this, GitlabCI introduces a special syntax for two different concepts: artifacts and caching.

If you need to transfer something from one phase to another you need to explicitly define it as cache. For example, let’s say you have two GitlabCI jobs that both use node modules. Unless you define the folder as cache, both of them will re-download everything.

The correct syntax in GitlabCI would be:

If you wish to just move things from one job to another you are expected to use artifacts. For example, if you create a jar file in one job and expect to find it in the next one, you first need to add the following to your GitlabCI file:

The distinction between caching and artifacts is not always very clear, forcing even the official documentation to offer advice on best practices for what to consider cache and what to consider an artifact.

So how does Codefresh deal with this issue?

In Codefresh, in order to transfer information from one step to the other, you do (drumroll please)….absolutely nothing. In Codefresh all pipeline phases share a common volume (which includes the code of your project). So everything that is created in the project folder is automatically available to the next phase.

Shared Codefresh volume
Shared Codefresh volume

This means that you don’t need to do anything special to cache node modules. In Codefresh yml the same thing would be:

The same goes for “artifacts”. There is no need to define something explicitly for binaries, test reports, or anything else that you wish to be visible to all pipeline steps.

The end result is that Codefresh pipelines are much more compact and readable. You can find more information about Codefresh pipelines in the documentation.

The Docker registry in Codefresh is fully automated

Both Codefresh and GitlabCI offer a built-in Docker registry that can be used for storage of Docker images. The Docker registry offered by GitlabCI acts as any other Docker registry and in order to use it, you have to explicitly call Docker commands in your yml file.

For example, in order to push an image in GitlabCI you need to do the following:

This yml syntax essentially reflects what you would write in locally on your workstation. Codefresh offers much better support for its own internal registry.

In order to push your image to the Codefresh registry you do (drumroll please)….absolutely nothing. By default, all your Docker images that are produced by your builds are automatically pushed to the internal registry. You don’t add anything in your yml file to enable this functionality.

Codefresh Registry
Codefresh Registry

And before you ask about wasted space, know the Codefresh pricing is independent of the number of Docker images you have, so don’t worry about overusing the internal registry. As we will also see in the next section, it is very easy to locate images even when their number is very big.

If you want to use an external registry, Codefresh helps you even further by allowing you to declare all your registries at your account level (including authentication details).

Adding a Docker Registry
Adding a Docker Registry

Once you want to use an external registry you only need a push step:

Notice the complete lack of login instructions in Codefresh. You only define the registry name as it was defined in the GUI. With GitlabCI you would need to replicate the Docker login commands as before.

In summary, working with the integrated Docker registry is completely automatic with Codefresh, while GitlabCI needs the exact push instructions.

The Docker registry in Codefresh is much more detailed

We have seen in the previous section how easy it is to use the Codefresh internal registry and talked about the yml syntax for each platform. Once you have many images in your Docker registry you need a way to find them and catalog them.

The GUI view of the registry in GitlabCI is very sparse:

GitlabCI registry
GitlabCI registry

You only see the tag, the size, and the date of the image. There is no other option available (which might make sense as we have already seen that the registry in GitlabCI is tied to a single project).

Codefresh, on the other hand, gives you several more options. As a starting point, you can narrow down your view using multiple filters

Image filtering
Image filtering

You can also do an analysis of the layers of each image to gain insights of the size:

Docker layers
Docker layers

And most importantly of all, you can annotate your Docker images with your own metadata. For example, you can mark images that have passed security scans, or code quality gates, or load testing approval. The metadata can be added either directly from the GUI or via the pipeline syntax.

Docker annotations
Docker annotations

This makes the Codefresh Registry very powerful, making it a central source of truth for developers, QA, operations and any other stakeholder of a project.

In summary, the integrated GitlabCI registry lacks a lot of features offered by the Codefresh version.

Codefresh has explicit support for Kubernetes deployments

Easy Kubernetes integration is one of the major features behind the development of Codefresh. Kubernetes support is one of the highlights of Codefresh functionality.

When you define a Kubernetes cluster in Codefresh, you get access to two major features: First, you have a built-in Kubernetes dashboard that shows you namespaces/pods and deployments:

Kubernetes Dashboard
Kubernetes Dashboard

Second, Codefresh allows you to deploy a Kubernetes service with just the GUI, which is a great way to quickly deploy demo apps.

Deploy on Kubernetes
Deploy on Kubernetes

In vanilla GitlabCI there is no such thing. Apart from the deploy boards, there is no other GUI that can help you with your first steps in Kubernetes management.

Codefresh has explicit support for Helm deployments

Helm is a package manager for Kubernetes that allows you to group multiple application into charts.

GitlabCI has some basic support for Helm. It allows you to easily install Helm on your Kubernetes cluster (i.e. the server component called Tiller).

Install Tiller
Install Tiller

Once Tiller has installed it is also very easy to use Helm to install packages.

Codefresh, on the other hand, takes Helm integration to the next level by providing:

  • an integrated Helm repository for all accounts,
  • a graphical app browser that can access both the internal and external helm repos,
  • and a Helm dashboard for monitoring deployments and even rolling them back.

None of these is offered by GitlabCI and having an internal Helm repository is really crucial for using Helm in the first place (as the built-in Docker registry is useful for Docker images).

Codefresh gives you a built-in Helm repository that you can use for your own charts. You can also connect other chart repositories and create an application catalog.

Helm Repository
Helm Repository

Once you install a Helm chart in your Kubernetes cluster you have full visibility on version history, active services, chart values, etc.

Helm Releases
Helm Releases

However, the most impressive capability is that you can rollback a version right from the GUI. And in this case, rollback means the Helm rollback (i.e. going to a previous version of the chart).

Helm Rollback
Helm Rollback

In summary, Helm support in Codefresh is much more extensive than GitlabCI and the presence of a built-in Helm repo and dashboard are very important factors for using Helm as part of the CI/CD process.

Autodevops is a hit-and-miss feature

In the first version of this comparison I didn’t say anything about the Auto-devops feature of GitlabCI. The reason was that I consider this feature experimental and it would not make sense to comment on its stability.

However, seeing how GitlabCI uses it as a direct discussion point on its own comparison page I couldn’t resist on reviewing it as well. I tried autodevops on 3 sample projects (Java, Python, Ruby on Rails) and it worked only on the Java project.

In the Python project it failed to find any tests (even thought the repository has unit tests).

Autodevops fails with a Python repo example
Autodevops fails with a Python repo example

It turns out that Auto-devops is based on the same ideas as Heroku buildpacks, which are good for starter projects, but cannot work in all possible cases.
In my Ruby project I got a completely different error:

Autodevops fails with a Ruby project example
Autodevops fails with a Ruby project example

Now of course I could track down these errors and try to fix them, but that would beat the whole purpose of “autodevops”. People that know enough to fix those kind of errors can also create their own pipelines manually.

It is also interesting to note that in the past Codefresh had its own “autodevops” feature. We tried as well to detect the kind of source code contained in a repository and tried to suggest a pipeline. But it didn’t work as reliably as we wanted and we scrapped this feature in order to avoid giving false information to our customers.

So while Auto-devops is a very nice idea, in practice it is so unpredictable that I wouldn’t consider it an advantage of GitlabCI over any other CI platform.


In summary, Codefresh is a solution designed specifically for microservices and containers, while GitlabCI is a generic platform where Docker support is an afterthought and Helm support is in its infancy. If you have already switched to Docker/Kubernetes and especially Helm, Codefresh brings much more value to the table.

At the time of writing the major advantages of GitlabCI over Codefresh are the built-in NPM and Maven registries and the capacity to define artifacts in a pipeline.

Update: See Gitlab’s response to this comparison here

Feature GitlabCI Codefresh
Native support for Gitlab GIT repos Yes Yes
Native support for Github, Bitbucket, Azure Git No (Open epic) Yes
Distributed docker layer cache No (Open issue) Yes
Distributed Docker Image cache No Yes
Pipelines per project 1 Unlimited
Parent/Child pipelines No (Open issue) Yes
First-class Docker support No (Open issue) Yes
Instance level Docker registry No (Open issue) Yes
Build caching Manual Automatic
Parallel pipeline stages No (Open issue) Yes
Built-in Helm chart repo No (Vision) Yes
Helm release dashboard No Yes
Helm deployment dashboard No Yes
Helm environment dashboard No Yes
Live pipeline debugging No Yes
Built-in NPM registry Yes No
Built-in Maven registry Yes No
Artifact Download support Yes No
Kubernetes dashboard Yes Yes
Monorepo support Yes Yes
Preview environments Yes Yes
Comprehensive API Yes Yes
Serverless support Yes Yes

New to Codefresh? Create Your Free Account Today!

Kostis Kapelonis

Kostis Kapelonis

Kostis is a software engineer/technical-writer dual class character. He lives and breathes automation, good testing practices and stress-free deployments with GitOps.

One response to “Codefresh vs. GitlabCI

  1. Romans Malinovskis says:

    Thank you for a great comparison and also linking to GitLab response.

Leave a Reply

* All fields are required. Your email address will not be published.

See how Codefresh helps you
deploy more and fail less!