Understanding GitLab CI/CD Variables for pipelines

Pradap Pandiyan
5 min readSep 8, 2024

--

GitLab CI/CD uses various types of variables to make pipelines dynamic, adaptable, and secure. Variables can store values such as paths, URLs, or secret credentials. You can create more flexible and reusable pipelines by utilizing predefined, global, and local variables. In this article, we will explore different types of GitLab CI/CD variables, how they are defined, and their use cases in a typical pipeline.

1. Global Variables

Global variables are defined at the top level of the .gitlab-ci.yml file and are accessible throughout the entire pipeline, across all stages and jobs. These variables can store common values that need to be used in multiple jobs, ensuring consistency and reducing redundancy.

Example:

variables:
GLOBAL_VARIABLE: "This is a global variable"
COMMON_URL: "https://example.com"
  • GLOBAL_VARIABLE: This variable is available across all stages and jobs.
  • COMMON_URL: A URL that could be used across different jobs, for instance, for making API requests.

2. Predefined Variables

GitLab CI provides a rich set of predefined variables that give information about the pipeline, project, or job. These variables are automatically set and can be accessed directly in the pipeline.

Example:

test-variables:
stage: predefined-variables
script:
- echo "CI_COMMIT_SHA=$CI_COMMIT_SHA"
- echo "CI_JOB_ID=$CI_JOB_ID"
- echo "CI_PROJECT_NAME=$CI_PROJECT_NAME"

Some commonly used predefined variables:

  • CI_COMMIT_SHA: The commit hash of the current commit.
  • CI_JOB_ID: The unique ID of the current job.
  • CI_PROJECT_NAME: The name of the project.

Predefined variables are useful for retrieving metadata about the pipeline without manually defining them. They can be used in scripts, logging, or reporting.

3. Merge Request Variables

When a pipeline runs in response to a merge request (MR), special variables are available to give information about the MR itself. These variables allow access to MR-specific data, such as the branch names, project IDs, and labels.

Example:

print-ci-merge-request-variables:
stage: merge-request-variables
script:
- echo "CI_MERGE_REQUEST_ID=$CI_MERGE_REQUEST_ID"
- echo "CI_MERGE_REQUEST_TITLE=$CI_MERGE_REQUEST_TITLE

Common merge request variables include:

  • CI_MERGE_REQUEST_ID: The ID of the merge request.
  • CI_MERGE_REQUEST_TITLE: The title of the merge request.

These variables can be handy when you want to customize your pipeline behavior based on the context of the merge request.

4. Local Variables (Job-Specific Variables)

Local variables are defined at the job level and are only available within that specific job. This allows for customizing job behavior without affecting the entire pipeline.

Example:

test-job:
stage: test
script:
- echo "Global Variable= $GLOBAL_VARIABLE"
- echo "Local Variable= $LOCAL_VARIABLE"
variables:
LOCAL_VARIABLE: "This is a local variable for test-job"

In this example:

  • LOCAL_VARIABLE is defined only for the test-job and is not accessible in other jobs.
  • GLOBAL_VARIABLE, however, is accessible because it was defined at the global level.

5. Environment-Specific Variables (Job-Specific)

You can define variables that are specific to certain environments, such as deployment environments. This is useful when you want to tailor your job for a specific environment, for example, using different URLs for staging and production.

Example:

deploy-job:
stage: deploy
script:
- echo "Deploy-specific Variable= $DEPLOY_URL"
variables:
DEPLOY_URL: "https://deploy.example.com"

Here, DEPLOY_URL is specific to the deploy-job and can contain deployment-related URLs or credentials.

6. Variable Precedence

GitLab CI/CD variables have a clear precedence order, which dictates which variable value will be used if there are conflicts. From highest to lowest priority:

  1. Trigger variables: Variables passed when triggering a pipeline.
  2. Pipeline variables: Variables defined when running a pipeline manually.
  3. Job-specific variables: Variables defined at the job level.
  4. Global variables: Variables defined at the top level in .gitlab-ci.yml.
  5. Environment variables: Variables defined in GitLab project settings or in the group.
  6. Predefined variables: Automatically provided by GitLab.

Here is the data which I have tested with the gitlab job to validate most of the variables

variables: 
GLOBAL_VARIABLE: "This is a global variable"
COMMON_URL: "https://example.com"

stages:
- predefined-variables
- merge-request-variables
- test
- deploy

test-variables:
stage: predefined-variables
script:
- echo "CHAT_CHANNEL=$CHAT_CHANNEL"
- echo "CHAT_INPUT=$CHAT_INPUT"
- echo "CHAT_USER_ID=$CHAT_USER_ID"
- echo "CI=$CI"
- echo "CI_API_V4_URL=$CI_API_V4_URL"
- echo "CI_API_GRAPHQL_URL=$CI_API_GRAPHQL_URL"
- echo "CI_BUILDS_DIR=$CI_BUILDS_DIR"
- echo "CI_COMMIT_AUTHOR=$CI_COMMIT_AUTHOR"
- echo "CI_COMMIT_BEFORE_SHA=$CI_COMMIT_BEFORE_SHA"
- echo "CI_COMMIT_BRANCH=$CI_COMMIT_BRANCH"
- echo "CI_COMMIT_DESCRIPTION=$CI_COMMIT_DESCRIPTION"
- echo "CI_COMMIT_MESSAGE=$CI_COMMIT_MESSAGE"
- echo "CI_COMMIT_REF_NAME=$CI_COMMIT_REF_NAME"
- echo "CI_COMMIT_REF_PROTECTED=$CI_COMMIT_REF_PROTECTED"
- echo "CI_COMMIT_REF_SLUG=$CI_COMMIT_REF_SLUG"
- echo "CI_COMMIT_SHA=$CI_COMMIT_SHA"
- echo "CI_COMMIT_SHORT_SHA=$CI_COMMIT_SHORT_SHA"
- echo "CI_COMMIT_TAG=$CI_COMMIT_TAG"
- echo "CI_COMMIT_TAG_MESSAGE=$CI_COMMIT_TAG_MESSAGE"
- echo "CI_COMMIT_TIMESTAMP=$CI_COMMIT_TIMESTAMP"
- echo "CI_COMMIT_TITLE=$CI_COMMIT_TITLE"
- echo "CI_CONCURRENT_ID=$CI_CONCURRENT_ID"
- echo "CI_CONCURRENT_PROJECT_ID=$CI_CONCURRENT_PROJECT_ID"
- echo "CI_CONFIG_PATH=$CI_CONFIG_PATH"
- echo "CI_DEBUG_TRACE=$CI_DEBUG_TRACE"
- echo "CI_DEBUG_SERVICES=$CI_DEBUG_SERVICES"
- echo "CI_DEFAULT_BRANCH=$CI_DEFAULT_BRANCH"
- echo "CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX=$CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX"
- echo "CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX=$CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX"
- echo "CI_DEPENDENCY_PROXY_PASSWORD=$CI_DEPENDENCY_PROXY_PASSWORD"
- echo "CI_DEPENDENCY_PROXY_SERVER=$CI_DEPENDENCY_PROXY_SERVER"
- echo "CI_DEPENDENCY_PROXY_USER=$CI_DEPENDENCY_PROXY_USER"
- echo "CI_DEPLOY_FREEZE=$CI_DEPLOY_FREEZE"
- echo "CI_DEPLOY_PASSWORD=$CI_DEPLOY_PASSWORD"
- echo "CI_DEPLOY_USER=$CI_DEPLOY_USER"
- echo "CI_DISPOSABLE_ENVIRONMENT=$CI_DISPOSABLE_ENVIRONMENT"
- echo "CI_ENVIRONMENT_NAME=$CI_ENVIRONMENT_NAME"
- echo "CI_ENVIRONMENT_SLUG=$CI_ENVIRONMENT_SLUG"
- echo "CI_ENVIRONMENT_URL=$CI_ENVIRONMENT_URL"
- echo "CI_ENVIRONMENT_ACTION=$CI_ENVIRONMENT_ACTION"
- echo "CI_ENVIRONMENT_TIER=$CI_ENVIRONMENT_TIER"
- echo "CI_GITLAB_FIPS_MODE=$CI_GITLAB_FIPS_MODE"
- echo "CI_HAS_OPEN_REQUIREMENTS=$CI_HAS_OPEN_REQUIREMENTS"
- echo "CI_JOB_ID=$CI_JOB_ID"
- echo "CI_JOB_IMAGE=$CI_JOB_IMAGE"
- echo "CI_JOB_JWT=$CI_JOB_JWT"
- echo "CI_JOB_JWT_V1=$CI_JOB_JWT_V1"
- echo "CI_JOB_JWT_V2=$CI_JOB_JWT_V2"
- echo "CI_JOB_MANUAL=$CI_JOB_MANUAL"
- echo "CI_JOB_NAME=$CI_JOB_NAME"
- echo "CI_JOB_NAME_SLUG=$CI_JOB_NAME_SLUG"
- echo "CI_JOB_STAGE=$CI_JOB_STAGE"
- echo "CI_JOB_STATUS=$CI_JOB_STATUS"
- echo "CI_JOB_TIMEOUT=$CI_JOB_TIMEOUT"
- echo "CI_JOB_TOKEN=$CI_JOB_TOKEN"
- echo "CI_JOB_URL=$CI_JOB_URL"
- echo "CI_JOB_STARTED_AT=$CI_JOB_STARTED_AT"
- echo "CI_KUBERNETES_ACTIVE=$CI_KUBERNETES_ACTIVE"
- echo "CI_NODE_INDEX=$CI_NODE_INDEX"
- echo "CI_NODE_TOTAL=$CI_NODE_TOTAL"
- echo "CI_OPEN_MERGE_REQUESTS=$CI_OPEN_MERGE_REQUESTS"
- echo "CI_PAGES_DOMAIN=$CI_PAGES_DOMAIN"
- echo "CI_PAGES_URL=$CI_PAGES_URL"
- echo "CI_PIPELINE_ID=$CI_PIPELINE_ID"
- echo "CI_PIPELINE_IID=$CI_PIPELINE_IID"
- echo "CI_PIPELINE_SOURCE=$CI_PIPELINE_SOURCE"
- echo "CI_PIPELINE_TRIGGERED=$CI_PIPELINE_TRIGGERED"
- echo "CI_PIPELINE_URL=$CI_PIPELINE_URL"
- echo "CI_PIPELINE_CREATED_AT=$CI_PIPELINE_CREATED_AT"
- echo "CI_PIPELINE_NAME=$CI_PIPELINE_NAME"
- echo "CI_PROJECT_DIR=$CI_PROJECT_DIR"
- echo "CI_PROJECT_ID=$CI_PROJECT_ID"
- echo "CI_PROJECT_NAME=$CI_PROJECT_NAME"
- echo "CI_PROJECT_NAMESPACE=$CI_PROJECT_NAMESPACE"
- echo "CI_PROJECT_NAMESPACE_ID=$CI_PROJECT_NAMESPACE_ID"
- echo "CI_PROJECT_PATH_SLUG=$CI_PROJECT_PATH_SLUG"
- echo "CI_PROJECT_PATH=$CI_PROJECT_PATH"
- echo "CI_PROJECT_REPOSITORY_LANGUAGES=$CI_PROJECT_REPOSITORY_LANGUAGES"
- echo "CI_PROJECT_ROOT_NAMESPACE=$CI_PROJECT_ROOT_NAMESPACE"
- echo "CI_PROJECT_TITLE=$CI_PROJECT_TITLE"
- echo "CI_PROJECT_DESCRIPTION=$CI_PROJECT_DESCRIPTION"
- echo "CI_PROJECT_URL=$CI_PROJECT_URL"
- echo "CI_PROJECT_VISIBILITY=$CI_PROJECT_VISIBILITY"
- echo "CI_PROJECT_CLASSIFICATION_LABEL=$CI_PROJECT_CLASSIFICATION_LABEL"
- echo "CI_REGISTRY=$CI_REGISTRY"
- echo "CI_REGISTRY_IMAGE=$CI_REGISTRY_IMAGE"
- echo "CI_REGISTRY_PASSWORD=$CI_REGISTRY_PASSWORD"
- echo "CI_REGISTRY_USER=$CI_REGISTRY_USER"
- echo "CI_RELEASE_DESCRIPTION=$CI_RELEASE_DESCRIPTION"
- echo "CI_REPOSITORY_URL=$CI_REPOSITORY_URL"
- echo "CI_RUNNER_DESCRIPTION=$CI_RUNNER_DESCRIPTION"
- echo "CI_RUNNER_EXECUTABLE_ARCH=$CI_RUNNER_EXECUTABLE_ARCH"
- echo "CI_RUNNER_ID=$CI_RUNNER_ID"
- echo "CI_RUNNER_REVISION=$CI_RUNNER_REVISION"
- echo "CI_RUNNER_SHORT_TOKEN=$CI_RUNNER_SHORT_TOKEN"
- echo "CI_RUNNER_TAGS=$CI_RUNNER_TAGS"
- echo "CI_RUNNER_VERSION=$CI_RUNNER_VERSION"
- echo "CI_SERVER_FQDN=$CI_SERVER_FQDN"
- echo "CI_SERVER_HOST=$CI_SERVER_HOST"
- echo "CI_SERVER_NAME=$CI_SERVER_NAME"
- echo "CI_SERVER_PORT=$CI_SERVER_PORT"
- echo "CI_SERVER_PROTOCOL=$CI_SERVER_PROTOCOL"
- echo "CI_SERVER_SHELL_SSH_HOST=$CI_SERVER_SHELL_SSH_HOST"
- echo "CI_SERVER_SHELL_SSH_PORT=$CI_SERVER_SHELL_SSH_PORT"
- echo "CI_SERVER_REVISION=$CI_SERVER_REVISION"
- echo "CI_SERVER_TLS_CA_FILE=$CI_SERVER_TLS_CA_FILE"
- echo "CI_SERVER_TLS_CERT_FILE=$CI_SERVER_TLS_CERT_FILE"
- echo "CI_SERVER_TLS_KEY_FILE=$CI_SERVER_TLS_KEY_FILE"
- echo "CI_SERVER_URL=$CI_SERVER_URL"
- echo "CI_SERVER_VERSION_MAJOR=$CI_SERVER_VERSION_MAJOR"
- echo "CI_SERVER_VERSION_MINOR=$CI_SERVER_VERSION_MINOR"
- echo "CI_SERVER_VERSION_PATCH=$CI_SERVER_VERSION_PATCH"
- echo "CI_SERVER_VERSION=$CI_SERVER_VERSION"
- echo "CI_SERVER=$CI_SERVER"
- echo "CI_SHARED_ENVIRONMENT=$CI_SHARED_ENVIRONMENT"
- echo "CI_TEMPLATE_REGISTRY_HOST=$CI_TEMPLATE_REGISTRY_HOST"
- echo "CI_TRIGGER_SHORT_TOKEN=$CI_TRIGGER_SHORT_TOKEN"
- echo "GITLAB_CI=$GITLAB_CI"
- echo "GITLAB_FEATURES=$GITLAB_FEATURES"
- echo "GITLAB_USER_EMAIL=$GITLAB_USER_EMAIL"
- echo "GITLAB_USER_ID=$GITLAB_USER_ID"
- echo "GITLAB_USER_LOGIN=$GITLAB_USER_LOGIN"

print-ci-merge-request-variables:
stage: merge-request-variables
script:
- echo "CI_MERGE_REQUEST_APPROVED= $CI_MERGE_REQUEST_APPROVED"
- echo "CI_MERGE_REQUEST_ASSIGNEES= $CI_MERGE_REQUEST_ASSIGNEES"
- echo "CI_MERGE_REQUEST_DIFF_BASE_SHA= $CI_MERGE_REQUEST_DIFF_BASE_SHA"
- echo "CI_MERGE_REQUEST_DIFF_ID= $CI_MERGE_REQUEST_DIFF_ID"
- echo "CI_MERGE_REQUEST_EVENT_TYPE= $CI_MERGE_REQUEST_EVENT_TYPE"
- echo "CI_MERGE_REQUEST_DESCRIPTION= $CI_MERGE_REQUEST_DESCRIPTION"
- echo "CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED= $CI_MERGE_REQUEST_DESCRIPTION_IS_TRUNCATED"
- echo "CI_MERGE_REQUEST_ID= $CI_MERGE_REQUEST_ID"
- echo "CI_MERGE_REQUEST_IID= $CI_MERGE_REQUEST_IID"
- echo "CI_MERGE_REQUEST_LABELS= $CI_MERGE_REQUEST_LABELS"
- echo "CI_MERGE_REQUEST_MILESTONE= $CI_MERGE_REQUEST_MILESTONE"
- echo "CI_MERGE_REQUEST_PROJECT_ID= $CI_MERGE_REQUEST_PROJECT_ID"
- echo "CI_MERGE_REQUEST_PROJECT_PATH= $CI_MERGE_REQUEST_PROJECT_PATH"
- echo "CI_MERGE_REQUEST_PROJECT_URL= $CI_MERGE_REQUEST_PROJECT_URL"
- echo "CI_MERGE_REQUEST_REF_PATH= $CI_MERGE_REQUEST_REF_PATH"
- echo "CI_MERGE_REQUEST_SOURCE_BRANCH_NAME= $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME"
- echo "CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED= $CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED"
- echo "CI_MERGE_REQUEST_SOURCE_BRANCH_SHA= $CI_MERGE_REQUEST_SOURCE_BRANCH_SHA"
- echo "CI_MERGE_REQUEST_SOURCE_PROJECT_ID= $CI_MERGE_REQUEST_SOURCE_PROJECT_ID"
- echo "CI_MERGE_REQUEST_SOURCE_PROJECT_PATH= $CI_MERGE_REQUEST_SOURCE_PROJECT_PATH"
- echo "CI_MERGE_REQUEST_SOURCE_PROJECT_URL= $CI_MERGE_REQUEST_SOURCE_PROJECT_URL"
- echo "CI_MERGE_REQUEST_SQUASH_ON_MERGE= $CI_MERGE_REQUEST_SQUASH_ON_MERGE"
- echo "CI_MERGE_REQUEST_TARGET_BRANCH_NAME= $CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
- echo "CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED= $CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED"
- echo "CI_MERGE_REQUEST_TARGET_BRANCH_SHA= $CI_MERGE_REQUEST_TARGET_BRANCH_SHA"
- echo "CI_MERGE_REQUEST_TITLE= $CI_MERGE_REQUEST_TITLE"

test-job:
stage: test
script:
- echo "Global Variable= $GLOBAL_VARIABLE"
- echo "Common URL= $COMMON_URL"
- echo "Local Variable= $LOCAL_VARIABLE"
variables:
LOCAL_VARIABLE: "This is a local variable for test-job"
TEST_URL: "https://test.example.com"

deploy-job:
stage: deploy
script:
- echo "Global Variable= $GLOBAL_VARIABLE"
- echo "Common URL= $COMMON_URL"
- echo "Deploy-specific Variable= $DEPLOY_URL"
variables:
DEPLOY_URL: "https://deploy.example.com"

Conclusion

Using different types of GitLab CI variables enables you to create more dynamic, reusable, and flexible pipelines. By combining global variables for consistency, job-specific variables for custom behavior, and predefined or merge request variables for environment-specific tasks, you can ensure that your pipeline runs smoothly across different scenarios.

Understanding the various types of variables and how to use them effectively is key to mastering GitLab CI/CD and creating scalable, efficient pipelines.

I have created a project on Gitlab and added the code here.

Feel free to hit clap if you like the content. Happy Automation Testing :) Cheers. 👏

--

--

Pradap Pandiyan
Pradap Pandiyan

Written by Pradap Pandiyan

I’m a passionate QA Engineer. I’m a motovlogger, content creator, off-roader and freelancer. Buy me a coffee here https://www.buymeacoffee.com/pradappandiyan

No responses yet