Skip to main content

CI/CD Deployment

Updated: October 29, 2026
By Willya Randika

CI/CD is the practice of automating build, test, and release. Every repository change triggers a pipeline: code is checked out, dependencies installed, tests run, artifacts built, and the result shipped to a server. The goal is fewer manual steps and more consistent releases.

Pipeline stages

A healthy pipeline starts with the correct branch, installs dependencies from the lockfile, runs lint and tests, then builds an artifact or Docker image. After that it deploys to staging and runs smoke tests. If that passes, it promotes to production with approval or a schedule. Finally, a health check and rollback if needed.

Fast tests are more useful than a long pipeline that rarely runs. Start with lint, unit tests, and build. Add staging and rollback once the basic flow is stable.

A GitHub Actions example

name: deploy
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test -- --run
      - run: npm run build
      - name: Deploy
        env:
          SSH_KEY: ${{ secrets.SSH_KEY }}
          SSH_KNOWN_HOSTS: ${{ secrets.SSH_KNOWN_HOSTS }}
        run: |
          install -m 600 /dev/stdin ~/.ssh/id_ed25519 <<< "$SSH_KEY"
          printf '%s\n' "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
          rsync -az --delete .next/ ${{ secrets.USER }}@${{ secrets.HOST }}:/var/www/app/.next-new/
          ssh ${{ secrets.USER }}@${{ secrets.HOST }} 'cd /var/www/app && mv .next .next-old && mv .next-new .next && pm2 restart app'

This example is simple. Real production should use immutable artifacts, health checks, and automatic rollback. Never store a private key in the repository. Use a secret manager. Store the host key in SSH_KNOWN_HOSTS and verify its fingerprint. Do not rely on ssh-keyscan during deployment, because it trusts whatever host key answers.

Atomic deploys and rollback

Instead of overwriting the application folder, deploy to a new directory and switch a symlink with ln -sfn /var/www/releases/2026-10-30 /var/www/current. If the health check fails, point the symlink back to the previous release.

For Docker, run a versioned image tag and keep the old image until the new release is stable. For databases, prepare backward-compatible migrations and back up before major changes.

Secrets and access

Use encrypted secrets, not variables printed in logs. Restrict SSH keys to the required commands and hosts. Use a dedicated deploy user, not root. Separate staging and production access, and rotate credentials if logs or artifacts leak.

Common mistakes

Automatic deploy without tests only ships bugs faster. A database migration without a rollback plan may be incompatible with the old version. No health check makes a deploy look successful even when the app errors.

Shipping .env in artifacts also spreads secrets to too many places. Test from staging because production differs. CI/CD relates to staging, SSH, Docker, and VPS Snapshot.

FAQ

Is CI/CD only for large teams?

No. Small projects also benefit from automated tests and consistent deploys. Start with a simple pipeline, then add staging and rollback.

Is automatic deployment safe for production?

It is safe with tests, health checks, permissions, and rollback. For risky changes, use manual approval or a deploy window.

How should database migrations be handled?

Make backward-compatible migrations, back up first, test in staging, and prepare a rollback plan. Never run a destructive migration at the same time as a code deploy.

Disclaimer: Hosting Wiki articles are prepared for educational and reference purposes. Hosting technology keeps evolving, so some technical details may change over time.