DevOps

Discord Bot CI/CD: GitHub Actions vs GitLab CI vs Jenkins

Rank.top Team
August 2025

CI/CD for Discord bots isn't just "run tests then deploy." Bots are long‑lived, stateful processes with persistent Gateway connections and sensitive tokens. Here's how the big three platforms compare for real‑world bot workflows - plus ready‑to‑use pipelines.

TL;DR: Which should you pick?

GitHub Actions

  • Best for GitHub repos. Easy setup, huge marketplace, OIDC to clouds.
  • Matrix builds, cache, services (DB), reusable workflows, environments.
  • GitHub‑centric; advanced customization ≲ Jenkins.

GitLab CI/CD

  • All‑in‑one DevOps. Child pipelines, Review Apps, Kubernetes integration.
  • Strong rules/needs, artifacts, security scanning (paid tiers).
  • Self‑hosted can be heavy; some features gated.

Jenkins

  • Ultimate flexibility via plugins, agents, and declarative pipelines.
  • Great for on‑prem/compliance or complex hybrid needs.
  • You manage upgrades, security, scaling.

What's different about bots?

Zero‑downtime restarts

Use rolling restarts (Kubernetes), PM2 reloads, or blue‑green swaps so Gateway sessions reconnect gracefully and slash commands remain responsive.

Secrets & rate limits

Protect the Discord token and Rank.top keys in platform secrets. Bake retry with jitter and identify concurrency per sharding strategy.

GitHub Actions (cloud‑native)

  • Matrix builds, cache, artifacts; services for DBs during tests.
  • Reusable workflows and environments with protection rules.
  • OIDC to clouds (AWS/GCP/Azure) for deploys without long‑lived keys.

Example workflow

name: Bot CI/CD
on:
push: { branches: [main] }
pull_request:
workflow_dispatch:
concurrency:
group: bot-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix: { node: [18, 20] }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: npm
- run: npm ci
- run: npm test --if-present

build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with: { name: dist, path: dist }

deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: production
url: ${{ vars.STATUS_URL }}
steps:
- name: Prepare SSH
run: |
echo "${{ secrets.SSH_KEY }}" > key
chmod 600 key
ssh -o StrictHostKeyChecking=no -i key ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "mkdir -p ~/app"
- name: Upload and reload (PM2)
run: |
tar -czf build.tgz dist package.json ecosystem.config.js
scp -i key -o StrictHostKeyChecking=no build.tgz ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:~/app/
ssh -i key -o StrictHostKeyChecking=no ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
"cd ~/app && tar -xzf build.tgz && npm ci --omit=dev && npx pm2 reload ecosystem.config.js --update-env"

Tip: use environments for manual approvals and protected secrets.

GitLab CI/CD (all‑in‑one)

  • Stages with rules and needs for parallelization.
  • Review Apps and Kubernetes integration streamline previews and rollouts.
  • Artifacts/caching and child pipelines scale monorepos.

Example .gitlab-ci.yml

image: node:20

cache:
key:
files:
- package-lock.json
paths:
- node_modules/

stages: [test, build, deploy]

test:
stage: test
script:
- npm ci
- npm test --if-present
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_BRANCH'

build:
stage: build
needs: ["test"]
script:
- npm ci
- npm run build
artifacts:
paths: [dist]
expire_in: 1 week

deploy_prod:
stage: deploy
needs: ["build"]
environment:
name: production
url: $STATUS_URL
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
script:
- apt-get update && apt-get install -y openssh-client
- mkdir -p ~/.ssh && echo "$SSH_PRIVATE_KEY" | tr -d '
' | ssh-add - >/dev/null 2>&1 || true
- ssh -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "mkdir -p ~/app && true"
- scp -o StrictHostKeyChecking=no -r dist package.json ecosystem.config.js $SSH_USER@$SSH_HOST:~/app/
- ssh -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "cd ~/app && npm ci --omit=dev && npx pm2 reload ecosystem.config.js --update-env"

Jenkins (maximum control)

  • Declarative pipelines, agents (including Docker agents), and shared libraries.
  • withCredentials for tokens/keys; disableConcurrentBuilds to prevent overlap.
  • Great when you must self‑host or deeply customize.

Example Jenkinsfile

pipeline {
agent { docker { image 'node:20' } }
options { disableConcurrentBuilds(); timestamps() }
environment {
NODE_ENV = 'production'
}
stages {
stage('Checkout') {
steps { checkout scm }
}
stage('Test') {
steps {
sh 'npm ci'
sh 'npm test --if-present'
}
}
stage('Build') {
steps { sh 'npm run build' }
post { success { archiveArtifacts artifacts: 'dist/**', fingerprint: true } }
}
stage('Deploy') {
environment {
SSH_HOST = credentials('ssh-host') // use credentials plugin
SSH_USER = credentials('ssh-user')
SSH_KEY = credentials('ssh-key')
}
steps {
sh '''
eval `ssh-agent -s`
echo "$SSH_KEY" | tr -d '\r' | ssh-add - >/dev/null 2>&1
scp -o StrictHostKeyChecking=no -r dist package.json ecosystem.config.js $SSH_USER@$SSH_HOST:~/app/
ssh -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST "cd ~/app && npm ci --omit=dev && npx pm2 reload ecosystem.config.js --update-env"
'''
}
}
}
}

Secrets, tokens, and safety

Best practices

  • Store the Discord bot token, RANK_TOP_API_KEY, and RANK_TOP_AUTH_TOKEN in platform secrets.
  • Use OIDC where possible (cloud deploys) to avoid static cloud keys.
  • Mask tokens in logs; never echo secrets on failure.

Common mistakes

  • Hardcoding tokens or committing .env files.
  • Deploying without concurrency guards (overlapping restarts).
  • Skipping graceful reloads, causing avoidable downtime.

Zero‑downtime deploy patterns

PM2 Reload (single host)

Keep a single instance alive while loading the new code.

npx pm2 reload ecosystem.config.js --update-env

Kubernetes rolling updates

Use a Deployment with a rolling strategy.

strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0

Chooser guide

Solo/Small team on GitHub: GitHub Actions. Add environments, concurrency, and a simple SSH/PM2 deploy.

GitLab‑native or need Review Apps/K8s: GitLab CI/CD.

On‑prem/compliance/complex: Jenkins with Docker agents and credentials.

Ship faster, grow smarter

List your bot on Rank.top for modern discovery, built‑in analytics, and passive vote revenue. Connect webhooks in minutes.