Introduction
Continuous Integration and Continuous Deployment (CI/CD) have evolved significantly. In 2026, pipelines are faster, more secure, and more automated than ever. From cloud-native builds to intelligent testing, modern CI/CD transforms how software gets delivered.
This guide covers the CI/CD landscape in 2026, from major platforms to best practices. Whether you’re setting up your first pipeline or optimizing existing workflows, this guide provides practical insights.
Modern CI/CD Platforms
GitHub Actions
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
env:
CI: true
DATABASE_URL: ${{ secrets.DATABASE_URL }}
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
build:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
deploy:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to production
run: |
echo "Deploying to production..."
# Add deployment commands
GitLab CI/CD
# .gitlab-ci.yml
stages:
- test
- build
- deploy
variables:
NODE_VERSION: "20"
DOCKER_IMAGE: $CI_REGISTRY_IMAGE
test:
stage: test
image: node:${NODE_VERSION}
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
script:
- npm ci
- npm run lint
- npm test -- --coverage
coverage: '/Coverage: \d+\.\d+%/'
build:
stage: build
image: docker:24
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA .
- docker push $DOCKER_IMAGE:$CI_COMMIT_SHA
only:
- main
deploy:
stage: deploy
image: alpine:latest
script:
- apk add --no-cache curl
- curl -X POST $DEPLOY_WEBHOOK
environment:
name: production
url: https://example.com
only:
- main
CircleCI
# .circleci/config.yml
version: 2.1
orbs:
node: circleci/node@5
docker: circleci/docker@2
workflows:
build-test-deploy:
jobs:
- node/test:
version: '20'
pkg-manager: npm
- docker/build:
image: myapp
tag: $CIRCLE_SHA1
- docker/publish:
requires:
- docker/build
registry: ghcr.io
repo: org/myapp
tag: $CIRCLE_SHA1
- deploy/production:
requires:
- docker/publish
filters:
branches:
only: main
Pipeline Security
Secret Management
# Using secrets in GitHub Actions
steps:
- name: Deploy
env:
API_TOKEN: ${{ secrets.API_TOKEN }}
run: |
curl -H "Authorization: Bearer $API_TOKEN" \
https://api.example.com/deploy
Security Scanning
# Dependency scanning
- name: Audit dependencies
run: npm audit --audit-level=high
# Container scanning
- name: Trivy vulnerability scan
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
severity: 'CRITICAL,HIGH'
exit-code: '1'
# SAST scanning
- name: CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
languages: javascript,typescript
queries: security-extended
# Infrastructure scanning
- name: Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: ./infrastructure
framework: terraform
Supply Chain Security
# SLSA compliance
- name: Generate SLSA provenance
uses: slsa-framework/slsa-action@v1
with:
provenancename: "provenance.json"
# SBOM generation
- name: Generate SBOM
uses: cyclonedx/cyclonedx-npm@v1
with:
output-file: sbom.json
Testing in CI/CD
Test Strategies
# Unit tests
- name: Unit Tests
run: npm run test:unit
# Integration tests
- name: Integration Tests
run: npm run test:integration
services:
- name: postgres
image: postgres:16
env:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
- name: redis
image: redis:7
# E2E tests
- name: E2E Tests
run: npm run test:e2e
environment:
BASE_URL: https://staging.example.com
# Performance tests
- name: Load Testing
run: |
k6 run --out json=k6-results.json tests/load.js
Test Parallelization
# Split tests across jobs
jobs:
test-part-1:
runs-on: ubuntu-latest
steps:
- run: npm test -- --grep "part1"
test-part-2:
runs-on: ubuntu-latest
steps:
- run: npm test -- --grep "part2"
test-part-3:
runs-on: ubuntu-latest
steps:
- run: npm test -- --grep "part3"
Deployment Strategies
Blue-Green Deployment
# Blue-green deployment
- name: Deploy to blue
run: |
kubectl set image deployment/app-blue app=$IMAGE:blue
kubectl rollout status deployment/app-blue
- name: Run smoke tests
run: |
curl -f https://blue.example.com/health || exit 1
- name: Switch traffic
run: |
kubectl patch service app -p '{"spec":{"selector":{"version":"blue"}}}'
- name: Monitor and rollback
if: failure()
run: |
kubectl rollout undo deployment/app-blue
Canary Deployment
# Canary deployment
- name: Deploy canary
run: |
kubectl apply -f canary.yaml
- name: Route 10% traffic to canary
run: |
kubectl apply -f canary-ingress.yaml
- name: Monitor metrics
run: |
# Check error rate
ERROR_RATE=$(curl -s metrics.example.com/error-rate)
if (( $(echo "$ERROR_RATE > 0.05" | bc -l) )); then
echo "Error rate too high, rolling back"
kubectl delete -f canary.yaml
exit 1
fi
- name: Promote canary
if: success()
run: |
kubectl scale deployment/app --replicas=10
GitOps Deployment
# ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/org/repo.git
targetRevision: HEAD
path: deploy
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true
selfHeal: true
Cloud-Native Build
Build Caching
# Docker layer caching
- name: Build with cache
uses: docker/build-push-action@v5
with:
context: .
cache-from: type=gha
cache-to: type=gha,mode=max
# npm cache
- name: Cache npm
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
# Build artifact caching
- name: Cache build
uses: actions/cache@v4
with:
path: |
dist/
build/
key: ${{ runner.os }}-build-${{ github.sha }}
Container Build
# Multi-platform build
- name: Build multi-platform
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: |
app:latest
app:${{ github.sha }}
Monitoring and Feedback
Pipeline Metrics
# Record metrics
- name: Report metrics
run: |
METRICS=$(npm run test:coverage -- --json)
echo "::notice::Coverage: $METRICS"
Slack Notifications
# Notify on completion
- name: Notify Slack
if: always()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
External Resources
CI/CD Platforms
- GitHub Actions - GitHub CI/CD
- GitLab CI - GitLab pipelines
- CircleCI - CircleCI documentation
- Jenkins - Jenkins docs
Tools
Security
Conclusion
CI/CD in 2026 is about speed, security, and reliability. Modern pipelines automate everything from code review to production deployment, with built-in security at every step.
Focus on incremental improvements: faster builds, better caching, comprehensive testing, and secure deployments. The best pipeline is one that gets code to production safely and quickly while maintaining high quality.
Stay current with platform features, adopt GitOps practices, and always prioritize security. Your pipeline is the backbone of your software delivery.
Comments