Skip to content
Back to Blog
1 min read

GitHub Actions Larger Runners Deep Dive

I wrote “GitHub Actions Larger Runners Deep Dive” to share practical, production-minded guidance on this topic.

Understanding Larger Runners

Available Runner Sizes

# Runner specifications comparison
runners:
  standard:
    name: ubuntu-latest
    cpu: 2 cores
    memory: 7 GB
    storage: 14 GB
    cost: included

  4-core:
    name: ubuntu-latest-4-cores
    cpu: 4 cores
    memory: 16 GB
    storage: 150 GB
    cost: 2x standard

  8-core:
    name: ubuntu-latest-8-cores
    cpu: 8 cores
    memory: 32 GB
    storage: 300 GB
    cost: 4x standard

  16-core:
    name: ubuntu-latest-16-cores
    cpu: 16 cores
    memory: 64 GB
    storage: 600 GB
    cost: 8x standard

  32-core:
    name: ubuntu-latest-32-cores
    cpu: 32 cores
    memory: 128 GB
    storage: 600 GB
    cost: 16x standard

  64-core:
    name: ubuntu-latest-64-cores
    cpu: 64 cores
    memory: 256 GB
    storage: 600 GB
    cost: 32x standard

When to Use Larger Runners

name: Optimized Build Pipeline

on:
  push:
    branches: [main]

jobs:
  # Standard runner for simple tasks
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm run lint

  # Larger runner for parallel tests
  test:
    runs-on: ubuntu-latest-8-cores
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      - run: npm ci
      - run: npm test -- --maxWorkers=8

  # Extra large for build-intensive tasks
  build:
    runs-on: ubuntu-latest-16-cores
    steps:
      - uses: actions/checkout@v3

      - name: Setup build environment
        run: |
          sudo apt-get update
          sudo apt-get install -y build-essential

      - name: Parallel compilation
        run: make -j16

      - uses: actions/upload-artifact@v3
        with:
          name: build-output
          path: dist/

  # Large runner for Docker builds
  docker:
    runs-on: ubuntu-latest-8-cores
    steps:
      - uses: actions/checkout@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Build image with parallel layers
        uses: docker/build-push-action@v4
        with:
          context: .
          push: false
          tags: myapp:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max
          build-args: |
            PARALLELISM=8

.NET Build Optimization

name: .NET Build with Larger Runners

on: [push]

jobs:
  build-and-test:
    runs-on: ubuntu-latest-8-cores
    steps:
      - uses: actions/checkout@v3

      - name: Setup .NET
        uses: actions/setup-dotnet@v3
        with:
          dotnet-version: '7.0.x'

      - name: Restore with parallel downloads
        run: dotnet restore --verbosity minimal /p:RestoreUseParallelPackages=true

      - name: Build with max parallelism
        run: dotnet build --configuration Release --no-restore /p:BuildInParallel=true /maxcpucount:8

      - name: Test with parallel execution
        run: dotnet test --configuration Release --no-build --parallel /p:ParallelizeTestCollections=true

Node.js/npm Optimization

name: Node.js Build Optimization

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest-4-cores
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install with network concurrency
        run: npm ci --prefer-offline

      - name: Build with parallel processing
        run: npm run build
        env:
          # Webpack/Vite parallelism
          PARALLEL_WEBPACK: true
          NODE_OPTIONS: --max-old-space-size=8192

      - name: Run Jest with workers
        run: npm test -- --maxWorkers=4 --coverage

Android Build Optimization

name: Android Build

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest-16-cores
    steps:
      - uses: actions/checkout@v3

      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Setup Gradle
        uses: gradle/gradle-build-action@v2
        with:
          gradle-home-cache-cleanup: true

      - name: Build with Gradle
        run: ./gradlew assembleRelease
        env:
          GRADLE_OPTS: -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=16 -Xmx8g

      - name: Run tests
        run: ./gradlew test
        env:
          GRADLE_OPTS: -Dorg.gradle.parallel=true -Dorg.gradle.workers.max=16

Cost Optimization Strategies

name: Cost-Optimized Pipeline

on:
  push:
    branches: [main]
  pull_request:

jobs:
  # Quick checks on standard runner
  quick-checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm run lint
      - run: npm run typecheck

  # Full build only on main or manual trigger
  full-build:
    if: github.ref == 'refs/heads/main' || github.event_name == 'workflow_dispatch'
    needs: quick-checks
    runs-on: ubuntu-latest-16-cores
    steps:
      - uses: actions/checkout@v3
      - run: npm ci
      - run: npm run build:production

  # PR builds use smaller runner
  pr-build:
    if: github.event_name == 'pull_request'
    needs: quick-checks
    runs-on: ubuntu-latest-4-cores
    steps:
      - uses: actions/checkout@v3
      - run: npm ci
      - run: npm run build

Monitoring Runner Performance

name: Build with Performance Metrics

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest-8-cores
    steps:
      - uses: actions/checkout@v3

      - name: Start timing
        id: timing
        run: echo "start=$(date +%s)" >> $GITHUB_OUTPUT

      - name: System info
        run: |
          echo "CPU Info:"
          nproc
          lscpu | grep "Model name"
          echo "Memory Info:"
          free -h
          echo "Disk Info:"
          df -h

      - name: Build
        run: npm ci && npm run build

      - name: Report timing
        run: |
          end=$(date +%s)
          duration=$((end - ${{ steps.timing.outputs.start }}))
          echo "Build duration: ${duration} seconds"
          echo "### Build Performance" >> $GITHUB_STEP_SUMMARY
          echo "- Duration: ${duration}s" >> $GITHUB_STEP_SUMMARY
          echo "- Runner: ubuntu-latest-8-cores" >> $GITHUB_STEP_SUMMARY

Best Practices

  1. Profile first - Measure before choosing runner size
  2. Use caching - Reduce repeated work regardless of runner
  3. Parallelize effectively - Ensure code can use multiple cores
  4. Right-size for task - Match runner to workload
  5. Monitor costs - Track usage and optimize

Larger runners can dramatically reduce build times when used effectively with parallelizable workloads.\n\n## Takeaways\n\nAdd a concise, personal takeaway and recommended next steps here.\n

Michael John Peña

Michael John Peña

Senior Data Engineer based in Sydney. Writing about data, cloud, and technology.