GitLab Environments and Deploy
An environment in GitLab represents a place where your application runs — development, staging, or production. Tracking deployments through environments gives you a clear view of what version is live where, and lets you roll back with a single click.
The Deployment Pipeline — From Code to Live
Developer pushes code
↓
Pipeline: build → test → deploy-staging → deploy-production
↓ ↓ ↓
passes staging.app.com app.com (live users)
Environment: Environment:
"staging" "production"
Defining an Environment in .gitlab-ci.yml
Add an environment block to any deploy job. GitLab creates the environment automatically on the first run.
deploy-staging:
stage: deploy
script:
- ./deploy.sh staging
environment:
name: staging
url: https://staging.myapp.com
deploy-production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://myapp.com
when: manual
only:
- main
Viewing Environments
Go to Deploy → Environments. Each environment shows its current deployment status, the version running, and a history of past deployments.
Environments ────────────────────────────────────────────────────────────────── Name Status URL Last deployed ────────────────────────────────────────────────────────────────── production Active https://myapp.com v2.1.0 · 2h ago staging Active https://staging.app.com v2.2.0 · 30m ago review/MR-48 Active https://48.app.com MR #48 · 10m ago ──────────────────────────────────────────────────────────────────
Review Apps — A Live Preview Per Merge Request
A review app spins up a temporary live environment for each merge request. Reviewers visit a URL to see and interact with the exact change being proposed, without checking out code locally.
MR #48 opens: "Add dark mode toggle"
↓
Pipeline creates a temporary environment:
URL: https://review-mr-48.myapp.com
↓
Product manager visits the URL and tests dark mode
↓
MR approved and merged → Review app deleted automatically
Review App CI/CD Configuration
deploy-review:
stage: deploy
script:
- ./deploy.sh review-$CI_MERGE_REQUEST_IID
environment:
name: review/$CI_COMMIT_REF_SLUG
url: https://review-$CI_MERGE_REQUEST_IID.myapp.com
on_stop: stop-review ← name of the cleanup job
only:
- merge_requests
stop-review:
stage: deploy
script:
- ./destroy.sh review-$CI_MERGE_REQUEST_IID
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
when: manual
only:
- merge_requests
Deployment Tracking — What Is Running Where
Click any environment to see its full deployment history. Each row is one deployment with the commit hash, who triggered it, and when.
production — Deployment History ────────────────────────────────────────────────────────────────── #12 v2.1.0 a1b2c3d Sara 2 hours ago ← current #11 v2.0.5 b2c3d4e Arjun 3 days ago #10 v2.0.4 c3d4e5f Riya 1 week ago #9 v2.0.3 d4e5f6a Sara 2 weeks ago ──────────────────────────────────────────────────────────────────
Rolling Back to a Previous Deployment
If a new deployment breaks production, roll back instantly. In the deployment history, click the Re-deploy button next to any previous deployment. GitLab re-runs that deployment's job using the old commit — no code changes required.
Production broken after deploying v2.1.0
↓
Go to Deploy → Environments → production
↓
Click "Re-deploy" next to v2.0.5
↓
Pipeline runs the old deploy job with commit b2c3d4e
↓
Production is back to v2.0.5 ✅ (in about 2 minutes)
Protected Environments
Protecting an environment restricts who can deploy to it. Only members with the allowed role can trigger a deployment to protected environments.
Protected environment: production ──────────────────────────────────────────────── Allowed to deploy: Maintainers, Owners only Required approvals: 1 approval before deploy runs ────────────────────────────────────────────────
Set this at Settings → CI/CD → Protected Environments.
Deployment Approvals
For high-stakes environments like production, require one or more humans to approve a deployment before it runs. The pipeline pauses at the deploy job and sends a notification to approvers.
Pipeline #115 — waiting for approval ────────────────────────────────────────────────────── build ✅ → test ✅ → staging ✅ → production ⏳ Approvers notified: Sara (Maintainer), Arjun (Owner) Sara reviews the MR and deployment details Sara clicks "Approve deployment" Pipeline resumes → production deployment starts ──────────────────────────────────────────────────────
Environment Variables Per Environment
Store environment-specific configuration as CI/CD variables scoped to one environment. The same pipeline job reads different values depending on which environment it deploys to.
Variable: DATABASE_URL ────────────────────────────────────────────────────── Scope: staging → postgres://staging-db:5432/appdb Scope: production → postgres://prod-db:5432/appdb ────────────────────────────────────────────────────── The deploy script uses $DATABASE_URL without knowing which environment it is in — GitLab injects the right value.
Add scoped variables at Settings → CI/CD → Variables → Add variable → Environment scope.
Kubernetes Integration for Deployments
GitLab integrates with Kubernetes clusters so you can deploy containers directly from a pipeline job using kubectl or Helm. Connect a cluster at Infrastructure → Kubernetes clusters → Add cluster. Once connected, use the cluster's credentials as CI/CD variables in your deploy jobs.
deploy-to-k8s:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/my-webapp
my-webapp=registry.gitlab.com/acme/my-webapp:$CI_COMMIT_SHORT_SHA
environment:
name: production
url: https://myapp.com
only:
- main
