Inside a build script, how do you read a -D system property versus a -P project property, and what does org.gradle.jvmargs in gradle.properties control?
answer
- gradleProperty vs systemProperty
- systemProp. prefix in file
- org.gradle.jvmargs = daemon JVM
- -Xmx for daemon OOM
- tests fork their own JVM
basics
~10 sRead a -P project property with providers.gradleProperty("x"); read a -D system property with providers.systemProperty("x"). They are separate namespaces. org.gradle.jvmargs sets the JVM arguments (heap, metaspace, etc.) for the Gradle daemon that runs the build.
solid answer
~40 sFrom the script's view there are distinct namespaces. A **project property** (`-Px=...` or a line in gradle.properties) is read with `providers.gradleProperty("x")`. A **system property** (`-Dx=...`, or `systemProp.x=...` in gradle.properties) lives in the JVM's `System` properties and is read with `providers.systemProperty("x")`. They never override each other. Separately, `org.gradle.jvmargs` in gradle.properties is **not** something you read as a property at all — it configures the **Gradle daemon JVM** itself: heap (`-Xmx`), metaspace, GC, file encoding, etc. For example `org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8` gives the daemon a 4 GB max heap. It's the most common fix for `OutOfMemoryError` during configuration/build. Note it tunes the *daemon* JVM, not forked test or compile JVMs (those have their own `maxHeapSize` / `jvmArgs`).
code
kotlin · 7 linesval flag = providers.gradleProperty("feature") // -Pfeature / gradle.properties
val seed = providers.systemProperty("seed") // -Dseed / systemProp.seed
tasks.test {
maxHeapSize = "2g" // forked test JVM, NOT org.gradle.jvmargs
jvmArgs("-XX:+UseG1GC")
}go deeper
Know -P is a project property and -D is a system property and they're read differently.
Use providers.gradleProperty vs providers.systemProperty correctly and know systemProp. prefix; know org.gradle.jvmargs sizes the daemon.
Distinguish daemon JVM from forked test/compile JVMs and tune each independently; understand daemon restart on jvmargs change.
Set org-wide daemon memory/GC defaults and per-module test fork sizing to keep CI stable and fast.
## Three different things people conflate ### 1. Project property (`-P`) Named value on the `Project`. Source: gradle.properties (any) or `-Pkey=value`. Read: ```kotlin val p = providers.gradleProperty("key") // Provider<String> ``` ### 2. System property (`-D`) A JVM-level `System.getProperty` value. Source: `-Dkey=value` on the CLI, or `systemProp.key=value` inside gradle.properties (the `systemProp.` prefix is how the file feeds system properties). Read: ```kotlin val s = providers.systemProperty("key") // Provider<String> ``` Project and system properties are **separate namespaces** — defining `-Pfoo` does not create `-Dfoo` and vice versa. ### 3. `org.gradle.jvmargs` — daemon JVM tuning This is one of the `org.gradle.*` settings Gradle itself consumes. It is **not** a property you read; it sets the command-line arguments of the JVM that hosts the **Gradle daemon** (the long-lived process that runs your build): ```properties # gradle.properties org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=1g -Dfile.encoding=UTF-8 ``` - `-Xmx4g` — max heap of the daemon; raise this when configuration/build hits `OutOfMemoryError: Java heap space`. - `-XX:MaxMetaspaceSize` — class-metadata space; large multi-module builds can exhaust it. - A `-D` inside jvmargs sets a system property *for the daemon JVM*. Changing `org.gradle.jvmargs` makes the running daemon **incompatible** with builds started under the old value, so Gradle starts a fresh daemon — expect a one-time restart. ## What it does NOT control Forked processes have their own knobs: - **Tests** run in a forked JVM configured by the `Test` task: `test { maxHeapSize = "2g"; jvmArgs("-XX:+UseG1GC") }`. - **Compilation** (e.g. forked `JavaCompile`) and other workers have their own settings. So bumping `org.gradle.jvmargs` fixes daemon OOMs, not a test that OOMs in its own fork. ## Quick mental table | Want | Supply | Read with | |------|--------|-----------| | project property | `-Pk=v` / `k=v` | `providers.gradleProperty("k")` | | system property | `-Dk=v` / `systemProp.k=v` | `providers.systemProperty("k")` | | daemon heap/GC | `org.gradle.jvmargs=...` | (consumed by Gradle, not read) |
- How do you set a system property from inside gradle.properties (not the command line)?Prefix the key with systemProp., e.g. systemProp.https.proxyHost=proxy.corp.com. Gradle strips the prefix and exposes it as the JVM system property https.proxyHost.
- A test task throws OutOfMemoryError. Does raising org.gradle.jvmargs fix it?Not necessarily — tests run in a forked JVM with its own heap. Set test { maxHeapSize = "..." } (and jvmArgs) on the Test task; org.gradle.jvmargs only sizes the Gradle daemon.
saying these in an interview costs you the question
- Reading a -D system property with providers.gradleProperty (wrong namespace).
- Thinking org.gradle.jvmargs sizes the test/compile forks rather than the daemon.
- Forgetting the systemProp. prefix when setting system properties in gradle.properties.