GitLab CI is a built-in continuous integration and delivery system in GitLab that automates building, testing, and deployment of mobile applications through YAML-configured pipelines. According to GitLab, 2024, the platform processes over 300 million pipelines monthly and supports both cloud and self-hosted runners.
Key Takeaways
GitLab CI is part of the unified DevSecOps GitLab application, encompassing continuous integration, delivery, and deployment. The system started as a separate project in 2012 but was later integrated directly into GitLab. The core principle is configuration as code via a .gitlab-ci.yml file in the repository root. GitLab CI is available both as a cloud SaaS version and as a self-managed installation.
For mobile development, GitLab CI offers automation of APK and IPA builds, running instrumented tests, static code analysis, app signing, and store publishing. The platform supports Docker images for custom environments, allowing pre-installation of Android SDK, NDK, Xcode, and other tools. The built-in Container Registry simplifies storing and distributing images within the team.
GitLab CI architecture consists of three key components. GitLab Runner is an agent that executes jobs. Runners can be shared (provided by GitLab), group (for a group of projects), or specific (for one project). Each runner is registered with an executor: Shell, Docker, Kubernetes, or VirtualBox. GitLab Runner supports auto-scaling to handle peak loads.
A pipeline is a set of stages executed sequentially. Within a single stage, jobs run in parallel. A typical structure for a mobile project is: build → test → deploy. If a job in the test stage fails, deploy is not triggered. Manual triggers (when: manual) can be configured for deployment. Multi-project pipeline triggers are also supported for complex CI/CD scenarios across repositories.
Docker executor is the most popular for mobile app CI/CD. Each job runs in a clean Docker container, ensuring isolation and reproducibility. For Android builds, the android-sdk image with pre-installed SDK is used; for iOS, a macOS runner with Shell executor is used.
The .gitlab-ci.yml file defines a pipeline in YAML format. Key sections include: image (Docker image), stages (list of stages), variables (environment variables), before_script (commands before each job), and jobs with script, artifacts, cache sections. GitLab CI supports include — enabling external YAML files for reusing common configurations across projects.
Variables in GitLab CI can be set at multiple levels: globally in the UI, in the config file, in group and project settings. Variable priority follows a hierarchy: trigger variables have the highest priority, followed by CI/CD variables from the UI, then from .gitlab-ci.yml. Variables can be protected, making them accessible only to protected branches and tags.
image: openjdk:17-jdk-slim
variables:
ANDROID_SDK_VERSION: "35"
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
stages:
- build
- test
- deploy
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .gradle/
The generate-apk job builds a Gradle project and saves the APK as an artifact. Artifacts are passed between stages — a deploy job can use the APK from the build stage. Artifact retention is configured via expire_in.
generate-apk:
stage: build
script:
- ./gradlew assembleRelease
artifacts:
paths:
- app/build/outputs/apk/release/
expire_in: 1 day
When choosing between GitLab CI and GitHub Actions for a mobile project, team infrastructure is a key factor. GitLab CI provides a built-in Container Registry for storing Docker images with Android SDK. GitHub Actions relies on GitHub Packages or external registries. GitLab also has built-in SAST (Static Application Security Testing) for code vulnerability analysis.
GitLab CI offers a more flexible runner model — it supports Kubernetes executor, auto-scaling, and custom images. GitHub Actions wins in GitHub ecosystem integration and its action marketplace. GitLab CI requires more manual configuration for many tasks that GitHub Actions solves with ready-made actions.
From a mobile CI/CD perspective: GitLab CI is better suited for companies already using GitLab Self-Managed and requiring self-hosted runners with Docker/Kubernetes. GitHub Actions is more convenient for small teams on cloud GitHub who value ready-made actions and ease of setup.
| Feature | GitLab CI | GitHub Actions |
|---|---|---|
| Configuration | .gitlab-ci.yml | .github/workflows/*.yml |
| Runner | Self-hosted + shared | Hosted + self-hosted |
| Executors | Docker, K8s, Shell | VM (Ubuntu, macOS, Win) |
| Action Marketplace | No (CI templates) | Marketplace (15k+ actions) |
| iOS Build | macOS runner or K8s | macOS hosted runner |
A complete Android pipeline includes: lint, unit test, build, and deploy to Firebase App Distribution. The pipeline uses a Docker image with Android SDK, Gradle caching, and parallel execution of lint and test in the same stage. This approach reduces overall pipeline time since lint and test tasks are independent of each other.
For iOS projects, the pipeline structure differs due to the need for a macOS runner and code signing. A typical iOS pipeline includes: installing CocoaPods or SPM, running simulator tests, archiving the Xcode project, exporting IPA, and uploading to TestFlight. GitLab CI for iOS uses macOS runners — either GitLab SaaS macOS runners with time limits or a self-hosted runner on a Mac Mini or MacStadium.
image: androidsdk/android-35:latest
stages:
- lint
- test
- build
- deploy
lint-check:
stage: lint
script: ./gradlew lint
unit-tests:
stage: test
script: ./gradlew test
assemble-release:
stage: build
script: ./gradlew assembleRelease
artifacts:
paths: [app/build/outputs/apk/release/]
deploy-firebase:
stage: deploy
script:
- firebase appdistribution:distribute
--app $FIREBASE_APP_ID
--token $FIREBASE_TOKEN
--groups testers
Optimizing mobile build pipelines in GitLab CI requires attention to detail. Proper configuration of cache and artifacts can reduce build time several times over. For performance analysis, GitLab provides CI/CD Analytics — a dashboard with pipeline duration metrics, runner load, and bottlenecks. Analyze these metrics regularly to find optimization opportunities. Configuring resource_group blocks parallel pipeline runs — useful for preventing deployment conflicts.
Branch strategy for CI is also important. It is recommended to run the full pipeline only for main and release branches, and for feature branches — only lint and unit tests. This saves runner minutes and speeds up developer feedback. GitLab CI supports workflow:rules — conditional rules for including or excluding jobs based on branch, changed files, or environment variables.
Dependency caching is the primary acceleration method. GitLab CI caches .gradle, Pods, and node_modules between runs. The cache key includes $CI_COMMIT_REF_SLUG or a lock-file hash. Android project build time drops from 10–15 to 2–4 minutes with proper caching. Cache can be distributed — GitLab supports cache:key with fallback to previous keys.
A Docker image with pre-installed tools saves installation time. It is recommended to create a custom image with Android SDK, NDK, and the required API level. Parallel job execution (lint, test, assemble) in different stages reduces overall pipeline time. Pull policies for images (if-not-present) speed up job starts. A dependency proxy can also be used for caching images at the GitLab instance level.
Another important optimization aspect is using artifacts between stages. Heavy files like APK and IPA should be passed through dependency rather than rebuilt in each job. For large projects with dozens of modules, it is recommended to enable Gradle Build Cache at the pipeline level and configure a remote cache on shared storage. Timeout for each job should be set based on expected build time — this prevents hanging processes.
cache:
key: $CI_COMMIT_REF_SLUG
paths:
- .gradle/
- app/build/
image:
name: registry.example.com/android-builder:3.5
pull_policy: if-not-present
Frequently Asked Questions
On GitLab.com, the free plan includes 400 CI/CD minutes per month and 5 users. Premium ($29/month) provides 10,000 minutes and more parallel jobs. Self-managed GitLab has no minute limits.
Use the ready-made Docker image androidsdk/android-35 or install the SDK via sdkmanager in before_script. In variables, specify ANDROID_SDK_ROOT and ANDROID_NDK_HOME for correct Gradle operation.
GitLab CI offers a built-in Container Registry, Kubernetes integration, and self-hosted auto-scaling. GitHub Actions wins in the number of ready-made actions and simplicity for small teams.
Yes, but iOS requires a macOS runner. You can use GitLab SaaS macOS runners (limited) or set up a self-hosted runner on a Mac Mini. GitLab does not provide cloud macOS infrastructure itself.
Through artifacts — files from one job are passed to another job within a pipeline. Through cache — for dependencies between runs. Through CI/CD variables — for string values and tokens.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also