Body
This article describes how to install and configure Gitlab Runners.
In This Article:
Before You Begin
Before creating a runner verify if there are any exiting runners via the GitLab UI.
- Navigate to your project in GitLab.
- From the left hand menu, go to Settings > CI/CD.
- Expand the Runners section.
- If the project has ‘Assigned project runners’, verify that they are not paused. If one is paused, you can resume accepting jobs by clicking the Triangle button to its right.
- If the project has NO ‘Assigned project runners’, but you see a group runner listed, then the group runner gets automatically assigned to the project when you run a pipeline. This should be fine as long as all the projects share the same runner environment and there are no delays due to queuing or resource contention. But in other cases, it is preferable to create a new runner.

Instructions
Step 1: Create and Register a Project Runner
- Navigate to your project in GitLab.
- From the left hand menu, go to Settings > CI/CD.
- Expand the Runners section.
- Click New project runner.
- To run tagged jobs (optional), in the Tags field, enter the job tags separated with a comma.
- For example,
macos, ruby.
- To run untagged jobs, select the Run untagged jobs checkbox.
- In the Maximum job timeout field, enter a value in seconds. The minimum value is 600 seconds (10 minutes). If not defined, the job timeout for the project is used instead.
- Restrict the runner to specific projects.

- Once you create runner, it should give you a page to register the runner.

Unfortunately, you cannot retrieve an existing runner's authentication token from the GitLab UI or API after it has been created. For security reasons, GitLab only displays the token once right after you create the runner.
- On the machine where the runner is installed and registered (as per Step 2), check
/etc/gitlab-runner/config.toml or ~/.gitlab-runner/config.toml and look for the token field under [[runners]]
Step 2: Install the runner and register
- Select your OS (Linux/macOS/Windows). This will generate a registration token and url.
- If you click on 'How do I install GitLab Runner', it will provide the command line instructions. Additionally you can refer to GitLab documentation to install runners
- Register the runner with GitLab (NOTE: the below commands might slightly differ based on the OS of the runner)
sudo gitlab-runner register
# You'll be prompted for:
# - GitLab instance URL
# - Registration token (from the UI)
# - Runner description
# - Tags (comma-separated, optional)
# - Executor (enter "shell" for direct execution)
# After registration, start the runner
sudo gitlab-runner run
- After registration, the runner configuration is stored in
/etc/gitlab-runner/config.toml (Linux) or ~/.gitlab-runner/config.toml (macOS).
- If you're using the GitLab Runner Operator or Helm chart, the token is stored in a Kubernetes secret. Look for secrets containing
runner-token in your namespace.
- Some installations pass the token via environment variables like
RUNNER_TOKEN
Step 3: Create a Project Pipeline
- Create a .gitlab-ci.yml file in root level of your project repository. You can edit the file using Pipeline Editor
- Below is a sample code, but you can refer to this yaml reference
# This file is a template, and might need editing before it works on your project.
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
# it uses echo commands to simulate the pipeline execution.
#
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
# Stages run in sequential order, but jobs within stages run in parallel.
#
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/#stages
#
# You can copy and paste this template into a new `.gitlab-ci.yml` file.
# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
#
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/development/cicd/templates/
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
stages: # List of stages for jobs, and their order of execution
- build
- test
- deploy
build-job: # This job runs in the build stage, which runs first.
stage: build
script:
- echo "Compiling the code..."
- echo "Compile complete."
unit-test-job: # This job runs in the test stage.
stage: test # It only starts when the job in the build stage completes successfully.
script:
- echo "Running unit tests... This will take about 60 seconds."
- sleep 60
- echo "Code coverage is 90%"
lint-test-job: # This job also runs in the test stage.
stage: test # It can run at the same time as unit-test-job (in parallel).
script:
- echo "Linting code... This will take about 10 seconds."
- sleep 10
- echo "No lint issues found."
deploy-job: # This job runs in the deploy stage.
stage: deploy # It only runs when *both* jobs in the test stage complete successfully.
environment: production
script:
- echo "Deploying application..."
- echo "Application successfully deployed."
Step 4: Job Execution Flow
When your runner picks up a job, GitLab follows this execution flow :
Source Preparation
Exports variables to shell context
Executes git fetch with depth=20 (optimized for CI)
Updates submodules if configured
Cache Download
Downloads cached files from previous runs
Artifact Download
Downloads artifacts from dependent jobs
Main Job Execution
Runs before_script commands
Executes main script commands
All scripts run with set -eo pipefail (fails early on errors)
After Script (Always runs, even on failure)
Executes cleanup or notification commands
Cache Upload
Uploads specified paths to cache
Artifact Upload
Saves job artifacts for dependent jobs
Step 5: Trigger a Pipeline
There are several ways to run the jobs defined in your .gitlab-ci.yml file. They range from fully automated triggers based on code changes to manual initiation and external API calls. The method you choose determines the value of the CI_PIPELINE_SOURCE predefined variable, which you can use in your rules to control which jobs run.
| Trigger Type |
CI_PIPELINE_SOURCE value |
Procedure |
Usage |
| Code Push |
push |
The push creates a pipeline, and a runner executes the jobs. |
Running tests, linters, and builds on every commit to get immediate feedback. |
| Merge Request |
merge_request_event |
The MR event creates a pipeline, and a runner executes the jobs. |
Pre-merge validation, such as running a full test suite or checking code coverage only when an MR is opened. |
| scheduled |
schedule |
The schedule creates a pipeline at a specific time, and a runner executes the jobs. |
Regular tasks like cleaning up temporary data, running dependency vulnerability scans, or executing long-running performance tests. |
| Manual (via UI) |
web |
A user clicks "Run pipeline", creating a pipeline, and a runner executes the jobs. |
Deployments to production that require a human to approve and initiate the process, or running a pipeline for a specific branch without making a code change. |
| API Trigger (with Trigger Token) |
trigger |
The API call creates a pipeline, and a runner executes the jobs. |
Integrating GitLab with external automation tools, allowing one microservice's pipeline to trigger another's. |
| Webhook |
webhook |
The external event creates a pipeline, and a runner executes the jobs. |
Triggering pipelines based on non-code events, like running a cleanup job when an issue is closed. |
| Multi-project Pipeline |
pipeline |
For multi-project pipelines created with CI_JOB_TOKEN or the trigger keyword. |
|
- All trigger types are automatically set in
CI_PIPELINE_SOURCE.
- You never need to define this variable in your
.gitlab-ci.yml.
- You only reference it in
rules: or only/except to control job execution.
Examples
- To run a job only for scheduled pipelines
nightly_cleanup:
script: echo "Running nightly cleanup..."
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" # This uses the variable, doesn't define it
- To skip certain jobs for merge request pipelines
deploy_to_prod:
script: echo "Deploying..."
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
when: never # Don't run in MRs
- when: manual # Run manually for other pipeline types
- To trigger a pipeline manually
- Go to your project in GitLab.
- Navigate to Build > Pipelines.
- Click Run pipeline.
- Select the branch and click Run pipeline.
Your runner should now pick up and execute the job. The output will look similar to:
Running with gitlab-runner 18.x.x
on project-runner-18.9.1 TOKEN, system ID: SYSTEM_ID
Preparing the "shell" executor
Using Shell (bash) executor...
Preparing environment
Running on HOSTNAME...
Getting source from Git repository
Fetching changes with git depth set to 20...
Checking out HEAD as detached...
Executing "step_script" stage of the job script
$ echo "Building the project for GitLab 18.9.1"
Building the project
Job succeeded
Tips and Troubleshooting
Handling Timeouts
Defining Timeout Limits
You can define how long a job can run before it times out.
- In the top bar, select Search or go to and find your project.
- Select Settings > CI/CD.
- Expand General pipelines.
- In the Timeout field, enter the number of minutes, or a human-readable value like 2 hours.
The timeout value must be 10 minutes or more, and less than one month. Default is 60 minutes. Pending jobs are dropped after 24 hours of inactivity.
Jobs that exceed the timeout are marked as failed.
When both a project timeout and a runner timeout are set, the lower value takes precedence.
Understanding Maximum Job Timeout
- Example 1 - Runner timeout bigger than project timeout
- You set the maximum_timeout parameter for a runner to 24 hours.
- You set the Maximum job timeout for a project to 2 hours.
- You start a job.
- The job, if running longer, times out after 2 hours.
- Example 2 - Runner timeout not configured
- You remove the maximum_timeout parameter configuration from a runner.
- You set the Maximum job timeout for a project to 2 hours.
- You start a job.
- The job, if running longer, times out after 2 hours.
- Example 3 - Runner timeout smaller than project timeout
- You set the maximum_timeout parameter for a runner to 30 minutes.
- You set the Maximum job timeout for a project to 2 hours.
- You start a job.
- The job, if running longer, times out after 30 minutes.
Working with Tags
Using Tags Effectively
job_specific:
tags:
- docker
- linux
script:
- echo "This job only runs on runners with these tags
Setting Concurrent Jobs
Configuring Concurrency in the config.toml File
# Set maximum concurrent jobs
sudo gitlab-runner start --concurrent=4
# If needed , add environment variables to runner
sudo gitlab-runner run --env "CUSTOM_VAR=v
Handling Missing Tokens
If you've lost the token and can't access the locations above, you have two options:
Option 1: Reset the Runner's Authentication Token (API Method)
You can generate a new authentication token for an existing runner using the API. This invalidates the old token, so the runner will need to be updated with the new one.
bash
# Reset token for a specific runner (requires runner ID)
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/runners/<runner_id>/reset_authentication_token"
The response will include the new token:
json
{ "token": "glrt-xxxxxxxxxxxx", "token_expires_at": null }
Option 2: Create a New Runner
If you can't reset the token or don't know the runner ID:
- Go to Settings > CI/CD > Runners.
- Click New project runner (or group/instance runner).
- Configure it with the same tags and settings.
- Copy the new token immediately.
- Update your runner configuration with the new token.
- Delete the old runner from the UI.
Picking Up Dropped Jobs
If jobs aren't picked up:
- Check runner status: gitlab-runner status.
- Verify registration: Ensure token is correct in config.toml.
- Check tags: Make sure job tags match runner tags.
- Check logs: sudo gitlab-runner --debug run.
Security Notes
- Tokens are stored in
config.toml. Keep this file secure.
- Use project-specific runners for isolated access.
- Regularly update GitLab Runner for security patches.
- To ensure runners don't reveal sensitive information, you can configure them to only run jobs on protected branches, or jobs that have protected tags.
- Runners configured to run jobs on protected branches can optionally run jobs in merge request pipelines.
- In the top bar, select Search or go to and find your project.
- Select Settings > CI/CD.
- Expand Runners.
- To the right of the runner you want to protect, select Edit (pencil icon).
- Select the Protected checkbox.
- Select Save changes.
Upgrading Runners
For a stable and fully functional CI/CD setup, install the version of the GitLab Runner that matches the major version of your GitLab server. This means:
- GitLab 17.x → Use the latest GitLab Runner 17.x
- GitLab 18.x → Use the latest GitLab Runner 18.x
You can get the Gitlab version from Gitlab UI:
- Log in to your GitLab instance.
- At the bottom of the left sidebar, select Help.
- From the dropdown menu, select Help.
- The version number is displayed at the top of the page.
- For example, GitLab Enterprise Editionv18.9.1-ee.
gitlab-runner --version or gitlab-runner -v
There may be situations where you are stuck with an older runner due to operating system constraints. In such cases:
- The runner will likely continue to function for basic jobs for some time.
- You risk not having access to new CI/CD features that rely on a newer runner.