GitLab CI/CD – Environment

This article covers the environment keyword in GitLab CI/CD, explaining its role in defining and managing deployment environments within your pipelines. We will explore how it links jobs to specific environments, tracks deployments, and provides access to environment-specific variables, enhancing visibility and control over your continuous delivery process.

What is an Environment in GitLab CI/CD?

An environment in GitLab CI/CD represents a specific deployment target for your application. It is a logical name you assign to a deployment, helping you organize and see where your code is running.

Common Environment Examples:

  • development
  • staging
  • production
  • review/feature-branch-xyz (for dynamic review apps)
  • qa-testing

By defining environments, GitLab gives you:

  1. Visibility: A dedicated “Environments” page in your project (Deployments > Environments) showing all active deployments.
  2. Tracking: A history of deployments to each environment, including who deployed what and when.
  3. Control: The ability to stop environments, browse deployed applications, and perform easy rollbacks.
  4. Integration: Direct links to the deployed application’s URL.

Defining Environments in .gitlab-ci.yml

You define an environment for a specific job using the environment keyword within your .gitlab-ci.yml file.

Basic Syntax:

deploy_to_staging:
  stage: deploy
  script:
    - echo "Deploying to staging..."
    - deploy_script --env=staging
  environment: staging # Defines this job as deploying to the 'staging' environment

This simple definition is enough for GitLab to recognize “staging” as an environment and start tracking deployments to it.

Key Attributes of the environment Keyword

The environment keyword can take several attributes, providing richer functionality:

environment:name

Purpose: This is the mandatory name of the environment. GitLab uses this to identify and group deployments. It is the primary way to refer to your deployment target.

Syntax: environment: <environment_name>

Example:

deploy_to_prod:
  stage: deploy
  script: deploy_to_production.sh
  environment: production # The name 'production'

environment:url

Purpose: Provides a direct link from the GitLab UI to the running application in that environment. This is invaluable for quick access and testing.

Syntax: environment: url: <url_string>

Example:

deploy_review_app:
  stage: deploy
  script:
    - deploy_review_app.sh "$CI_COMMIT_REF_SLUG" # Script deploys and gets URL
  environment:
    name: review/$CI_COMMIT_REF_SLUG # Dynamic environment name based on branch
    url: https://$CI_COMMIT_REF_SLUG.my-review-app.com # Dynamic URL for the review app

Explanation: $CI_COMMIT_REF_SLUG is a predefined variable that provides a “slug” version of the branch name (e.g., feature/my-new-feature becomes feature-my-new-feature), perfect for creating dynamic URLs.

environment:on_stop

Purpose: Specifies a job that GitLab should run when this environment is manually stopped from the UI or automatically via auto_stop_in. This is essential for cleaning up dynamic environments (like review apps) to save resources.

Syntax:

environment:
  name: <name>
  on_stop: <stop_job_name> # Links to a separate job definition

Example:

deploy_review_app:
  stage: deploy
  script: deploy_review_app.sh "$CI_COMMIT_REF_SLUG"
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    url: https://$CI_COMMIT_REF_SLUG.my-review-app.com
    on_stop: stop_review_app # Link to the stop job

stop_review_app:
  stage: cleanup # A dedicated cleanup stage (could be hidden until needed)
  script:
    - delete_review_app.sh "$CI_COMMIT_REF_SLUG"
  when: manual # This job is manually triggered by the 'Stop' button
  rules:
    # This rule ensures the job only appears in the pipeline when its 'on_stop' action is triggered.
    # It also makes it so the job doesn't run automatically in regular pipelines.
    - if: '$CI_ENVIRONMENT_ACTION == "stop"'
      when: on_success
  allow_failure: true # Cleanup should ideally not fail the main pipeline

Explanation: The stop_review_app job will be associated with the review/$CI_COMMIT_REF_SLUG environment. When you go to Deployments > Environments and click “Stop” on that specific review app, GitLab will execute the stop_review_app job. The rules with $CI_ENVIRONMENT_ACTION == "stop" are critical here to ensure the job runs only when explicitly triggered by the stop action.

environment:action

Purpose: The action keyword is defined within the environment block of a job to specify how that job interacts with the environment. It tells GitLab the role of the job regarding the environment’s lifecycle. It is important for granular control over environment states and for integrating with GitLab’s deployment tracking features.

Keyword Type: Job keyword, meaning it is used only as part of a job definition.

Supported Values:

start (Default):

Meaning: This is the default action. It indicates that the job starts or creates the environment. A new deployment record is typically created after this job starts.

Use Case: Your primary deployment jobs (e.g., deploy_to_staging, deploy_production).

Example:

deploy_app_to_dev:
  stage: deploy
  script: deploy_dev_script.sh
  environment:
    name: development
    url: https://dev.my-app.com
    action: start # This is the default, often omitted
prepare:

Meaning: Indicates that the job is only preparing the environment. It does not trigger a deployment record in GitLab.

Use Case: Jobs that set up infrastructure prerequisites before the actual deployment job, but don’t deploy the application itself (e.g., provisioning a database, setting up a VPC).

Example:

provision_db:
  stage: infra
  script: provision_db_script.sh
  environment:
    name: staging
    action: prepare # This job prepares 'staging' but doesn't show as a deployment
stop:

Meaning: Indicates that the job stops or tears down an environment. This action is critical when paired with on_stop or auto_stop_in to clean up resources. When an on_stop job runs, the $CI_ENVIRONMENT_ACTION predefined variable is set to "stop".

Use Case: Jobs that delete review apps, de-provision temporary testing environments.

Example:

stop_review_app:
  stage: cleanup
  variables:
    GIT_STRATEGY: none # Often no need to clone repo for cleanup
  script: make delete-app "$CI_COMMIT_REF_SLUG"
  when: manual
  environment:
    name: review/$CI_COMMIT_REF_SLUG # Refers to the environment name being stopped
    action: stop # Explicitly marks this job as stopping the environment
  rules:
    # This rule ensures the job only appears in the pipeline when its 'on_stop' action is triggered.
    - if: '$CI_ENVIRONMENT_ACTION == "stop"'
      when: on_success
verify:

Meaning: Indicates that the job is only verifying the environment. It does not trigger a deployment record.

Use Case: Post-deployment smoke tests, health checks, or integration tests that run against a deployed environment without being part of the deployment itself.

Example:

smoke_test_staging:
  stage: verify
  script: run_smoke_tests.sh --env=staging
  environment:
    name: staging
    action: verify # This job verifies 'staging' but isn't a deployment
access:

Meaning: Indicates that the job is only accessing the environment. It does not trigger a deployment record.

Use Case: Jobs that gather information about an environment (e.g., getting current status, listing resources) or interact with it for administrative purposes, but don’t modify its state.

Example:

get_prod_status:
  stage: ops
  script: get_production_status.sh
  environment:
    name: production
    action: access # This job accesses 'production' without deploying

environment:auto_stop_in

Purpose: Automatically stops a dynamic environment after a specified duration. This requires an on_stop job to be defined. This is great for managing temporary testing environments to prevent resource waste.

Syntax:

environment:
  name: <name>
  auto_stop_in: <duration> # e.g., '1 week', '2 days', '3 hours', '90 minutes'
  on_stop: <stop_job_name>

Example:

deploy_temp_test_env:
  stage: deploy
  script: deploy_temp_env.sh
  environment:
    name: temporary-test-$CI_COMMIT_SHORT_SHA
    url: https://temp-$CI_COMMIT_SHORT_SHA.my-app.com
    on_stop: cleanup_temp_env
    auto_stop_in: 4 hours # This environment will automatically be stopped after 4 hours

cleanup_temp_env:
  stage: cleanup
  script: delete_temp_env.sh
  when: manual # Will be automatically triggered by auto_stop_in
  rules:
    - if: '$CI_ENVIRONMENT_ACTION == "stop"'
      when: on_success

Explanation: The environment temporary-test-... will be automatically marked for stopping after 4 hours. Once that time passes, the cleanup_temp_env job will be automatically triggered.

environment:kubernetes

Purpose: Integrates with a Kubernetes cluster configured in GitLab. When this is set, GitLab automatically provides a Kubeconfig file to the job, allowing it to interact with the specified Kubernetes cluster context. This is particularly useful for deployments to Kubernetes.

Syntax:

environment:
  name: <name>
  kubernetes:
    namespace: <kubernetes_namespace> # Optional: default is project's
    # Optional: You can specify an actual Kubernetes service account name if needed
    # service_account_name: my-app-service-account

Example:

deploy_to_k8s_staging:
  stage: deploy
  image: alpine/helm:3.8.1 # Or any image with kubectl/helm
  script:
    - helm upgrade --install my-app ./charts --namespace "$CI_ENVIRONMENT_SLUG"
  environment:
    name: staging
    kubernetes:
      namespace: myapp-staging # Deploy to this specific namespace
    url: https://staging.my-k8s-app.com

Explanation: The deploy_to_k8s_staging job will be configured to use the Kubernetes cluster integrated with your GitLab project. The namespace attribute directs the deployment to a specific Kubernetes namespace. The job automatically receives credentials to interact with that cluster.

environment:deployment_tier

Purpose: Categorizes your environments into predefined tiers (e.g., production, staging, development, testing, other). This helps GitLab understand the criticality and role of an environment, which can influence how it’s displayed, protected, or integrated with other features.

Syntax:

environment:
  name: <name>
  deployment_tier: <tier_name> # e.g., production, staging, development, testing, other

Example:

deploy_to_prod:
  stage: deploy
  script: deploy_production.sh
  environment:
    name: production
    url: https://my-app.com
    deployment_tier: production # Mark this environment as production tier

deploy_to_dev:
  stage: deploy
  script: deploy_dev.sh
  environment:
    name: development
    url: https://dev.my-app.com
    deployment_tier: development # Mark this as a development tier

Explanation: GitLab’s UI might visually distinguish environments based on their tier. More critically, features like Protected Environments (which prevent unauthorized deployments) specifically leverage the production tier by default.

Dynamic Environments

Dynamic environments are environments whose names (and often URLs) are generated at runtime, usually based on branch names or merge request IDs. They are typically short-lived and are crucial for creating “review apps” or temporary testing instances for every feature branch or merge request.

  • How they work: You use predefined CI/CD variables like $CI_COMMIT_REF_SLUG in the name and url attributes of your environment definition.
  • Cleanup: To prevent sprawl and cost, dynamic environments are almost always paired with an on_stop job and often auto_stop_in to ensure they’re automatically cleaned up when no longer needed.
  • Example: (See deploy_review_app and auto_stop_in examples above for dynamic environment usage).

The Environments Page (Deployments > Environments)

This dedicated section in GitLab is where the power of environments truly comes to life:

  • Current Deployments: See all active environments, their last deployed commit, and the associated job.
  • History: View a full history of deployments to each environment.
  • Browse Live: Click the URL link to directly access your deployed application.
  • Rollback: Easily re-deploy a previous successful deployment to an environment. This triggers a new pipeline for the historical commit.
  • Stop Environment: Manually trigger the on_stop job for cleanup.

Environment-Scoped Variables

Beyond the environment keyword, GitLab also lets you define CI/CD variables (in Project/Group settings) that are scoped to specific environments. This is extremely useful for managing secrets or configuration that differs between environments (e.g., database URLs, API keys).

  • You could set a variable DB_HOST to db.staging.example.com for the staging environment and db.prod.example.com for the production environment.
  • These variables are only injected into jobs that declare they are deploying to that specific environment (using environment: <name>).

Best Practices for Using Environments

  • Name Consistently: Use clear and consistent naming conventions for your environments (e.g., dev, staging, production, review/MR-ID).
  • Leverage Dynamic Environments: For feature branches or merge requests, use dynamic environment names (e.g., review/$CI_COMMIT_REF_SLUG) to provide isolated testing environments for each change.
  • Define on_stop for Dynamic Environments: Always pair dynamic environments with an on_stop job. This ensures resources are cleaned up efficiently, preventing “environment sprawl” and unnecessary cloud costs.
  • Automate urls: Whenever possible, programmatically generate and set the url for your environments so they are directly clickable from GitLab.
  • Secure Production Deployments:
    • Use when: manual for production deployment jobs.
    • Protect the production environment in GitLab settings (Project > Settings > CI/CD > Environments > Protected Environments) to restrict who can trigger deployments.
    • Use protected variables for production credentials.
    • Consider using dedicated runners with specific tags for production deployments.
  • Utilize Environment-Scoped Variables: For any configuration that varies per environment, store it as an environment-scoped CI/CD variable.
  • Monitor the Environments Dashboard: Regularly check the Deployments > Environments page to get an overview of your active deployments and their status.

FAQs – GitLab CI/CD Environment


What is the environment keyword in GitLab CI/CD?
The environment keyword in GitLab CI/CD defines where your code is being deployed (e.g., staging, production). It allows GitLab to track deployments, show them in the Environments dashboard, and optionally enable features like manual rollbacks, deployment history, and auto-stop of review apps.


How do I define an environment in a GitLab CI job?
Use the environment keyword inside a job to specify the environment’s name:

deploy_staging:
  stage: deploy
  script:
    - ./deploy.sh staging
  environment:
    name: staging

This tells GitLab to track this job as a deployment to staging.


What are the common use cases for the environment keyword?

  • Track which job deployed to which environment.
  • Enable manual deployments and rollbacks.
  • View deployment logs and environment states in GitLab UI.
  • Automatically stop dynamic environments like review apps.

Can I create dynamic environment names with variables?
Yes. You can use GitLab predefined or custom variables to create dynamic names, often used in review apps:

review:
  script: ./deploy.sh $CI_COMMIT_REF_NAME
  environment:
    name: review/$CI_COMMIT_REF_NAME

This creates a separate environment per branch.


How do I define a URL for the environment?
You can include a url: key to make the environment accessible via the GitLab UI:

environment:
  name: production
  url: https://prod.example.com

GitLab shows a “View Environment” button in the UI that links to this URL.


How can I stop a dynamic environment when it is no longer needed?
Use the on_stop: keyword to define a job that stops the environment (e.g., when a branch is deleted or closed):

review:
  script: ./deploy-review.sh
  environment:
    name: review/$CI_COMMIT_REF_NAME
    on_stop: stop_review

stop_review:
  script: ./remove-review.sh
  environment:
    name: review/$CI_COMMIT_REF_NAME
    action: stop
  when: manual

This configuration links the stop job to the environment and allows it to be triggered manually or automatically.


What is the action: stop keyword used for in environments?
The action: stop is used in conjunction with on_stop: to mark a job as the environment shutdown job:

environment:
  name: review/$CI_COMMIT_REF_NAME
  action: stop

This job will be responsible for cleaning up or shutting down the environment.


Can I restrict a job to run only in a specific environment?
Indirectly, yes. You can use rules or only/except keywords with environment-related variables like $CI_ENVIRONMENT_NAME:

deploy:
  environment: production
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

This ensures that the job only runs when deploying to production.


What happens when I deploy multiple times to the same environment?
GitLab shows only the most recent deployment in the Environments dashboard. Previous deployments are still accessible via the deployment history tab.


How do I view environments and deployments in GitLab?
Go to your project and navigate to:

Operations → Environments

Here, you can view:

  • Active environments
  • Deployment history
  • Associated pipeline jobs
  • Environment URLs

Can environments be used with manual jobs?
Yes. You can mark deployment jobs as manual so they require a user trigger from the UI:

deploy_prod:
  stage: deploy
  script: ./deploy-prod.sh
  when: manual
  environment:
    name: production

This adds a “Play” button to the job in the GitLab UI.


Can I define multiple environments in the same pipeline?
Yes. You can create multiple deployment jobs targeting different environments:

deploy_staging:
  stage: deploy
  script: ./deploy.sh staging
  environment:
    name: staging

deploy_production:
  stage: deploy
  script: ./deploy.sh production
  environment:
    name: production

You can control which one runs using rules, only, or manual.


What happens if I delete an environment from the GitLab UI?
Deleting an environment removes:

  • The environment from the Environments dashboard.
  • Access to deployment history via UI.

Note: This does not remove any infrastructure unless your stop job or cleanup script explicitly handles that.


Can I track deployment time and status using environments?
Yes. GitLab automatically tracks:

  • When the deployment started and ended
  • Which user or pipeline deployed it
  • Whether the deployment succeeded or failed

This information is visible in the Environments and Deployments tabs.


Author

Debjeet Bhowmik

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

Leave a Comment