---
# === IDENTITY ===
id: software/migrations/jenkins-to-github-actions/2026
canonical_question: "How do I migrate from Jenkins to GitHub Actions?"
aliases:
  - "Jenkins to GitHub Actions migration"
  - "convert Jenkinsfile to GitHub Actions"
  - "replace Jenkins with GitHub Actions"
  - "Jenkins pipeline to GitHub workflow"
  - "CI/CD migration Jenkins to GitHub"
  - "Jenkinsfile to YAML workflow"
  - "GitHub Actions Importer Jenkins"
  - "Jenkins shared library to reusable workflows"
entity_type: software_reference
domain: software > migrations > jenkins_to_github_actions
region: global
jurisdiction: global
temporal_scope: 2020-2026

# === VERIFICATION ===
last_verified: 2026-05-17
confidence: 0.93
version: 2.1
first_published: 2026-02-17

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: stable
  last_breaking_change: "GitHub postponed the self-hosted runner $0.002/min platform charge (originally planned for March 2026) on 2025-12-18 — re-evaluation pending"
  next_review: 2026-11-13
  change_sensitivity: medium

# === CONSTRAINTS ===
constraints:
  - "Pin third-party actions to full commit SHAs (not @v* tags) — immutable actions enforcement is rolling out on hosted runners in 2026"
  - "Self-hosted runners on public repos must never run untrusted fork PRs — use pull_request_target or restrict to private repos"
  - "GitHub Actions has a 6-hour job timeout and 72-hour workflow timeout — restructure long-running Jenkins jobs before migrating"
  - "GitHub-hosted runners provide 7 GB RAM / 2 CPU / 14 GB SSD by default — use larger runners ($$$) or self-hosted for resource-intensive builds"
  - "Secrets must never appear in workflow YAML — use GitHub Secrets (repo/org/environment level) and OIDC federation for cloud providers"
  - "Self-hosted runner $0.002/min platform charge originally scheduled for March 2026 is POSTPONED (per GitHub 2025-12-18) — do not budget around it without checking the GitHub Changelog first"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "Code is hosted on GitLab, not GitHub"
    use_instead: "Use GitLab CI/CD (Jenkins-to-GitLab is platform-native — GitHub Actions does not run on GitLab)"
  - condition: "User wants to migrate from CircleCI or Travis CI (not Jenkins)"
    use_instead: "software/migrations/circleci-to-github-actions/2026"
  - condition: "User wants a fully on-premises CI/CD solution with no cloud dependency"
    use_instead: "Keep Jenkins, or evaluate Gitea Actions / Drone CI for self-hosted GitHub-Actions-compatible workflows"

# === AGENT HINTS ===
inputs_needed:
  - key: pipeline_complexity
    question: "How complex are your Jenkins pipelines?"
    type: choice
    options: ["Simple (build+test+deploy, <10 stages)", "Moderate (10-20 stages, some shared libraries)", "Complex (heavy shared libraries, custom plugins, 20+ stages)"]
  - key: runner_requirements
    question: "Do you need self-hosted runners (GPU, special hardware, on-prem network access)?"
    type: choice
    options: ["No — GitHub-hosted runners are fine", "Yes — we need self-hosted runners", "Hybrid — some jobs need self-hosted"]
  - key: repo_structure
    question: "What is your repository structure?"
    type: choice
    options: ["Single repo per project", "Monorepo with multiple services", "Multi-repo with shared libraries"]

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/software/migrations/jenkins-to-github-actions/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-05-17)"

# === RELATED UNITS ===
related_kos:
  related_to:
    - id: "software/migrations/circleci-to-github-actions/2026"
      label: "CircleCI to GitHub Actions Migration"
    - id: "software/migrations/docker-compose-to-kubernetes/2026"
      label: "Docker Compose to Kubernetes Migration"
  solves:
    - id: "software/migrations/heroku-to-aws/2026"
      label: "Heroku to AWS Migration (deployment pipeline)"
  often_confused_with:
    - id: "software/migrations/circleci-to-github-actions/2026"
      label: "CircleCI to GitHub Actions (different source platform — Jenkins uses Groovy DSL, CircleCI uses YAML)"

# === SOURCES (5-8 authoritative sources) ===
sources:
  - id: src1
    title: "Migrating from Jenkins to GitHub Actions"
    author: GitHub
    url: https://docs.github.com/en/actions/migrating-to-github-actions/migrating-from-jenkins-to-github-actions
    type: official_docs
    published: 2025-09-01
    reliability: authoritative
  - id: src2
    title: "GitHub Actions Documentation"
    author: GitHub
    url: https://docs.github.com/en/actions
    type: official_docs
    published: 2025-10-01
    reliability: authoritative
  - id: src3
    title: "Migrating from Jenkins with GitHub Actions Importer"
    author: GitHub
    url: https://docs.github.com/en/actions/migrating-to-github-actions/automated-migrations/migrating-from-jenkins-with-github-actions-importer
    type: official_docs
    published: 2025-08-01
    reliability: authoritative
  - id: src4
    title: "Jenkins Pipeline Syntax Reference"
    author: Jenkins.io
    url: https://www.jenkins.io/doc/book/pipeline/syntax/
    type: official_docs
    published: 2025-06-01
    reliability: authoritative
  - id: src5
    title: "GitHub Actions Marketplace"
    author: GitHub
    url: https://github.com/marketplace?type=actions
    type: official_docs
    published: 2025-10-01
    reliability: authoritative
  - id: src6
    title: "GitHub Actions: Self-hosted Runners"
    author: GitHub
    url: https://docs.github.com/en/actions/hosting-your-own-runners
    type: official_docs
    published: 2025-08-01
    reliability: authoritative
  - id: src7
    title: "Pricing Changes for GitHub Actions (2026)"
    author: GitHub
    url: https://resources.github.com/actions/2026-pricing-changes-for-github-actions/
    type: official_docs
    published: 2025-12-17
    reliability: authoritative
  - id: src8
    title: "Securing GitHub Actions Workflows with Immutable Actions"
    author: GitHub Security Blog
    url: https://ghsioux.github.io/2024/12/10/securing-workflow-immutable-actions
    type: technical_blog
    published: 2024-12-10
    reliability: high
  - id: src9
    title: "Update to GitHub Actions pricing (self-hosted runner fee postponed)"
    author: GitHub
    url: https://github.blog/changelog/2025-12-16-coming-soon-simpler-pricing-and-a-better-experience-for-github-actions/
    type: official_docs
    published: 2025-12-18
    reliability: authoritative
  - id: src10
    title: "What's coming to our GitHub Actions 2026 security roadmap"
    author: GitHub Blog
    url: https://github.blog/news-insights/product-news/whats-coming-to-our-github-actions-2026-security-roadmap/
    type: official_docs
    published: 2026-03-04
    reliability: authoritative
---

# How to Migrate from Jenkins to GitHub Actions

## TL;DR

- **Bottom line**: Map Jenkins pipeline stages to GitHub Actions jobs, replace Jenkins plugins with GitHub Actions marketplace equivalents, and convert Jenkinsfile Groovy DSL to GitHub Actions YAML -- most pipelines convert in 1-2 days per project. Use the GitHub Actions Importer CLI to automate the initial conversion. [src1, src3]
- **Key tool/command**: `gh actions-importer dry-run jenkins --source-url $JENKINS_URL --output-dir out/` to auto-convert Jenkinsfiles, then create `.github/workflows/ci.yml` to replace your `Jenkinsfile`.
- **Watch out for**: Jenkins shared libraries and custom Groovy functions have no direct equivalent -- extract logic into shell scripts or composite actions. The $0.002/min self-hosted-runner platform charge originally slated for March 2026 has been **postponed** after community pushback -- track the GitHub Changelog before factoring it into ROI. [src7, src9]
- **Works with**: Any GitHub-hosted repository; supports Linux, macOS, Windows runners; self-hosted runners for custom environments. GitHub-hosted runners now include M2 macOS and Windows Server 2025 images.

## Constraints
<!-- Agents: read this section before recommending any action from this unit.
     These are hard constraints that must not be violated. -->

- Pin third-party actions to full commit SHAs (not `@v*` tags) -- immutable actions enforcement is rolling out on hosted runners in 2026. [src8]
- Self-hosted runners on public repos must never run untrusted fork PRs -- use `pull_request_target` or restrict to private repos. [src6]
- GitHub Actions has a 6-hour job timeout and 72-hour workflow timeout -- restructure long-running Jenkins jobs before migrating. [src2]
- GitHub-hosted runners provide 7 GB RAM / 2 CPU / 14 GB SSD by default -- use larger runners or self-hosted for resource-intensive builds. [src2]
- Secrets must never appear in workflow YAML -- use GitHub Secrets (repo/org/environment level) and OIDC federation for cloud providers. [src2]
- Self-hosted-runner $0.002/min platform charge originally planned for March 2026 has been **postponed** by GitHub (announced 2025-12-18) following community backlash -- do not budget around it without confirming current status in the GitHub Changelog. [src7, src9]
- Pin actions to immutable releases where available -- GitHub has begun migrating standard hosted runners to immutable action resolution, and the 2026 security roadmap adds a `dependencies:` block in workflow YAML that locks transitive action SHAs. [src8, src10]

## Quick Reference

| Jenkins Concept | GitHub Actions Equivalent | Notes |
|---|---|---|
| `Jenkinsfile` | `.github/workflows/*.yml` | YAML instead of Groovy DSL [src1] |
| `pipeline { }` | `on:` + `jobs:` | Triggers + job definitions [src1] |
| `stage('Build')` | `jobs: build:` | Each stage -> separate job (or steps within a job) [src1] |
| `steps { sh 'cmd' }` | `steps: - run: cmd` | Direct mapping [src1] |
| `agent { docker { image 'node:20' } }` | `container: node:20` or `runs-on:` | Use `container:` for Docker, `runs-on:` for VM [src1] |
| `when { branch 'main' }` | `on: push: branches: [main]` | Trigger filtering [src2] |
| `parameters { string(...) }` | `workflow_dispatch: inputs:` | Manual trigger with parameters [src2] |
| `environment { VAR = 'val' }` | `env:` (workflow/job/step level) | Can scope to workflow, job, or step [src2] |
| `credentials('secret-id')` | `${{ secrets.SECRET_NAME }}` | GitHub Secrets (repo or org level) [src2] |
| `post { always { ... } }` | `if: always()` | Conditional step execution [src1] |
| `parallel { }` | Multiple jobs (run in parallel by default) | Jobs run in parallel unless `needs:` is specified [src2] |
| `stash/unstash` | `actions/upload-artifact` / `download-artifact` | Artifact passing between jobs [src2] |
| Shared libraries | Reusable workflows / composite actions | `uses: org/repo/.github/workflows/ci.yml@main` [src2] |
| Jenkins plugins | GitHub Actions Marketplace | 15,000+ actions available [src5] |
| Jenkins agents/nodes | GitHub-hosted or self-hosted runners | `runs-on: ubuntu-latest` or self-hosted [src6] |
| `Multibranch Pipeline` | `on: pull_request:` | Auto-triggers on PRs [src2] |
| `cron('H/15 * * * *')` | `schedule: - cron: '*/15 * * * *'` | Standard cron syntax (no `H` hash) [src2] |

## Decision Tree

```
START
├── Is the code on GitHub?
│   ├── YES -> GitHub Actions is the natural choice [src2]
│   └── NO (GitLab/Bitbucket) -> Consider platform-native CI/CD instead
├── How complex are Jenkins pipelines?
│   ├── Simple (build + test + deploy, <10 stages) -> Direct YAML conversion [src1]
│   ├── Moderate (10-20 stages, some shared libs) -> Use Actions Importer + create composite actions [src3]
│   └── Complex (heavy shared libraries, custom plugins, 20+ stages) -> Phased migration with parallel running [src3]
├── Do you need self-hosted runners?
│   ├── YES (GPU, special hardware, on-prem) -> Set up self-hosted runners (NB: the originally planned $0.002/min charge is currently POSTPONED but may return -- track Changelog) [src6, src9]
│   └── NO -> GitHub-hosted runners (ubuntu/windows/macos) [src2]
├── Multi-repo or monorepo?
│   ├── Multi-repo -> One workflow per repo [src2]
│   └── Monorepo -> Path filters + reusable workflows [src2]
├── Need automated conversion?
│   ├── YES -> Run GitHub Actions Importer for initial conversion [src3]
│   └── NO -> Manual conversion for full control
└── DEFAULT -> Start with simplest pipeline, migrate incrementally
```

## Step-by-Step Guide

### 1. Audit and inventory your Jenkins pipelines

List all Jenkins jobs, their triggers, plugins, credentials, and build environments. Use the Actions Importer for an automated audit. [src3]

```bash
# Install GitHub Actions Importer
gh extension install github/gh-actions-importer

# Run audit to inventory all Jenkins pipelines
gh actions-importer audit jenkins \
  --source-url http://jenkins.example.com \
  --jenkins-access-token $JENKINS_TOKEN \
  --output-dir audit-results/

# Review the audit summary
cat audit-results/audit_summary.md
```

**Verify**: Check `audit-results/` for a complete list of pipelines and their complexity ratings.

### 2. Map your Jenkinsfile to GitHub Actions YAML

Convert Groovy DSL to YAML. Each Jenkins stage becomes a job or a group of steps. [src1]

```groovy
// BEFORE: Jenkinsfile
pipeline {
    agent { docker { image 'node:20' } }
    stages {
        stage('Install') {
            steps { sh 'npm ci' }
        }
        stage('Test') {
            steps { sh 'npm test' }
        }
        stage('Build') {
            steps { sh 'npm run build' }
        }
        stage('Deploy') {
            when { branch 'main' }
            steps {
                withCredentials([string(credentialsId: 'deploy-token', variable: 'TOKEN')]) {
                    sh 'deploy.sh $TOKEN'
                }
            }
        }
    }
    post {
        always { junit '**/test-results/*.xml' }
        failure { slackSend channel: '#alerts', message: 'Build failed!' }
    }
}
```

```yaml
# AFTER: .github/workflows/ci.yml
name: CI/CD Pipeline
on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  build-and-test:
    runs-on: ubuntu-latest
    container: node:20
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test
      - run: npm run build
      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: test-results
          path: '**/test-results/*.xml'

  deploy:
    needs: build-and-test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh ${{ secrets.DEPLOY_TOKEN }}

  notify:
    needs: [build-and-test, deploy]
    if: failure()
    runs-on: ubuntu-latest
    steps:
      - uses: slackapi/slack-github-action@v1
        with:
          channel-id: '#alerts'
          slack-message: 'Build failed!'
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_TOKEN }}
```

**Verify**: `actionlint .github/workflows/ci.yml` -> no errors.

### 3. Migrate credentials and secrets

Move Jenkins credentials to GitHub Secrets. Use OIDC federation for cloud providers instead of long-lived keys. [src2]

```bash
# List Jenkins credentials (via Jenkins CLI or API)
# For each credential, create a GitHub secret:
gh secret set DEPLOY_TOKEN --body "your-token-value"
gh secret set DOCKER_PASSWORD --body "your-password"

# For organization-wide secrets:
gh secret set ORG_SECRET --org my-org --body "value"

# For environment-specific secrets (e.g., staging vs production):
gh secret set AWS_ACCESS_KEY_ID --env production --body "AKIAIOSFODNN7EXAMPLE"
```

**Verify**: `gh secret list` -> all required secrets are listed.

### 4. Replace Jenkins plugins with GitHub Actions

Map each Jenkins plugin to its GitHub Actions marketplace equivalent. Pin to commit SHAs for security. [src5, src8]

```yaml
# Jenkins: Docker build + push plugin
# GitHub Actions equivalent (pinned to SHA):
- uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db  # v3.6.1
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567  # v3.3.0
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@4f58ea79222b3b9dc7c8ddd91569dbe374b16e0d  # v5.10.0
  with:
    push: true
    tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

# Jenkins: SonarQube Scanner
# GitHub Actions equivalent:
- uses: SonarSource/sonarcloud-github-action@v2
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
```

**Verify**: Workflow runs successfully -> check Actions tab in GitHub.

### 5. Convert shared libraries to reusable workflows

Jenkins shared libraries -> GitHub reusable workflows or composite actions. [src2]

```yaml
# .github/workflows/reusable-deploy.yml (in shared repo)
name: Reusable Deploy
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    secrets:
      deploy-token:
        required: true
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      - uses: actions/checkout@v4
      - run: ./deploy.sh
        env:
          TOKEN: ${{ secrets.deploy-token }}

# Usage in another repo:
jobs:
  deploy-staging:
    uses: my-org/shared-workflows/.github/workflows/reusable-deploy.yml@main
    with:
      environment: staging
    secrets:
      deploy-token: ${{ secrets.DEPLOY_TOKEN }}
```

**Verify**: `gh workflow list` shows the reusable workflow; calling repo triggers it successfully.

### 6. Run Jenkins and GitHub Actions in parallel (validation phase)

Run both systems side-by-side for 1-2 weeks before decommissioning Jenkins. Compare build outputs, timing, and test results. [src3]

```yaml
# Add a comparison step to your GitHub Actions workflow
  compare-results:
    needs: [build-and-test]
    runs-on: ubuntu-latest
    steps:
      - name: Compare with Jenkins build
        run: |
          echo "GitHub Actions build: ${{ needs.build-and-test.result }}"
          echo "Compare timing, test counts, and artifact checksums with Jenkins"
```

**Verify**: Both CI systems produce identical build artifacts and test results for at least 1 week.

## Code Examples

### Bash: Automated Jenkinsfile to GitHub Actions converter (basic)

> Full script: [bash-automated-jenkinsfile-to-github-actions-conve.sh](scripts/bash-automated-jenkinsfile-to-github-actions-conve.sh) (32 lines)

```bash
#!/bin/bash
# Input:  Jenkinsfile path
# Output: Basic .github/workflows/ci.yml
set -euo pipefail
JENKINSFILE="${1:-Jenkinsfile}"
# ... (see full script)
```

### YAML: Matrix build migration (Jenkins matrix -> GitHub Actions strategy)

```yaml
# Jenkins: matrix { axes { axis { name 'OS'; values 'linux', 'windows' } } }
# GitHub Actions equivalent:
jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: [18, 20, 22]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test
```

### YAML: OIDC authentication (replacing Jenkins cloud credentials)

```yaml
# Instead of storing AWS keys as secrets, use OIDC federation
jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write  # Required for OIDC
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
          aws-region: us-east-1
      - run: aws s3 sync ./dist s3://my-bucket/
```

## Anti-Patterns

### Wrong: One massive job with all stages

```yaml
# BAD -- no parallelism, slow feedback, one failure blocks everything
jobs:
  everything:
    runs-on: ubuntu-latest
    steps:
      - run: npm ci && npm test && npm run build && npm run deploy
```

### Correct: Separate jobs with dependencies

```yaml
# GOOD -- parallel where possible, clear dependencies [src2]
jobs:
  lint:
    runs-on: ubuntu-latest
    steps: [...]
  test:
    runs-on: ubuntu-latest
    steps: [...]
  deploy:
    needs: [lint, test]  # runs after both complete
    runs-on: ubuntu-latest
    steps: [...]
```

### Wrong: Hardcoding secrets in workflow files

```yaml
# BAD -- secrets exposed in version control
env:
  API_KEY: sk-12345abcdef
```

### Correct: Use GitHub Secrets with OIDC where possible

```yaml
# GOOD -- encrypted, never logged, rotated via GitHub UI [src2]
env:
  API_KEY: ${{ secrets.API_KEY }}
# BEST -- use OIDC for cloud providers (no stored secrets at all)
permissions:
  id-token: write
```

### Wrong: Using floating action tags

```yaml
# BAD -- @v4 can change under you, supply chain risk [src8]
- uses: actions/checkout@v4
```

### Correct: Pin actions to commit SHAs

```yaml
# GOOD -- immutable, auditable, matches upcoming immutable actions enforcement [src8]
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
```

### Wrong: Running self-hosted runners on public repos without restrictions

```yaml
# BAD -- any fork PR can execute arbitrary code on your runner [src6]
on: pull_request
jobs:
  build:
    runs-on: self-hosted
```

### Correct: Restrict self-hosted runners to trusted events

```yaml
# GOOD -- only trigger on internal events, or use pull_request_target with caution [src6]
on:
  push:
    branches: [main]
  pull_request_target:
    branches: [main]
jobs:
  build:
    runs-on: self-hosted
    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
```

## Common Pitfalls

- **Jenkins shared libraries have no 1:1 equivalent**: Extract Groovy logic into shell scripts or composite actions. Reusable workflows handle orchestration but cannot contain arbitrary Groovy. Fix: create composite actions for logic, reusable workflows for orchestration. [src1, src3]
- **Jenkins `when` conditions are more flexible**: GitHub Actions `if:` expressions cover most cases but cannot match complex Groovy conditionals. Fix: use job-level outputs and multi-step conditionals. [src1]
- **Artifact passing differs**: Jenkins stash/unstash is within a single pipeline. GitHub Actions needs explicit upload/download between jobs. Fix: use `actions/upload-artifact` and `actions/download-artifact`. [src2]
- **Cron syntax differences**: Jenkins uses `H` for hash-based distribution; GitHub Actions uses standard cron. Fix: replace `H` with specific minutes. [src1]
- **Self-hosted runner security**: GitHub self-hosted runners on public repos can execute code from any fork PR. Fix: use `pull_request_target` or restrict self-hosted runners to private repos. [src6]
- **No built-in pipeline visualization**: Jenkins Blue Ocean provides visual pipeline progress. GitHub Actions has a simpler view. Fix: use descriptive job/step names and group steps with composite actions. [src1]
- **2026 pricing volatility**: GitHub announced (2025-12-16) then postponed (2025-12-18) a $0.002/min self-hosted-runner platform charge after community pushback; hosted-runner price cuts (up to 39% on Jan 2026) did ship. The self-hosted fee may return in a different form. Fix: build cost models against current Changelog state, not against the original December 2025 announcement. [src7, src9]
- **GitHub Actions Importer output needs review**: The automated converter produces functional but not optimal YAML. Fix: always review and optimize the generated workflows -- merge redundant jobs, add caching, and pin action versions. [src3]

## Decision Logic

### If Jenkins pipelines are simple (build + test + deploy, <10 stages, no shared libraries)
--> Convert the Jenkinsfile to a single `.github/workflows/ci.yml` by hand using the Quick Reference mapping table. Pipelines this size typically convert in <1 day. [src1]

### If Jenkins pipelines are moderate (10-20 stages, 1-2 shared libraries, several plugins)
--> Run `gh actions-importer dry-run jenkins` to auto-generate a first-pass YAML, then refactor the output into reusable workflows for shared steps and composite actions for Groovy logic. [src3]

### If Jenkins pipelines are complex (20+ stages, heavy shared libraries, custom Groovy plugins)
--> Use a phased migration: run Jenkins and GitHub Actions in parallel for 1-2 weeks, migrate one pipeline per sprint, and keep Jenkins authoritative until artifact checksums match across both. Do NOT attempt a big-bang cutover. [src3]

### If the workload needs GPUs, special hardware, or on-prem network access
--> Configure self-hosted runners and pin to private repos or use `pull_request_target` with strict actor allowlists. NB: GitHub's original $0.002/min self-hosted-runner platform charge was postponed on 2025-12-18 -- track the GitHub Changelog before assuming current pricing. [src6, src9]

### If the codebase is hosted on GitLab or Bitbucket (not GitHub)
--> Do NOT migrate to GitHub Actions; use the platform-native CI/CD (GitLab CI/CD or Bitbucket Pipelines). GitHub Actions cannot run against repositories outside GitHub. [src2]

### If you need to enforce SHA-pinned third-party actions
--> Pin every `uses:` line to a full commit SHA (40 hex chars), enable repository rulesets that require immutable actions, and plan for the 2026 security roadmap `dependencies:` block once it ships. [src8, src10]

### If a Jenkins shared library contains arbitrary Groovy logic
--> Do NOT try to translate Groovy into reusable-workflow YAML. Extract the logic into a shell script (committed to the shared repo) or a composite action under `action.yml`, then call it from the workflow. Reusable workflows are for orchestration, not arbitrary code. [src1, src3]

## Diagnostic Commands

```bash
# Analyze Jenkinsfile complexity (count key directives)
grep -c "stage\|step\|when\|parallel" Jenkinsfile

# List all Jenkins plugins used (Jenkins CLI)
java -jar jenkins-cli.jar -s http://jenkins:8080/ list-plugins

# Run GitHub Actions Importer dry-run (preview conversion)
gh actions-importer dry-run jenkins \
  --source-url http://jenkins.example.com \
  --output-dir dry-run-results/

# Validate GitHub Actions workflow syntax
actionlint .github/workflows/ci.yml

# List workflows and recent runs
gh workflow list && gh run list --limit 10

# Check self-hosted runner status
gh api /repos/{owner}/{repo}/actions/runners

# View workflow run logs
gh run view <run-id> --log

# Check GitHub Actions billing usage
gh api /orgs/{org}/settings/billing/actions
```

## Version History & Compatibility

| Feature | Jenkins | GitHub Actions | Notes |
|---|---|---|---|
| Config format | Groovy DSL (Jenkinsfile) | YAML | YAML anchors supported (2025) |
| Execution | Self-hosted (always) | GitHub-hosted or self-hosted | Self-hosted $0.002/min charge POSTPONED 2025-12-18 [src9] |
| Plugin ecosystem | 1,800+ plugins | 15,000+ marketplace actions | Immutable actions in preview [src8] |
| Cost model | Free (self-hosted infra) | Free for public repos; 2,000 min/mo free private | Hosted runner prices reduced up to 39% Jan 2026 [src7] |
| Matrix builds | `matrix { }` directive | `strategy: matrix:` | GitHub supports `fail-fast` and `max-parallel` |
| Container support | Docker agent | `container:` keyword or Docker actions | Service containers also supported |
| Runner images | Custom AMIs/Docker | ubuntu-latest, windows-2025, macos-15 | M2 macOS runners GA, Windows Server 2025 in preview |
| Cache | Custom solutions | `actions/cache` (>10 GB limit since 2025) | Cache sharing across branches supported |
| Automated migration | N/A | GitHub Actions Importer CLI [src3] | Supports audit, dry-run, and migrate commands |

## When to Use / When Not to Use

| Migrate When | Don't Migrate When | Use Instead |
|---|---|---|
| Code is on GitHub | Code is on GitLab/Bitbucket | Platform-native CI/CD (GitLab CI, Bitbucket Pipelines) |
| Jenkins maintenance is a burden | Complex shared library ecosystem you cannot rewrite | Phased migration; keep Jenkins for complex jobs initially |
| Want managed CI/CD infrastructure | Need 100% on-premises with zero cloud dependency | Keep Jenkins, or use Gitea Actions / Drone |
| Team already uses GitHub ecosystem | Custom hardware requirements (FPGA, GPU farms) | Jenkins + specialized agents, or hybrid approach |
| <2,000 min/mo private repo usage (free tier) | Very high build volume on private repos | Compare costs: Jenkins self-hosted vs. GitHub Actions pricing |
| Need OIDC-based cloud authentication | Regulatory requirement for all compute on-prem | Jenkins with cloud-provider plugins |

## Important Caveats

- GitHub Actions has a 6-hour job timeout and 72-hour workflow timeout. Long-running Jenkins jobs may need restructuring.
- GitHub-hosted runners have limited resources (7 GB RAM, 2 CPU, 14 GB SSD). Complex builds may need larger runners ($$$) or self-hosted. Larger runners (up to 64 CPU) are available on Team and Enterprise plans.
- Free tier: 2,000 minutes/month for private repos. Large organizations may see cost increases vs. self-hosted Jenkins. Hosted runner prices were reduced up to 39% in January 2026 (this change shipped); the companion $0.002/min self-hosted platform charge was postponed on 2025-12-18 and remains under re-evaluation. [src7, src9]
- Jenkins plugins with side effects (modifying Jenkins config, managing agents) have no equivalent -- those are Jenkins admin features, not CI/CD features.
- 67% of organizations that used Jenkins as primary CI/CD in 2022 have either migrated away or are in process (2024 State of DevOps Report).
- GitHub Actions Importer can automate initial conversion but output needs manual review and optimization. [src3]
- Agentic workflows (AI-powered automation in GitHub Actions) are in technical preview as of February 2026 -- not yet production-ready.

## Related Units
<!-- Generated from related_kos frontmatter -->

- [CircleCI to GitHub Actions Migration](/software/migrations/circleci-to-github-actions/2026)
- [Docker Compose to Kubernetes](/software/migrations/docker-compose-to-kubernetes/2026)
- [Heroku to AWS Migration](/software/migrations/heroku-to-aws/2026)
