DEV Community

John Kagunda
John Kagunda

Posted on

CI/CD Explained: From Git Push to Production Deployment

Imagine you've just finished building a feature.

You test it locally. Everything works. You commit your changes, push them to GitHub, and then the real work begins.

Someone has to install the dependencies, run the tests, check whether the application builds correctly, create the production version, deploy it to a server, and make sure the application is actually running.

Now imagine doing all of that manually every time you make a change.

It works for a small project, but as your application grows, this process quickly becomes slow, repetitive, and error-prone.

This is where CI/CD comes in.

CI/CD is a development practice that automates the journey from writing code to delivering that code to users. Instead of manually testing, building, and deploying every change, we create a pipeline that performs these steps automatically.

A typical workflow might look like this:

Developer
    ↓
git push
    ↓
GitHub / GitLab
    ↓
Run Tests
    ↓
Build Application
    ↓
Build Docker Image
    ↓
Push Image to Registry
    ↓
Deploy
    ↓
Health Check
    ↓
Production 🚀
Enter fullscreen mode Exit fullscreen mode

The idea is simple:

You write the code. The pipeline handles the repetitive work.

In this article, we'll break down how a modern CI/CD pipeline works from start to finish. We'll look at where Git, automated testing, Docker, container registries, and deployment platforms fit into the process—and, more importantly, how all these pieces work together.

By the end, you should be able to look at a CI/CD pipeline and understand exactly what is happening at every stage.

1. What CI/CD actually means

  • CI — Continuous Integration: Automatically test and validate code whenever changes are pushed.
  • CD — Continuous Delivery/Deployment: Automatically prepare or deploy validated code to an environment.

2. A realistic example

Show a developer working on:

my-app/
├── frontend/
├── backend/
├── Dockerfile
├── docker-compose.yml
└── .github/
    └── workflows/
        └── ci-cd.yml
Enter fullscreen mode Exit fullscreen mode

Then explain what happens when they run:

git add .
git commit -m "Add authentication"
git push origin main
Enter fullscreen mode Exit fullscreen mode

3. CI starts automatically

GitHub Actions, GitLab CI, Jenkins, etc. detects the push.

Example:

name: CI/CD

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install dependencies
        run: npm install

      - name: Run tests
        run: npm test

      - name: Build application
        run: npm run build
Enter fullscreen mode Exit fullscreen mode

Then explain each step rather than just dumping YAML.

4. Where Docker fits

This is where Docker becomes particularly useful:

Source Code
    ↓
CI
    ↓
Tests
    ↓
Docker Build
    ↓
Docker Image
    ↓
Container Registry
    ↓
Production Server
    ↓
Docker Container
Enter fullscreen mode Exit fullscreen mode

For example:

docker build -t myapp:latest .
docker push username/myapp:latest
Enter fullscreen mode Exit fullscreen mode

The important concept is:

CI verifies the application. Docker packages the application. CD delivers that package to the target environment.

5. Deployment

The CD stage could SSH into a server and run:

docker pull username/myapp:latest
docker stop myapp || true
docker rm myapp || true
docker run -d \
  --name myapp \
  -p 80:3000 \
  username/myapp:latest
Enter fullscreen mode Exit fullscreen mode

Or, for a Compose-based application:

docker compose pull
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

6. The complete production workflow

I'd end the article with something like:


text
                 ┌──────────────┐
                 │  Developer   │
                 └──────┬───────┘
                        │
                     git push
                        │
                        ▼
                 ┌──────────────┐
                 │ GitHub/GitLab│
                 └──────┬───────┘
                        │
                        ▼
                 ┌──────────────┐
                 │     CI       │
                 │              │
                 │ Tests        │
                 │ Lint         │
                 │ Build        │
                 └──────┬───────┘
                        │
                    Success?
                    /       \
                  No         Yes
                  │           │
                  ▼           ▼
                Stop     Docker Build
                              │
                              ▼
                       Docker Registry
                              │
                              ▼
                           CD
                              │
                              ▼
                       Production
                              │
                              ▼
                       Health Check
                              │
                              ▼
                         🚀 Live App
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
pushpum_vats profile image
Pushpum Vats

You clearly walk through how a simple git push can trigger a CI/CD pipeline that ultimately lands the change in production. Could you elaborate on how you handle automated rollback or versioning when a deployment fails after the pipeline passes the tests?