DEV Community

Cover image for 6 CI/CD Patterns That Turn Manual JavaScript Deploys Into Zero-Downtime Releases
JSGuruJobs
JSGuruJobs

Posted on

6 CI/CD Patterns That Turn Manual JavaScript Deploys Into Zero-Downtime Releases

Most JavaScript apps still deploy with SSH and git pull. That breaks the moment you have users. Here are 6 CI/CD patterns that remove downtime, prevent bad deploys, and scale with real traffic.

1. Run Tests Before Every Deploy

If your pipeline deploys without tests, it will ship bugs.

Before (manual deploy):

ssh user@server
cd app
git pull
npm install
pm2 restart app
Enter fullscreen mode Exit fullscreen mode

After (GitHub Actions with test gate):

name: Deploy

on:
  push:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - run: echo "Only runs if tests pass"
Enter fullscreen mode Exit fullscreen mode

Bad code never reaches production. This alone eliminates a large class of outages.

2. Use Environment Variables From Secrets, Not Files

Hardcoding .env works locally and fails in CI.

Before:

DATABASE_URL=postgres://localhost:5432/app
Enter fullscreen mode Exit fullscreen mode
const db = new PrismaClient({
  datasources: { db: { url: process.env.DATABASE_URL } }
});
Enter fullscreen mode Exit fullscreen mode

After (GitHub Actions secrets):

env:
  DATABASE_URL: ${{ secrets.DATABASE_URL }}
Enter fullscreen mode Exit fullscreen mode
- name: Run migrations
  run: npx prisma migrate deploy
Enter fullscreen mode Exit fullscreen mode

Secrets never touch your repo. You remove the risk of leaking credentials and avoid "works locally" failures.

3. Build Once, Deploy Many

Rebuilding on the server creates inconsistencies.

Before:

npm install
npm run build
pm2 restart app
Enter fullscreen mode Exit fullscreen mode

After (build artifact in CI):

- name: Build
  run: |
    npm ci
    npm run build
    tar -czf build.tar.gz dist/

- name: Upload artifact
  uses: actions/upload-artifact@v4
  with:
    name: build
    path: build.tar.gz
Enter fullscreen mode Exit fullscreen mode
- name: Deploy artifact
  run: |
    scp build.tar.gz user@server:/app
    ssh user@server "cd /app && tar -xzf build.tar.gz"
Enter fullscreen mode Exit fullscreen mode

You deploy the exact same build that passed tests. No drift. No surprises.

4. Zero-Downtime Deploy With PM2 Reload

Restarting the app drops requests.

Before:

pm2 restart app
Enter fullscreen mode Exit fullscreen mode

After:

pm2 reload app --update-env
Enter fullscreen mode Exit fullscreen mode

PM2 spins up new instances before killing old ones. Users never see downtime. For production systems, this is non-negotiable.

5. Separate Migrations From Code Deploy

Schema changes break rollbacks if done wrong.

Before (unsafe):

- run: npx prisma migrate deploy
- run: npm run build && pm2 reload app
Enter fullscreen mode Exit fullscreen mode

After (safe two-step):

-- Migration 1
ALTER TABLE users ADD COLUMN display_name TEXT;
Enter fullscreen mode Exit fullscreen mode
// Deploy 2
return user.display_name || user.name;
Enter fullscreen mode Exit fullscreen mode

Schema first. Code second. This keeps rollback safe because old code still works with the new schema.

This pattern becomes critical when combined with pipelines like the ones in the CI/CD pipeline patterns that prevent broken production deploys where migrations are treated as a separate deployment stage.

6. Rollback in Seconds With Versioned Deploys

If rollback takes minutes, your users already noticed.

Before:

git checkout previous-commit
npm install
npm run build
pm2 restart app
Enter fullscreen mode Exit fullscreen mode

After (Docker versioning):

docker build -t my-app:v15 .
docker tag my-app:v15 my-app:latest
Enter fullscreen mode Exit fullscreen mode

Rollback:

docker stop app
docker run -d --name app my-app:v14
Enter fullscreen mode Exit fullscreen mode

No rebuild. No install. You switch versions instantly.


These patterns are not "DevOps extras." They are baseline expectations for any production system. Start by adding test gates and PM2 reload. Then move to artifacts and versioned deploys. Your deploys go from risky to boring, and boring is exactly what you want in production.

Top comments (0)