In today’s blog post, we will discuss image keyword in .gitlab-ci.yml
file. Specifically, what is image keyword in .gitlab-ci.yml
?, how to define image with example?, tips and best practices of using image in GitLab CI/CD pipeline. So without any further delay, let us get started.
What is the image Keyword?
The image
keyword in your .gitlab-ci.yml
file allows you to define the Docker image that GitLab Runner will use to execute the before_script
, script
, and after_script
commands for a job.
When a job starts, the GitLab Runner (specifically, if it is configured with a Docker or Kubernetes executor) will:
- Pull the specified Docker image.
- Start a new container based on that image.
- Mount your project’s code into this container.
- Execute the job’s commands inside this isolated container.
This ensures a clean, consistent, and reproducible environment for every job run.
Where to Define the image
Keyword
You can define the image
keyword at two primary levels:
Global (Default) Level
Purpose: To set a default Docker image that applies to all jobs in your .gitlab-ci.yml
file, unless overridden by a job-specific image
.
Location: At the top level of your .gitlab-ci.yml
file.
Example:
default:
image: node:20-alpine # All jobs will use Node.js 20 on Alpine Linux by default
stages:
- build
- test
build_frontend:
stage: build
script:
- npm install
- npm run build
run_unit_tests:
stage: test
script:
- npm test
Explanation: Both build_frontend
and run_unit_tests
jobs will automatically use the node:20-alpine
Docker image.
Job-Specific Level
Purpose: To override the global default:image
and specify a different Docker image for a particular job. This is useful when different jobs require different toolsets or environments.
Location: Within an individual job definition.
Example:
default:
image: node:20-alpine # Default for most jobs
stages:
- build
- test
- deploy
build_frontend:
stage: build
script: npm run build
run_backend_tests:
stage: test
image: python:3.10-slim-buster # This job uses a Python image
script:
- pip install -r requirements.txt
- pytest
deploy_to_cloud:
stage: deploy
image: google/cloud-sdk:latest # This job uses Google Cloud SDK image
script:
- gcloud app deploy
Explanation:
build_frontend
usesnode:20-alpine
(fromdefault
).run_backend_tests
usespython:3.10-slim-buster
.deploy_to_cloud
usesgoogle/cloud-sdk:latest
.
How to Specify Docker Images
You can specify images from various sources:
- Docker Hub (Official and Community Images): Most commonly used.
image: ubuntu:latest
image: maven:3.8.6-openjdk-17
image: golang:1.20
- GitLab Container Registry: If your project hosts its own Docker images in the GitLab Container Registry (e.g., for custom build environments or application images).
image: registry.gitlab.com/your-group/your-project/my-custom-build-image:1.0
image: $CI_REGISTRY_IMAGE/my-app:latest
(using predefined variables for project path)
- Other Private Registries: If you have credentials configured for external private registries (e.g., Amazon ECR, Google Container Registry).
image: my.private.registry.com/my-image:tag
Best Practices for Using the image Keyword
- Use Specific Tags, Not
latest
for Production/Stable Builds: Whilelatest
might be convenient for development, it can lead to non-reproducible builds as thelatest
tag constantly changes. For stable builds, releases, or critical paths, always pin to a specific version tag (e.g.,node:20.10.0-alpine
,python:3.9.18-slim-buster
).
# Good
image: node:20.10.0-alpine
# Bad (for stable builds)
# image: node:latest
- Choose Minimal Images: Opt for
slim
oralpine
variants of images where possible. They are smaller, pull faster, and reduce the attack surface. Install only the necessary tools within yourbefore_script
orscript
.
# Good
image: python:3.10-slim-buster
# Potentially too large if you only need Python
# image: python:3.10
- Build Custom Images for Complex Environments: If your pipeline jobs require a very specific set of tools and dependencies that are not readily available in public images (or are too large to install repeatedly in
before_script
), create your own custom Docker image.- This image would contain all your tools pre-installed.
- Build this image with a separate CI/CD pipeline and push it to your GitLab Container Registry.
- Then, reference your custom image in your
.gitlab-ci.yml
. This speeds up subsequent job runs significantly.
- Balance Global vs. Job-Specific:
- Use a global
default:image
for the most common environment needed by the majority of your jobs. - Override with job-specific
image
only when a different environment is strictly necessary. This keeps your.gitlab-ci.yml
clean.
- Use a global
- Consider Runners’ Executors: The
image
keyword is primarily relevant for GitLab Runners using the Docker or Kubernetes executors. If your runner is using the Shell executor, theimage
keyword is ignored, and jobs run directly on the host machine (which is generally less reproducible and not recommended for most scenarios). - Security and Trust: Be mindful of the source of your Docker images. Stick to official images from trusted sources or images you build yourself.
FAQs – Image
What is the image
keyword in GitLab CI/CD?
The image
keyword in GitLab CI/CD specifies the Docker image to be used by the GitLab Runner when executing a job. This allows jobs to run in a pre-configured environment with the necessary tools, such as Node.js, Python, Java, or any custom image.
How do I use the image
keyword in a job?
You can define an image per job by using the image
keyword:
build:
image: node:20
script:
- node --version
- npm install
In this example, the job runs inside a container using the official node:20
image from Docker Hub.
Can I define a global image for all jobs?
Yes. You can specify a global image
at the top level of the .gitlab-ci.yml
file, and it will apply to all jobs, unless overridden:
image: python:3.11
lint:
script:
- python --version
- flake8 .
All jobs will use the python:3.11
image unless they specify their own.
How do I use a private image registry with the image
keyword?
You can reference private Docker registries in the image
keyword. If credentials are needed, configure them under CI/CD settings → Variables:
image: registry.example.com/my-group/custom-image:latest
Also define CI variables like CI_REGISTRY_USER
and CI_REGISTRY_PASSWORD
if needed.
Can I override the global image in specific jobs?
Yes. Any job can override the globally defined image
:
image: ruby:3.2
rspec:
image: ruby:3.1
script:
- ruby --version
- bundle exec rspec
In this example, the global image is ruby:3.2
, but the rspec
job uses ruby:3.1
.
Can I use custom Docker images in GitLab CI/CD?
Yes. You can use your own custom-built Docker images by hosting them on:
- Docker Hub
- GitLab Container Registry
- AWS ECR, GCR, or other registries
Example:
image: registry.gitlab.com/myproject/custom-ci-image:latest
Make sure the image contains all the tools required by your pipeline.
Can I specify a tag or use latest
in the image name?
Yes. You can specify a particular tag, or omit it to use latest
by default:
image: golang:1.21
or
image: golang # This uses golang:latest
Using explicit versions is recommended for pipeline reproducibility.
Is the image
keyword required in .gitlab-ci.yml
?
No. If you do not define an image
, the GitLab Runner uses its default shell executor, which runs directly on the host. However, using image
with the Docker executor ensures clean, isolated, and reproducible environments.
Can I pull images from GitLab’s own Container Registry?
Yes. If your image is stored in your GitLab project’s registry, use:
image: registry.gitlab.com/<namespace>/<project>/<image>:tag
You may need to authenticate using CI/CD variables if the image is private.
Can I use a Docker image with entrypoint
defined?
Yes. GitLab will honor the ENTRYPOINT
defined in the Docker image. If needed, you can override it using the entrypoint
keyword:
job:
image:
name: alpine:latest
entrypoint: [""]
script:
- echo "Running without entrypoint"
Setting entrypoint: [""]
disables the image’s default entrypoint.
Does each job get a new container from the image?
Yes. Each job gets a fresh container from the specified image. This ensures jobs are isolated and do not share state, which improves consistency and security.
What happens if the image cannot be pulled?
If GitLab Runner fails to pull the image (e.g., due to authentication errors or the image not existing), the job fails immediately, and the pipeline stops at that stage.
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com