# Properties and Providers

version 9.2.0-20250807002717+0000

Gradle provides properties that are important for lazy configuration. When implementing a custom task or plugin, it’s imperative that you use these lazy properties.

Gradle represents lazy properties with two interfaces:

1. Property - Represents a value that can be queried and changed.

2. Provider - Represents a value that can only be queried and cannot be changed.

Properties and providers manage values and configurations in a build script.

In this example, `configuration` is a `Property<String>` that is set to the `configurationProvider` `Provider<String>`. The `configurationProvider` lazily provides the value `"Hello, Gradle!"`:

build.gradle.kts

    abstract class MyIntroTask : DefaultTask() {
        @get:Input
        abstract val configuration: Property<String>

        @TaskAction
        fun printConfiguration() {
            println("Configuration value: ${configuration.get()}")
        }
    }

    val configurationProvider: Provider<String> = project.provider { "Hello, Gradle!" }

    tasks.register("myIntroTask", MyIntroTask::class) {
        configuration = configurationProvider
    }

build.gradle

    abstract class MyIntroTask extends DefaultTask {
        @Input
        abstract Property<String> getConfiguration()

        @TaskAction
        void printConfiguration() {
            println "Configuration value: ${configuration.get()}"
        }
    }

    Provider<String> configurationProvider = project.provider { "Hello, Gradle!" }

    tasks.register("myIntroTask", MyIntroTask) {
        it.setConfiguration(configurationProvider)
    }

## Understanding Properties

Properties in Gradle are variables that hold values. They can be defined and accessed within the build script to store information like file paths, version numbers, or custom values.

Properties can be set and retrieved using the `project` object:

build.gradle.kts

    // Setting a property
    val simpleMessageProperty: Property<String> = project.objects.property(String::class)
    simpleMessageProperty.set("Hello, World from a Property!")
    // Accessing a property
    println(simpleMessageProperty.get())

build.gradle

    // Setting a property
    def simpleMessageProperty = project.objects.property(String)
    simpleMessageProperty.set("Hello, World from a Property!")
    // Accessing a property
    println(simpleMessageProperty.get())

Properties:

- Properties with these types are configurable.

- `Property` extends the `Provider` interface.

- The method Property.set(T) specifies a value for the property, overwriting whatever value may have been present.

- The method Property.set(Provider) specifies a `Provider` for the value for the property, overwriting whatever value may have been present. This allows you to wire together `Provider` and `Property` instances before the values are configured.

- A `Property` can be created by the factory method ObjectFactory.property(Class).

## Understanding Providers

Providers are objects that represent a value that may not be immediately available. Providers are useful for lazy evaluation and can be used to model values that may change over time or depend on other tasks or inputs:

build.gradle.kts

    // Setting a provider
    val simpleMessageProvider: Provider<String> = project.providers.provider { "Hello, World from a Provider!" }
    // Accessing a provider
    println(simpleMessageProvider.get())

build.gradle

    // Setting a provider
    def simpleMessageProvider = project.providers.provider { "Hello, World from a Provider!" }
    // Accessing a provider
    println(simpleMessageProvider.get())

Providers:

- Properties with these types are read-only.

- The method Provider.get() returns the current value of the property.

- A `Provider` can be created from another `Provider` using Provider.map(Transformer).

- Many other types extend `Provider` and can be used wherever a `Provider` is required.

## Chaining Providers

Chaining `Providers` preserves laziness and is essential to use when writing build logic.

These methods allow you to transform, combine, or provide fallback values without triggering eager evaluation:

Method | Purpose
--- | ---
`map()` | Transforms the value using a function, producing a new `Provider`.
`flatMap()` | Transforms the value into another `Provider`, and flattens the result.
`zip()` | Combines multiple `Providers` into one, applying a function to their values.
`orElse()` | Supplies a fallback `Provider` if the original is missing or undefined.

Using `map()` is a common example:

build.gradle.kts

    val majorVersion: Provider<String> = versionProvider.map { it.split(".")[0] }

You can see the following example for a detailed breakdown at `Provider` chaining using `map()`:

build.gradle

    tasks.register("printFloatFromFile") {
        // Type: RegularFile
        def myFile = layout.projectDirectory.file("someNumber.txt")

        // Type: Provider<Float>
        def floatProvider = project.providers
            // Type: Provider<FileContents>
            .fileContents(myFile)
            // Type: Provider<String>
            .asText
            // Type: Provider<Float>
            .map {
                // Type: Float
                it.toFloat()
            }

        doLast {
            // Type: Provider<Float>
            println ">>> Float value from file: $floatProvider"
            // Type: Float
            println ">>> Float value from file: ${floatProvider.get()}"
        }
    }

## Using Gradle Managed Properties

Gradle’s managed properties allow you to declare properties as getters (Java, Groovy) or properties (Kotlin).

Gradle then automatically provides the implementation for these properties, managing their state.

A property may be mutable, meaning that it is of type `Property`, which has both a `get()` and a `set()` method:

build.gradle.kts

    abstract class MyPropertyTask : DefaultTask() {
        @get:Input
        abstract val messageProperty: Property<String> // message property

        @TaskAction
        fun printMessage() {
            println(messageProperty.get())
        }
    }

    tasks.register<MyPropertyTask>("myPropertyTask") {
        messageProperty.set("Hello, Gradle!")
    }

build.gradle

    abstract class MyPropertyTask extends DefaultTask {
        @Input
        abstract Property<String> getMessageProperty()

        @TaskAction
        void printMessage() {
            println(messageProperty.get())
        }
    }

    tasks.register('myPropertyTask', MyPropertyTask) {
        messageProperty.set("Hello, Gradle!")
    }

Or read-only, meaning that it is of type `Provider`, which only has a `get()` method:

build.gradle.kts

    abstract class MyProviderTask : DefaultTask() {
        val messageProvider: Provider<String> = project.providers.provider { "Hello, Gradle!" } // message provider

        @TaskAction
        fun printMessage() {
            println(messageProvider.get())
        }
    }

    tasks.register<MyProviderTask>("MyProviderTask") {

    }

build.gradle

    abstract class MyProviderTask extends DefaultTask {
        final Provider<String> messageProvider = project.providers.provider { "Hello, Gradle!" }

        @TaskAction
        void printMessage() {
            println(messageProvider.get())
        }
    }

    tasks.register('MyProviderTask', MyProviderTask)

### Mutable Managed Properties

A mutable managed property is declared using a getter method of type `Property<T>`, where `T` can be any serializable type or a fully managed Gradle type. The property must not have any setter methods.

Here is an example of a task type with an `uri` property of type `URI`:

Download.java

    public abstract class Download extends DefaultTask {
        @Input
        public abstract Property<URI> getUri(); // abstract getter of type Property<T>

        @TaskAction
        void run() {
            System.out.println("Downloading " + getUri().get()); // Use the `uri` property
        }
    }

Note that for a property to be considered a mutable managed property, the property’s getter methods must have `public` or `protected` visibility. It is recommended to also make the property `abstract`, so Gradle can manage the initialization of the property.

The property type must be one of the following:

Property Type | Note
--- | ---
`Property<T>` | Where `T` is typically `Double`, `Integer`, `Long`, `String`, or `Bool`
`RegularFileProperty` | Configurable regular file location, whose value is mutable
`DirectoryProperty` | Configurable directory location, whose value is mutable
`ListProperty<T>` | List of elements of type `T`
`SetProperty<T>` | Set of elements of type `T`
`MapProperty<K, V>` | Map of `K` type keys with `V` type values
`ConfigurableFileCollection` | A mutable `FileCollection` which represents a collection of file system locations
`ConfigurableFileTree` | A mutable `FileTree` which represents a hierarchy of files

### Read-only Managed Properties (Providers)

You can declare a read-only managed property, also known as a provider, using a getter method of type `Provider<T>`. The method implementation needs to derive the value. It can, for example, derive the value from other properties.

Here is an example of a task type with a `uri` provider that is derived from a `location` property:

Download.java

    public abstract class Download extends DefaultTask {
        @Input
        public abstract Property<String> getLocation();

        @Internal
        public Provider<URI> getUri() {
            return getLocation().map(l -> URI.create("https://" + l));
        }

        @TaskAction
        void run() {
            System.out.println("Downloading " + getUri().get());  // Use the `uri` provider (read-only property)
        }
    }

### Read-only Managed Nested Properties (Nested Providers)

You can declare a read-only managed nested property by adding an abstract getter method for the property to a type annotated with `@Nested`. The property should not have any setter methods. Gradle provides the implementation for the getter method and creates a value for the property.

This pattern is useful when a custom type has a nested complex type which has the same lifecycle. If the lifecycle is different, consider using `Property<NestedType>` instead.

Here is an example of a task type with a `resource` property. The `Resource` type is also a custom Gradle type and defines some managed properties:

Download.java

    public abstract class Download extends DefaultTask {
        @Nested
        public abstract Resource getResource(); // Use an abstract getter method annotated with @Nested

        @TaskAction
        void run() {
            // Use the `resource` property
            System.out.println("Downloading https://" + getResource().getHostName().get() + "/" + getResource().getPath().get());
        }
    }

    public interface Resource {
        @Input
        Property<String> getHostName();
        @Input
        Property<String> getPath();
    }

### Read-only Managed "name" Property (Provider)

If the type contains an abstract property called "name" of type `String`, Gradle provides an implementation for the getter method, and extends each constructor with a "name" parameter, which comes before all other constructor parameters.

If the type is an interface, Gradle will provide a constructor with a single "name" parameter and `@Inject` semantics.

You can have your type implement or extend the Named interface, which defines such a read-only "name" property:

    import org.gradle.api.Named

    interface MyType : Named {
        // Other properties and methods...
    }

    class MyTypeImpl(override val name: String) : MyType {
        // Implement other properties and methods...
    }

    // Usage
    val instance = MyTypeImpl("myName")
    println(instance.name) // Prints: myName

## Using Gradle Managed Types

A managed type as an abstract class or interface with no fields and whose properties are all managed. These types have their state entirely managed by Gradle.

For example, this managed type is defined as an interface:

Resource.java

    public interface Resource {
        @Input
        Property<String> getHostName();
        @Input
        Property<String> getPath();
    }

A named managed type is a managed type that additionally has an abstract property "name" of type `String`. Named managed types are especially useful as the element type of NamedDomainObjectContainer:

build.gradle.kts

    interface MyNamedType {
        val name: String
    }

    class MyNamedTypeImpl(override val name: String) : MyNamedType

    class MyPluginExtension(project: Project) {
        val myNamedContainer: NamedDomainObjectContainer<MyNamedType> =
            project.container(MyNamedType::class.java) { name ->
                project.objects.newInstance(MyNamedTypeImpl::class.java, name)
            }
    }

build.gradle

    interface MyNamedType {
        String getName()
    }

    class MyNamedTypeImpl implements MyNamedType {
        String name

        MyNamedTypeImpl(String name) {
            this.name = name
        }
    }

    class MyPluginExtension {
        NamedDomainObjectContainer<MyNamedType> myNamedContainer

        MyPluginExtension(Project project) {
            myNamedContainer = project.container(MyNamedType) { name ->
                new MyNamedTypeImpl(name)
            }
        }
    }

## Using Java Bean Properties

Sometimes you may see properties implemented in the Java bean property style. That is, they do not use a `Property<T>` or `Provider<T>` types but are instead implemented with concrete setter and getter methods (or corresponding conveniences in Groovy or Kotlin).

This style of property definition is legacy in Gradle and is discouraged:

    public class MyTask extends DefaultTask {
        private String someProperty;

        public String getSomeProperty() {
            return someProperty;
        }

        public void setSomeProperty(String someProperty) {
            this.someProperty = someProperty;
        }

        @TaskAction
        public void myAction() {
            System.out.println("SomeProperty: " + someProperty);
        }
    }