Setup CI with GitLab Pipelines
How to configure GitLab CI/CD pipelines for testing, building, and deploying applications using .gitlab-ci.yml with stages, jobs, caching, and runners.
Note: This guide follows English-language naming conventions and terminology standards common in international development teams. Examples use English identifiers and comments to maximize compatibility across codebases and tooling.
Overview
GitLab CI/CD is a built-in continuous integration and deployment platform that uses a .gitlab-ci.yml file to define pipelines. Jobs run in isolated Docker containers on shared or self-hosted runners, making it easy to automate testing, building, and releasing software.
Before CI/CD pipelines, teams ran tests and deployments manually from local machines. This led to “works on my laptop” bugs, inconsistent environments, and no audit trail of what was deployed when. GitLab CI/CD solves this by codifying every step of the delivery process in version-controlled YAML.
When to Use
Use this recipe when:
- Setting up automated testing for a GitLab-hosted project on every push or merge request.
- Building and pushing Docker images to a registry as part of the release process.
- Deploying to staging or production with environment-specific variables and manual approvals.
- Running scheduled pipelines for nightly backups, dependency audits, or periodic cleanup tasks.
- Using self-hosted runners for private infrastructure or specialized build environments.
What Works
- Use
npm ciinstead ofnpm installin CI for reproducible builds that strictly respectpackage-lock.json. - Cache dependencies between jobs using the
cachekeyword to dramatically reduce build times. - Pin Docker image versions instead of using
latesttags to ensure reproducible builds. - Use
artifactsto pass files between stages (e.g., compiled bundles from build to deploy). - Set
onlyorrulescarefully to avoid running expensive deploy jobs on feature branches. - Use
environmentblocks for deployment jobs to track what is deployed and enable rollbacks.
Common Mistakes
- Not caching
node_modulescauses every job to reinstall dependencies from scratch, wasting minutes per run. - Using
onlyinstead ofrules—rulesis the modern, more flexible way to control job execution. - Running DIND without TLS can expose the Docker socket to other jobs on the same runner.
- Storing secrets in
.gitlab-ci.yml— always use CI/CD variables from the project settings. - Forgetting
tagsfor self-hosted runners causes jobs to queue indefinitely on shared runners.
Performance Tips
- Use
needsfor DAG execution. Reduce wall-clock time by starting jobs as soon as their dependencies finish:
test:
needs: [build] # Starts immediately after build
- Cache per-branch. Avoid cache collisions between branches:
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- Use
interruptible: truefor MR jobs. Save runner time by canceling superseded pipelines:
test:
interruptible: true
- Use small images. Reduce pull time:
# Bad: large image
image: node:20
# Good: slim image
image: node:20-slim
# Best: alpine if compatible
image: node:20-alpine
- Use
before_scriptandafter_scriptwisely. They run for every job in the file:
default:
before_script:
- npm ci --silent
after_script:
- echo "Job completed with exit code $?" Related Resources
GitHub Actions CI/CD
How to build and deploy with GitHub Actions using workflows, matrices, caching, and secrets.
RecipeDocker Basics
How to containerize an application, write a Dockerfile, and run containers with Docker Compose.
RecipeEnvironment Variables
How to read, set, and manage environment variables securely across Python, JavaScript, and Java.
Frequently Asked Questions
- What is a GitLab Runner?
- A GitLab Runner is the agent that executes pipeline jobs. It can be shared, group-specific, or project-specific, and runs on Linux, Windows, macOS, or Kubernetes.
- How do I cache dependencies in GitLab CI?
- Use the cache keyword to persist directories like node_modules, .m2, or .pip between pipelines. Use key to scope caches per branch or lockfile.
- What is the difference between stages and jobs?
- Stages define execution phases (build, test, deploy) that run sequentially. Jobs are the individual tasks within a stage, which can run in parallel if they share a stage.