← All Posts

Writing · April 18, 2026

CI/CD Explained: Continuous Integration vs Continuous Delivery (2026)

CI/CD Explained: Continuous Integration vs Continuous Delivery (2026)

What is the difference between continuous integration and continuous delivery? A complete guide to CI/CD pipelines with GitHub Actions, Docker, Terraform, and real-world examples from AWS and Azure deployments.

DevOpsCloudAWSAzure


What is CI/CD? {#what-is-cicd}

CI/CD is the practice of automating the build, test, and deployment of software. Instead of manually building and deploying code, every commit triggers an automated pipeline that validates and ships the change.

  WITHOUT CI/CD:
  Developer writes code → manually builds → manually tests →
  manually deploys → hopes nothing breaks → fixes production at 2am

  WITH CI/CD:
  Developer pushes commit → pipeline runs automatically →
  tests pass → deploys to staging → approved → deploys to production
  (all in 10 minutes, while developer works on the next feature)

The three terms are often used interchangeably but mean different things:

Term What it automates Manual step?
CI (Continuous Integration) Build + test on every commit None
CD (Continuous Delivery) CI + deploy to staging Manual approval to production
CD (Continuous Deployment) CI + deploy to production None — fully automated

Continuous Integration {#ci}

CI means every developer commit triggers an automated build and test run. The goal: catch bugs within minutes, not days.

  Developer pushes to feature branch
          │
          ▼
  ┌───────────────────────────────────────────────────┐
  │              CI PIPELINE                           │
  │                                                    │
  │  1. Checkout code                                  │
  │  2. Install dependencies                           │
  │  3. Run linter (code style)                        │
  │  4. Run unit tests                                 │
  │  5. Run integration tests                          │
  │  6. Security scan (SAST, dependency audit)         │
  │  7. Build Docker image                             │
  │  8. Run container tests                            │
  │                                                    │
  │  ✅ All pass → PR can be merged                    │
  │  ❌ Any fail → PR blocked, developer notified      │
  └───────────────────────────────────────────────────┘

CI best practices:


Continuous Delivery {#cd-delivery}

Continuous Delivery extends CI by automatically deploying every passing build to a staging environment. Production deployment requires a manual approval.

  CI passes
      │
      ▼
  Deploy to STAGING (automatic)
      │
      ▼
  Run smoke tests on staging
      │
      ▼
  ┌─────────────────────────┐
  │  Manual approval gate   │  ← Human reviews staging
  │  (product owner / QA)   │
  └────────────┬────────────┘
               │ Approved
               ▼
  Deploy to PRODUCTION (automatic after approval)

Continuous Deployment {#cd-deployment}

Continuous Deployment removes the manual gate — every commit that passes all tests deploys to production automatically.

  Commit → CI → Staging → Automated tests → PRODUCTION
                                            (no human approval)

This requires extremely high test coverage and confidence in your pipeline. Companies like Netflix, Amazon, and GitHub deploy to production hundreds of times per day using this model.


Building a CI/CD Pipeline {#pipeline}

  ┌─────────────────────────────────────────────────────────┐
  │                  FULL CI/CD PIPELINE                     │
  │                                                          │
  │  SOURCE          BUILD           TEST            DEPLOY  │
  │  ──────          ─────           ────            ──────  │
  │  Git push   →  Compile/    →  Unit tests   →  Staging   │
  │               Install         Integration      (auto)   │
  │               deps            E2E tests                  │
  │               Lint            Security scan              │
  │               Docker build    Performance                │
  │               Image scan      Contract tests             │
  │                                    │                     │
  │                               ┌────┴────┐               │
  │                               │Approval?│               │
  │                               └────┬────┘               │
  │                                    │ Yes                 │
  │                                    ▼                     │
  │                               Production                 │
  │                               (blue/green)               │
  └─────────────────────────────────────────────────────────┘

GitHub Actions Example {#github-actions}

A complete CI/CD pipeline for a containerised application deploying to AWS ECS:

# .github/workflows/deploy.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  AWS_REGION: us-east-1
  ECR_REPOSITORY: my-app
  ECS_SERVICE: my-app-service
  ECS_CLUSTER: production

jobs:
  # ── CI: Build and Test ──────────────────────────────────
  ci:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
          cache: pip

      - name: Install dependencies
        run: pip install -r requirements.txt -r requirements-dev.txt

      - name: Lint
        run: ruff check .

      - name: Unit tests
        run: pytest tests/unit/ -v --cov=app --cov-report=xml

      - name: Security scan
        run: |
          pip install bandit safety
          bandit -r app/
          safety check

  # ── CD: Build image and deploy ──────────────────────────
  deploy:
    needs: ci
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials (OIDC — no stored keys)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::$:role/github-actions-deploy
          aws-region: $

      - name: Login to ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build, tag, and push image
        env:
          ECR_REGISTRY: $NaN
          IMAGE_TAG: $
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v2
        with:
          task-definition: task-definition.json
          service: $
          cluster: $
          wait-for-service-stability: true

Deployment Strategies {#deployment-strategies}

Strategy How it works Downtime Rollback speed Risk
Recreate Stop old, start new Yes Slow High
Rolling Replace instances one by one No Medium Medium
Blue/Green Run both versions, switch traffic No Instant Low
Canary Route 5% traffic to new version, monitor, increase No Instant Very low
Feature flags Deploy code, enable feature separately No Instant Very low

Blue/Green with AWS CodeDeploy:

resource "aws_codedeploy_deployment_group" "app" {
  app_name               = aws_codedeploy_app.app.name
  deployment_group_name  = "production"
  service_role_arn       = aws_iam_role.codedeploy.arn
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }
    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 5
    }
  }

  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route { listener_arns = [aws_lb_listener.https.arn] }
      target_group { name = aws_lb_target_group.blue.name }
      target_group { name = aws_lb_target_group.green.name }
    }
  }
}

Infrastructure CI/CD with Terraform {#iac-cicd}

Infrastructure changes should go through CI/CD too — not applied manually from a laptop.

# .github/workflows/terraform.yml
name: Terraform CI/CD

on:
  pull_request:
    paths: ['terraform/**']
  push:
    branches: [main]
    paths: ['terraform/**']

jobs:
  plan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.9.0

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::$:role/terraform-ci
          aws-region: us-east-1

      - name: Terraform Init
        run: terraform -chdir=terraform init

      - name: Terraform Validate
        run: terraform -chdir=terraform validate

      - name: Terraform Plan
        run: terraform -chdir=terraform plan -out=tfplan

      - name: Post plan to PR
        uses: actions/github-script@v7
        # Posts the plan output as a PR comment

  apply:
    needs: plan
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production  # requires manual approval in GitHub
    steps:
      - name: Terraform Apply
        run: terraform -chdir=terraform apply tfplan

FAQ {#faq}

What is the difference between continuous integration and continuous delivery? CI automatically builds and tests every commit. Continuous Delivery extends CI by automatically deploying to staging, with a manual approval gate before production. Continuous Deployment removes the manual gate entirely.

What is the best CI/CD tool in 2026? GitHub Actions for teams on GitHub — tight integration, generous free tier, huge marketplace. GitLab CI/CD for self-hosted or GitLab teams. Jenkins for enterprises with existing investment. Azure DevOps Pipelines for Microsoft-stack teams.

What is a deployment pipeline? An automated sequence of stages — build, test, security scan, package, deploy to staging, integration test, deploy to production. Each stage is a quality gate. Failure stops the pipeline and notifies the team.

How do you roll back a bad deployment? Blue/green: switch traffic back to the old version instantly. Canary: reduce traffic to new version to 0%. Feature flags: disable the feature without redeploying. Rolling: redeploy the previous image tag. The fastest rollback is always blue/green or feature flags.


Building CI/CD pipelines on AWS or Azure? Let's connect on LinkedIn.


Comments & Reactions