What is the difference between passing -Pname=value and -Dname=value on the Gradle command line?
answer
- -P = project property
- -D = JVM system property
- separate namespaces, no crossover
- findProperty / System.getProperty
- forked test JVM doesn't inherit -D
basics
~10 s-P sets a Gradle project property (read in the build script as a project property). -D sets a JVM system property (read via System.getProperty). They land in different namespaces.
solid answer
~40 s`-Pname=value` defines a **project property**, available on the `Project` object and via the providers API; it is Gradle's own concept and is the idiomatic way to pass build inputs like a version override. `-Dname=value` sets a standard **JVM system property** on the Gradle daemon's JVM, retrievable with `System.getProperty("name")` — the same mechanism every Java program uses. So `-P` is build-domain configuration and `-D` is JVM-level configuration. A subtle trap: a project property named `foo` and a system property named `foo` are unrelated; reading one will not see the other. Tasks like tests that fork a new JVM do NOT automatically inherit `-D` properties — you must forward them explicitly via `systemProperty(...)` in the `test {}` block.
code
bash · 5 lines# project property: read via findProperty / providers.gradleProperty
./gradlew build -PappVersion=1.4.0
# JVM system property: read via System.getProperty
./gradlew test -Denv=staginggo deeper
State the basic split: -P is a Gradle project property, -D is a JVM system property, read with different accessors.
Add that the namespaces never cross and that forked test JVMs need -D properties forwarded explicitly.
Discuss when to choose each (build inputs vs JVM/tool config) and the configuration-cache-friendly providers accessors.
Frame conventions for a team: standardize on -P for build inputs, document required -D flags, and avoid leaking secrets through command-line properties visible in process listings.
## Two separate namespaces Gradle distinguishes two kinds of named values you can inject from the command line: - **Project properties** (`-P`): a Gradle concept. They are attached to the `Project` and form the input vocabulary the build script speaks. You read them with `project.findProperty("x")`, `project.property("x")`, or the lazy `providers.gradleProperty("x")`. - **System properties** (`-D`): the plain JVM mechanism. `-Dfoo=bar` puts `foo` into the system property table of the JVM running Gradle (the daemon). You read it with `System.getProperty("foo")` or `providers.systemProperty("foo")`. The two tables never cross-populate. `-Pfoo=bar` does NOT make `System.getProperty("foo")` return anything, and vice versa. ## Why both exist `-P` is for **your build's own configuration** — overriding a publish version, toggling a feature, choosing an environment. `-D` is for **JVM-level / tool-level configuration** — things a library or the JVM itself reads, e.g. `-Dorg.gradle.jvmargs`, `-Dhttp.proxyHost`, or a system property a plugin documents. ## The forked-JVM gotcha Gradle's own daemon JVM receives `-D` properties, but tasks that fork a new JVM (most importantly `Test`) start a fresh process that does NOT inherit them. To make a system property visible inside tests you forward it: ```kotlin tasks.test { systemProperty("env", System.getProperty("env") ?: "local") } ``` ## Reading a project property defensively `project.property("x")` throws if absent; `findProperty("x")` returns null. The modern, configuration-cache-friendly path is `providers.gradleProperty("x")`, which yields a lazy `Provider<String>`. Knowing which flag feeds which API is the core skill: pick `-P` for build inputs, `-D` for JVM/system-level inputs, and never assume one is visible through the other's accessor.
- Will System.getProperty("appVersion") return anything after passing -PappVersion=1.4.0?No. -P populates Gradle's project-property table only; System.getProperty reads the JVM system-property table, which -P never touches. You'd need -DappVersion=1.4.0 for that.
- Why might a -D property set on the command line not show up inside a test?The Test task forks a new JVM that doesn't inherit the daemon's system properties. You must forward it explicitly with systemProperty(...) in the test block.
-P is a note pinned to the build's own bulletin board; -D is a setting written into the JVM's global config file. Reading one board never shows notes from the other.
saying these in an interview costs you the question
- Claiming -P and -D are interchangeable.
- Assuming -D properties are automatically visible inside forked test JVMs.
- Saying project properties are read with System.getProperty.