Nx guide

Nx S3 cache: what to do after @nx/s3-cache was deprecated

Putting the Nx remote cache in an S3 bucket used to be a one-plugin job. The first-party plugin that did it is now deprecated over a design flaw that cannot be patched, so the honest answer to "how do I use S3 for the Nx cache?" changed. This page covers what the plugin did, what the vulnerability actually is, when a bucket you own is still the right call, and how to move without touching your task configuration.

What "Nx S3 cache" means today

The phrase covers four different setups, and they have very different security and maintenance stories:

  • @nx/s3-cache - the first-party Nx Powerpack plugin that wrote artifacts straight to a bucket. Deprecated as of 2026-05-21.
  • Community plugins such as nx-remotecache-s3 - the same shared-bucket-credential shape, maintained outside Nx, with the same poisoning exposure.
  • Your own cache server backed by S3 - a service that implements the Nx remote cache OpenAPI specification and happens to store bytes in S3. This is the shape Nx now points self-hosters at, because the server can enforce write rules the bucket cannot.
  • A managed implementation of the same protocol - identical two-variable client config, someone else operates the storage and the access control.

All four speak to Nx through the same place in the pipeline: Nx computes a content hash for a task, and something either returns a stored artifact for that hash or does not. If you want that mechanism explained first, start with the Nx remote cache guide.

The deprecated @nx/s3-cache plugin

@nx/s3-cache was configured with an s3 block in nx.json - a bucket, a region, and credentials, with optional settings for an alternate endpoint, path-style URLs, an encryption key, a cache key prefix, and separate local and CI modes:

{
  "s3": {
    "bucket": "my-nx-cache",
    "region": "us-east-1",
    "localMode": "read",
    "ciMode": "read-write"
  }
}

It was licensed separately from Nx itself (the self-hosted cache license), and it is now deprecated together with @nx/gcs-cache, @nx/azure-cache, and @nx/shared-fs-cache. Nx's notice is blunt about the reason and the plan: the CREEP vulnerability (CVE-2025-36852) affects all four, the flaw is in their design and cannot be patched, and the packages stay on npm so existing builds keep working but will receive no updates or security patches and may be removed.

Read the primary sources rather than this page: Nx's deprecation notice for the self-hosted cache packages and CVE-2025-36852. Checked July 2026.

Why a shared bucket cannot be safe

The attack does not need a compromised package. It needs a bucket credential that can both read and write every key, which is exactly what a bucket-adapter plugin distributes to every build:

  • Open a pull request off the default branch with no source changes, but a modified CI workflow.
  • The workflow file is not part of the Nx task hash, so the pull-request build hashes to the same key the default branch will later hash to, and it can build whatever artifact it likes.
  • It uploads first. Every later trusted build with that key gets a cache hit and ships the planted output without rebuilding.

Nothing in a bucket records which branch produced which artifact, so there is no server-side rule to break the tie. That is why the fix is not a patch: the write decision has to move to something that can refuse it. Two rules close the hole - untrusted builds get read-only credentials, and the server returns 409 Conflict instead of overwriting a key that already exists. Nx's own guidance to anyone building a cache server calls out the 409 requirement explicitly. The longer walkthrough is in the CREEP write-up, and our trust model documents how Cachely enforces both.

MinIO, R2, and other S3-compatible stores

A lot of "Nx S3 cache" searches are not about AWS at all - they are about MinIO, Cloudflare R2, DigitalOcean Spaces, or LocalStack behind the S3 API. The deprecated plugin supported those through an endpoint setting, with forcePathStyle for providers that need it.

Worth being clear about what that changes and what it does not: swapping AWS for an S3-compatible endpoint changes who stores the bytes and what egress costs. It does not change the trust model. A MinIO bucket handed to CI with one read-write credential is poisonable in exactly the same way as an S3 bucket. Object storage is the right place for the bytes - Cachely keeps artifacts in Cloudflare R2 - but the permission decision belongs in front of it.

Your four options, compared

Options for caching Nx task outputs in S3 or S3-compatible storage.
OptionWrite controlYou operateBest fit
Deprecated @nx/s3-cache or a community bucket pluginNone. One credential reads and writes every keyBucket, IAM, lifecycle rules, key rotationNothing new. Migrate off it
Your own server implementing the Nx OpenAPI spec, backed by S3Yours to build: scoped tokens plus 409 on existing keysServer, auth, TLS, storage, monitoring, on-callData residency or on-premises requirements, with a team to run it
Nx CloudManaged by NxNothingTeams that also want distributed task execution and CI agents
CachelyRead-only tokens plus immutable artifacts, enforced at the APINothing. Two environment variablesTeams that want the self-hosted protocol without running the backend

Nx's own recommendation is Nx Cloud, or disabling the remote cache until you have something safe. If distributed task execution or managed CI agents are in your plans, Nx Cloud is the better product and we do not pretend otherwise - the trade-offs are laid out in the Nx Cloud alternative guide.

When keeping S3 yourself is right

Do not read this page as "never self-host". A bucket you control is the correct answer when:

  • Artifacts must stay in a specific account, region, or on-premises environment for contractual or regulatory reasons.
  • You already run a hardened cache server that enforces scoped tokens and rejects overwrites, and S3 is just its storage layer.
  • Your monorepo pushes cache volumes where negotiated storage and egress pricing beats a subscription, and you have staffed the upkeep.

If that is you, keep the bucket and put a compliant server in front of it - not a plugin holding a shared credential. Cachely vs a self-hosted Nx cache lists what that upkeep actually includes.

Migrating off the S3 plugin

The migration is a backend swap, not an Nx migration. Your nx.json targets, inputs, outputs, and namedInputs stay exactly as they are, because the cache key is computed by Nx either way.

1. Remove the plugin and its config

npm uninstall @nx/s3-cache   # or nx-remotecache-s3

Then delete the s3 block from nx.json and remove the AWS access key, secret, region, and bucket variables from CI and from developer environments. Revoke the credential afterwards - a key that is no longer used is still a key that can still write.

2. Point Nx at a protocol-compliant server

NX_SELF_HOSTED_REMOTE_CACHE_SERVER=https://remote.cachely.dev
NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN=<your-token>

That is the official Nx self-hosted remote cache API, available in the CLI since Nx 19.8, so no plugin or custom task runner is involved. Set both variables everywhere builds run, including laptops, so developers reuse what CI produced.

3. Give untrusted builds read-only tokens

Issue a read-only token to pull-request and fork workflows and a read-write token only to protected branches. This is the step that closes CREEP; a read-only build still gets every cache hit, it simply cannot plant one. Verify it by re-running a task and confirming Nx reports it as read from the remote cache.

4. Confirm the cache is actually being used

A migration that silently stops caching looks like a successful migration until the CI bill arrives. Check hit rate after the switch, and if it is lower than expected, work through the hit-rate diagnosis guide before blaming the backend. The CI savings calculator turns that hit rate into minutes and money.

Related guides

Keep the self-hosted protocol, drop the bucket plumbing
Two environment variables, read-only tokens for pull requests, and immutable artifacts enforced at the API.
Start freeSee pricing
FAQ

Nx S3 cache: frequently asked questions

Can I still use S3 as an Nx remote cache?
Yes, but not through @nx/s3-cache, which Nx deprecated on 2026-05-21 over the CREEP cache-poisoning vulnerability (CVE-2025-36852). The supported way to keep artifacts in your own bucket is to run a server that implements the Nx remote cache OpenAPI specification and use S3 as its storage layer, so the server - not the bucket - decides who may write.
What did the @nx/s3-cache configuration look like?
An s3 block in nx.json with bucket and region, plus optional endpoint, forcePathStyle, ssoProfile, accessKeyId, secretAccessKey, encryptionKey, cacheKeyPrefix, disableChecksum, and separate localMode and ciMode read/write settings. Migrating away means deleting that block and the AWS credentials from CI; the Nx targets, inputs, and outputs stay unchanged because Nx computes the cache key either way.
Why is a shared S3 bucket unsafe for a build cache?
Every build gets one credential that can read and write every key, and the bucket records nothing about which branch produced an artifact. A pull request that changes only the CI workflow - which is not part of the Nx task hash - can upload an artifact under a key the default branch will later hash to, and trusted builds then download it. The fix needs a server that gives untrusted builds read-only tokens and returns 409 Conflict rather than overwriting an existing key.
Does using MinIO, Cloudflare R2, or DigitalOcean Spaces instead of AWS help?
It changes storage cost, egress, and data location, not the trust model. The deprecated plugin reached those providers through its endpoint and forcePathStyle settings, and a bucket handed to CI with one read-write credential is poisonable regardless of who hosts it. Object storage is the right place for the bytes - Cachely stores artifacts in Cloudflare R2 - but the write decision belongs in an API in front of it.
Is nx-remotecache-s3 a safe replacement for @nx/s3-cache?
It solves the same problem the same way: a plugin holding a bucket credential with cache-wide read and write access. That is the design CVE-2025-36852 describes, so swapping first-party for community maintenance does not remove the exposure. It is a reasonable stopgap only if every build that holds the credential is trusted.
How do I switch from an S3 bucket to Cachely?
Uninstall the plugin, delete the s3 block from nx.json, and set NX_SELF_HOSTED_REMOTE_CACHE_SERVER=https://remote.cachely.dev with NX_SELF_HOSTED_REMOTE_CACHE_ACCESS_TOKEN everywhere builds run. Give pull-request and fork workflows a read-only token, confirm remote hits on a repeated target, then revoke the old bucket credentials.
When does keeping your own S3 bucket still make sense?
When artifacts must stay in a specific account, region, or on-premises environment for contractual or regulatory reasons, when you already operate a cache server that enforces scoped tokens and rejects overwrites, or when negotiated storage and egress pricing at your volume beats a subscription and you have staffed the upkeep. In those cases keep the bucket and put a compliant server in front of it.