home / skills / eddiebe147 / claude-settings / ci-cd-pipeline-builder
/skills/ci-cd-pipeline-builder
This skill helps you design and automate robust CI/CD pipelines across GitHub Actions and Vercel for reliable builds, tests, and deployments.
npx playbooks add skill eddiebe147/claude-settings --skill ci-cd-pipeline-builderReview the files below or copy the command above to add this skill to your agents.
---
name: ci-cd-pipeline-builder
description: Expert guide for building CI/CD pipelines with GitHub Actions, Vercel, and other platforms. Use when automating builds, tests, deployments, or release workflows.
---
# CI/CD Pipeline Builder Skill
## Overview
This skill helps you build robust CI/CD pipelines for automated testing, building, and deployment. Covers GitHub Actions, Vercel integration, testing strategies, deployment patterns, and security best practices.
## CI/CD Philosophy
### Pipeline Principles
1. **Fast feedback**: Fail early, inform quickly
2. **Reproducible**: Same inputs = same outputs
3. **Secure**: Secrets protected, dependencies verified
4. **Observable**: Clear logs, status visibility
### Pipeline Stages
```
Trigger → Lint → Test → Build → Deploy → Verify
```
## GitHub Actions Fundamentals
### Basic Workflow Structure
```yaml
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test
build:
runs-on: ubuntu-latest
needs: [lint, test]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
```
### Complete Next.js CI/CD Pipeline
```yaml
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
jobs:
# ===================
# Quality Checks
# ===================
quality:
name: Code Quality
runs-on: ubuntu-latest
steps:
- name: Checkout
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: Type check
run: npm run typecheck
- name: Lint
run: npm run lint
- name: Format check
run: npm run format:check
# ===================
# Unit & Integration Tests
# ===================
test:
name: Tests
runs-on: ubuntu-latest
needs: quality
steps:
- name: Checkout
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 tests
run: npm run test:ci
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage/lcov.info
fail_ci_if_error: false
# ===================
# Build
# ===================
build:
name: Build
runs-on: ubuntu-latest
needs: [quality, test]
steps:
- name: Checkout
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: Build
run: npm run build
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
name: build
path: .next
retention-days: 1
# ===================
# E2E Tests
# ===================
e2e:
name: E2E Tests
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout
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: Install Playwright browsers
run: npx playwright install --with-deps chromium
- name: Download build
uses: actions/download-artifact@v4
with:
name: build
path: .next
- name: Run E2E tests
run: npm run test:e2e
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
- name: Upload test results
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: playwright-report
retention-days: 7
# ===================
# Deploy Preview (PRs)
# ===================
deploy-preview:
name: Deploy Preview
runs-on: ubuntu-latest
needs: [build, e2e]
if: github.event_name == 'pull_request'
environment:
name: preview
url: ${{ steps.deploy.outputs.url }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Vercel CLI
run: npm install -g vercel
- name: Pull Vercel Environment
run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project
run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel
id: deploy
run: |
url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }})
echo "url=$url" >> $GITHUB_OUTPUT
- name: Comment PR with URL
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `🚀 Preview deployed to: ${{ steps.deploy.outputs.url }}`
})
# ===================
# Deploy Production
# ===================
deploy-production:
name: Deploy Production
runs-on: ubuntu-latest
needs: [build, e2e]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment:
name: production
url: https://myapp.com
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Vercel CLI
run: npm install -g vercel
- name: Pull Vercel Environment
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
- name: Build Project
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
- name: Deploy to Vercel
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
```
## Testing Strategies
### Parallel Test Execution
```yaml
# .github/workflows/test-parallel.yml
name: Parallel Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Run tests (shard ${{ matrix.shard }}/4)
run: npm run test -- --shard=${{ matrix.shard }}/4
merge-results:
needs: test
runs-on: ubuntu-latest
steps:
- name: Report results
run: echo "All test shards passed!"
```
### Matrix Testing
```yaml
# .github/workflows/matrix-test.yml
name: Matrix Tests
on: [push, pull_request]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [18, 20, 22]
exclude:
- os: windows-latest
node: 18
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test
```
## Database Integration
### Supabase in CI
```yaml
# .github/workflows/test-with-db.yml
name: Tests with Database
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Setup Supabase CLI
uses: supabase/setup-cli@v1
- name: Start Supabase
run: supabase start
- name: Run migrations
run: supabase db reset
env:
SUPABASE_DB_URL: postgresql://postgres:postgres@localhost:54322/postgres
- name: Run tests
run: npm run test:integration
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:54322/postgres
SUPABASE_URL: http://localhost:54321
SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }}
```
## Release Automation
### Automated Releases
```yaml
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Create Release
uses: google-github-actions/release-please-action@v4
with:
release-type: node
package-name: my-app
- name: Publish to npm
if: ${{ steps.release.outputs.release_created }}
run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
```
### Changelog Generation
```yaml
# .github/workflows/changelog.yml
name: Changelog
on:
release:
types: [published]
jobs:
update-changelog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
- name: Update CHANGELOG
uses: stefanzweifel/changelog-updater-action@v1
with:
latest-version: ${{ github.event.release.tag_name }}
release-notes: ${{ github.event.release.body }}
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "docs: update CHANGELOG for ${{ github.event.release.tag_name }}"
file_pattern: CHANGELOG.md
```
## Security Scanning
### Dependency & Code Scanning
```yaml
# .github/workflows/security.yml
name: Security
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 0' # Weekly
jobs:
dependency-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm audit --audit-level=high
codeql:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v3
with:
languages: javascript
- uses: github/codeql-action/analyze@v3
secrets-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
## Caching Strategies
### Effective Caching
```yaml
# .github/workflows/cached-build.yml
name: Cached Build
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
# Cache Next.js build
- name: Cache Next.js
uses: actions/cache@v4
with:
path: |
.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
# Cache Playwright browsers
- name: Cache Playwright
uses: actions/cache@v4
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
- run: npm ci
- run: npm run build
```
## Environment Management
### Environment-Based Deployments
```yaml
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches:
- main
- develop
jobs:
deploy:
runs-on: ubuntu-latest
environment:
name: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
url: ${{ github.ref == 'refs/heads/main' && 'https://myapp.com' || 'https://staging.myapp.com' }}
steps:
- uses: actions/checkout@v4
- name: Deploy to ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
run: |
echo "Deploying to ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}"
env:
API_URL: ${{ vars.API_URL }}
API_KEY: ${{ secrets.API_KEY }}
```
## Workflow Optimization
### Conditional Jobs
```yaml
# .github/workflows/smart-ci.yml
name: Smart CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
changes:
runs-on: ubuntu-latest
outputs:
frontend: ${{ steps.filter.outputs.frontend }}
backend: ${{ steps.filter.outputs.backend }}
docs: ${{ steps.filter.outputs.docs }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
frontend:
- 'src/app/**'
- 'src/components/**'
backend:
- 'src/api/**'
- 'src/lib/**'
docs:
- 'docs/**'
- '*.md'
test-frontend:
needs: changes
if: ${{ needs.changes.outputs.frontend == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:frontend
test-backend:
needs: changes
if: ${{ needs.changes.outputs.backend == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:backend
deploy-docs:
needs: changes
if: ${{ needs.changes.outputs.docs == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run build:docs
```
## Notification & Reporting
### Slack Notifications
```yaml
# .github/workflows/notify.yml
name: CI with Notifications
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
notify:
needs: build
runs-on: ubuntu-latest
if: always()
steps:
- name: Notify Slack
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "${{ needs.build.result == 'success' && '✅' || '❌' }} Build ${{ needs.build.result }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*${{ github.repository }}* - ${{ github.ref_name }}\nCommit: ${{ github.sha }}\nBy: ${{ github.actor }}"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
```
## Pipeline Checklist
### Essential Components
- [ ] Lint and format checks
- [ ] Type checking (TypeScript)
- [ ] Unit and integration tests
- [ ] Build verification
- [ ] Security scanning
### Deployment
- [ ] Preview deployments for PRs
- [ ] Production deployment on main
- [ ] Environment-specific configs
- [ ] Rollback capability
### Performance
- [ ] Effective caching strategy
- [ ] Parallel job execution
- [ ] Conditional job execution
- [ ] Build artifact reuse
### Security
- [ ] Secrets properly managed
- [ ] Dependency auditing
- [ ] Code scanning enabled
- [ ] Protected environments
## When to Use This Skill
Invoke this skill when:
- Setting up CI/CD for a new project
- Optimizing slow pipelines
- Adding deployment automation
- Implementing release management
- Setting up security scanning
- Configuring environment-based deployments
- Creating preview environments
This skill is an expert guide for building reliable CI/CD pipelines using GitHub Actions, Vercel, and related tools. It focuses on automating linting, testing, building, deployments, and release workflows while emphasizing speed, reproducibility, security, and observability. Use it to design pipelines that scale from single-repo apps to multi-environment deployments.
I provide ready-to-adopt workflow patterns and practical examples: lint/test/build job graphs, deploy previews for PRs, production deploys, parallel and matrix test strategies, database-backed integration testing, caching, release automation, and security scanning. Each pattern includes concrete YAML snippets, environment and secrets handling, artifact management, and failure/notification hooks so you can copy, customize, and run quickly.
How do I keep secrets safe when deploying from CI?
Store tokens and keys in repository or organization secrets, reference them via secrets.* in workflows, and avoid printing them. Use environment-level protection and limited-permission tokens where possible.
When should I use prebuilt deployments to Vercel?
Use prebuilt deployments when you want to separate build and deploy steps, speed up deploys, or run E2E tests against the exact build artifact before pushing to production.