DevOpsLesson
DevOpsLesson

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Stay Updated

Get notified about new tutorials and features.

Tutorials

  • What is DevOps?
  • Docker Tutorial
  • Terraform Tutorial
  • CI/CD Pipeline
  • All Tutorials

Roadmaps

  • DevOps Engineer
  • Cloud Engineer
  • SRE Path
  • All Roadmaps

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 DevOpsLesson. All rights reserved.

DOCKERKUBERNETESTERRAFORMAWSCI/CDLINUXGITDEVOPS ROADMAPCLOUD ROADMAPSRE ROADMAPGIT CHEATSHEETDOCKER CHEATSHEETK8S CHEATSHEETTF CHEATSHEETLINUX CHEATSHEETDOCKERFILE LINTERYAML VALIDATORCRON PARSERREGEX TESTER

Cicd Tutorial

Introduction to CI/CD
Getting Started with GitLab CI/CD
Stages, Jobs, Artifacts & Cache
Variables, Secrets and Environments in GitLab CI
GitLab Runners
GitLab CI Pipeline Rules
GitLab CI Environments
GitLab CI Docker Workflows
GitLab CI Testing
GitLab CI Security Scanning
GitLab CI Deploy to AWS
GitLab CI Multi-Project Pipelines
GitLab CI Best Practices

GitLab CI Environments

PreviousPrev
Next

Learn GitLab CI environments, deployment tracking, review apps, environment URLs, protected environments, deployment approvals, scoped variables, DORA metrics, and a complete multi-environment deployment example.

In GitLab CI/CD, an environment is not just a label you attach to a deployment job. It is a first-class deployment tracking concept that helps GitLab understand where your application was deployed, when it was deployed, which job performed the deployment, and which commit reached that target. If you treat environments seriously, GitLab becomes more than a build runner. It becomes a deployment history system, a release visibility system, and a foundation for safer delivery.

That is why topics like GitLab CI environments, GitLab environment tracking, GitLab review apps, GitLab protected environments, and GitLab deployment approval matter so much in modern DevOps workflows.

What Are GitLab Environments?

A GitLab environment represents a deployment target such as:

  • development
  • staging
  • production
  • review/my-feature-branch

When a CI job declares an environment, GitLab records the deployment and links it to the commit, pipeline, job, and, when available, a URL. This gives your team a clear answer to operational questions such as:

  • What version is currently in staging?
  • When was production last deployed?
  • Which merge request created this review app?
  • What deployment failed?
  • How frequently are we releasing?

This is the reason GitLab environments are about deployment tracking, not only syntax.

The environment Keyword in Jobs

You define environments using the environment keyword inside a job.

deploy-staging:
  stage: deploy
  script:
    - ./deploy-staging.sh
  environment:
    name: staging
    url: https://staging.example.com

This does two things:

  1. tells GitLab that the job deploys to an environment called staging
  2. attaches the environment URL so users can click directly to the deployed app

name

The name field identifies the environment. Static names such as dev, staging, and production are common for long-lived environments.

url

The url field improves usability. Instead of making teammates search for the deployed site, GitLab can display a direct environment link. This is especially helpful for QA, product managers, and reviewers.

Static vs Dynamic Environments

A big part of understanding GitLab CI deployment environments is recognizing that not all environments are permanent.

Static environments

A static environment is long-lived and reused over time. Examples include:

  • development
  • qa
  • staging
  • production

These environments usually represent stable infrastructure targets and receive repeated deployments.

Dynamic environments

A dynamic environment is created temporarily, often for a branch or merge request, and then removed when no longer needed.

Examples include:

  • review/feature-login
  • review/mr-42
  • preview/my-change

Dynamic environments are the foundation of GitLab review apps, which create per-merge-request previews that reviewers can click and test.

Viewing Deployment History in GitLab

One of the best benefits of environment tracking is visibility in the GitLab UI. Once jobs declare environments, GitLab can show:

  • current environments and their status
  • the latest deployment for each environment
  • a history of previous deployments
  • links to the relevant pipeline and job
  • environment URLs

This makes release troubleshooting much easier. If someone asks, “What commit is in staging right now?” you do not need to dig through Slack or guess from timestamps. GitLab already knows.

For regulated or fast-moving teams, this audit trail is extremely valuable because deployment information stays close to the source code and pipeline that produced it.

Dynamic Environments for Merge Requests

Dynamic environments become especially powerful in merge request workflows. A common pattern is to create a unique environment name using the merge request IID.

review-app:
  stage: deploy
  script:
    - ./deploy-review.sh
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    url: https://review-$CI_MERGE_REQUEST_IID.example.com

This means each merge request gets its own preview environment, such as:

  • review/17
  • review/18
  • review/19

That preview can be linked directly in the merge request, making it easy for reviewers to test behavior without checking out code locally.

Review Apps in GitLab CI/CD

GitLab review apps are one of the most developer-friendly features in GitLab CI. Instead of reviewing screenshots or abstract descriptions, product and QA teams can interact with a live deployment created just for the merge request.

A review app usually includes:

  • a deployment job that creates the temporary environment
  • a dynamic environment:name
  • an environment:url
  • a stop job that removes the environment later

Typical use cases:

  • frontend UI validation
  • stakeholder demos
  • testing feature flags and content changes
  • manual verification before merging

The experience becomes even better when the environment URL is automatically posted into the merge request widget.

The on_stop Keyword and Stop Job Pattern

Dynamic environments should not live forever. Cloud resources cost money, and stale review environments create confusion. GitLab solves this with the on_stop keyword and a paired stop job.

Deployment job

review-app:
  stage: deploy
  script:
    - ./deploy-review.sh
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    url: https://review-$CI_MERGE_REQUEST_IID.example.com
    on_stop: stop-review-app

Stop job

stop-review-app:
  stage: deploy
  script:
    - ./destroy-review.sh
  when: manual
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    action: stop

This pattern tells GitLab which job stops the environment. In many teams, the stop job is triggered manually, automatically on merge, or via cleanup policies depending on the platform.

The important point is conceptual: creating a dynamic environment should always come with a cleanup strategy.

Protected Environments and Deployment Approvals

Production is different from development. Most organizations do not want any successful pipeline to push straight to production. That is where GitLab protected environments come in.

A protected environment lets you restrict who can deploy to a specific target such as production. Depending on your GitLab tier and settings, you can require:

  • only certain roles or users may deploy
  • deployment approvals before the job proceeds
  • controlled manual actions for sensitive releases

This creates a stronger governance layer around GitLab deployment approval workflows.

Why protected environments matter

Protected environments help prevent:

  • accidental deployments from the wrong branch
  • unauthorized manual triggers
  • overexposure of production deployment capability
  • release bypasses outside of approved processes

A good pattern is to combine:

  • protected branches
  • protected CI variables
  • protected runners
  • protected environments

Each layer reduces the chance of an unsafe production release.

Deployment Frequency and DORA Metrics

GitLab environments also support measurement. Because GitLab can track deployments to environments, it can contribute to metrics such as deployment frequency, one of the DORA metrics widely used to evaluate software delivery performance.

DORA metrics often include:

  • deployment frequency
  • lead time for changes
  • change failure rate
  • time to restore service

When your pipeline accurately records deployments to real environments, GitLab can provide better operational insight. This is another reason to model environments explicitly instead of treating deployments as anonymous scripts.

If your organization wants to improve release speed without sacrificing stability, proper environment tracking is a foundational step.

Environment-Scoped Variables

Another powerful feature is environment scoped variables. Sometimes the same application uses different values depending on where it is deployed:

  • different database URLs
  • different API endpoints
  • different feature flags
  • different credentials

Instead of hardcoding separate jobs for every small variation, you can define variables in GitLab settings and scope them to specific environments.

Examples:

  • DATABASE_URL scoped to staging
  • DATABASE_URL scoped to production
  • API_BASE_URL scoped to review/*

Then the same deployment logic can run across multiple targets while GitLab injects the correct value for the current environment.

This reduces duplication and helps keep sensitive configuration out of the repository.

Complete Example: Dev to Staging to Production

Here is a complete example showing environment tracking across a simple delivery flow.

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'
    - when: never

stages:
  - test
  - deploy

unit-tests:
  stage: test
  image: node:20
  script:
    - npm ci
    - npm test

review-app:
  stage: deploy
  script:
    - ./scripts/deploy-review.sh
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    url: https://review-$CI_MERGE_REQUEST_IID.example.com
    on_stop: stop-review-app

stop-review-app:
  stage: deploy
  script:
    - ./scripts/destroy-review.sh
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
      when: manual
      allow_failure: true
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    action: stop

deploy-dev:
  stage: deploy
  script:
    - ./scripts/deploy-dev.sh
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  environment:
    name: development
    url: https://dev.example.com

deploy-staging:
  stage: deploy
  script:
    - ./scripts/deploy-staging.sh
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual
  environment:
    name: staging
    url: https://staging.example.com

deploy-production:
  stage: deploy
  script:
    - ./scripts/deploy-production.sh
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
      when: manual
  environment:
    name: production
    url: https://app.example.com

What this pipeline does

  • merge request pipelines create a review app with a unique environment name and URL
  • a stop job can tear the review app down
  • main branch deployments automatically push to development
  • staging is a manual promotion step
  • production is a separate manual promotion step with its own tracked environment

This single file now gives you:

  • clear environment history
  • clickable environment URLs
  • review app previews
  • cleaner release promotion visibility
  • a better basis for approvals and operational metrics

Practical Tips for Designing Environments

  1. Use meaningful names. Prefer staging over vague labels like env2.
  2. Always set URLs when possible. They make environments more useful for non-engineers.
  3. Pair dynamic environments with cleanup. Use on_stop and a stop job.
  4. Protect production. Do not make production just another ordinary job.
  5. Use scoped variables. They simplify safe multi-environment configuration.
  6. Keep promotion paths obvious. A visible dev → staging → production flow reduces mistakes.

Common Mistakes to Avoid

  • treating environments as mere job names instead of tracked deployment targets
  • forgetting the stop job for review apps
  • reusing one environment name for many different temporary previews
  • storing production values directly in YAML instead of scoped variables
  • skipping protected environment controls for high-risk deployments

Final Takeaway

GitLab environments are one of the features that turn a basic CI pipeline into a real delivery platform. By using the environment keyword, setting URLs, modeling static and dynamic targets, adding review apps, wiring stop jobs with on_stop, protecting production, and scoping variables per environment, you gain far more than deployment automation. You gain visibility, safer releases, better collaboration, and stronger operational insight.


Knowledge Check

Exercise

Question 1: Environment Basics

What is the main value of a GitLab environment beyond simply labeling a job?

Exercise

Question 2: Review App Cleanup

Why is the on_stop pattern important for dynamic review app environments?

Exercise

Question 3: Protected Environments

What is the main purpose of a protected environment in GitLab CI/CD?

PreviousPrev
Next

Continue Learning

Variables, Secrets and Environments in GitLab CI

Master GitLab CI/CD variables, predefined variables, custom variables, masked and protected secrets, group-level variables, environment-scoped variables, and .env file injection.

12 min read·Easy

GitLab Runners

Learn what a GitLab Runner is, how GitLab CI runners execute jobs, runner types, executor choices, runner registration, tags, security, concurrency, and a full Docker executor example.

12 min read·Easy

GitLab CI Pipeline Rules

Learn GitLab CI rules, rules if, rules changes, rules exists, workflow rules, merge request pipeline conditions, manual jobs, and how to control exactly when GitLab pipelines and jobs run.

12 min read·Easy

Explore Related Topics

Do

Docker Tutorials

Build and push Docker images in your pipelines

Gi

Git Tutorials

Trigger CI/CD pipelines from Git events

Try the Tool

YAML Validator

Validate GitHub Actions and CI/CD pipeline YAML files.

Cron Parser

Build and understand scheduled workflow cron expressions.

On This Page

What Are GitLab Environments?The `environment` Keyword in Jobs`name``url`Static vs Dynamic EnvironmentsStatic environmentsDynamic environmentsViewing Deployment History in GitLabDynamic Environments for Merge RequestsReview Apps in GitLab CI/CDThe `on_stop` Keyword and Stop Job PatternDeployment jobStop jobProtected Environments and Deployment ApprovalsWhy protected environments matterDeployment Frequency and DORA MetricsEnvironment-Scoped VariablesComplete Example: Dev to Staging to ProductionWhat this pipeline doesPractical Tips for Designing EnvironmentsCommon Mistakes to AvoidFinal TakeawayKnowledge Check