Pipeline CI Next.js harus menyajikan feedback cepat tanpa menyalahi validasi esensial. Dengan lint incremental berbasis cache ESLint, turbo run untuk pengujian terfokus, dan cache pnpm workspace, Anda bisa meminimalkan waktu run-job dan memaksimalkan determinisme build.

Artikel ini menguraikan susunan job GitHub Actions, konfigurasi cache per job, cara mendeteksi perubahan yang relevan, serta strategi fail fast sebelum deployment agar pipeline siap dipakai sehari-hari.

Pipeline CI Next.js dengan lint incremental, turbo testing, dan cache

Untuk pipeline yang efisien, pisahkan job menjadi tahapan: persiapan (checkout + pnpm install), lint incremental, turbo testing, lalu deployment. Tahapan lint bertugas memblokir PR yang tidak memenuhi aturan kode, sebelum job test dijalankan, dan deployment hanya berlanjut jika lint dan test sukses. Cache ESLint, turbo cache, dan paket pnpm menjaga setiap job tidak harus mengunduh ulang seluruh dependensi.

  • Lint incremental: jalankan pnpm lint dengan --cache agar hanya file yang berubah dianalisis.
  • Turbo testing: gunakan turbo run test --since origin/main untuk menjalankan uji yang dipengaruhi oleh perubahan terbaru.
  • Deployment: job ini needs lint dan test agar pipeline selalu fail fast bila ada masalah awal.

Desain job GitHub Actions dan cache per langkah

GitHub Actions tetap menjadi pilihan umum. Pertimbangkan struktur berikut:

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
      - name: Restore pnpm store
        uses: actions/cache@v4
        with:
          path: ~/.pnpm-store
          key: pnpm-store-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      - name: Restore ESLint cache
        uses: actions/cache@v4
        with:
          path: .cache/eslint
          key: eslint-cache-${{ hashFiles('**/tsconfig*.json', '**/.eslintrc*') }}
      - name: Lint incremental
        run: pnpm lint -- --cache --cache-location .cache/eslint
  test:
    runs-on: ubuntu-latest
    needs: lint
    steps:
      - name: Checkout + pnpm
        uses: actions/checkout@v4
      - name: Setup pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
      - name: Restore pnpm store
        uses: actions/cache@v4
        with:
          path: ~/.pnpm-store
          key: pnpm-store-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
      - name: Restore turbo cache
        uses: actions/cache@v4
        with:
          path: .turbo
          key: turbo-cache-${{ runner.os }}-${{ hashFiles('**/turbo.json', '**/pnpm-lock.yaml') }}
      - name: Install dependencies
        run: pnpm install --frozen-lockfile
      - name: Run Turbo tests
        run: pnpm turbo run test --since origin/main
  deploy:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      

Cache pnpm store dipisahkan karena lint dan test bisa berbagi dependensi yang sama. Cache ESLint fokus pada hasil lint per file agar lint incremental tidak menganalisis ulang file besar. Cache turbo menyimpan artefak build untuk mempercepat next run turbo.

Lint incremental: deteksi perubahan dan cache

Lint dapat disesuaikan untuk hanya memproses file yang berubah dengan mengombinasikan Turbo dan ESLint cache. Turbo menyediakan --since origin/main yang membatasi paket/aps yang mengalami perubahan.

pnpm turbo run lint --since origin/main

Perintah ini berguna di job lint agar hanya paket yang terkena dampak perubahan dijalankan. Untuk mempercepat lagi, tambahkan flag ESLint --cache --cache-location .cache/eslint, dan simpan cache tersebut di GitHub Actions. Karena cache ESLint tergantung konfigurasi dan file TypeScript, gunakan hashFiles('**/tsconfig*.json', '**/.eslintrc*') sebagai key agar cache beregenerasi saat aturan berubah.

Debugging tip: jika lint terasa lambat, periksa apakah cache hit dengan melihat output langkah actions/cache. Bila cache tidak ditemukan, pastikan key dan paths selaras dengan struktur workspace.

Turbo testing: fail fast dan cache artefak

Job testing harus mengikuti lint agar pipeline fail fast. Turbo cache memperpendek waktu uji dengan menyimpan artefak build dan hasil test sebelumnya. Gunakan konfigurasi turbo.json berikut:

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "lint": {
      "outputs": []
    },
    "test": {
      "dependsOn": ["lint"],
      "outputs": ["dist/**"]
    }
  }
}

Pengaturan ini memaksa Turbo menyelesaikan lint sebelum test dan menyimpan dist agar uji berjalan cepat saat artefak masih relevan. Jika hanya sebagian paket berubah, Turbo menjalankan test untuk paket-paket tersebut saja. Fail fast terjadi karena job test tidak dimulai jika lint gagal, dan job deploy perlu needs: [lint, test].

Mengunci cache pnpm workspace

Proyek Next.js besar biasanya menggunakan pnpm workspace. Pastikan pnpm-lock.yaml dimasukkan ke dalam cache key dan proses install selalu menggunakan pnpm install --frozen-lockfile. Dalam pnpm-workspace.yaml, definisikan paket agar Turbo tahu struktur workspace.

packages:
  - apps/*
  - packages/*

Cache pnpm-store membatasi biaya instalasi. Cache ini dipulihkan pada job lint dan test agar node_modules tidak dibangun dari nol setiap job. Jika key cache terlalu sering berubah, pastikan hashFiles('**/pnpm-lock.yaml') hanya berubah ketika dependensi memang berubah.

Transparansi: cache yang terlalu sering invalid berarti Anda kehilangan manfaatnya, tetapi cache yang terlalu stabil bisa menyebabkan bug karena dependensi yang tidak sinkron. Pastikan pipeline menampilkan versi lockfile di log agar mudah memeriksa kapan cache diperbarui.

Checklist verifikasi pipeline sebelum deployment

  • Lint incremental benar-benar hanya meninjau file yang berubah, dipastikan dengan pnpm turbo run lint --since origin/main.
  • Cache ESLint, Turbo, dan pnpm store berhasil dipulihkan (periksa log actions/cache).
  • Job test tidak berjalan bila lint gagal (perhatikan needs: lint).
  • Turbo cache menyimpan output yang diperlukan (dist/** atau folder build lain dijelaskan di turbo.json).
  • Deploy hanya terjadi bila lint dan test sukses (needs: [lint, test]), memastikan strategi fail fast.
  • Pipeline dapat mendeteksi perubahan cukup untuk skip lint/test saat tidak ada file Next.js yang terpengaruh.
  • Adaptasi cache key saat struktur monorepo berubah agar tidak terjadi cache pollution.

Dengan desain ini, Pipeline CI Next.js menawarkan validasi cepat, lint incremental, turbo testing, dan cache yang tepat sasaran sebelum Anda memulai deployment.