Introduction: Why CI/CD Is Not a Luxury but a Necessity
Imagine: you make a small change to the code, push it to the repository, and within 5 minutes the new version is already running in production. No manual testing, no long build waits, no fear of "what if something breaks." This isn't magic — it's CI/CD. In 2026, when the speed of feature delivery determines competitiveness, building a continuous integration and delivery pipeline has become the de facto standard for any development team.
In this article, we'll break down how to build a complete automation cycle using GitHub Actions and GitLab CI, from the first commit to deploying to production. You'll learn what stages a modern pipeline includes, how to set up testing and building, and how to avoid common mistakes.
What Is a CI/CD Pipeline?
CI/CD (Continuous Integration / Continuous Delivery) is a methodology where every commit automatically goes through a chain of stages:
- Continuous Integration (CI): automatic building and testing of code with every push.
- Continuous Delivery (CD): automatic deployment to staging or production after successful CI.
A pipeline is a sequence of steps (jobs) that execute in a specific order. Modern tools like GitHub Actions and GitLab CI allow you to describe pipelines as YAML files directly in the repository.
Stages of an Ideal Pipeline: From Commit to Production
Let's look at a classic pipeline that can be implemented in 5 minutes (with ready-made configs). It consists of four key stages:
| Stage | Tool | Duration | Result |
|---|---|---|---|
| 1. Linting and Static Analysis | ESLint, Pylint | 30 sec | Clean code with no errors |
| 2. Unit Tests | Jest, pytest | 1–2 min | All tests green |
| 3. Build | Docker, Webpack | 1–2 min | Ready artifact (image, bundle) |
| 4. Deploy | SSH, Kubernetes | 30 sec | New version on the server |
1. Linting and Static Analysis
The first step is checking the code against standards. This is a cheap operation that filters out obvious issues before running tests. For example, in GitHub Actions you can add a step:
- name: Run ESLint
run: npx eslint .
2. Unit Tests
Testing is the heart of CI. It's important to set up parallel test execution to stay within time limits. In GitLab CI, this is done via parallel:
test:
script: pytest
parallel: 4
3. Build
After successful tests, we build an artifact — for example, a Docker image. This ensures reproducibility: the same code will run on any environment.
4. Deploy
The final stage is sending the artifact to the server. For production, blue-green or rolling updates are often used to avoid downtime.
GitHub Actions vs GitLab CI: Which to Choose?
Both tools are popular, but each has its own features. Let's compare key parameters:
| Characteristic | GitHub Actions | GitLab CI |
|---|---|---|
| Free minutes | 2000 min/month | 400 min/month |
| Runners on your own servers | Yes (self-hosted) | Yes (self-hosted) |
| Built-in registry | GitHub Container Registry | GitLab Container Registry |
| Conditional expressions | if: github.ref == 'refs/heads/main' |
only: - main |
| Parallel jobs | Yes | Yes (with limitations) |
In practice, the choice depends on the project's ecosystem. If your code is on GitHub — Actions is ideal. If you use the full GitLab stack (repository, issues, CI/CD) — choose GitLab CI.
Example of a Simple Pipeline on GitHub Actions
Here's a minimal config that does everything described above:
```yaml
name: CI/CD Pipeline
on:
push:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
bu
Comments