Infrastructure worth keeping — and kept patched.

Migrate from Build Cache Node: setup, checklist, checks

The Develocity Build Cache Node is going away, and your builds still need a remote cache. FosterStack Cache replaces it: run a new server, change one URL, and check that it works, about 30 minutes for Gradle with no data to move.

Before you start

A build cache holds copies of things your builds can always rebuild, so there is nothing to export from the old node. Your first build on the new server just fills it. If you have not read why the node is going away, see Build Cache Node end of life.

Step 1: Run the new cache server

docker run -d -p 127.0.0.1:8080:8080 -v fscache-data:/home/nonroot ghcr.io/fosterstack/cache:latest

For anything beyond a first look, pin a specific version instead of latest. This command listens on this machine only. For other machines to use it, put an HTTPS proxy in front. For a walk-through, see your first 15 minutes. Other ways to run it: bare binary with systemd, Kubernetes, or a disconnected network.

If the server can be reached by anyone you do not trust, turn on Basic Auth. Anyone who can write to the cache can change what your later builds use.

Step 2: Gradle build cache setup

Turn the cache on, in gradle.properties:

org.gradle.caching=true

Then point Gradle at the new server in settings.gradle.kts. If you used the old node, you only change the URL:

// FosterStack Cache — remote Gradle build cache.
// https://github.com/fosterstack/cache
buildCache {
    remote<HttpBuildCache> {
        url = uri("https://cache.example.com/")
        isPush = true
        credentials {
            username = "gradle"
            password = System.getenv("FSCACHE_PASSWORD")
        }
    }
}

Or in settings.gradle (Groovy):

// FosterStack Cache — remote Gradle build cache.
// https://github.com/fosterstack/cache
buildCache {
    remote(HttpBuildCache) {
        url = 'https://cache.example.com/'
        push = true
        credentials {
            username = 'gradle'
            password = System.getenv('FSCACHE_PASSWORD')
        }
    }
}

Keep the comment lines: a cache block that points at an unfamiliar host looks like data theft to a reviewer without them. Keep the trailing slash on the URL. Leave the credentials block in even if the server has no password; it is ignored then.

Step 3: Maven build cache setup

Maven uses Apache's Build Cache Extension. FosterStack Cache implements the server side of it.

Add the extension in .mvn/extensions.xml (check Maven Central for the current version):

<extensions>
  <extension>
    <groupId>org.apache.maven.extensions</groupId>
    <artifactId>maven-build-cache-extension</artifactId>
    <version>1.2.3</version>
  </extension>
</extensions>

Point it at the server in .mvn/maven-build-cache-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://maven.apache.org/BUILD-CACHE-CONFIG/1.2.0"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/BUILD-CACHE-CONFIG/1.2.0 https://maven.apache.org/xsd/build-cache-config-1.2.0.xsd">
  <configuration>
    <enabled>true</enabled>
    <!-- FosterStack Cache — remote Maven build cache.
         https://github.com/fosterstack/cache -->
    <remote enabled="true" saveToRemote="true" id="fosterstack-cache">
      <url>https://cache.example.com/</url>
    </remote>
  </configuration>
</cache>

The remote element must be inside configuration, and saveToRemote="true" is what makes the machine upload; without it the server stays empty. If the server uses Basic Auth, add a matching <server> with the same id (fosterstack-cache) in ~/.m2/settings.xml. Then run mvn install.

The extension itself is Apache's project. If your hit rate looks low, start with the extension's own configuration guide.

Step 4: Check that it works

For Gradle, build, clean, and build again. Without the clean, the second build prints UP-TO-DATE, which tells you nothing about the cache:

./gradlew build --build-cache
./gradlew clean
./gradlew build --build-cache

On the second build, look for FROM-CACHE next to tasks. This hit may come from your own machine, because Gradle also has a local cache that gives hits even when the remote is broken. To test the remote itself, run clean, delete the local cache, stop the daemon, then build with -i:

./gradlew clean
rm -rf ~/.gradle/caches/build-cache-1
./gradlew --stop
./gradlew build --build-cache -i

On the server, the hit counter should go up. The output also has comment lines that start with #; the numbers are on the counter lines:

curl -s https://cache.example.com/metrics | grep -E 'fscache_cache_(hits|misses)_total'

For Maven, build twice from a clean checkout and look for cache hits in the log for unchanged modules.

Step 5: Retire the old node

Once builds hit the new server, stop the old Build Cache Node container. Watch the new one with monitoring, and size its disk with server sizing.

Build Cache Node migration checklist for Gradle

Our advice, not a test result. Where a line says "in our runs", it comes from the table under How we checked.

Find every place your builds point at the old node

Search your repositories and CI settings for HttpBuildCache and for the node's address. The old node's address ends in /cache/. Write the list down: each entry is one line to change.

Change one line in each place

buildCache {
    remote<HttpBuildCache> {
-       url = uri("http://old-node.example.com:5071/cache/")
+       url = uri("https://cache.example.com/")
        isPush = true
    }
}

If the new server has a password, also add a credentials block. See authentication and 401 errors.

Decide about the /cache/ part of the URL

You can drop it, as above, or keep it. FosterStack Cache uses the whole request path as the key, so a prefix works. Entries under different paths are separate, so pick one and use it everywhere.

Keep the old node running until you are sure

With Gradle, rolling back is the same one-line change in reverse. In our runs, we tested that; see the table under How we checked.

What you give up

The old node had a small web page with a purge button. FosterStack Cache has no settings page. You set it with flags and environment variables, and a read-only status page shows size and hit counts. To empty the cache, remove its volume and start again.

What to check in a replacement build cache

A build cache sits inside your supply chain: what it stores ends up in your builds. Ask these seven questions of any candidate. We answer each one for FosterStack Cache.

1. Does it speak your build tool's protocol?

It should work with the tool's own remote cache setting, with nothing extra to install on developer machines. How to test: build, run clean, and build again with the local cache turned off, and look for FROM-CACHE on the second build. FosterStack Cache: Gradle through its HttpBuildCache setting; Maven through Apache's Build Cache Extension.

2. Who can write to it?

Anything that can write to the cache can change what later builds use. Ask for authentication, and ask what permission levels exist. FosterStack Cache: Basic Auth with a read-write login and an optional read-only login, where any write from the read-only one is refused. Per-person identity is not built.

3. Can you verify what you download?

Look for signatures, a software bill of materials, build provenance and vulnerability statements, and check whether you need an account to see them. FosterStack Cache: signed images and checksums, an SBOM per binary archive, build provenance and a VEX file, all public. See how we build.

4. Is it kept patched?

Ask how often published files are rescanned and how fast fixes ship. FosterStack Cache: a release is blocked on scanner findings unless a VEX statement explains them, and the current release's images are rescanned daily, at every severity the scanners report. Vulnerable dependencies fixed fast — our target is 48 hours from disclosure (the scope is in SECURITY.md).

5. Does it call home?

A server in your build network should not need to reach out. FosterStack Cache: no telemetry, no update check, no licence check. It can run on a network with no route to the internet.

6. How do you run and watch it?

You want size limits, metrics and a way to see it is healthy. FosterStack Cache: size-capped eviction, Prometheus metrics, a health check and a read-only status page. There is no admin web console, on purpose.

7. What are the licence terms, and what if the project goes away?

FosterStack Cache: MIT licensed, one static binary, nothing you need from us to keep running it. Paid tiers are described, not built, and security patches are never withheld from the free tier.

How we checked

In our runs for the table below, we used Gradle 9.8.0 and a small Java project, built twice against each server. The old side was a Build Cache Node image (version 21.2, built June 2025), run locally and set up to allow anonymous reads and writes for the test. The new side was a FosterStack Cache 0.2.1 server with no password. We did not test Maven in this run.

Each row is two builds of the same project with gradle clean in between and Gradle's own local cache turned off, so a hit can only come from the server:

Pointed atFirst buildSecond build
The old node, URL ending in /cache/:compileJava ran:compileJava FROM-CACHE
FosterStack Cache, only the URL changed (no /cache/):compileJava ran: the new server was empty:compileJava FROM-CACHE
FosterStack Cache, URL kept with /cache/:compileJava ran: separate entries:compileJava FROM-CACHE
Back to the old node (rollback):compileJava FROM-CACHE: its entries were still therenot run

We then ran the steps again on a GitHub-hosted Linux machine with release 0.2.2, Gradle 9.8.0 and Maven 3.10.0. Results:

The old node rows and the rollback were not run again. The run and its log are public.

The new server's status page agreed: two entries stored, two hits, two misses. One small difference you may notice: a successful upload returns 200 from the old node and 201 from FosterStack Cache. Gradle accepted both.

More than kept patched.

How we build · Security policy · Verify a release

Full details: Gradle docs, Maven docs, migration guide on GitHub.

FosterStack Cache on GitHub FosterStack home