Tags for GitLab CI and tags for Git are two different concepts.

When you write your .gitlab-ci.yml, you can specify some jobs with the tag testing. If a runner with this tag associated is available, it will pickup the job.

In Git, within your repository, tags are used to mark a specific commit. It is often used to tag a version.

The two concepts can be mixed up when you use tags (in Git) to start your pipeline in GitLab CI. In your .gitlab-ci.yml, you can specify the section only with tags.

Refer to GitLab documentation for tags and only.

An example is when you push a tag with git:

$ git tag -a 1.0.0 -m "1.0.0"
$ git push origin 1.0.0

And a job in .gitlab-ci.yml like this:

compile:
    stage: build
    only: [tags]
    script:
        - echo Working...
    tags: [testing]    

would start using a runner with the testing tag.

By my understanding, what is missing in your steps is to specify the tag testing to your runner. To do this, go in GitLab into your project. Next to Wiki, click on Settings. Go to CI/CD Pipelines and there you have your runner(s). Next to its Guid, click on the pen icon. On next page the tags can be modified.

Answer from sgy on Stack Overflow
🌐
Reddit
reddit.com › r/gitlab › runner/job tag best practices feedback
r/gitlab on Reddit: Runner/Job tag best practices feedback
August 25, 2022 -

I was tasked with upgrading old runners (Win7 yikes!) and found our tag practices a but uncoordinated. The way things are setup I often had to pause a runner and unpause the new runner hoping to catch my test job. Untagged jobs, a crazy mix of instance/project runners with overlapping configurations, tags like "win" and "win_new".. made it difficult to figure out what will run where.

So I thought I would try to propose some best practices, and figured this would be a good place for feedback.

Broad tag categories and examples

  • Base Functionality, OS information. As much detail as necessary:

    • win_server_2019

    • win_desktop_10

    • linux

    • aix

  • Software installed, with version (in the case of msvs, workloads supported):

    • InstallShield9

    • msvs2019_c#_c++_vb

    • msvs2017_vb

    • python2.7

  • Security Scope - define capabilities that have security implications:

    • public_internet

    • local_network

    • external_wan_to_other_business_unit

    • code_signing

  • Arbitrary tags to assist runner migrations. This is purely self serving, if every job and runner had a gen_1 tag it would pin the jobs to 'gen_1' runners. When I need to migrate a runner, stand up a copy incrementing the gen_x tag and I can start migrating/testing jobs in a very controlled manner:

    • gen_1

    • gen_2

    • you get the idea.

Hope that all makes sense. We have a lot of small teams scattered all over the world, 142 projects in a single GitLab instance and no standards ;-)

Thanks for any feedback...

Top answer
1 of 3
9
I have some opinions in this area that may help you reduce the number of tags and optimize your runner availability and bring delight to your engineering teams. On software I don't think software tags are needed at all. You should ideally have just one (current) image for each OS/architecture and maybe some special cases for things like device farms where emulation is not practical. That image should install a baseline set of software that includes all the runtimes/versions/etc. that you need across the org. You can control the default versions through environment variables in most cases. Docker-based executors are ideal for your untagged jobs, even better if you can define your software images using image: instead of tags: where possible. Use tags: for changing major os family (e.g., linux, windows, macos) or architecture where needed. You can cache all the predefined docker images on the runner host so jobs are quick to start (doesn't matter if the images are very large!). Tagging for your 'generations' of images (again, ideally as a docker image tag instead of runner tag!) is a good idea. Examples of this practice in the wild: GitHub-hosted actions runner pre-installed software for ubuntu , windows , and macos , and appveyor preinstalled software . On security By default, all your runners should have the same baseline (unprivileged) security context. Escalating the security context should always go through authn/authz. Do not use your runners for security contexts! It will only (1) introduce security issues at worst or (2) needlessly proliferate the number of required runners at best. To access security-sensitive contexts, you should always require authentication and authorization and, ideally, log the access recording the relevant job/user responsible for triggering the access. To cover the use cases you mentioned: Code signing (and secrets, generally) Use a secrets manager instead (Hasicorp Vault, AWS Secrets Manager, Azure KeyVault, etc.) Access to secrets should require authn/authz and record access. Avoid using CI/CD variables for secrets if you can help it. Use OIDC to authenticate jobs to cloud environments and/or appropriate secrets. Most cloud providers and products support OIDC directly (i.e., use CI_JOB_JWT_V2) Use "just in time" access where applicable (example: use AWS Systems Manager sessions instead of static SSH keys) For code signing specifically, ideally use an asymmetric signing mechanism to avoid exposing your private keys to jobs directly where applicable (e.g., using something like AWS KMS ) Networking For accessing various networks, ideally, you would use a proxy (with authentication) instead of needing to place your runners in a particular subnet or whatever it is you are doing today. If you have lots of these, you would need to place a runner in each context, which is inefficient. If you use proxies, all your runners can run all the same jobs, but only jobs with appropriate needs should be able to auth to the relevant proxies. Authenticating and/or obtaining credentials for the relevant proxies should follow the above advice regarding secrets. Ideally, use scoped credentials so your proxy can log activity back to the source job. This is not always straightforward and may require significant work to implement depending on your existing network architecture and other institutional requirements, but shouldn't be a huge problem for a small org. Closing thoughts One last anecdotal note: I administer a GitLab instance for a large global 500 company. Everyone uses runners managed by my team. Our company develops software for just about everything under the sun (Windows, MacOS, iOS, Android, most Linux distributions, custom hardware, and more)... we have just a handful of tags -- one for each major OS family and architecture and a few tags for our in-house device farms and hardware racks. Beyond that, we have a few docker images (one for each OS/distro we need with various architecture variants within the same image manifest) but all the images have all the same installed software list where possible. Untagged jobs run on Linux/AMD64 (because that's what most of our development targets) and use our latest build image by default when no image: key is defined. Containers are a key part of how we make this strategy work with such little effort. Many of our teams very much enjoy the ability to create their own purpose-built docker images for GitLab CI builds. Highly recommend you use container-based executors if you are not doing so already.
2 of 3
2
Thought I should provide a bit more background. I was hired as a software engineer, they knew I had experience managing servers and build infrastructure (20 or so years worth) and nobody else in engineering wanted to (or was skilled to) handle this work. I'm in essence 'part time' on this type of work, big initiatives such as moving to containers are likely off the table at least short term. Prime driver for recent work was to get rid of 2 windows 7 runner boxes (that's almost done). My goal with the above 'best practices' is to try and make sense of the mess we currently have, within the confines of the current landscape/culture. Perhaps in the future I'll be in a position to make big changes, for now I'm eating this elephant one bite at a time. I appreciate the feedback, and believe me I'm taking notes!
🌐
Bitslovers
bitslovers.com › gitlab-runner-tags-2026
GitLab Runner Tags: The Complete Guide for 2026 | Bits Lovers' - Cloud Computing and DevOps
April 10, 2026 - # Backend team runners gitlab-runner register --tag-list "team:backend,docker" --concurrency 4 # Frontend team runners gitlab-runner register --tag-list "team:frontend,docker" --concurrency 3 # Data team runners (shared high-compute) gitlab-runner register --tag-list "team:data,high-compute" --concurrency 2 · This prevents one team’s runaway jobs from blocking another team’s builds. You can allocate capacity and costs per team. You can upgrade or change hardware for one team without affecting others. In practice, most organizations use some combination of all three.
Discussions

git - Understanding Gitlab CI tags - Stack Overflow
I've read documentation, some articles and you might call me dumb, but this is my first time working with a concept like this. I've registered runner with tag "testing" created tag "testing" in git... More on stackoverflow.com
🌐 stackoverflow.com
How to use tags to use a specific runner?
How to use tags to use a specific runner? I wrote tag in .gitlab-ci.yml: appBuild: stage: build tags: - android I wrote “android” tag in runner config. But job is in pending state and is waiting to be picked by a runner. What is wrong? More on forum.gitlab.com
🌐 forum.gitlab.com
8
0
March 11, 2021
How to set tags on Gitlab runner instances? - Stack Overflow
The documentation specifies how to set tags on the job side so it only runs on runners equipped with the right tags: osx job: stage: build tags: - osx script: - echo "Hello, $USER!& More on stackoverflow.com
🌐 stackoverflow.com
GitLab runner tags
It depends how you're handling runner registration. Tags are initially set at registration time only and they are not part of the runner config file. After registration, tags can only be changed in the UI settings. So, if you use the same auth token of an already-registered runner, redeploying your runner container(s) with new tag parameters will not change the tags. I'm guessing that's your situation. More on reddit.com
🌐 r/gitlab
4
1
October 4, 2024
🌐
OneUptime
oneuptime.com › home › blog › how to use gitlab runners effectively
How to Use GitLab Runners Effectively
December 21, 2025 - When registering a runner, use --tag-list: gitlab-runner register \ --tag-list "gpu,linux,cuda" \ --run-untagged=false
🌐
Bitslovers
bitslovers.com › gitlab-runner-tags
GitLab Runner Tags – Complete Guide for Complex Scenarios | Bits Lovers' - Cloud Computing and DevOps
October 8, 2021 - Tags are optional. You can assign zero tags, one tag, or several tags to a single runner. A runner with no tags can pick up untagged jobs (depending on its run_untagged setting). Only GitLab administrators can assign tags to shared runners.
🌐
GitLab
docs.gitlab.com › gitlab docs › administer › administer gitlab runner › configure runners
Configuring runners | GitLab Docs
To the right of the runner you want to protect, select Edit ( ). Select the Protected checkbox. Select Save changes. You can use tags to control the jobs a runner can run.
🌐
Medium
medium.com › @aymenfarhani28 › gitlab-runners-ff2be56a1985
Gitlab Runners. In GitLab CI/CD, runners are the agents… | by Aymen FARHANI | Medium
December 19, 2024 - — In your .gitlab-ci.yml configuration file, you can specify the tags for jobs. Only runners with the specified tags will pick up those jobs. 2- Example: Here’s an example of how you might set up a job to deploy to EC2 after a Docker image is tagged: Press enter or click to view image in full size · Deploy to EC2 after a Docker image is tagged · Best Practices for Deploying to EC2 ·
Find elsewhere
🌐
Programster
blog.programster.org › gitlab-pipeline-tags
GitLab Pipeline Tags | Programster's Blog
April 24, 2024 - GitLab runners support the use of tags in order to restrict which runners a job can be executed on.
🌐
GitLab
docs.gitlab.com › gitlab docs › use gitlab › use ci/cd to build your application › runners
Runners | GitLab Docs
A runner must first be registered with GitLab, which establishes a persistent connection between the runner and GitLab.
🌐
GitLab
forum.gitlab.com › how to use gitlab
How to use tags to use a specific runner? - How to Use GitLab - GitLab Forum
March 11, 2021 - How to use tags to use a specific runner? I wrote tag in .gitlab-ci.yml: appBuild: stage: build tags: - android I wrote “android” tag in runner config. But job is in pending state and is waiting to be picked by a runner. What is wrong?
🌐
Bitslovers
bitslovers.com › gitlab-runner-handbook
GitLab Runner Handbook [2026 Edition] | Bits Lovers' - Cloud Computing and DevOps
April 4, 2026 - The old method was removed in GitLab 18.0. ... That’s the short version. It does what you need without much fuss. Here’s what I recommend based on running these in production: Keep it updated. New versions come out regularly with bug fixes and features. Set a reminder to check every few months. Use tags. Tag your jobs and runners so the right work goes to the right place.
🌐
GitLab
docs.gitlab.com › gitlab docs › administer › administer gitlab runner
GitLab Runner | GitLab Docs
Runner token: A unique identifier that allows a runner to authenticate with GitLab. Tags: Labels assigned to runners that determine which jobs they can execute.
🌐
Reddit
reddit.com › r/gitlab › gitlab runner tags
r/gitlab on Reddit: GitLab runner tags
October 4, 2024 -

All these years we were setting:

gitlab-runner:
  runners:
    tags: "my-tag" 

In the values.yaml file of the Helm chart. However, I'm in chart version 8.3.2 currently and this value is not respected anymore. Whenever I update it, or upgrade it, it doesn't respect whatever values are set there, and the runner is created without the tag.

Why is that? I have searched for a new way, in case there is one, and couldn't find it. Or maybe it's a bug.

🌐
GitLab
forum.gitlab.com › gitlab ci/cd
A question about Tags when creating a runner - GitLab CI/CD - GitLab Forum
March 10, 2025 - Hello, When creating a runner, there is a section called Tags. Is this section mandatory? If so, how should its name be chosen? Thank you.
🌐
DevOps as Craft
virtualizare.net › devops › how-to-specify-a-runner-in-gitlab-ci-yml-best-practices.html
How to Specify a Runner in GitLab CI YML: Best Practices
August 18, 2024 - ... Always avoid storing tools ... upload job monitoring data for better analysis. Optimize runner performance by using tags and CI/CD variables for dynamic job handling....