How Turborepo and Nx Cache JavaScript Builds
Monorepo build tools like Turborepo and Nx optimize JavaScript development by ensuring tasks are never executed twice if their inputs have not changed. By treating build scripts as deterministic functions, these tools calculate a unique cryptographic hash for each task, evaluate whether an identical run exists in a local or remote storage system, and instantly restore saved build artifacts and terminal logs instead of executing the actual compiler.
1. Generating the Input Hash (The Cache Key)
Before executing any script (such as build,
lint, or test), the tool creates a fingerprint
representing the exact state of that task. This hash is computed from
several key inputs:
- Source Files: The contents of the package folder and any specific file patterns associated with the task.
- Internal and External Dependencies: Changes to
dependent packages within the workspace or updates to dependencies in
the root lockfile (e.g.,
package-lock.json,pnpm-lock.yaml,yarn.lock). - Environment Variables: Variables explicitly defined
in configuration files (
turbo.jsonornx.json/project.json) that alter compilation behavior (such asNODE_ENVor public API keys). - Task Configuration: The exact command being run, CLI flags, runtime versions, and system architecture parameters.
If any of these factors change, the calculated hash changes, resulting in a cache miss.
2. Output and Log Capture
When a task runs for the first time, a cache miss occurs. The tool executes the command normally while intercepting two primary types of data:
- Artifacts: The files and directories generated by
the process (e.g.,
dist,build, or.nextfolders) as declared in the pipeline configuration. - Terminal Logs: The standard output
(
stdout) and standard error (stderr) streams emitted during execution.
Once the process completes successfully, the tool packages the specified output directories and log files into an archive (typically a compressed tarball) and stores it using the input hash as the key.
3. Cache Retrieval and Replay
On subsequent executions, the tool recalculates the input hash:
- Cache Hit: If the hash matches an existing entry, the tool bypasses process execution entirely. It extracts the stored build artifacts into the expected target directories and replays the original terminal output in milliseconds.
- Cache Miss: If the hash is new, the tool executes the script, captures the new outputs, and writes a new entry to the cache.
4. Local vs. Remote Caching
- Local Cache: Stored directly on the developer’s
machine (for example, in
node_modules/.cache/turboor.nx/cache). This speeds up local branch switching and recurring builds on a single workstation. - Remote Cache: Uploaded to a centralized cloud service (such as Vercel Remote Cache, Nx Cloud, or custom self-hosted storage like AWS S3). Remote caching allows Continuous Integration (CI) systems and all team members to share build outputs. If one developer or a CI runner builds a specific commit, no other machine in the organization needs to rebuild it.
5. Dependency Graph Integration
Turborepo and Nx analyze the project’s dependency graph to ensure
correct cache invalidation across interdependent packages. If
Package A depends on Package B, a modification
to Package B changes Package B’s hash. Because
Package A includes the hash of its dependencies in its own
input calculation, Package A’s cache is invalidated
automatically, ensuring that dependent code is always built against
up-to-date upstream artifacts.