skip to content

How do you enable pushing to a remote HTTP build cache and supply credentials securely?

level: middleimportance: must knowfreq 60%

answer

  1. push = true to upload
  2. credentials { username/password } = HTTP Basic
  3. read secrets from env / gradle.properties
  4. HTTPS mandatory (Basic = base64, not encrypted)
  5. asymmetric: devs pull, CI pushes

basics

~10 s

Set push = true on the remote(HttpBuildCache) and provide credentials { username = ...; password = ... }. Read the secrets from environment variables or gradle.properties rather than hardcoding them in the settings file.

solid answer

~40 s

By default `push = false`, so the remote is read-only. To upload entries you set `push = true` inside the `remote<HttpBuildCache>` block. If the server requires auth, add a `credentials { username = ...; password = ... }` block (HttpBuildCache uses HTTP **Basic** auth). The secrets must **not** be hardcoded; read them from environment variables (`System.getenv`) or Gradle properties so they can be injected per-environment and kept out of version control. The common pattern is: developers run read-only (`push = false`), and only CI sets `push = true` with credentials, often gating it on an env var so the same settings file behaves differently locally vs. on CI. Always use HTTPS so Basic credentials aren't sent in clear text.

code

kotlin · 10 lines
kotlin
buildCache {
    remote<HttpBuildCache> {
        url = uri("https://cache.example.com/cache/")
        push = providers.environmentVariable("CI").isPresent
        credentials {
            username = System.getenv("GRADLE_CACHE_USER")
            password = System.getenv("GRADLE_CACHE_PASSWORD")
        }
    }
}

go deeper

for a junior

Know push=true enables uploads and credentials{} supplies username/password.

for a middle

Explain reading secrets from env/properties, HTTP Basic + HTTPS, and the dev-pull/CI-push split.

for a senior

Reason about cache poisoning risk, best-effort write semantics, and env-driven push toggles.

for a principal

Define org policy: who may write, credential rotation/scoping, and centralizing the config via init scripts.

## Why push is off by default A shared cache is only useful if its entries are trustworthy. If every developer pushed, a machine with a misconfigured toolchain or a compromised dependency could poison the cache for everyone. So Gradle defaults `push = false`: the remote is a **read-only** source. You consciously opt into writing. ## Turning on push ```kotlin // settings.gradle.kts buildCache { remote<HttpBuildCache> { url = uri("https://cache.example.com/cache/") push = System.getenv("CI").toBoolean() // only CI uploads credentials { username = System.getenv("GRADLE_CACHE_USER") password = System.getenv("GRADLE_CACHE_PASSWORD") } } } ``` `HttpBuildCache` exposes a `credentials { }` block taking `username`/`password`. On the wire this is HTTP **Basic** authentication: the values are base64-encoded in the `Authorization` header — encoding, not encryption — so **HTTPS is mandatory** for any non-trivial deployment. ## Keeping secrets out of the repo Never inline literal credentials in `settings.gradle.kts` — it is committed to VCS. Read them from: - **Environment variables** (`System.getenv("...")`) — ideal for CI secret stores. - **Gradle properties** — e.g. `providers.gradleProperty("cacheUser")`, sourced from `~/.gradle/gradle.properties` (per-user, outside the project) or `-PcacheUser=...`. ## The asymmetric pattern The canonical setup is **asymmetric**: developers pull but do not push; CI both pulls and pushes (seeds the cache). Driving `push` off an env var like `CI` keeps a single settings file working everywhere. Read credentials may even be omitted if the server allows anonymous reads, with write credentials supplied only on CI. ## Gotchas - A `401/403` on PUT but working GETs usually means read is anonymous but write needs credentials you haven't supplied. - `push = true` without write permission on the server silently produces store failures (logged, build still succeeds — cache writes are best-effort).

  • What kind of authentication does HttpBuildCache use, and what does that imply?
    HTTP Basic auth — username/password base64-encoded in the Authorization header. Base64 is encoding, not encryption, so you must use HTTPS to avoid leaking credentials in transit.
  • Why not just write credentials directly in settings.gradle.kts?
    The settings file is committed to version control, so literal secrets would leak. Read them from environment variables or per-user gradle.properties kept outside the repo.
  • Builds succeed but nothing ever appears in the cache. What could be wrong?
    push is still false, or push=true but the server rejects writes (missing/invalid write credentials). Cache writes are best-effort, so failures are logged rather than failing the build.

saying these in an interview costs you the question

  • Hardcoding username/password literals in the committed settings file.
  • Enabling push for all developers instead of only trusted CI.
  • Using plain HTTP with Basic credentials.

context