skip to content

In a GitLab CI job, what does the `environment:` keyword do, and what do its `name` and `url` fields control?

level: juniorimportance: must knowfreq 74%

answer

  1. metadata, not a deploy action
  2. GitLab records what is live where
  3. name identifies, slash makes folders
  4. url becomes the View app link
  5. CI_ENVIRONMENT_NAME / _SLUG / _URL

basics

~20 s

The environment: keyword marks a GitLab CI job as a deployment, so GitLab records what is deployed where. The name identifies the tracked environment; the url is the address GitLab links to from that environment, the job, and the merge request.

solid answer

~50 s

`environment:` is metadata you attach to a job. It does not deploy anything — your `script:` still does the work — but when the job runs, GitLab creates or updates an **Environment** record with that `name` and appends a **Deployment** to its history pointing at the commit and the job. That is what powers the Environments page: which commit is live on staging, when it got there, a link to open it, and the re-deploy/rollback buttons. `name` is the identifier, and a slash groups environments into folders in the UI, so `review/$CI_COMMIT_REF_SLUG` collapses hundreds of review apps under one `review` folder. `url` is where the app can be reached; GitLab turns it into an "Open live environment" link on the environment and a "View app" button in the merge request widget. Without `environment:`, a deploy job still works — GitLab just has no idea it happened.

code

yaml · 8 lines
yaml
deploy_staging:
  stage: deploy
  script:
    - ./deploy.sh staging
    - curl --fail "$CI_ENVIRONMENT_URL/health"
  environment:
    name: staging
    url: https://staging.example.com

go deeper

for a junior

Be able to write a deploy job with environment: name and url and say plainly that the script deploys while the keyword records the deployment for GitLab to display.

for a middle

Explain what GitLab stores — an environment plus a deployment tied to a commit and job — and name CI_ENVIRONMENT_NAME, CI_ENVIRONMENT_SLUG and CI_ENVIRONMENT_URL along with what a slash in the name does.

for a senior

Show why the record matters in production: without it there is no deployment history, no rollback button and no way to answer "what commit is live" during an incident. Mention action: prepare for non-deploying jobs.

for a principal

Own the naming scheme across many projects — stable names for fixed environments, folder prefixes for ephemeral ones — because environment names are what dashboards, DORA metrics and protected-environment rules key on.

## What the keyword is, and what it is not `environment:` is **job-level metadata** in `.gitlab-ci.yml`. Adding it does not make GitLab deploy anything, and removing it does not stop a deployment: the job's `script:` is what runs `kubectl`, `helm`, `scp`, `aws s3 sync` or whatever else. What the keyword changes is GitLab's *bookkeeping*. When a job carrying `environment:` starts, GitLab creates the named environment if it does not exist, and records a **deployment** — an entry tying that environment to the commit SHA, the pipeline, the job, the user who triggered it, and a status (running, success, failed). That record is the whole point. Everything GitLab offers around delivery is built on it: the Environments page listing what is currently live where, per-environment deployment history, the re-deploy and rollback buttons, the merge request widget showing that this branch is deployed, environment-scoped CI/CD variables, and protected environments. ```yaml deploy_staging: stage: deploy script: - ./deploy.sh staging environment: name: staging url: https://staging.example.com ``` ## `name` `name` is the identifier, and it is unique per project: two jobs using `name: staging` update the *same* environment, which is exactly what you want — the second deployment appends to the first one's history rather than creating a rival entry. The name may contain CI/CD variables, which is how dynamic environments work (`name: review/$CI_COMMIT_REF_SLUG`). A slash in the name has one extra meaning: GitLab groups environments whose names share a prefix before the slash into a **folder** in the UI. With hundreds of merge requests open, `review/add-login`, `review/fix-navbar` and friends appear as one collapsible `review` folder rather than hundreds of top-level rows. Inside the job, GitLab exposes `CI_ENVIRONMENT_NAME` (the name as written, after variable expansion) and `CI_ENVIRONMENT_SLUG` — a shortened, lowercased, DNS-safe version of the name that is safe to use as a hostname label or a Kubernetes namespace. ## `url` `url` is the address at which the deployed application can be reached. GitLab does not check it, ping it, or route to it; it renders it as a link. That link appears in three useful places: an "Open live environment" button on the environment, a link on the job page, and — for an environment attached to a merge request's branch — a "View app" button in the merge request widget, which is what makes review apps usable by a reviewer who has never opened a terminal. The value may be built from variables (`url: https://$CI_COMMIT_REF_SLUG.review.example.com`), and it is exposed to the job as `CI_ENVIRONMENT_URL`, so a smoke-test step can curl the thing it just deployed without repeating the hostname. When the URL is only known *after* the job runs — a platform that hands you a generated hostname — you can leave `url` out of the static config and have the script write the value into a `dotenv` report artifact, which GitLab reads back and attaches to the deployment. ## `action` `environment:action` says what this job does to the environment. The default is `start`, which is the recording behaviour described above. `stop` marks the environment stopped (see teardown of review apps). `prepare` attaches the job to the environment — making environment-scoped variables available — **without** recording a deployment, which is what you want for a plan or dry-run job that must read production credentials but is not deploying. `verify` and `access` are similar non-deploying variants used for verification and access-only jobs. ## Where teams get this wrong The most common mistake is simply never adding `environment:`, so deploys are invisible: GitLab's Environments page is empty, nobody can tell which commit is on staging, and there is no rollback button to press during an incident. The second is expecting the keyword to *perform* something — candidates sometimes claim `url` makes GitLab route traffic or health-check the app. It does neither. The third is giving each pipeline a unique environment name for a fixed environment (`staging-$CI_PIPELINE_ID`), which destroys the deployment history the feature exists to give you.

  • If two different jobs in different pipelines both use `environment: name: staging`, what does GitLab do?
    They update the same environment. Environment names are unique per project, so the second job appends a new deployment to `staging`'s history and that deployment becomes the current one. That is the intended behaviour — it is how the Environments page can say which commit is live and offer a rollback to the previous entry.
  • When would you set `environment:action: prepare` instead of the default?
    When a job must be associated with an environment without counting as a deployment — for example a plan, dry-run or verification job that needs the environment's scoped CI/CD variables. `prepare` attaches the job to the environment so those variables resolve, but records no deployment, so the environment's history and "what is live" state stay accurate.
  • How do you set the environment URL when the hostname is only known once the job has run?
    Have the script write the value into a `dotenv` report artifact and reference that variable from `environment:url`. GitLab reads the report after the job finishes and attaches the resolved URL to the deployment, so the "View app" link points at the address the platform actually allocated.

saying these in an interview costs you the question

  • Claims environment: performs the deployment itself
  • Thinks url makes GitLab route or health-check traffic
  • Gives a fixed environment a unique name per pipeline
  • Believes environments must be created in the UI first
  • Confuses environment:name with the job name

context