---
title: Caching
description: Caching allows Turborepo to skip work that's already been done, for the fastest builds.
---

import { Callout } from "../../../../components/Callout";

# Caching Tasks

Every JavaScript or TypeScript codebase will need to run `package.json` scripts, like `build`, `test` and `lint`. In Turborepo, we call these **tasks**.

Turborepo can cache the results and logs of your tasks - leading to enormous speedups for slow tasks.

## Missing the cache

Each task in your codebase has **inputs** and **outputs**.

- A `build` task might have source files as inputs and outputs logs to `stderr` and `stdout` as well as bundled files.
- A `lint` or `test` task might have source files as inputs and outputs logs to `stdout` and `stderr`.

Let's say you run a `build` task with Turborepo using `turbo run build`:

![](/images/docs/cache-miss.png)

1. Turborepo will **evaluate the inputs to your task** and **turn them into a hash** (e.g. `78awdk123`).

2. **Check the local filesystem cache** for a matching cache artifact (e.g.`./node_modules/.cache/turbo/78awdk123.tar.zst`).

3. If Turborepo doesn't find any matching artifacts for the calculated hash, Turborepo will then **execute the task**.

4. Once the task is succesfully completed, Turborepo **saves all specified outputs** (including files and logs) into a new cache artifact, addressed by the hash.

<Callout type="info">
  Turborepo takes a lot of information into account when creating the hash: the dependency graph, tasks it depends on, source files, environment variables, and more!
</Callout>

## Hitting the cache

Let's say that you run the task again without changing any of its inputs:

![](/images/docs/cache-hit.png)

1. The **hash will be the same** because **the inputs haven't changed** (e.g. `78awdk123`)

2. Turborepo will find the cache artifact with a matching hash (e.g. `./node_modules/.cache/turbo/78awdk123.tar.zst`)

3. **Instead of running the task**, Turborepo will **replay the output** - printing the saved logs to `stdout` and restoring the saved output files to their respective position in the filesystem.

Restoring files and logs from the cache happens near-instantaneously. This can reduce your build times from minutes or hours down to seconds or milliseconds. Although specific results will vary depending on the shape and granularity of your codebase's dependency graph, most teams find that they can reduce their overall monthly build time by around 40-85% with Turborepo's caching.

## Turn off caching

In some environments you don't want to write the cache output. To disable cache writes, append `--no-cache` to any command. For example, this will run `dev` (and all tasks that it `dependsOn`) in all workspaces, but it won't cache the output:

```shell
turbo run dev --no-cache
```

Note that `--no-cache` disables cache writes but does not disable cache reads. If you want to disable cache reads, use the `--force` flag.

You can also configure specific tasks to skip writing to the cache by setting the [`pipeline.<task>.cache`](/repo/docs/reference/configuration#cache) configuration to `false`:

```json
{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
```

## Force overwrite cache

Conversely, if you want to disable reading the cache and force `turbo` to re-execute a previously cached task, add the `--force` flag:

```shell
# Run `build` npm script in all workspaces ignoring the cache.
turbo run build --force
```

Note that `--force` disables cache reads but does not disable cache writes. If you want to disable cache writes, use the `--no-cache` flag.

## Handling Node.js versions

To account for Node.js versions, use [the `engines` key in package.json](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines). Turborepo will see the changes to your `package.json` and miss cache when the field is updated.

## Handling platforms and other arbitrary hash contributors

For advanced use cases, you may want the operating system (OS), architecture, or other external factors to contribute to your hash. You can do this in four quick steps.

### 1. Write an arbitrary file to disk

First, create a script that accounts for the hash contributors that you are interested in. For example, here is a Node.js script that looks at platform and architecture and writes those details to a file (`turbo-cache-key.json`):

```js
#!/usr/bin/env node

const { writeFileSync } = require('fs');
const { join } = require('path');

const { platform, arch } = process;
const file = "turbo-cache-key.json";
const str = JSON.stringify({ platform, arch });
console.log(`Generating cache key: ${str}`);
writeFileSync(file, str);
```

### 2. Add the file to your .gitignore

You won't want to commit this file to source control since it's dependent on environment. Add it to your `.gitignore`:

```txt
// .gitignore

+ turbo-cache-key.json
```

### 3. Add the file to the hash

Now, make sure that `turbo` is aware of the file by adding it to task inputs. You can do this two ways:

- **For specific tasks**: Include the file in [the `inputs` array](/repo/docs/reference/configuration#inputs) of the task(s):

```json
{
  "$schema": "https://turbo.build/schema.json",
  "pipelines": {
    "build-for-platforms": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", "turbo-cache-key.json"]
    }
  }
}
```

- **For all tasks**: Add the file to [`globalDependencies`](/repo/docs/reference/configuration#globaldependencies)

```json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["turbo-cache-key.json"],
  "pipelines": {
    ...
  }
}
```

### 4. Generate the file before running `turbo`

Last, you'll want to ensure that you run the script before running `turbo`. For example:

```json
{
  "scripts": {
    "build-for-platforms": "node ./scripts/create-turbo-cache-key.js && turbo run build"
  }
}
```

`turbo run build` will now take into account the contents of `turbo-cache-key.json` when calculating the hash for the `build` task.

## Logs

Not only does `turbo` cache the output of your tasks, it also records the terminal output (i.e. combined `stdout` and `stderr`) to (`<package>/.turbo/run-<command>.log`). When `turbo` encounters a cached task, it will replay the output as if it happened again, but instantly, with the package name slightly dimmed.

## Hashing

By now, you're probably wondering how `turbo` decides what constitutes a cache hit vs. miss for a given task. Good question!

First, `turbo` constructs a hash of the current global state of the codebase. This includes things like:

- Hash of the contents of any files that satisfy the glob patterns in [`globalDependencies`](/repo/docs/reference/configuration#globaldependencies)
- The values of environment variables listed in [`globalEnv`](/repo/docs/reference/configuration#globalenv)
- Select information from `turbo.json`, `package.json`, and any lockfile
- and more!

Then it adds more factors relevant to a given workspace's task:

- Hash of the contents of all version-controlled files in the workspace folder (or the files matching the `inputs` globs, if configured)
- The configured `outputs` specified in the [`pipeline`](/repo/docs/reference/configuration#pipeline)
- The set of resolved versions of all installed `dependencies`, `devDependencies`, and `optionalDependencies`
- The workspace task's name
- The sorted list of environment variable key-value pairs specified in [`pipeline.<task>.env`](/repo/docs/reference/configuration#env) list.
- and more!

Once `turbo` encounters a given workspace's task in its execution, it checks the cache (both locally and remotely) for a matching hash. If it's a match, it skips executing that task, moves or downloads the cached output into place, and replays the previously recorded logs instantly. If there isn't anything in the cache (either locally or remotely) that matches the calculated hash, `turbo` will execute the task locally and then cache the specified `outputs`.

The hash of a given task is available to the task at execution time as an environment variable `TURBO_HASH`. This value can be useful in stamping outputs or tagging Dockerfile etc.
