.moon/cache, relative from the workspace root (be sure to git ignore this folder).
Overview
The caching system consists of two main components:- Hashing - Determines if a task needs to re-run
- Archiving - Stores and restores task outputs
Caching is automatic and enabled by default for all tasks. You can disable it per-task with
options.cache: false.Hashing
Incremental builds are possible through a concept known as hashing, where in multiple sources are aggregated to generate a unique hash. In the context of moon, each time a target is ran we generate a hash, and if this hash already exists we abort early (cache hit), otherwise we continue the run (cache miss). The tiniest change may trigger a different hash, for example, changing a line of code (when an input), or updating a package version, so don’t worry if you see a lot of hashes.Hash Sources
Our smart hashing currently takes the following sources into account:- Command (
command) being ran and its arguments (args) - Input sources (
inputs) - Output targets (
outputs) - Environment variables (
env) - Dependencies between projects (
dependsOn) and tasks (deps)
- Deno version
deno.json/deps.tsimports, import maps, and scopestsconfig.jsoncompiler options (when applicable)
- Bun/Node.js version
package.jsondependencies (including development and peer)tsconfig.jsoncompiler options (when applicable)
- Rust version
Cargo.tomlandCargo.lockcontents
Hash Generation Example
moon.yml
- Command:
webpack --mode production - All files matching
src/**/*.ts - Contents of
webpack.config.jsandpackage.json - Output directory:
dist - Environment variable:
NODE_ENV=production - Node.js version from toolchain
- Dependencies from
package.json
Cache Hit vs Cache Miss
Cache Hit:Hash Inspection
Inspect hash contents for debugging:Archiving & Hydration
On top of our hashing layer, we have another concept known as archiving, where in we create a tarball archive of a task’s outputs and store it in.moon/cache/outputs. These are akin to build artifacts.
How It Works
- Task Runs - Command executes and produces outputs
- Archiving - Outputs are compressed into
.tar.gz - Storage - Archive stored with hash as filename
- Hydration - On cache hit, archive is unpacked to restore outputs
Hydration Process
When we encounter a cache hit on a hash, we trigger a mechanism known as hydration, where we efficiently unpack an existing tarball archive into a task’s outputs. This can be understood as a timeline, where every point in time will have its own hash + archive that moon can play back.Smart Skipping
Furthermore, if we receive a cache hit on the hash, and the hash is the same as the last run, and outputs exist, we exit early without hydrating and assume the project is already hydrated. In the terminal, you’ll see a message for “cached”.File Structure
The following diagram outlines our cache folder structure and why each piece exists:State Files
Moon stores various state information:Cache Configuration
Per-Task Cache Control
moon.yml
Output Specifications
Be explicit about outputs for optimal caching:moon.yml
If
outputs is not specified, moon won’t create an archive, but will still use hashing to determine if the task should run.Remote Caching
Share cache artifacts across machines and CI environments:.moon/workspace.yml
Benefits of Remote Caching
- Share builds across team members
- Faster CI by reusing local builds
- Consistent artifacts across environments
- Reduced compute costs in CI/CD
Cache Management
Clearing Cache
Cache Debugging
When tasks aren’t caching as expected:Performance Tips
Use explicit inputs
Use explicit inputs
Avoid
**/* inputs when possible. Explicitly list input files and patterns to reduce hash calculation time and prevent unexpected cache invalidation.Define outputs precisely
Define outputs precisely
Only include actual output files/directories. This reduces archive size and speeds up hydration.
Leverage remote caching
Leverage remote caching
Enable remote caching for teams and CI. The initial setup pays off quickly with shared build artifacts.
Monitor cache size
Monitor cache size
Periodically clean old cache entries. Consider adding a cleanup script to CI:
Best Practices
Git ignore the cache directory
Git ignore the cache directory
Always add
.moon/cache/ to .gitignore. Cache should be generated locally or pulled from remote cache..gitignore
Use consistent tool versions
Use consistent tool versions
Ensure all team members and CI use the same tool versions (via
.moon/toolchains.yml) for consistent cache hits.Audit inputs regularly
Audit inputs regularly
Periodically review hash manifests to ensure only relevant files are included as inputs.
Related Concepts
- Tasks - Define inputs and outputs for caching
- Targets - Run cached tasks
- Affected - Smart task execution based on changes