Skip to content
Latchkey

CI workflow (vitejs/vite)

The CI workflow from vitejs/vite, explained and optimized by Latchkey.

A

CI health: A - excellent

Point runs-on at Latchkey and get job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: vitejs/vite.github/workflows/ci.ymlLicense MITView source

What it does

This is the CI workflow from the vitejs/vite repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: CI

env:
  # 7 GiB by default on GitHub, setting to 6 GiB
  # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
  NODE_OPTIONS: --max-old-space-size=6144
  # install playwright binary manually (because pnpm only runs install script once)
  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
  # Vitest auto retry on flaky segfault
  VITEST_SEGFAULT_RETRY: 3

# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}

on:
  push:
    branches:
      - main
      - release/*
      - feat/*
      - fix/*
      - perf/*
      - "v[0-9]+" # v1, v2, ...
      - "v[0-9]+.[0-9]+" # v4.0, v4.1, ...
  pull_request:
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
  cancel-in-progress: true

jobs:
  changed:
    name: Get changed files
    runs-on: ubuntu-slim
    outputs:
      should_skip: ${{ steps.changed-files.outputs.only_changed == 'true' }}

    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          # Assume PRs are less than 50 commits
          fetch-depth: 50
          persist-credentials: false

      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
        with:
          files: |
            docs/**
            .github/**
            !.github/workflows/ci.yml
            packages/create-vite/template**
            **.md

  test:
    needs: changed
    if: needs.changed.outputs.should_skip != 'true'
    timeout-minutes: 20
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        node_version: [20, 22, 24, 26]
        include:
          # Active LTS + other OS
          - os: macos-latest
            node_version: 24
          - os: windows-latest
            # use older minor to workaround https://github.com/nodejs/node/issues/63638
            node_version: 24.15.0
      fail-fast: false

    name: "Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}"
    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          persist-credentials: false

      - name: Install pnpm
        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

      - name: Set node version to ${{ matrix.node_version }}
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: ${{ matrix.node_version }}
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      # Install playwright's binary under custom directory to cache
      - name: (non-windows) Set Playwright path and Get playwright version
        if: runner.os != 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV
          PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
      - name: (windows) Set Playwright path and Get playwright version
        if: runner.os == 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV
          $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV

      - name: Cache Playwright's binary
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
        with:
          key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }}
          path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
          restore-keys: |
            ${{ runner.os }}-playwright-bin-v1-

      - name: Install Playwright
        # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved
        run: pnpm playwright install chromium

      - name: Build
        run: pnpm run build

      - name: Test unit
        run: pnpm run test-unit

      - name: Test serve
        run: pnpm run test-serve

      - name: Test build
        run: pnpm run test-build

  test-passed:
    if: (!cancelled() && !failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Passed or Skipped
    steps:
      - run: echo "Build & Test Passed or Skipped"

  test-failed:
    if: (!cancelled() && failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Failed
    steps:
      - run: echo "Build & Test Failed"

  lint:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    name: "Lint: node-24, ubuntu-latest"
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          persist-credentials: false

      - name: Install pnpm
        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

      - name: Set node version to 24
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: 24
          cache: "pnpm"

      - name: Install deps
        run: pnpm install

      - name: Build
        run: pnpm run build

      - name: Lint
        run: pnpm run lint

      - name: Check formatting
        run: pnpm format && git diff --exit-code

      - name: Typecheck
        run: pnpm run typecheck

      - name: Test docs
        run: pnpm run test-docs

      # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
      - name: Check workflow files
        run: |
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
          ./actionlint -color -shellcheck=""

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: CI
 
env:
  # 7 GiB by default on GitHub, setting to 6 GiB
  # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
  NODE_OPTIONS: --max-old-space-size=6144
  # install playwright binary manually (because pnpm only runs install script once)
  PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
  # Vitest auto retry on flaky segfault
  VITEST_SEGFAULT_RETRY: 3
 
# Remove default permissions of GITHUB_TOKEN for security
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions: {}
 
on:
  push:
    branches:
      - main
      - release/*
      - feat/*
      - fix/*
      - perf/*
      - "v[0-9]+" # v1, v2, ...
      - "v[0-9]+.[0-9]+" # v4.0, v4.1, ...
  pull_request:
  workflow_dispatch:
 
concurrency:
  group: ${{ github.workflow }}-${{ github.event.number || github.sha }}
  cancel-in-progress: true
 
jobs:
  changed:
    timeout-minutes: 30
    name: Get changed files
    runs-on: ubuntu-slim
    outputs:
      should_skip: ${{ steps.changed-files.outputs.only_changed == 'true' }}
 
    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          # Assume PRs are less than 50 commits
          fetch-depth: 50
          persist-credentials: false
 
      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
        with:
          files: |
            docs/**
            .github/**
            !.github/workflows/ci.yml
            packages/create-vite/template**
            **.md
 
  test:
    needs: changed
    if: needs.changed.outputs.should_skip != 'true'
    timeout-minutes: 20
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest]
        node_version: [20, 22, 24, 26]
        include:
          # Active LTS + other OS
          - os: macos-latest
            node_version: 24
          - os: windows-latest
            # use older minor to workaround https://github.com/nodejs/node/issues/63638
            node_version: 24.15.0
      fail-fast: false
 
    name: "Build&Test: node-${{ matrix.node_version }}, ${{ matrix.os }}"
    steps:
      - name: Checkout
        uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          persist-credentials: false
 
      - name: Install pnpm
        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
 
      - name: Set node version to ${{ matrix.node_version }}
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: ${{ matrix.node_version }}
          cache: "pnpm"
 
      - name: Install deps
        run: pnpm install
 
      # Install playwright's binary under custom directory to cache
      - name: (non-windows) Set Playwright path and Get playwright version
        if: runner.os != 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV
          PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV
      - name: (windows) Set Playwright path and Get playwright version
        if: runner.os == 'Windows'
        run: |
          echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV
          $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')"
          echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV
 
      - name: Cache Playwright's binary
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
        with:
          key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }}
          path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }}
          restore-keys: |
            ${{ runner.os }}-playwright-bin-v1-
 
      - name: Install Playwright
        # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved
        run: pnpm playwright install chromium
 
      - name: Build
        run: pnpm run build
 
      - name: Test unit
        run: pnpm run test-unit
 
      - name: Test serve
        run: pnpm run test-serve
 
      - name: Test build
        run: pnpm run test-build
 
  test-passed:
    timeout-minutes: 30
    if: (!cancelled() && !failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Passed or Skipped
    steps:
      - run: echo "Build & Test Passed or Skipped"
 
  test-failed:
    timeout-minutes: 30
    if: (!cancelled() && failure())
    needs: test
    runs-on: ubuntu-slim
    name: Build & Test Failed
    steps:
      - run: echo "Build & Test Failed"
 
  lint:
    timeout-minutes: 10
    runs-on: latchkey-small
    name: "Lint: node-24, ubuntu-latest"
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
        with:
          persist-credentials: false
 
      - name: Install pnpm
        uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
 
      - name: Set node version to 24
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
        with:
          node-version: 24
          cache: "pnpm"
 
      - name: Install deps
        run: pnpm install
 
      - name: Build
        run: pnpm run build
 
      - name: Lint
        run: pnpm run lint
 
      - name: Check formatting
        run: pnpm format && git diff --exit-code
 
      - name: Typecheck
        run: pnpm run typecheck
 
      - name: Test docs
        run: pnpm run test-docs
 
      # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions
      - name: Check workflow files
        run: |
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
          ./actionlint -color -shellcheck=""
 

What changed

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 5 jobs (8 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow