Skip to content
Source

Start jobs warm

Each job of your workflow sets up Node, restores a cache and runs pnpm install before it tests anything. In a large repository, that takes minutes in every job. Your lockfile changes only a few times a week.

A warm start skips that work. After a job installs its dependencies, it packs its checkout and its home folder as one image, and saves the image in the cache. The next job with the same lockfile mounts that image before its checkout, so node_modules is there at once. Its setup and install steps do not run.

1. Add warm to the job

Put the steps that prepare the job first, and name the last one in through. In files, name the files that those steps depend on:

import { defineWorkflow, pullRequest, push, setup } from '@tanstack-source/ci'

export default defineWorkflow('ci', { on: [pullRequest({ branches: ['main'] }), push({ branches: ['main'] })] })
  .job('test', {
    warm: { files: ['pnpm-lock.yaml', 'package.json', '.nvmrc'], through: 'Install dependencies' },
    steps: [
      setup.node(),
      setup.pnpm(),
      { name: 'Install dependencies', run: 'pnpm install --frozen-lockfile' },
      { name: 'Test', run: 'pnpm test' },
    ],
  })

Put each step that must run in every job after through, like the tests and the build. The image holds only the checkout and the home folder (~). A step that installs into other folders, like apt-get install, goes after through too.

2. Push the workflow

Push it to main. The first run has no image yet, so each job runs every step. The first line of its log says so:

No warm start for these files yet: this job installs, and saves one for the next jobs.

When Install dependencies passes, the job packs the image. At the end of the job, one more step, Save the warm start, saves it in the cache.

3. Push a change

Push a change that does not touch the files in files. The jobs of the new run mount the image:

  • The steps up to and including Install dependencies have (warm start) after their name, and they take 0 s.
  • The log of each of these steps names the commit of the job that packed the image.
  • The checkout is at the commit of the new run. node_modules and the other ignored folders are there from the image.
  • The folders that the skipped steps put on the PATH, like the Node of setup.node(), are on the PATH again.

The jobs go from the checkout straight to Test.

When a job runs every step

A job runs every step, and starts with a note in its log, in these cases:

  • A file of files changed: the key of the image is new. The job saves an image for the new key.
  • The image did not mount: the note says why. The job installs as usual.
  • The cache evicted the image: the cache of the repository was full. The job saves a new one.

A warm start never makes a job fail.

Who mounts which image

An image is a cache entry, so it follows the cache scopes. A pull request from a fork saves its image in the scope of its pull request, and no trusted run mounts it. A hidden workflow takes no warm start and makes none.

To see the images, run src ci cache list: their keys start with warm-. To delete them, run src ci cache delete, or use Settings > CI > Cache. The CI reference has every rule.