Skip to Content

๐Ÿ”„ CI/CD

Continuous Integration and Continuous Deployment โ€” automate builds, tests, and deployments so every push can ship safely.

CI/CD is essential for production Web3 apps: run tests on every commit, deploy contracts and frontends from a single pipeline, and avoid manual mistakes.


๐ŸŽฏ Why CI/CD Matters for Web3

  • Catch bugs before mainnet โ€” Run tests and lint on every PR
  • Reproducible deployments โ€” Same steps every time, no โ€œI forgot to run Xโ€
  • Audit trail โ€” Who deployed what, when, from which commit
  • Security โ€” Run secret scanning, dependency checks, and contract verification in the pipeline

๐Ÿ“š Key Concepts

TermMeaning
CIAutomatically build and test code on every push/PR
CDAutomatically deploy (or prepare artifacts) after successful CI
PipelineSequence of steps (install โ†’ test โ†’ build โ†’ deploy)
WorkflowThe config file that defines your pipeline

  • GitHub Actions โ€” Native to GitHub, free for public repos, generous free tier for private
  • GitLab CI/CD โ€” Built into GitLab, powerful and flexible
  • CircleCI โ€” Fast, good for complex workflows
  • Vercel / Netlify โ€” Auto-deploy from Git (CD-focused)
  • Railway / Render โ€” Git-based deploys with env and Docker support

๐Ÿš€ GitHub Actions: Quick Start

Create .github/workflows/ci.yml in your repo:

# .github/workflows/ci.yml name: CI on: push: branches: [main, develop] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci - run: npm run lint - run: npm test

This runs npm ci, npm run lint, and npm test on every push and PR to main/develop.


๐Ÿ“ฆ Build and Test (Node / Hardhat)

Example for a typical Web3 monorepo (app + contracts):

# .github/workflows/build-and-test.yml name: Build and Test on: push: branches: [main] pull_request: branches: [main] jobs: test-contracts: name: Test contracts runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci - name: Compile contracts run: npx hardhat compile - name: Run contract tests run: npx hardhat test test-app: name: Test app runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci - run: npm run build

๐Ÿ” Using Secrets in CI/CD

Never commit API keys or private keys. Use your platformโ€™s secrets and inject them as environment variables.

GitHub Actions: Encrypted secretsย 

  1. Repo โ†’ Settings โ†’ Secrets and variables โ†’ Actions
  2. Add e.g. PRIVATE_KEY, ALCHEMY_API_KEY, VERCEL_TOKEN
# Use secrets in a job jobs: deploy: runs-on: ubuntu-latest env: PRIVATE_KEY: ${{ secrets.DEPLOYER_PRIVATE_KEY }} RPC_URL: ${{ secrets.SEPOLIA_RPC_URL }} steps: - uses: actions/checkout@v4 - run: npm ci - run: npx hardhat run scripts/deploy.js --network sepolia

Best practice: Use a deployer wallet with minimal funds; never use a wallet holding real user assets.


๐Ÿšข Deploy from CI (CD)

Deploy frontend to Vercel

Vercel GitHub integrationย  deploys automatically. For custom control, use the Vercel CLIย  in Actions:

# .github/workflows/deploy-vercel.yml name: Deploy to Vercel on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci - run: npm run build - name: Deploy to Vercel uses: amondnet/vercel-action@v25 with: vercel-token: ${{ secrets.VERCEL_TOKEN }} vercel-org-id: ${{ secrets.VERCEL_ORG_ID }} vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }} working-directory: ./

Deploy with Docker (e.g. Railway)

# .github/workflows/deploy-railway.yml name: Deploy to Railway on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install Railway CLI run: npm i -g @railway/cli - name: Deploy env: RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }} run: railway up --service my-app

See Railwayโ€™s deployment docsย  for tokens and service names.


โœ… Good Practices

  • Run tests and lint on every PR โ€” Block merge if they fail
  • Use matrix builds for multiple Node versions if you support them
  • Cache dependencies โ€” cache: 'npm' or actions/cacheย  to speed up runs
  • Pin actions by tag โ€” Prefer @v4 over @main
  • Store all secrets in the platform โ€” Never log or commit them
  • Document your workflows โ€” Brief comment in the YAML or a CONTRIBUTING.md

๐Ÿ”— Further Reading

Last updated on