fyrer Build Caching: Skip Tasks with Unchanged Inputs
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:
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:
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:
- The fully-qualified task ID (
package:task) - The task's
cmdstring - The task's working directory
- The fully resolved environment (all env layers merged in precedence order)
- The contents of every file matched by the task's
inputsglobs
Outputs are archived as tar.zst under .fyrer/cache/<key>/ relative to the workspace root and restored on a hit. An additional output digest (blake3 of outputs) decides whether hydration is needed — unchanged outputs are left in place.
The cache key does not include transitive dependency keys. If app:build depends on shared:build and shared changes, app:build will not be invalidated unless its own inputs also cover the change. Add the shared outputs or a version file to inputs if you need cross-package invalidation, or rely on watch restarts during development.
Cache storage
Outputs are archived under .fyrer/cache/ in the monorepo root. On a cache hit:
- fyrer restores the archived outputs to their declared locations.
- The task is skipped and reported as
⚡ Cached. - 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:
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— Watched tasks restart on input changes and have no single deterministic "done" state to cache.- Tasks without
inputs— If noinputsare 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 declareinputsfor tasks that read source files.