Back to Learn
DevOps Automation

CI/CD Pipeline Explained 2026 - CI vs CD, Stages & Jenkins vs GitHub Actions

Understand CI/CD in simple terms: what a pipeline is, the real difference between continuous integration and continuous delivery/deployment, the key stages, and how Jenkins compares to GitHub Actions.

Firoz Ahmed, AWS Certified Solutions Architect & DevOps Lead
Jan 21, 2026
25 min read
Updated

CI/CD is the assembly line of modern software - it takes a code change and automatically builds, tests and ships it. It is the single most important automation practice in DevOps, and the one interviewers push hardest on, because someone who has actually maintained a pipeline talks about it very differently from someone who has only read about one.

This guide is written for the second group who want to become the first. It has two complete, working pipelines in it - one for GitHub Actions and one for Jenkins - and spends as much time on how pipelines fail as on how they are supposed to work, because that is where the job actually is.

What is a CI/CD pipeline?

A CI/CD pipeline is an automated workflow that builds, tests and deploys your code every time a change is pushed - replacing slow, error-prone manual steps. CI (continuous integration) covers the build and test half; CD (continuous delivery or deployment) covers getting the passing build into an environment.

Concretely: you push a branch. A server notices, checks out your code, installs dependencies, compiles it, runs the tests, packages the result into an artifact or a container image, and pushes that artifact somewhere a deployment can pick it up. If any step exits with a non-zero status, the pipeline stops and tells you which one. That is the whole idea. Everything after that is detail.

The word "pipeline" is doing real work in that sentence. The steps run in a fixed order, each one only starts if the previous one succeeded, and the thing that passes through them is the same artifact from start to finish. Those three properties are what separate a pipeline from a folder of scripts someone runs by hand on release day. A pipeline that rebuilds the code for production after testing a different build in staging has quietly broken the third property, and it is one of the most common mistakes I see in batches.

It is also worth being clear about what a pipeline is not. It is not the tool. Jenkins, GitHub Actions and GitLab CI are pipeline runners; the pipeline is the definition you write for them, which is why the same skills transfer between all three and why this article shows the same pipeline in two of them. And it is not a deployment tool either - a pipeline hands a versioned artifact to a deployment, whether that is a shell script, a Helm chart or an Argo CD application. Keeping those responsibilities separate in your head makes the rest of DevOps much easier to learn.

CI vs CD - the real difference

Continuous Integration (CI) is about code: developers merge changes frequently, and each merge automatically builds and runs tests so bugs are caught early. Continuous Delivery (CD) takes every passing build and gets it ready to release, with a human approving the final push to production. Continuous Deployment goes one step further and releases to production automatically with no manual gate. In short: CI = integrate and test; CD = deliver/deploy what passed.

The bit that catches people out in interviews is that delivery and deployment share the same initials and are not the same thing. Delivery means every green build is deployable and a person still clicks the button. Deployment means there is no button. Both are correct answers to "what does CD stand for" - say which one you mean.

Continuous Integration Continuous Delivery Continuous Deployment
Question it answers Does this change break anything? Could we release this right now? Why has this not been released yet?
Ends with A tested artifact That artifact in staging, waiting for approval That artifact in production
Human step Code review before merge One approval before production None
What it needs to be safe A test suite people trust Staging that resembles production Monitoring and one-step rollback
Common in India at Almost everyone Most product companies and GCCs Mature SaaS teams; rare in services

Most teams you will join in India run continuous delivery and call it continuous deployment. That is fine; the distinction matters when you are the one deciding whether to remove the approval gate, and the last row of the table is what decides it. If you cannot watch a release and undo it in one step, keep the gate.

What is CI/CD in DevOps? Where the pipeline sits

CI/CD in DevOps is the automation layer that connects the "build" and "test" stages of the DevOps lifecycle to "release" and "deploy". DevOps is the wider practice: shared ownership between the people who write software and the people who run it, measured by how quickly and safely changes reach users. CI/CD is the piece of that practice you can actually point at. It is the thing that turns "we deploy on Fridays after the manager signs off" into "every merged change is built, tested and in staging within fifteen minutes".

A useful way to hold the relationship in your head: DevOps is the goal, CI/CD is the machinery, and the rest of the toolchain plugs into the machinery. Infrastructure as code (Terraform) runs as a pipeline stage. Container builds and Kubernetes deployments are pipeline stages. Security scanning, the DevSecOps part, is a pipeline stage. Monitoring is what tells the pipeline whether the last deploy was a good idea. When someone says a company "does DevOps" but has no pipeline, what they usually have is a culture slide and a shared Slack channel.

This is also why CI/CD is the first thing interviewers ask a DevOps candidate about. It is the part of the job that is concrete enough to test. "What does DevOps mean to you" gets a vague answer from everyone; "walk me through what happens after git push on your current project" separates people who have run a pipeline from people who have read about one.

The five stages, and what actually goes wrong in each

Most pipelines are some version of these five stages. The failure column is the useful part: it is what you will spend your time on once the pipeline exists.

Stage What it does How it usually breaks
Trigger A push, a pull request or a schedule starts the run. Nothing runs, because the workflow only listens on main and you pushed a branch.
Build Install dependencies, compile, produce an artifact or image. Works locally, fails on the runner - because your machine has a tool or an environment variable the clean runner does not.
Test Unit tests, then integration tests, then linting and security scans. Flaky tests. One in twenty runs fails for no reason, the team starts re-running until green, and the suite stops meaning anything.
Deploy to staging Ship the artifact to an environment that resembles production. Staging has drifted from production, so a passing staging deploy proves very little.
Deploy to production Release, with or without an approval gate, then watch. There is no rollback path, so the fix for a bad release is a panicked forward-fix at 11pm.

Notice that only one of those five failures is really about the build tooling. The rest are about environments and discipline, which is why CI/CD is treated as a practice rather than a product.

An end-to-end CI/CD pipeline, from commit to production

"End to end" means the pipeline covers the whole path, not just build-and-test. Here is the shape of one as it runs at a typical product company, written as the sequence of things that happen to a single change. The two full examples later on this page implement exactly this flow in GitHub Actions and Jenkins.

Step What happens Typical tool Gate
1. CommitDeveloper pushes a branch and opens a pull requestGit, GitHub / GitLabBranch protection: no direct pushes to main
2. ValidateLint, unit tests, dependency audit, secret scanGitHub Actions / Jenkins, Trivy, gitleaksAll checks green before merge
3. BuildOn merge to main: build the container image, tag it with the commit SHA, push to a registryDocker, GHCR / ECRImage scan passes
4. InfrastructurePlan and apply any infrastructure change in the same repoTerraformPlan reviewed in the PR; apply only on main
5. Deploy to stagingRoll the new image out to a staging clusterkubectl / Helm, or ArgoCD watching the repoAutomatic
6. VerifySmoke tests and integration tests against stagingTest suite, synthetic checksFail here and nothing goes further
7. Deploy to productionCanary or rolling release of the same imageKubernetes rollout, ArgoCD / Argo RolloutsManual approval (delivery) or automatic (deployment)
8. ObserveWatch error rate and latency for the new version; roll back if they movePrometheus, Grafana, alertingRollback is one command, rehearsed

Two details that separate a real end-to-end pipeline from a diagram of one. First, the same artifact moves through every environment. You build the image once at step 3 and promote that exact image to staging and then production; you never rebuild for production, because a rebuild is a chance for something to differ. Second, the production gate is a decision you make deliberately, per team. Continuous delivery keeps a human approval at step 7; continuous deployment removes it. Most Indian product teams I see run delivery for customer-facing services and deployment for internal ones, and that is a perfectly sensible place to start.

If you are building this for a portfolio, the version that impresses an interviewer is not the one with the most stages. It is the one where you can explain what happens when step 6 fails, where the rollback command is, and what you would look at first if step 8 lit up. That is the difference between a workflow you copied and a pipeline you own.

Building your first pipeline, step by step

If you have never built one, do this before reading the two full examples below. It takes an evening, and everything afterwards will make more sense because you will have seen each failure with your own eyes.

  1. Pick a project that already has a test. Any small app with one passing unit test. If it has no tests, write one - a pipeline with nothing to check is a very expensive way to run npm install.
  2. Make it build from a clean machine. Clone your own repo into a fresh directory and run the install and test commands there. This is where you discover the global tool you forgot you installed two years ago. Fix it now, in the repo, or the runner will find it for you.
  3. Write the smallest possible workflow. One job, three steps: check out, install, test. Trigger on pull requests only. Commit it on a branch and open a PR against yourself. Watch it run. Read the log even though it passed - you want to know what a healthy log looks like before you have to read a broken one.
  4. Break it on purpose. Change a test so it fails and push. Confirm the PR shows red. Now change it back. Most people skip this, and then the first time the pipeline fails for real they do not know whether the pipeline is wrong or the code is.
  5. Add the build step - the container image or the packaged artifact - as a second job that depends on the first. Tag it with the commit SHA, never with latest.
  6. Add a deploy to somewhere disposable. A free-tier VM, a test namespace, a static bucket. The point is not the target; it is proving that the artifact you built is the artifact that arrived.
  7. Add branch protection so nothing can merge to main with a red build. Until this is on, the pipeline is advice. After it, the pipeline is the rule.

Seven steps, and the order matters. People who start at step five - because deploying is the exciting part - end up with a pipeline that deploys untested code very efficiently. The steps that matter most are two and four, which is also why they are the ones people skip.

Once this works you have covered what most "CI/CD implementation" tutorials take four hours to say. The two pipelines below add the things a real team needs on top: caching, a test matrix, secrets, environment gates and rollback.

CI/CD pipeline automation: what to automate first

Teams that try to automate everything at once usually end up with a pipeline nobody trusts. The order below is the one that has worked on every legacy estate I have been handed, and it is roughly the order of how much pain each manual step causes.

  1. The build. If "it works on my machine" is still a sentence anyone says, start here. One command, in a clean container, that produces the artifact. Until this is reliable nothing downstream can be.
  2. The tests that already exist. Run them on every pull request. Do not wait until the suite is good; run what you have and make the red build visible. A test that runs automatically and occasionally fails is worth more than a perfect suite someone runs by hand once a fortnight.
  3. Deployment to one non-production environment. This is where most teams stall, because it means the deployment steps have to be written down. That is the point. Once staging deploys itself, the production runbook is already two-thirds written.
  4. Infrastructure changes. Move the Terraform plan and apply into the pipeline so that infrastructure is reviewed like code. The plan output in a pull request is the best code review tool a DevOps team has.
  5. Security checks. Image scanning and secret detection are cheap to add once the build is in the pipeline, and they catch the kind of mistake that makes the news.
  6. Production, with a gate. Automate the mechanics (the rollout, the health check, the rollback) and keep a human approval until the team trusts steps 1 to 5. Then remove the approval for low-risk services first.

Things people automate too early: performance tests (slow, flaky, and they block the ten-minute build), database migrations without a rollback plan, and anything that notifies the whole company on every run. Things people automate too late: rollback. Rehearse it in staging before you need it in production, and make it one command.

The pipeline automation that makes the biggest difference is rarely a clever tool. It is the boring discipline of putting every manual step into code, one at a time, in the order above, and refusing to let a new manual step creep back in.

A real pipeline in GitHub Actions

This is a complete, working workflow for a Node service. Put it in .github/workflows/ci.yml. It runs tests on every pull request, and on a push to main it builds an image, pushes it to the GitHub container registry, deploys to staging automatically and waits for an approval before production. It is longer than the tutorial version, because it is the version you would actually run.

name: CI/CD

on:
  pull_request:
  push:
    branches: [main]

# A second push to the same branch cancels the run already in flight.
# Without this, a busy PR queues up six runs that nobody wants.
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

permissions:
  contents: read
  packages: write

env:
  IMAGE: ghcr.io/${{ github.repository }}

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [20, 22]
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v6
        with:
          node-version: ${{ matrix.node }}
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm test -- --ci
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results-node${{ matrix.node }}
          path: reports/

  build:
    needs: test
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    outputs:
      tag: ${{ steps.meta.outputs.tag }}
    steps:
      - uses: actions/checkout@v5
      - id: meta
        run: echo "tag=${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT"
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v6
        with:
          push: true
          tags: ${{ env.IMAGE }}:${{ steps.meta.outputs.tag }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v5
      - run: ./deploy.sh staging ${{ needs.build.outputs.tag }}

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v5
      - run: ./deploy.sh production ${{ needs.build.outputs.tag }}

Block by block, here is what each part is for and what goes wrong if you leave it out.

The trigger. Tests run on every pull request and every push to main. Notice the build job has if: github.event_name == 'push' - PRs get tested but never produce an image. That single line is the difference between a registry with forty tagged images and one with four thousand.

Concurrency. Push three commits to a PR in five minutes and, without this block, all three runs execute to completion. With it, the first two are cancelled the moment the third starts. On a busy team this is the largest single saving of runner minutes you will make, and it is four lines.

Permissions. The workflow asks for exactly what it needs: read the code, write to packages. The GITHUB_TOKEN used to log in to the registry is minted automatically for each run with those permissions and expires when the run ends. There is no personal access token to create, rotate, or accidentally commit - which is the whole reason to use the built-in registry when you are starting out.

The matrix. Tests run twice, on Node 20 and Node 22, in parallel. The obvious use is checking you have not broken an older runtime. The less obvious use is that when you upgrade production to 22, the matrix has already been proving your code runs there for months.

Caching, twice. cache: npm on the setup step caches the package download. cache-from and cache-to on the Docker build cache image layers between runs. On a typical service those two settings take a build from six minutes to under two, and the second one is the one most people do not know exists.

The artifact upload with if: always(). Test reports get uploaded whether the tests passed or not. Without always(), the step is skipped on failure - which is precisely when you wanted the report.

Job outputs. The build job computes the tag once and passes it forward through outputs. Both deploy jobs consume the same value, so there is no way for staging and production to disagree about which image is being shipped. The alternative, recomputing the tag in each job, works right up until someone changes one of them.

Environments. This is the part that turns a CI script into a delivery pipeline. In the repository settings, the production environment is configured to require a reviewer. The workflow reaches that job, pauses, and someone gets a notification asking them to approve. Staging has no such rule, so it deploys itself. Environment-scoped secrets live here too, which means the production database credential is not even visible to the staging job.

Four things in there are worth copying into your own pipelines even if you take nothing else:

  • npm ci, not npm install. It installs exactly what the lockfile says and fails if the lockfile is out of date. A CI run should never quietly resolve a different dependency tree than the one you tested.
  • cache: npm on the setup step. Dependency install is usually the slowest part of a small pipeline, and caching it is one line.
  • needs: test makes build wait for test. Without it the two jobs run in parallel and you cheerfully build images from code that does not pass.
  • Tagging the image with the commit SHA rather than latest. When something breaks in production you want to know precisely which commit is running, and rolling back becomes "deploy the previous tag" instead of an archaeology exercise.

Actions are pinned to a major version here (@v5, @v6), which picks up patches automatically. Majors do move - check the current one for any action you copy from an older tutorial, because a workflow referencing a retired major will simply stop running. For anything security-sensitive, pin to a full commit SHA instead; a major tag can be moved by the action's maintainer, a SHA cannot.

The same pipeline in Jenkins

Jenkins expresses the same thing as a Jenkinsfile committed to the repository root. The shape is recognisably the same; the difference is that you are responsible for the machine it runs on. This is the declarative form, which is the one to learn - scripted pipelines exist and you will meet them in older estates, but nobody should be writing new ones.

pipeline {
  agent { label 'linux' }

  tools { nodejs 'node-22' }

  options {
    timeout(time: 20, unit: 'MINUTES')
    disableConcurrentBuilds()
    buildDiscarder(logRotator(numToKeepStr: '30'))
  }

  environment {
    IMAGE = 'ghcr.io/acme/myapp'
    TAG   = "${env.GIT_COMMIT.take(12)}"
  }

  stages {
    stage('Install') {
      steps { sh 'npm ci' }
    }

    stage('Checks') {
      parallel {
        stage('Lint')  { steps { sh 'npm run lint' } }
        stage('Test')  { steps { sh 'npm test -- --ci' } }
        stage('Audit') { steps { sh 'npm audit --audit-level=high' } }
      }
    }

    stage('Build image') {
      when { branch 'main' }
      steps { sh 'docker build -t $IMAGE:$TAG .' }
    }

    stage('Push') {
      when { branch 'main' }
      steps {
        withCredentials([usernamePassword(
            credentialsId: 'ghcr',
            usernameVariable: 'REG_USER',
            passwordVariable: 'REG_PASS')]) {
          sh 'echo "$REG_PASS" | docker login ghcr.io -u "$REG_USER" --password-stdin'
          sh 'docker push $IMAGE:$TAG'
        }
      }
    }

    stage('Deploy staging') {
      when { branch 'main' }
      steps { sh './deploy.sh staging $TAG' }
    }

    stage('Deploy production') {
      when { branch 'main' }
      input { message 'Promote this build to production?' }
      steps { sh './deploy.sh production $TAG' }
    }
  }

  post {
    always {
      junit allowEmptyResults: true, testResults: 'reports/**/*.xml'
    }
    failure {
      slackSend channel: '#ci', message: "FAILED ${env.JOB_NAME} #${env.BUILD_NUMBER}"
    }
  }
}

The parts that matter, and the parts people get wrong:

The agent. agent { label 'linux' } means this runs on whichever Jenkins agent carries that label. That agent needs Docker installed and its user in the docker group, and the NodeJS plugin provides Node through the tools block. This is the honest cost of Jenkins: in GitHub Actions the runner just has these things; here, someone built and maintains that agent, and when the pipeline breaks after an OS update, that someone is you.

The options block. A twenty-minute timeout stops a hung test from occupying an agent all night. disableConcurrentBuilds is the Jenkins equivalent of the concurrency block above. The log rotator stops the Jenkins disk filling up with build history, which, if you are wondering, is the single most common reason a Jenkins server stops working.

The parallel block. Lint, test and audit run at the same time on the same agent. In Jenkins this is the easiest speed-up available and almost nobody uses it - stages default to sequential, and a great many Jenkinsfiles in the wild run three independent checks one after another for no reason.

Credentials, and single quotes. Look at the sh lines inside withCredentials. They use single quotes, so the shell expands $REG_PASS, not Groovy. If you write them with double quotes, Groovy interpolates the password into the command string before it runs, and the value ends up in the build log in plain text. Jenkins prints a warning about this now; older versions did not. It is the most common credential leak in Jenkins, and it is a punctuation mark.

The input step. input on the production stage pauses the build and waits for a person to click Proceed. It is the manual gate that makes this continuous delivery rather than continuous deployment. Note that it holds the agent while it waits; on a busy server you would wrap it in agent none at the top and give each stage its own agent, but that is a refinement for later.

The post block is the part people forget. It runs whether the build passed or failed, which is exactly when you want test reports collected and a notification sent. allowEmptyResults stops the report step itself failing when the tests never ran because install broke.

CI/CD workflows - the four common shapes

The pipeline definition is only half of a CI/CD workflow. The other half is the branching model it sits on - when code merges, what triggers a release, and how a change moves between environments. There are four shapes you will meet, and which one a team uses tells you a lot about how they ship.

Trunk-based development. Everyone works on short-lived branches - hours or a day or two - and merges to main constantly. Main is always releasable. Unfinished features hide behind feature flags rather than on long branches. The pipeline runs on every PR and deploys main automatically to staging, and often to production. This is what the high-performing teams in the DORA research run, and it is the workflow the pipeline above assumes. The cost is discipline: it needs small changes, fast reviews and a test suite people trust.

GitFlow. A develop branch collects work, release branches are cut from it and stabilised, then merged to main and tagged. Hotfix branches come off main. The pipeline typically tests everything, builds artifacts from release branches, and deploys tagged commits on main. GitFlow made sense for boxed software with versioned releases and is still common in Indian service companies delivering to enterprise clients on quarterly cycles. For a SaaS product it adds ceremony without adding safety, and the long-lived develop branch is exactly the thing continuous integration was invented to remove.

Release branches from trunk. A middle ground. Development is trunk-based, but a release branch is cut when you need to freeze a version - mobile apps waiting on app store review, or a client who wants a specific build. Fixes go to main first and are cherry-picked back. The pipeline treats release branches as deployable and main as the source of truth.

Environment promotion. This one is less about branches and more about how the artifact moves. One build is produced from main, deployed to dev, then promoted - the identical image, not a rebuild - to staging, then production, with a gate at each hop. Both full pipelines above are doing this. The important property is that "promote to production" is a deployment of something that already exists, never a new build, which is what makes the staging result meaningful.

If you are joining a team and want to know which shape they use, ask two questions: how long does a branch usually live, and does production get a rebuild or a promotion? The answers tell you more than the tool name does. And if you are setting up a workflow from scratch, use trunk-based with environment promotion unless you have a specific reason not to. The reasons exist - regulated industries, app store cycles, client-mandated release windows - but "we have always done GitFlow" is not one of them.

Jenkins vs GitHub Actions vs GitLab CI

Jenkins GitHub Actions GitLab CI
Who runs it You. It is a Java server you install, patch and back up. GitHub, on hosted runners. Self-hosted runners optional. GitLab, or your own runners. Self-hosting is a first-class path.
Config Jenkinsfile, Groovy-based YAML in .github/workflows/ YAML in .gitlab-ci.yml
Strength Enormous plugin ecosystem; will talk to anything, including old on-prem systems. Nothing to run. Marketplace actions cover most common steps. CI, registry, issues and environments in one product.
Cost of that Plugin sprawl and upgrade pain. Someone owns that server. You are on GitHub, and runner minutes are metered. Smaller action ecosystem than GitHub.
Reach for it when You have existing Jenkins, or builds that must run inside your own network. Your code is already on GitHub. This is the default for new projects. You want one self-hosted tool for the whole workflow.

An honest note for anyone job-hunting in India: plenty of listings still say "Jenkins" because that is what the client's estate runs, even at companies whose newer teams have moved to GitHub Actions. Learn the concepts on Actions if you are starting from zero - the feedback loop is much faster - but be able to read a Jenkinsfile, because you will be handed one. Azure DevOps Pipelines deserves a mention too: it is the fourth runner you will meet, mostly in Microsoft-stack enterprises and the GCCs that serve them, and its YAML is close enough to GitHub's that the skills carry over in an afternoon.

How long should a pipeline take?

Ten minutes, for the build that runs on every commit. That number is not arbitrary: it comes from Extreme Programming practice and is still the guideline in Martin Fowler's article on Continuous Integration, which puts it plainly - "for most projects, the XP guideline of a ten minute build is perfectly within reason".

The reason is behavioural rather than technical. Past about ten minutes people stop waiting for the result, start batching changes, and go back to the habits CI was supposed to remove. If your suite genuinely cannot finish in that window, split it: a fast commit build on every push, and a slower nightly build for the long-running integration and end-to-end tests.

Why pipelines fail in practice

The technical failures are easy to fix. These are the ones that quietly kill a pipeline, and every one of them is common on real teams:

  • A red main branch that nobody fixes. Once the team accepts a failing build as normal, the pipeline has stopped being a signal. Fixing a broken main is the highest-priority work on the board, or the whole thing is theatre. The version of this I see most often is a build that has been red for three weeks because of one test everyone agrees is "not really a failure", and by then two real failures have been merged underneath it unnoticed.
  • Flaky tests treated as noise. Re-running until green trains everyone to ignore failures. Quarantine the flaky test and fix it properly, rather than making "just run it again" the team's reflex. The usual causes, in order: tests that depend on wall-clock time, tests that share state through a database, tests that hit a real network. All three are fixable in an afternoon each. The team that has thirty of them did not fix the first one.
  • Secrets pasted into the config. An API key in a committed YAML file is in your Git history permanently, even after you delete the line. Use the platform's secret store from day one. And once a secret has been committed, rotate it - deleting the commit does not help, because every clone made in between still has it.
  • No rollback. A pipeline that can deploy but not un-deploy is only half a pipeline. Being able to redeploy the previous image tag in one step is worth more than most of the fancy stages above it. Test the rollback the same way you tested the deploy - actually run it, on staging, before you need it - because a rollback script that has never been executed is a hypothesis.
  • Long-lived branches. A branch that lives for three weeks is not continuous integration, whatever the tooling says. The merge at the end of those three weeks is where the integration actually happens, all at once, and it goes about as well as you would expect.
  • The forty-minute build. It did not start at forty minutes. It started at eight, and every month someone added a step, and nobody owned the number. Now developers push and go for lunch, batch their changes to avoid waiting, and the pipeline has recreated the exact problem it was meant to solve. Put the duration on a dashboard and treat a rise the way you would treat a rise in error rate.
  • Staging that lies. Staging runs a different database version, has half the data, or shares a cache with dev. Deploys pass there and fail in production, and after a few of those the team stops trusting staging - which is worse than not having it, because now the gate is decorative. Staging does not need production's size. It does need production's shape.
  • Nobody can read the pipeline. The Jenkinsfile is 600 lines, calls a shared library nobody has looked at since the person who wrote it left, and the one time it broke, the fix took four days. A pipeline that only one person understands is a single point of failure with a nicer name.

What these have in common is that none of them show up as a red build. The pipeline is green; it is just not doing its job any more. Checking for these is a good thing to do in your first month on a new team - and a good set of things to ask about in an interview, because the answers tell you what the job will actually be like.

Modernising a legacy pipeline

Most engineers in India do not get to build a pipeline from scratch. They inherit one - typically a Jenkins job configured through the web UI in 2018, with steps nobody remembers adding, running on a server that has not been patched because nobody dares reboot it. If that is your situation, here is the order that works.

First, get it into code. If the job is defined in the Jenkins UI, convert it to a Jenkinsfile in the repo, step by step, until the UI job is nothing but "run the Jenkinsfile". Do not change what it does yet. You cannot safely modernise something you cannot diff.

Second, make it reproducible. Find every tool the build assumes is installed on the agent and either declare it in the pipeline or move the build into a container. This is usually where you discover the build only works on one specific machine because of a library someone installed by hand years ago.

Third, add the missing guard rails - timeout, concurrency limit, log rotation, secret store - before adding anything new. These are what stop the modernisation itself from causing an outage.

Only then decide whether to migrate the runner. A clean, containerised Jenkinsfile can be translated to GitHub Actions or GitLab CI in a day. A UI-configured job with tribal knowledge cannot be translated at all, which is why teams that start with "let's move to GitHub Actions" tend to end up with two half-working pipelines and a migration that never finishes. The runner was never the problem. The undocumented build was.

CI/CD certifications - what is worth it

There is no CI/CD certification that hiring managers in India ask for by name, in the way they might ask about a CKA or an AWS Solutions Architect. That is worth knowing before you spend money. The credentials that exist - GitHub Actions certification, GitLab's CI/CD certification, the Jenkins Engineer certification from CloudBees - are recognised within their own ecosystems and are a reasonable way to structure learning, but none of them will get a CV through a screen on its own.

What does move a CV is CI/CD showing up inside a broader credential: the pipeline questions in the Kubernetes exams, the CodePipeline and CodeBuild sections of the AWS DevOps Engineer Professional, the pipeline half of the Azure DevOps Engineer Expert. Those are respected because the exam is hard and the pipeline knowledge is applied in context.

And what moves an interview is a pipeline you built. A public repository with a working workflow, a README that explains why each stage exists, and a commit history showing you broke it and fixed it, beats every certificate in this section. If you have budget for one thing, put it towards cloud or Kubernetes, where certification genuinely carries weight, and learn CI/CD by doing - there is a longer discussion of which certificates pay for themselves in whether DevOps certification is worth it in 2026.

Git and version control - where every pipeline starts

A CI/CD pipeline is triggered by a Git event, so version control is not a separate topic from CI/CD - it is the first stage of it. Git tracks every change to your code and lets a team work on the same repository without overwriting each other.

The concepts that actually matter day to day: a branch is an isolated line of work; a merge brings that work back into the main line; a pull request (or merge request on GitLab) is the review gate where your pipeline runs tests before anyone approves. Merge keeps the full history and creates a merge commit; rebase replays your commits on top of the target branch for a linear history - most teams rebase feature branches and merge to main.

GitHub vs GitLab: both do Git hosting, reviews and built-in CI. GitHub has the larger ecosystem and GitHub Actions; GitLab ships a more complete DevOps toolchain in one product and self-hosts more readily. The Git commands are identical either way - the choice is about the platform around them.

A trunk-based workflow (short-lived branches merged to main daily, behind feature flags) is what most high-performing teams run, because long-lived branches defeat the point of continuous integration.

CI/CD interview questions you should be able to answer

These come up constantly, and the second half of each one is where candidates separate:

  • What is the difference between continuous delivery and continuous deployment - and which does your current project use?
  • Walk me through what happens between your git push and the code reaching production.
  • Your pipeline passes but production breaks. Where do you look first?
  • How do you handle secrets in a pipeline? What is wrong with putting them in the config file?
  • A test fails once in every twenty runs. What do you do about it?
  • How would you roll back a bad deploy? Talk me through the actual steps.
  • Your build takes thirty-five minutes. What are the first three things you would look at?
  • Why should staging and production deploy the same image rather than rebuilding?

If you have built even one real pipeline, these answer themselves. If you have only read about pipelines, they are very hard to fake - which is exactly why interviewers like them. There is a broader set, covering the rest of the stack, in the DevOps interview questions guide, and the interview preparation strategy covers how to structure the answers.

Why it matters

Every modern engineering organisation relies on CI/CD to ship software faster and more safely, which is why building and debugging a pipeline is a baseline DevOps skill rather than a specialisation. It is also the most portable thing you can learn early: the tools differ between companies, but the five stages, the ten-minute rule and the failure modes above are the same everywhere.

The fastest way to learn it is to build one. Take any small project of your own, add the GitHub Actions file above, and break it on purpose until you understand each failure. It sits naturally after Linux and Docker in the DevOps roadmap, because a pipeline needs something to build and somewhere to put it. In the DevOps certification course it is week five, after Linux, AWS, Docker and Kubernetes, and it is the week where the earlier material starts to connect.

Once the pipeline works, the next question is how the change reaches the cluster. A pipeline that runs kubectl apply from outside is one answer; a controller that pulls from Git and reconciles continuously is the other. GitOps explained covers that step, plus canary and blue-green rollouts. And once things are shipping, the question becomes whether you would know if they broke - which is what monitoring and reliability is for.

Frequently Asked Questions

What is a CI/CD pipeline in simple terms?

An automated sequence that takes every code change, builds it, runs the tests, packages it and deploys it - stopping and reporting at whichever step fails. CI is the build-and-test half. CD is getting the passing build into staging and production. The point is that the same artifact moves through every step, so what you tested is what you shipped.

What is the difference between CI and CD?

Continuous integration answers 'does this change break anything' - merge often, build and test automatically. Continuous delivery answers 'could we release right now' - every green build is deployable and a person approves the production push. Continuous deployment removes that approval and releases automatically. Most Indian teams run delivery and call it deployment.

What is the difference between continuous delivery and continuous deployment?

One button. In continuous delivery, every passing build is ready for production and a human clicks to release it. In continuous deployment there is no click - a green build goes straight to production. Both are correct expansions of CD, so say which one you mean in an interview.

What are the stages of a CI/CD pipeline?

Trigger, build, test, deploy to staging, deploy to production. Trigger is a push or pull request. Build installs dependencies and produces an artifact or image. Test runs unit tests, integration tests, lint and security scans. Staging deploys the artifact somewhere production-like. Production releases it, with or without an approval gate, and then you watch.

How do I build my first CI/CD pipeline?

Take a project that has at least one passing test. Make it build from a clean clone. Write a three-step workflow - check out, install, test - that runs on pull requests. Break a test on purpose and confirm the build goes red. Then add a build step tagged with the commit SHA, a deploy to something disposable, and branch protection. Seven steps, in that order.

Jenkins or GitHub Actions - which should I learn first?

GitHub Actions if you are starting from zero, because there is nothing to install and the feedback loop is minutes. But learn to read a Jenkinsfile, because most Indian job listings still name Jenkins and you will be handed one. The concepts - stages, triggers, artifacts, secrets, gates - are identical across both.

How long should a CI pipeline take?

About ten minutes for the build that runs on every commit. Past that, people stop waiting for the result and start batching changes, which undoes the point of CI. If the full suite cannot fit, split it into a fast commit build and a slower nightly run for the long integration tests.

How should secrets be handled in a CI/CD pipeline?

In the platform's secret store - GitHub environment secrets, Jenkins credentials, GitLab CI variables - never in the committed config. A key in a YAML file is in Git history permanently, even after you delete the line. In Jenkins, use single quotes in sh steps so the shell expands the secret rather than Groovy, or it prints into the build log.

What is a CI/CD workflow?

The pipeline definition plus the branching model it runs on: when code merges, what triggers a release, and how a build moves between environments. The four common shapes are trunk-based development, GitFlow, release branches from trunk, and environment promotion. Trunk-based with promotion of one immutable artifact is the default for new projects.

Is there a CI/CD certification worth getting?

Not one that hiring managers ask for by name. GitHub, GitLab and CloudBees each offer one, and they are fine for structuring your learning, but a public repository with a working pipeline and a commit history showing you broke and fixed it carries more weight in an interview. Put certification budget towards cloud or Kubernetes instead.

What is the difference between CI/CD and DevOps?

DevOps is the broad set of practices and culture for building and running software - collaboration, automation, monitoring, fast feedback. CI/CD is one specific practice inside it, covering how a change gets built, tested and released. You can have a CI/CD pipeline without doing DevOps well, and plenty of teams do.

What is an end-to-end CI/CD pipeline?

A pipeline that covers the whole path from a commit to production, not just build and test: validate the pull request, build one container image on merge, apply infrastructure changes, deploy that same image to staging, run smoke and integration tests, promote the identical image to production with a canary or rolling release, and watch error rate and latency with a rehearsed rollback ready. The two details that make it real are that the same artifact moves through every environment, and that rollback is one command.

What is CI/CD in DevOps?

CI/CD is the automation layer inside DevOps that connects the build and test stages of the lifecycle to release and deploy. DevOps is the wider practice of shared ownership between the people who write software and the people who run it; CI/CD is the machinery that makes it concrete, and the rest of the toolchain (Terraform, Kubernetes, security scanning, monitoring) plugs into it as pipeline stages. It is also the part of DevOps that interviewers can test, which is why it comes up first.

What should be automated first in a CI/CD pipeline?

In order: the build (one command, in a clean container), the tests that already exist on every pull request, deployment to one non-production environment, infrastructure changes via Terraform plan and apply, security scanning, and finally production with a human gate until the earlier steps are trusted. Rollback should be rehearsed early, not last. Performance tests and anything that notifies the whole company on every run are usually automated too early.

Related Topics:cicd pipelinewhat is cicdjenkins pipelinegithub actionsgitlab ciazure devopscontinuous integrationcontinuous deployment

Ready to Start Your DevOps Career?

Join our comprehensive DevOps + GenAI course with hands-on projects, live mentorship, and placement support