
pnpm Now Speaks Turborepo's Remote Cache API
Quick answer: pnpm 12.12.0 can share task results and dependency build output between machines through any server that implements Turborepo's Remote Cache API, Vercel's included. The wire protocol is borrowed; the trust model is not. pnpm signs artifacts with a P-256 key pair and treats anything it cannot verify as a cache miss, where Turborepo's signing is opt-in and uses a symmetric secret. If you adopt this, the keys are the work — not the URL.
The headline reads like a convenience feature: point pnpm at a cache server and stop rebuilding what CI already built. The interesting part is underneath. pnpm implemented a client for someone else’s cache protocol and then refused that protocol’s security model, and the result is a cache where a stolen read credential buys reads, not the ability to poison anyone else’s build.
What actually shipped on 10 October
pnpm 12.12.0 introduces a single remoteCache setting that now feeds two separate features: the pnpm pipeline task cache and sideEffectsCache.remote, which shares the output of dependency install scripts. Set remoteCache.url and pnpm talks to a Turborepo Remote Cache API server. Leave it unset and pnpm talks to a pnpr server named by pnprServer instead.
The work landed in pnpm/pnpm#16812, titled "feat: share build output between machines through pnpr or a Turborepo remote cache", opened by zkochan on 9 October and merged the next day across 13 commits. The same PR also refuses two settings it removed, artifacts.compilerCaches and pipeline.workspaces, rather than ignoring them. pnpm is not gatecrashing: Turborepo’s own docs state that "A Remote Cache can be implemented by any HTTP server that meets Turborepo’s Remote Caching API specification", publish the spec in OpenAPI form, and list three community implementations.
Temper your enthusiasm on maturity. pnpm’s docs say plainly that "pnpm pipeline is experimental. Its configuration and output may change", pnpr is labelled experimental, and sideEffectsCache.remote is described as a proof of concept. It arrives four days after the experimental loaded node linker shipped in 12.10, which tells you something about the current release cadence.
The trust model is the whole story
A remote build cache is a machine that hands your CI runners files it claims were produced by a trusted build. Get the authentication wrong and you have built a supply chain attack with a CDN in front of it. Turborepo and pnpm answer that risk very differently.
Turborepo's artifact signing is opt-in: you set signature: true under remoteCache in turbo.json and supply a key through TURBO_REMOTE_CACHE_SIGNATURE_KEY. The docs state the mechanism exactly: "Turborepo uses HMAC-SHA256 signatures on artifacts using a secret key you provide", and "Any artifacts that fail to verify will be ignored and treated as a cache miss by Turborepo."
HMAC is symmetric: the key that verifies an artifact is the key that signs it, so every machine allowed to consume the cache can also manufacture entries every other machine accepts. Where dozens of CI jobs share one environment variable, that is not a theoretical distinction.
pnpm went asymmetric. Task results are signed P-256 envelopes verified against trustedKeys, described in the settings reference as "The public keys an artifact must be signed by, keyed by key id" — each value a base64 P-256 SubjectPublicKeyInfo DER public key, the kind of blob you will want a base64 decoder for when a key id stops matching. Publishing requires privateKey, keyId and builderId. Consumers hold public keys only, so a leaked consumer configuration buys an attacker reads, not writes.
| Behaviour | Turborepo | pnpm 12.12 |
|---|---|---|
| Signing | Opt-in (signature: true) | Required to publish or restore |
| Algorithm | HMAC-SHA256, shared secret | P-256 envelopes, public/private key pair |
| Where the key lives | Environment variable | Global config or environment only |
| Repo-committed config | turbo.json enables signing | Trust fields refused in the workspace file |
| Verification failure | Treated as a cache miss | Treated as a miss, variant quarantined per server |
Why none of this can live in your repository
Every field in remoteCache except org is machine-only. Put one of them in pnpm-workspace.yaml and you get ERR_PNPM_WORKSPACE_REMOTE_CACHE_TRUST rather than a silently weaker setup; the dependency-build equivalent raises ERR_PNPM_WORKSPACE_REMOTE_SIDE_EFFECTS_TRUST. The reasoning is in one sentence of the docs, and it is the best line in the release: "A cloned repository is not a trust root."
The token is machine-only for a narrower reason: it is not URL-scoped, so a committed token would travel to whatever server the config later names. Both transports also refuse to send credentials to a server that is neither HTTPS nor a loopback address. If you are auditing what your workspace file currently declares, a YAML to JSON converter makes the diff easier to read than scrolling the raw file.
One friction point is already filed: pnpm does not read the token turbo login stores, and the docs tell you to use pnpm config set instead of _auth. Issue 122 in pnpm/tasks asks for that to change; until it does, a team migrating from turbo keeps two credential stores alive. Registry credentials have moved the same way — see npm’s trusted publishing configs, where the hard part is lifecycle rather than cryptography.
A task is only cacheable if you declare what it produces
This trips people up on day one. A pipeline task becomes cacheable only when it declares outputs. A task with no outputs key always runs. For a linter or a type check that writes nothing, you set outputs: [] — an empty list is an assertion, not an omission.
From there, inputs narrows the cache key, env adds environment variable values to it (hashed, not stored), and cache: false opts a task out. The key also covers the script, the keys of dependency tasks, the lockfile and the runtime. On a hit pnpm restores the outputs and replays the recorded log, which is why a cached lint pass still prints its warnings.
Your terminal logs are part of the artifact
Both projects warn about this and both warnings get skipped. pnpm’s version: published results include output files and terminal logs, so "publish only from machines whose logs every reader may see." Turborepo treats logs as artifacts and tells you to check what you print to the console. Any step that echoes a token or a verbose environment dump now writes that string into an entry every teammate and every runner restores — audit the noisy steps before you enable publishing.
What pnpm says it has not verified
Credit where it is due: the PR is unusually candid about its own test coverage. Compatibility was checked against the real Vercel Remote Cache with a small task result — published, restored on an empty cache, and refused under a foreign key. Two things were explicitly not verified: whether Vercel's terms permit non-Turborepo clients, and what Vercel's per-upload size limit actually is. A review summary on the PR adds the caveat that API compatibility does not make pnpm's artifacts interchangeable with native Turborepo ones.
The documented limits are worth writing down before your first large test build: dependency builds allow 64 MiB per file and per artifact; task results allow 4 GiB per file and 16 GiB total; the file cap is 10,000; the signed manifest is capped at 2 MiB. Publish from the machine with the oldest OS you support, too: a build is restored only on systems meeting its minimum OS or glibc version.
Failure modes are deliberately boring: missing, untrusted or unverifiable results count as misses, an unreachable server does not fail the run, Cargo build state stays local, and a bad remote variant is quarantined for that server. That is the right shape for a cache — never the reason a build breaks.
Should you turn it on
If you already pay for a Turborepo-compatible cache and your monorepo is on pnpm, the read-only half is close to free: configure url, team, token and trustedKeys on consumers, leave publish off everywhere except one hardened CI machine, and measure. What you should not do is treat pnpm pipeline as a drop-in task runner yet; its watch mode is described in pnpm’s own docs as "a proof of concept, not a hosted CI service".
The real cost is key management: one P-256 key pair, one publishing identity, and trustedKeys distributed to every consumer's global config. That is a rotation story you need an owner for. If you are weighing this against Nx, Turborepo or Bazel-shaped alternatives, our notes on how to compare developer tools apply, and the cloud and DevOps category on TechLogHub tracks the surrounding CI tooling.
FAQ
Can pnpm restore a cache entry that Turborepo wrote?
Do not plan on it. pnpm implements the Turborepo Remote Cache API as transport, but a review note on the merging PR states that API compatibility does not imply interchangeability with native Turborepo task artifacts. pnpm also requires a verified P-256 signature before it will restore anything, and Turborepo signing is opt-in HMAC. Treat the two caches as separate namespaces that happen to share a server.
Do I need pnpm pipeline to use remote caching?
No. remoteCache drives two consumers. sideEffectsCache.remote shares dependency build output on a normal pnpm install, with the caveat that a package must also pass allowBuilds, declare requiresBuild: true and have verified source integrity. The pipeline task cache is the other, and it is the more experimental of the two.
Where do the signing keys have to live?
Global config or environment variables, never the workspace file. PNPM_REMOTE_CACHE_TRUSTED_KEYS takes a JSON object for CI. pnpm raises a dedicated error if trust fields appear in pnpm-workspace.yaml, on the principle that a cloned repository is not a trust root.
What happens when the cache server is down?
The run continues. An unreachable server does not fail the pipeline, and signature or integrity failures are counted as cache misses rather than errors, so the task simply executes. Restored artifacts are also re-checked against the machine's current keys before reuse, which means rotating a key invalidates previously restored entries instead of trusting them retroactively.
Is it safe to point pnpm at Vercel's Remote Cache in production?
Technically it works and was tested against the live service. Commercially, pnpm's own PR says it did not verify whether Vercel's terms allow non-Turborepo clients, so that is a question for your account, not for a changelog. Self-hosting one of the open-source Remote Cache implementations, or pnpm's own pnpr server, avoids the question entirely.
Borrowing a competitor's wire protocol and refusing its threat model is a good trade. Just budget for the key rotation nobody mentions in the release notes.

