Series Posts

· 5 min read Posted by Tadeas Kriz

Gradle Properties

Understanding how Gradle properties work can save you a lot of time debugging. This post explains how to set properties and what their priorities are.
Diane Picchiottino - https://unsplash.com/photos/white-and-black-chess-board-itHFvqW09yM
Credit: Diane Picchiottino - https://unsplash.com/photos/white-and-black-chess-board-itHFvqW09yM

In our last post about Gradle, we talked about how configuring org.gradle.jvmargs can lead to unexpected out of memory errors. Now let’s talk about all the places Gradle gets its configuration from, so we can make sure you’re in full control of your build.

Most of your projects will have a gradle.properties file in the root. But not all the properties in that file have the same behavior.

The Configuring the Build Environment page in Gradle documentation tries to explain the different property types and their behavior. From our testing it behaves slightly differently than the page might lead you to believe. The table Priority for configurations looks like this:

PriorityMethodLocationExampleDetails
1Command-line flagsCommand line--build-cacheThese have precedence over properties and environment variables.
2System propertiesProject Root DirsystemProp.http.proxyPort=443Stored in a gradle.properties file
3Gradle propertiesGRADLE_USER_HOME
Project Root Dir
GRADLE_HOME
org.gradle.logging.level=quietStored in a gradle.properties file
4Environment variablesEnvironmentGRADLE_OPTSSourced by the environment that executed Gradle

Once you start playing around with properties, you’ll find that this table misses some important information. For example, System properties are actually loaded from GRADLE_HOME and GRADLE_USER_HOME too, not just the Project Root Dir. And if you’re using a Gradle wrapper (invoking Gradle with ./gradlew which you probably do), then the gradle.properties file in $GRADLE_HOME is ignored.

With that in mind, let’s make our own tables. Yes, tables plural as we’ll capture behaviors of different property types. You see, the documentation speaks about Project, System and Gradle properties, as if they were completely separate. Instead we need to separate how are properties passed in, and how properties can be used in our build script. So let’s make a table for each property type.

System properties

System properties are used in JVM to pass in configuration using the -D argument. Though Gradle allows setting system properties in similar ways to project properties in gradle.properties files.

PriorityMethodExampleDetails
1Command-line flags-Da-system-property=cmdlineThese have precedence over property files and environment variables.
2gradle.properties file in $GRADLE_USER_HOMEsystemProp.a-system-property=gradle-user-homeDefaults to ~/.gradle/gradle.properties if GRADLE_USER_HOME not set
3gradle.properties file in project root directorysystemProp.a-system-property=project-dirStored in a gradle.properties file
4gradle.properties file in $GRADLE_HOMEsystemProp.a-system-property=gradle-homeIgnored if started using a Gradle Wrapper
5Environment variablesGRADLE_OPTS="-Da-system-property=env"Sourced by the environment that executed Gradle

Project properties

There are many ways to access project properties in your build script. One such way is findProperty("a-project-property") which returns a value or null if not set.

PriorityMethodExampleDetails
1Command-line flags-Pa-project-property=cmdlineThese have precedence over property files and environment variables.
2System properties-Dorg.gradle.project.a-project-property=cmdline (any system property with org.gradle.project. prefix)See the table above for priorities
3gradle.properties file in $GRADLE_USER_HOMEa-project-property=gradle-user-homeDefaults to ~/.gradle/gradle.properties if GRADLE_USER_HOME not set
4gradle.properties file in project root directorya-project-property=project-dirStored in a gradle.properties file
5gradle.properties file in $GRADLE_HOMEa-project-property=gradle-homeIgnored if started using a Gradle Wrapper
6Environment variablesORG_GRADLE_PROJECT_a_project_property=env (hyphens - not supported this way)Sourced by the environment that executed Gradle

Notice that project properties can be set using a system property. If the system property name starts with org.gradle.project., Gradle will automatically create a project property using the remaining suffix as its name. Consider the following two lines from a gradle.properties file:

systemProp.org.gradle.project.a-project-property=hello
a-project-property=world

You might expect that the a-project-property will have value world, but it’s hello instead. That’s because the project property set through a system property has a higher priority. When declared in a single gradle.properties file, it might not be that big of a deal. But it can easily be something you spend a lot of time debugging, if you have it set in multiple gradle.properties files, or even in GRADLE_OPTS.

Another interesting behavior is that anything you declare in one of the gradle.properties files, will be available as a project property. So findProperty("systemProp.org.gradle.project.a-project-property") will give you the same value as findProperty("a-project-property") in the above example. But if you pass in -Pa-project-property=cmdline to the Gradle invocation, findProperty("a-project-property") is overridden, while findProperty("systemProp.org.gradle.project.a-project-property") stays the same.

Gradle properties

Lastly we have the Gradle properties, which are special.

PriorityMethodExampleDetails
1Command-line flags--console=plainThese have precedence over property files and environment variables.
2System properties*-Dorg.gradle.console=plain* only on command-line or GRADLE_OPTS
3gradle.properties file in $GRADLE_USER_HOMEorg.gradle.console=plainDefaults to ~/.gradle/gradle.properties if GRADLE_USER_HOME not set
4gradle.properties file in project root directoryorg.gradle.console=plainStored in a gradle.properties file
5gradle.properties file in $GRADLE_HOMEorg.gradle.console=plainIgnored if started using a Gradle Wrapper

Note that if configured using gradle.properties, it becomes a project property as well. That means that findProperty("org.gradle.console") would return a value. Similarly, if configured using a system property, we can use System.getProperty("org.gradle.console"). However, if that value is overridden by a command line flag, value we’d get from either wouldn’t be correct.

Common issues with $GRADLE_USER_HOME

Now that we looked at the priorities, we can look at one common issue caused by them. Notice that the gradle.properties in $GRADLE_USER_HOME has a higher priority than the one in your project’s root. It’s common that we consider whatever is closest to the project to have the highest priority, but that isn’t the case with gradle.properties. Anything that you put into $GRADLE_USER_HOME/gradle.properties will override your project’s gradle.properties and if you’re not careful, can lead to unexpected behavior. For example, let’s say you’ve set org.gradle.jvmargs in $GRADLE_USER_HOME/gradle.properties so that all your Gradle daemons have the same JVM args. Some time passes and you’re working on a project that needs more heap size. So you update the project’s gradle.properties and nothing happens. Unless you remember that you’ve set it in $GRADLE_USER_HOME/gradle.properties, you might spend too much time trying to figure it out (don’t ask me how I know). It’d be really helpful if there was a way to ask Gradle to print all properties and where are they coming from. That’d make debugging this way easier.