View : 143

28/10/2026 08:46am

A row of model wooden stations on a small conveyor carrying plain wooden blocks, beside a card summarising the Build, Test and Deploy stages of a CI/CD pipeline

What Is CI/CD? Build Your First Pipeline with GitHub Actions

#CI/CD

#CI/CD Pipeline

#GitHub Actions

#Continuous Integration

#Continuous Delivery

#Continuous Deployment

Picture a Friday evening. A teammate fixes a small bug and quickly merges it into main before heading home. Nobody runs the tests, because everyone thinks "it's a one-line change". Two hours later the live site shows an error on every page, and the person opening a laptop at 9 p.m. to fix it is you.

In short: CI/CD means letting a machine build and test your code automatically every time someone pushes, then delivering the code that passes to users through the same steps every time, instead of relying on someone remembering whether the tests were run.

Today Superdev Academy walks through how CI differs from CD, why CD has two meanings, what stages a pipeline has, and then writes a first GitHub Actions file that runs npm test for you on every push.

What does CI/CD stand for?

CI stands for Continuous Integration. CD can stand for two things: Continuous Delivery or Continuous Deployment. They are not the same, and mixing them up is the most common source of confusion in this topic.

"Continuous" is the key word. The idea is to do things often and in small pieces, instead of merging or releasing one big batch a month and hoping nothing breaks.

What is CI?

GitHub Docs defines Continuous Integration as a practice where developers commit code to a shared repository frequently, and every commit is built and tested automatically to make sure it does not introduce errors (see the original at GitHub Docs: Continuous integration).

CI is not limited to unit tests. GitHub Docs lists linters that check style formatting, security checks, code coverage and functional tests as examples. Put simply, anything you used to have to remember to run before merging can be handed to the machine.

If you have never written a test, start with How to Write Unit Tests and Integration Tests Effectively. CI with no tests to run only proves the build passes and turns green.

What is CD? Continuous Delivery vs Continuous Deployment

The two differ only at the last step: who presses the button that releases to production (the real system your users use).

  • Continuous Delivery: every change that passes the pipeline is always in a releasable state, but a person still decides when to release it.

  • Continuous Deployment: every change that passes the pipeline is released to production automatically, with no human step in between.

Martin Fowler explains in ContinuousDelivery that Continuous Delivery means a team is able to deploy frequently but may choose not to, while Continuous Deployment means every change goes through the pipeline and into production on its own. He adds that you must be doing Continuous Delivery before you can do Continuous Deployment.

Whenever you see "CD" in a document, check which meaning it uses. GitHub Docs' Continuous deployment page uses CD to mean Continuous Deployment specifically.

For a small team or a first project, Continuous Delivery is usually the safer starting point, because a person still looks before anything real ships.

What is a CI/CD pipeline, and what are its stages?

A pipeline is the sequence of steps code walks through from the moment it is pushed until it reaches users. If a stage fails, the next one does not run, so broken code never reaches the end. Every team's pipeline looks a little different, but most have these three main stages.

1. Build: make the code runnable

Install dependencies, compile or bundle the code into something that can run. If the build fails, the code is incomplete and there is no point going further.

2. Test: check it still works

Run unit tests, linting or whatever checks the team has agreed on. This is the heart of CI, and the stage that would have saved the Friday evening above.

3. Deploy: ship it to the target

Send whatever passed the first two stages to staging or production. This is where you choose between a human approval (Delivery) and releasing automatically (Deployment).

What is GitHub Actions?

GitHub Actions is the CI/CD system built into GitHub. You write your steps as a YAML file in the repository, and GitHub runs them on a machine called a runner whenever a chosen event happens, such as a push or a new pull request. (If GitHub itself is new to you, read What is GitHub? first.)

You only need four terms, per GitHub Docs: Workflow syntax:

  • Workflow: one .yml or .yaml file, which must live in the .github/workflows directory.

  • on: the events that start the workflow.

  • Job: a group of work that runs on one runner. If there are several jobs, they run in parallel by default.

  • Step: one instruction inside a job, either calling a ready-made action with uses or running a shell command with run.

On cost, GitHub Docs' billing page says usage is free for public repositories on standard GitHub-hosted runners, and private repositories on the GitHub Free plan get 2,000 minutes per month. (Checked on 1 October 2026. These quotas can change, so recheck the page before you plan around them.)

Example: a first workflow that runs npm test

We will build the smallest possible Node.js project, with one function and one test, and have GitHub Actions run the test on every push or pull request to main. Everything below was run by our team on Node.js v26.7.0 and npm 11.19.0 on 1 October 2026.

Step 1: the code and the test

The file sum.js:

function sum(a, b) {
  return a + b;
}
module.exports = { sum };

The file sum.test.js uses the test runner that ships with Node.js, so there is nothing to install:

const test = require('node:test');
const assert = require('node:assert');
const { sum } = require('./sum');

test('sum adds two numbers', () => {
  assert.strictEqual(sum(2, 3), 5);
});

The package.json makes npm test call node --test with the TAP reporter, which prints plain text that reads well in a log:

{
  "name": "ci-demo",
  "version": "1.0.0",
  "scripts": {
    "test": "node --test --test-reporter=tap"
  }
}

Step 2: create .github/workflows/ci.yml

name: CI

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

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
      - run: npm test

Reading it piece by piece:

  • on runs the workflow on a push or pull request to the main branch.

  • runs-on: ubuntu-latest asks for the latest Ubuntu runner GitHub provides.

  • actions/checkout@v7 pulls the repository's code onto the runner.

  • actions/setup-node@v7 installs Node.js 24, following the example in this action's README.

  • npm test runs the tests. If a test fails, this step fails.

On version numbers: we checked each action's Releases page on 1 October 2026. The latest actions/checkout is v7.0.1 (20 July 2026) and the latest actions/setup-node is v7.0.0 (14 July 2026). Worth noticing: the Node.js example in GitHub Docs on the same day still used actions/checkout@v6. When the docs and the action's own repository disagree, go with the repository.

Step 3: run the tests locally before pushing

Before GitHub runs anything, make sure the same command passes on your own machine. Real output from ours (trailing lines trimmed):

> ci-demo@1.0.0 test
> node --test --test-reporter=tap

TAP version 13
# Subtest: sum adds two numbers
ok 1 - sum adds two numbers
  ---
  duration_ms: 0.480792
  type: 'test'
  ...
1..1
# tests 1
# suites 0
# pass 1
# fail 0

Next, break the code on purpose: change a + b to a - b and run again. The result is not ok 1 - sum adds two numbers with the message -1 !== 5 and # fail 1, and the command ends with exit code 1. When the test passes, the exit code is 0.

That number is what GitHub Actions decides on. The Workflow syntax docs state that the runner reports each step as failed or succeeded based on the command's exit code. So if that Friday-evening teammate opens a pull request that breaks a test, GitHub shows a failed status for everyone to see before anyone merges. We have not pasted a log from a real runner here, because this article was tested on a local machine, not on GitHub.

Step 4: check that the YAML parses

YAML breaks easily on a wrong indent. A quick check is to have Python load the file (we used PyYAML 6.0.3):

python3 -c "import yaml; print(yaml.safe_load(open('.github/workflows/ci.yml')))"

Fun Fact: the output shows a key called True where you wrote on, because PyYAML follows YAML 1.1, which treats the word on as a boolean. Your file is fine and GitHub reads on correctly. Just do not panic when you see it during a local check.

This only tells you the YAML is syntactically valid, not that the keys are the ones GitHub expects. For that, compare against the Workflow syntax reference, or push and look at the Actions tab of your repository.

Once you have CI/CD, will your code never break again?

No. CI can only run the tests you wrote. If a bug lives in code no test covers, the pipeline turns green with full confidence while the code is broken. Green means "passed everything we asked it to check", not "correct".

What actually helps is building the fences properly: protect main so it only accepts pull requests whose CI passed, add a test every time you find a new bug, and if you do not yet trust your test suite, start with Continuous Delivery, where a person still presses release, before moving to Continuous Deployment. For a branch setup the whole team can share, read Git for Team: The Professional Workflow Guide to Collaborative Coding, and if your team is still arguing about how to combine branches, Git Rebase vs Merge: The Difference, Shown on a Real Repo is waiting.

Once your first workflow runs, the next step is adding linting, a build, or choosing other tools that suit your team. Our article 10 Ways to Enhance Code Development Efficiency Using CI/CD Tools collects techniques and tools such as Jenkins and GitLab CI/CD to read through next.


Summary: what CI/CD is and where to start

CI means letting a machine build and test every new piece of code. CD means getting the code that passed to users: Continuous Delivery still has a person press release, while Continuous Deployment releases everything automatically. Most pipelines have three stages, Build, Test and Deploy, and GitHub Actions can run all of it from a single YAML file in .github/workflows.

You do not need a big project to start. Take the project you have now, write one test, drop in a ci.yml like the one above, and push. The first time you see a green check next to a commit, you will not want to go back to merging and hoping.

Follow more articles and tips for people starting out as programmers on our channels.

Facebook: Superdev Academy Thailand (https://www.facebook.com/superdev.academy.th)

YouTube: Superdev Academy Channel (https://www.youtube.com/@SuperdevAcademy)

Instagram: @superdevacademy (https://www.instagram.com/superdevacademy/)

TikTok: @superdevacademy (https://www.tiktok.com/@superdevacademy?lang=th-TH)

FAQ: Frequently Asked Questions about This Article

A collection of questions and answers to help you better understand the content of this article.