Conditional GitLab CI/CD Pipeline for Dev, Main and Merge Requests

A Conditional GitLab CI/CD Pipeline allows teams to control how jobs execute based on branches and events. Instead of running the same jobs for every commit, this approach ensures that development, production, and merge request workflows are clearly separated.

In this guide, we implement a Conditional GitLab CI/CD Pipeline that triggers automatically and executes different jobs depending on whether code is pushed to dev, pushed to main, or submitted through a merge request.

This structured approach reflects real-world DevOps practices and prevents unnecessary or risky deployments.

Understanding the Objective

The goal of this pipeline is simple in theory but critical in practice:

  • When code is pushed to the dev branch, only development or staging jobs should run.
  • When code is pushed to the main branch, only production-related jobs should execute.
  • When a merge request is created or updated, only validation and testing jobs must run.
  • Deployment jobs must never run during merge requests.
  • The pipeline should trigger automatically without manual intervention.

This ensures efficiency, prevents accidental production deployments, and maintains a clean DevOps workflow.


Why Use a Conditional GitLab CI/CD Pipeline?

A Conditional GitLab CI/CD Pipeline ensures that:

  • Development branches trigger only staging-related tasks
  • Production branches trigger only production jobs
  • Merge requests run validation checks without deploying

Without conditional logic, pipelines waste resources and increase the risk of accidental production releases. Branch-based rules solve this problem by using GitLab’s built-in CI variables.


Designing the Pipeline Structure

A well-structured pipeline must include clearly defined stages. For this task, we define:

  • validate
  • build
  • deploy

Each stage represents a logical phase in the software lifecycle.


Conditional GitLab CI/CD Pipeline flow for dev main and merge request branches

Writing the .gitlab-ci.yml Configuration

Below is the working configuration that satisfies all acceptance criteria.

stages:
  - validate
  - build
  - deploy

# Validation job (Runs for all branches and merge requests)
validate_job:
  stage: validate
  script:
    - echo "Running validation checks..."
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "dev"'
    - if: '$CI_COMMIT_BRANCH == "main"'

# Development build (Only for dev branch)
build_dev:
  stage: build
  script:
    - echo "Building application for development..."
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'

# Production build (Only for main branch)
build_prod:
  stage: build
  script:
    - echo "Building application for production..."
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

# Staging deployment (Only for dev branch)
deploy_staging:
  stage: deploy
  script:
    - echo "Deploying to staging environment..."
  rules:
    - if: '$CI_COMMIT_BRANCH == "dev"'

# Production deployment (Only for main branch)
deploy_production:
  stage: deploy
  script:
    - echo "Deploying to production environment..."
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'

This configuration ensures that jobs execute only when their branch conditions are satisfied.


How the Conditional Logic Works

GitLab evaluates the rules section inside each job. If the condition evaluates to true, the job runs. Otherwise, it is skipped.

For example:

  • When pushing to dev, only build_dev and deploy_staging execute.
  • When pushing to main, only production jobs run.
  • During merge requests, only the validation job runs.

This prevents accidental production deployments and avoids unnecessary job execution.


Step-by-Step Implementation in GitLab

Step 1: Create or Open Your GitLab Project

Navigate to your repository in GitLab.


Step 2: Create the .gitlab-ci.yml File

Go to:

Repository → Files → Create New File

Name it:

.gitlab-ci.yml

Paste the configuration shown above and commit the changes.

Creating gitlab-ci.yml file for Conditional GitLab CI/CD Pipeline

Cloning the Repository for Testing

To properly test branch-based execution, clone your repository locally.

Go to:

Project → Code → Clone → HTTPS

Then run the following commands in your terminal:

git clone https://gitlab.com/your-username/your-project-name.git
cd your-project-name

Step 3: Verify Automatic Pipeline Trigger

After committing, navigate to:

CI/CD → Pipelines

You should see a pipeline automatically triggered.


Testing All Required Scenarios

To pass the task validation, you must test all three scenarios.

Scenario 1: Push to Dev Branch

Switch to or create the dev branch:

git checkout -b dev

If it already exists:

git checkout dev

Make a small change in your project (for example, modify README.md), then execute:

git add .
git commit -m "Testing dev branch pipeline"
git push origin dev

After pushing, GitLab automatically triggers the pipeline.

Conditional GitLab CI/CD Pipeline running dev branch jobs
Scenario 2: Push to Main Branch

Switch to main:

git checkout main

Pull latest changes:

git pull origin main

Make a small change and run:

git add .
git commit -m "Testing production pipeline"
git push origin main

The production pipeline should now execute.

Conditional GitLab CI/CD Pipeline running production jobs on main branch
Scenario 3: Create a Merge Request

Push changes to dev first, then create a merge request:

  1. Navigate to GitLab → Merge Requests
  2. Click “New Merge Request”
  3. Source branch: dev
  4. Target branch: main
  5. Create the merge request

GitLab automatically triggers a pipeline for the merge request.

Conditional GitLab CI/CD Pipeline triggered by merge request showing validation stage only
How Reviewers Validate This Task

A reviewer should be able to:

  1. Push to dev and see only development jobs.
  2. Push to main and see only production jobs.
  3. Create a merge request and see only validation jobs.

If all three conditions behave correctly, the task is successfully completed.


Common Failure Scenarios to Avoid

Several mistakes can cause rejection:

  • Running identical jobs for all branches.
  • Allowing production deployment from dev.
  • Triggering deployments during merge requests.
  • Using only instead of rules incorrectly.
  • Failing to trigger pipelines automatically.

Always test thoroughly before submission.


Best Practices for Branch-Based Pipelines

When building real-world CI/CD systems:

  • Separate environments strictly.
  • Never allow production deployment from development branches.
  • Keep validation jobs lightweight.
  • Use clear stage naming.
  • Monitor logs under CI/CD → Jobs for transparency.

GitLab logs provide full visibility into execution, which helps debugging and auditing.


Conclusion

Implementing a conditional GitLab pipeline is not just an academic task; it reflects real DevOps maturity. By structuring the pipeline into stages and using rule-based execution, we ensure safe deployments, optimized resource usage, and environment isolation.

This approach prevents accidental production releases, improves development workflow, and satisfies strict review requirements.

A properly designed conditional pipeline demonstrates clear understanding of CI/CD architecture and practical DevOps implementation.