CI/CD Pipelines
Learn to set up continuous integration and continuous deployment pipelines for Node.js applications using GitHub Actions and other CI/CD tools. This is a foundational concept in server-side JavaScript development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Node.js experience. Take your time with each section and practice the examples
CI/CD Fundamentals
Continuous Integration and Continuous Deployment automate the process of building, testing, and deploying applications, ensuring faster and more reliable releases.. This is an essential concept that every Node.js developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
GitHub Actions Setup
# .github/workflows/ci.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node - version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node - version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage --watchAll=false
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.infoDeployment Pipeline
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '18.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
env:
NODE_ENV: production
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Push Docker image
run: |
docker tag myapp:${{ github.sha }} myapp:latest
docker push myapp:${{ github.sha }}
docker push myapp:latest
- name: Deploy to AWS ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: task-definition.json
service: myapp-service
cluster: myapp-clusterEnvironment-specific Deployments
# .github/workflows/deploy-staging.yml
name: Deploy to Staging
on:
push:
branches: [ develop ]
jobs:
deploy-staging:
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v3
- name: Deploy to staging
run: |
echo "Deploying to staging environment"
# Add staging deployment commands here
- name: Run smoke tests
run: |
echo "Running smoke tests against staging"
# Add smoke test commands here
---
# .github/workflows/deploy-production.yml
name: Deploy to Production
on:
push:
tags:
- 'v*'
jobs:
deploy-production:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- name: Deploy to production
run: |
echo "Deploying to production environment"
# Add production deployment commands heresecurity Scanning
# .github/workflows/security.yml
name: security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run npm audit
run: npm audit --audit-level moderate
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
- name: Run CodeQL Analysis
uses: github/codeql-action/analyze@v2
with:
languages: javascriptMini-Project: Complete CI/CD Pipeline
# Complete CI/CD pipeline with multiple environments
# .github/workflows/complete-pipeline.yml
name: Complete CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
env:
NODE_VERSION: '18.x'
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Test job
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node - version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage --watchAll=false
- name: Upload coverage
uses: codecov/codecov-action@v3
# Build and push Docker image
build:
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'push'
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Container Registry
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=sha,prefix={{branch}}-
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Deploy to staging
deploy-staging:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/develop'
environment: staging
steps:
- name: Deploy to staging
run: |
echo "Deploying to staging environment"
# Add staging deployment commands
# Deploy to production
deploy-production:
runs-on: ubuntu-latest
needs: build
if: startsWith(github.ref, 'refs/tags/v')
environment: production
steps:
- name: Deploy to production
run: |
echo "Deploying to production environment"
# Add production deployment commands
# Notify deployment status
notify:
runs-on: ubuntu-latest
needs: [deploy-staging, deploy-production]
if: always()
steps:
- name: Notify Slack
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}