> ## Documentation Index
> Fetch the complete documentation index at: https://fyrer.vinm.me/llms.txt
> Use this file to discover all available pages before exploring further.

# fyrer Build Caching: Skip Tasks with Unchanged Inputs

> Learn how fyrer's content-addressed local cache skips tasks whose inputs haven't changed, and how to enable and configure it with inputs and outputs.

fyrer can skip tasks whose inputs haven't changed since the last successful run. Cached tasks report `⚡ Cached` and have their declared outputs restored instantly — no recompilation, no rebundling.

## Enabling the cache

To enable caching for a task, set `cache: true` and declare its `inputs`. You also need to enable a cache provider at the top level of `fyrer.yml`:

```yaml theme={null}
version: 1
cache:
  provider: local
```

`local` is the only available provider today. It stores cache artifacts on disk under `.fyrer/cache/` in your monorepo root.

A minimal cached task looks like this:

```yaml theme={null}
tasks:
  build:
    cmd: bun run build
    inputs:
      - src/**
      - package.json
    outputs:
      - dist/**
    cache: true
```

## How the cache key is computed

The cache key is a **blake3** hash of the following inputs, all resolved at run time:

1. The fully-qualified task ID (`package:task`)
2. The task's `cmd` string
3. The task's working directory
4. The fully resolved environment (all env layers merged in precedence order)
5. The contents of every file matched by the task's `inputs` globs
6. The cache keys of every task listed in `depends_on`

Because dependency cache keys are included, a change anywhere upstream automatically invalidates all downstream tasks — even if their own source files haven't changed. You never need to manually bust the cache.

## Cache storage

Outputs are archived under `.fyrer/cache/` in the monorepo root. On a cache hit:

1. fyrer restores the archived outputs to their declared locations.
2. The task is skipped and reported as `⚡ Cached`.
3. No process is spawned for the task.

You should add `.fyrer/` to your `.gitignore` to avoid committing cache artifacts:

```
# .gitignore
.fyrer/
```

## inputs, outputs, and ignore

Three glob-based fields control what the cache considers and what it preserves:

| Field     | Purpose                                                                      |
| --------- | ---------------------------------------------------------------------------- |
| `inputs`  | Files the task reads. A change in any matched file causes a cache miss.      |
| `outputs` | Files the task produces. Archived on a cache write; restored on a cache hit. |
| `ignore`  | Files excluded from both `inputs` and `outputs`.                             |

All glob paths are relative to the package root. Here is a full example:

```yaml theme={null}
build:
  cmd: bun build src/index.ts --outdir dist
  inputs:
    - src/**
    - package.json
  outputs:
    - dist/**
  ignore:
    - node_modules/**
  cache: true
```

## Restrictions

A few combinations are not allowed and will be rejected at startup:

* **`cache: true` + `persistent: true`** — Dev servers run indefinitely and never produce a stable final output, so they cannot be cached.
* **`cache: true` + `watch: true`** — The `watch` flag is reserved for a future release; combining it with `cache: true` is rejected at startup regardless, because a watch-mode task would not have a single deterministic "done" state to cache.
* **Tasks without `inputs`** — If no `inputs` are declared, the cache key is computed from the task config alone (ID, command, environment). Any file change in the package will *not* invalidate the cache. Always declare `inputs` for tasks that read source files.
