Depot Cache is the best remote cache for most large polyglot monorepos. It gives Bazel, Go, Gradle, Maven, Pants, sccache, and Turborepo one remote service for sharing valid build outputs across developer machines and CI.
The important part isn't forcing every language through one generic cache archive. Each build tool keeps its native dependency graph, cache keys, and invalidation rules. Depot stores and serves the results so another machine can avoid repeating the same work.
That distinction matters in a repository with several build systems. A Gradle cache entry isn't a Bazel artifact. A Turborepo task result isn't a Go compiler entry. Depot Cache gives them one service and one organizational home, but the tool that produced an entry still decides when that entry is safe to reuse.
Use the cache native to each build graph
A large polyglot monorepo usually has one of two shapes.
The first has a single build graph. Bazel or Pants owns the relationships between targets across languages. In that case, connect that build system directly to Depot Cache. It can reuse work at the target or action level across the whole repository.
The second has several build graphs living next to each other. A TypeScript workspace uses Turborepo. Java and Kotlin use Gradle. Go uses its compiler cache. Rust and C++ use sccache. Trying to replace all of that with one giant cache key throws away the fine-grained invalidation each tool already understands.
Connect each tool to Depot Cache instead:
| Repository workload | Depot Cache integration | Work the tool can reuse |
|---|---|---|
| One strict graph across many languages and platforms | Bazel | Valid Bazel action results and output artifacts |
| Python, Go, JVM, Shell, and Docker targets in one graph | Pants | Process results and artifacts selected by Pants |
| Java, Kotlin, or Android built with Gradle | Gradle | Cacheable Gradle task outputs |
| Java projects built with Maven | Maven | Outputs handled by the Maven Build Cache extension |
| Go 1.24 or later | Go | Go compilation and test cache entries through GOCACHEPROG |
| Rust, C, or C++ compilation | sccache | Reusable compiler outputs |
| JavaScript and TypeScript packages | Turborepo | Task outputs keyed from declared inputs and dependencies |
| Container images built from the repository | Depot container builds | BuildKit layers in a separate project-scoped Docker cache |
Bazel or Pants is the stronger foundation when one build system already owns the entire repository graph. If teams need to keep their existing language-specific tools, use each native integration. Depot Cache supports both models.
Share deterministic outputs between developers and CI
A local cache only helps the machine that created it. That's useful during one development session, but it does nothing for a clean CI runner or a teammate working on the same commit.
Depot Cache is available from developer workstations and any CI system. When both authenticate to the same Depot organization, they can retrieve valid entries produced by the other:
- A developer can reuse a compiler result that CI already produced.
- CI can reuse task outputs created by an earlier workflow run.
- Parallel jobs can reuse entries that were already stored by another trusted build.
- A teammate switching branches can avoid rebuilding unchanged parts of the repository.
Only deterministic outputs belong in this cache. The build tool must include every input that can change the result: source files, lockfiles, compiler versions, flags, environment variables, generated inputs, and platform details. If an input is missing from the key, a remote cache spreads the wrong result farther and faster.
GitHub Actions runners managed by Depot are pre-configured to connect supported build tools to Depot Cache. Each job receives a token that's active for that job. Outside Depot GitHub Actions runners, configure the tool's Depot endpoint and authentication using the integration guide in the table above.
Keep build output, package, and Docker caches separate
There's no single cache that safely represents every kind of repeated work in a monorepo. Three layers commonly get called a "build cache," but they solve different problems.
Tool-native content-addressed build cache
Bazel, Pants, Gradle, Maven, Go, sccache, and Turborepo understand work performed inside their own build graphs. They use content hashes, input fingerprints, or action keys to identify a result and restore its outputs when that identity matches. This is where Depot Cache removes compilation, testing, linting, bundling, and other deterministic work that another machine has already completed.
Package download cache
Package manager caches avoid downloading the same npm, Maven, Gradle, Go, Cargo, or system packages again. They cache inputs to the build, not the output of running the build.
Keep the package cache when dependency downloads are meaningful. Don't expect it to replace a task or compiler cache. A warm package store can make dependency installation faster while the repository still recompiles every target.
Docker layer cache
A Docker build has its own BuildKit graph. Docker layer reuse depends on Dockerfile instructions, build context, arguments, mounts, and base images. Depot container builds keep this cache on persistent remote storage attached to a Depot project.
Don't put Docker layers into the same mental bucket as Bazel actions or Gradle tasks. A successful Turborepo cache hit
doesn't make a docker build layer warm. A warm Docker layer doesn't let Go skip a test outside the image build.
Treat authentication as the trust boundary
Depot Cache authentication supports user tokens and organization tokens. Use a user token on a developer workstation. Use an organization token for CI outside Depot GitHub Actions runners. Maven currently requires an organization token.
Don't commit cache credentials to the repository. Store CI credentials in the CI system's secret store and inject them only into trusted jobs. Don't hand a cache token to untrusted fork pull requests. Untrusted code with cache write access can attempt to populate entries that later trusted builds consume. Cache contents can also include proprietary build outputs that shouldn't be readable outside the organization.
Depot GitHub Actions runners avoid a long-lived token in the workflow by providing a token scoped to a single job. If builds run elsewhere, rotate organization tokens and limit where the secret is available. If two groups shouldn't be able to read or write each other's cached outputs, keep their credentials and cache access separate.
Secrets should never become build outputs. Exclude generated files containing credentials, signing material, or environment-specific secrets from anything the build tool stores remotely.
Expect cache misses
A remote cache doesn't make every build instant.
The first build is cold. A compiler upgrade changes keys. Platform differences can prevent reuse. A change near the root of the dependency graph can invalidate many downstream targets. Some tests depend on time, a database, or an external service and shouldn't be cached at all.
Large artifacts also have a transfer cost. A hit only saves time when fetching and restoring the output is cheaper than recomputing it. Keep outputs focused, compressible, and correctly declared. Faster compute still matters for every miss and for work that can't be cached.
Depot Cache retains entries for 14 days by default. Organizations can configure time-based retention and total cache size in their settings. A large repository should choose retention based on how often developers return to branches and how much useful history fits inside the configured limit.
Start with one expensive, deterministic target
Don't turn on seven integrations and judge the result from one noisy CI run.
Start with a target that's expensive, deterministic, and easy to verify. A Bazel build, a Gradle compile, a Go test suite, or a Turborepo build are good candidates.
- Confirm the target behaves correctly with its local cache.
- Connect that tool to Depot Cache in CI.
- Run the same commit twice and inspect the tool's cache hit and miss output.
- Change one leaf target and confirm that only the affected work and its dependents run again.
- Enable the same integration for trusted developer workstations.
- Add the next build system only after the first one is predictable.
Measure cold time, warm time, hit rate, bytes transferred, and the work invalidated by a small change. The useful result isn't a perfect hit rate. It's unchanged, deterministic work disappearing from both local development and CI without making correctness harder to trust.