CI/CD Basics: Continuous Integration, Delivery, and Deployment Explained
Tutorials make CI/CD sound intimidating, but it solves a single problem: "Every time I change code, I manually rebuild, test, and upload — it is tiring and error-prone. Can it be automated?" Think of manual releases as a fast-food shop where the owner alone preps, cooks, boxes, and delivers every order. With CI/CD, it is like installing a conveyor line in the kitchen: a customer places an order (a code commit), and machines automatically prep ingredients (build), run quality checks (test), pack the box (artifact), and hand it to the courier (deploy). This guide explains the difference between CI and the two CDs, the stages of a pipeline, the mainstream tools, and gives an example you can copy.
First, tell the three terms apart: CI, CD, CD
The three abbreviations blur together when read aloud, but they are clear once separated:
- CI (Continuous Integration): Frequently merge everyone's code into the main branch, and after every merge, build and run tests automatically. Its purpose is to catch "your change conflicts with mine" as early as possible.
- CD (Continuous Delivery): On top of CI, guarantee that every commit is in a "ready to release" state — all tests pass and artifacts are generated, but a human decides whether to release.
- CD (Continuous Deployment): One step further — after tests pass, deploy to production automatically, with no human approval anywhere.
One line to remember: CI handles "test," delivery-CD handles "be ready," and deployment-CD handles "ship directly." Risk-sensitive businesses (e-commerce, finance) usually stop at continuous delivery; internal tools and low-risk sites can go all the way to continuous deployment.
What stages a pipeline has
A typical pipeline usually looks like this:
- Trigger: A push to a Git branch, a tag, or a schedule;
- Checkout: Pull the latest code;
- Install dependencies: For example, npm install or composer install;
- Build: Compile and bundle frontend assets;
- Test: Run unit tests, lint, and build-artifact checks;
- Artifact: Store the deployable package (such as a Docker image);
- Deploy: Push to staging, pre-production, or production;
- Notify: Email, Slack, or DingTalk on success or failure.
A failure at any stage halts the pipeline and notifies you — this is the value of "surfacing problems early." To see how to apply this to your own site, check the website CI/CD pipeline guide.
Mainstream tools compared
| Tool | Hosting | Learning curve | Strengths | Best for |
|---|---|---|---|---|
| GitHub Actions | Cloud (built into GitHub) | Low | Zero-config integration with the repo, rich ecosystem | GitHub users, individuals to mid-size teams |
| GitLab CI | Cloud / self-hosted | Medium | Built-in container registry, strong all-in-one | GitLab users, DevOps-heavy teams |
| Jenkins | Self-hosted | High | Tons of plugins, highly customizable | Existing Java ecosystems, complex pipelines |
Selection tip: use the CI of the platform where your code lives — do not maintain a separate Jenkins just to look "professional." To get started with GitHub Actions, see the GitHub Actions CI/CD guide; for the GitLab case, see GitLab CI/CD best practices.
A pipeline example (GitHub Actions)
For "test automatically after a commit, then deploy to a server," the core logic of .github/workflows/deploy.yml looks like this:
name: CI/CD
on:
push:
branches: [main]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
deploy:
needs: build-test
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
run: ssh deploy@server "cd /var/www/app && git pull && npm ci && pm2 restart app"
Meaning: after a push to main, install dependencies and run tests; only when they are all green, log into the server over SSH, pull the code, and restart the service. In a real project, put secrets in the repository's Secrets and refine the flow with the GitHub Actions SSH deploy guide and Docker Compose production deployment.
The path to adopting CI/CD from scratch
If you have never used CI/CD, work through these three steps gradually rather than going all-in at once:
- Automate build and test first: Wire commands like "npm test" or "php artisan test" into CI so every commit runs tests automatically — solve the "quality" problem first.
- Then add artifacts and images: Build artifacts (or Docker images) automatically after tests pass and store them, so a "releasable thing" always exists.
- Add auto-deploy last: Deploy to staging, get manual sign-off, then gradually open up to production; every stage can start with a "manual trigger" and move to an "auto trigger."
One easy-to-miss point: the pipeline itself is code — version it and review it. Maintain .github/workflows or .gitlab-ci.yml like any other code; changes to the pipeline should also go through tests and review, so the pipeline never breaks unnoticed. Remember, the value of CI/CD is not "using an advanced tool" but "every change is validated and delivered automatically and consistently" — even automating a single test command beats having nothing.
FAQ
Q1: Is CI/CD the same as deployment? No. Deployment is the single act of putting artifacts into production; CI/CD strings build, test, and deploy into one automated pipeline.
Q2: Do small sites need it? Individuals and small sites can start with "auto-pull via Git"; move to full CI/CD when tests multiply and releases get frequent.
Q3: The pipeline keeps failing. What now? Break the pipeline into small pieces, get "build + test" green first, then add deploy stages gradually, and read the logs to find which step fails.
Q4: Is continuous deployment dangerous? It can be. If risk is high, stop at continuous delivery (manual release button) and only consider auto-deploy after adding canary releases and rollback.
Q5: Where should the pipeline run? Managed runners are simplest; self-hosted runners suit scenarios needing intranet access or specific hardware (GPUs, build caches), but you maintain them.