skip to content

How do you inject repository credentials from environment variables in CI without writing any gradle.properties file, and what exactly must the variables be named?

level: middleimportance: must knowfreq 60%

answer

  1. ORG_GRADLE_PROJECT_ prefix
  2. maps env var to project property
  3. exact camelCase suffix
  4. no file, job-scoped secret
  5. lazy — fails at publish if absent

basics

~10 s

Set environment variables ORG_GRADLE_PROJECT_<repoName>Username and ORG_GRADLE_PROJECT_<repoName>Password. Gradle maps any ORG_GRADLE_PROJECT_<x> env var to project property <x>, so credentials(PasswordCredentials::class) picks them up automatically.

solid answer

~40 s

Gradle reads project properties from environment variables that follow the prefix convention `ORG_GRADLE_PROJECT_<propertyName>`. Since `credentials(PasswordCredentials::class)` resolves `<repoName>Username`/`<repoName>Password`, you expose them in CI as `ORG_GRADLE_PROJECT_<repoName>Username` and `ORG_GRADLE_PROJECT_<repoName>Password`. No file is needed. In a CI system you wire the secret store to those env names. The case matters — the suffix after the prefix must exactly match the property (including the camelCase repo name). This keeps secrets out of the filesystem entirely, scoped to the job, and works identically across local and CI because it's the same property-resolution mechanism. If a `publish` task runs and the vars are absent, Gradle fails naming the missing property.

code

bash · 4 lines
bash
# Repository declared as name = "myRepo" with credentials(PasswordCredentials::class)
export ORG_GRADLE_PROJECT_myRepoUsername=alice
export ORG_GRADLE_PROJECT_myRepoPassword="$NEXUS_TOKEN"
./gradlew publish

go deeper

for a junior

Recall that env vars can supply credentials and that there's a special prefix; rough name is fine.

for a middle

State the exact ORG_GRADLE_PROJECT_<repoName>Username/Password mapping and explain why CI uses it (no file, job-scoped).

for a senior

Contrast the prefix mapping with manual System.getenv in a lambda, noting the laziness/configuration-cache implications.

for a principal

Standardize secret injection across pipelines, enforce naming conventions, and keep the build script source-agnostic so local/CI use one code path.

## Gradle property sources, again The `credentials(PasswordCredentials::class)` convention resolves two **Gradle project properties**: `<repoName>Username` and `<repoName>Password`. Anything that can set a Gradle project property can therefore supply credentials. ## The environment-variable channel Gradle maps environment variables to project properties with this rule: > An env var named `ORG_GRADLE_PROJECT_<name>` becomes project property `<name>`. So to feed a repository named `myRepo`, you set: ```bash export ORG_GRADLE_PROJECT_myRepoUsername=alice export ORG_GRADLE_PROJECT_myRepoPassword=$NEXUS_TOKEN ``` The part after `ORG_GRADLE_PROJECT_` must match the property name **exactly**, including camelCase. `ORG_GRADLE_PROJECT_myrepoUsername` (lowercase r) would map to the wrong property and credentials would not resolve. ## Why CI prefers this over files - **No file on disk** to leak or accidentally commit. - **Job-scoped**: the secret only exists for the duration of the job's process. - **Same code path** as local `gradle.properties` — you don't special-case CI in the build script. ## Mapping CI secrets In GitHub Actions, for example: ```yaml - run: ./gradlew publish env: ORG_GRADLE_PROJECT_myRepoUsername: ${{ secrets.NEXUS_USER }} ORG_GRADLE_PROJECT_myRepoPassword: ${{ secrets.NEXUS_TOKEN }} ``` ## Failure behavior Credentials are lazy: nothing fails at configuration time. When a task consuming the repository runs (`publish`, `publishAllPublicationsToMyRepoRepository`), Gradle requires the properties. If absent it errors, naming the missing one, e.g. *"Cannot query the value of ... because it has no value available. Could not resolve credential 'myRepoUsername'."* ## Common alternative Some teams instead read raw env vars manually inside a `credentials { }` lambda using `System.getenv("NEXUS_USER")`. That works but loses laziness (it's read at configuration time) and the convention integration, so the `ORG_GRADLE_PROJECT_` form is generally cleaner.

  • Does using env vars require any change to the build script versus using gradle.properties?
    No — both feed the same project property, so `credentials(PasswordCredentials::class)` is unchanged. Only the source of the property differs.
  • What's a downside of reading `System.getenv()` directly inside a `credentials { }` lambda instead?
    It's evaluated eagerly at configuration time and bypasses lazy resolution, so the value is read even when no publish task runs, and you lose the convention integration.
  • Why does the casing of the env-var suffix matter?
    The suffix after `ORG_GRADLE_PROJECT_` must exactly match the property name; a casing mismatch maps to a different (nonexistent) property and credentials silently fail to resolve.

saying these in an interview costs you the question

  • Saying the env vars are named exactly `USERNAME`/`PASSWORD` or `GRADLE_<repo>...` without the `ORG_GRADLE_PROJECT_` prefix.
  • Claiming you must write a temporary gradle.properties in CI.
  • Ignoring that the camelCase suffix must match the property name exactly.

context