# Writing Build Scripts

version 8.1

Use a build script to configure a project. Each Gradle project corresponds to a software component that needs to be built, like a library or an application. Each build script is associated with an object of type Project. As the build script executes, it configures this `Project`.

| Build scripts, Settings scripts, and Init scripts Build scripts define `Project` objects. Gradle uses other scripts as well: Settings scripts define Settings objects. Init scripts define Gradle objects.

## Properties

Many top-level properties and blocks in a build script are part of the `Project` API. The following build script uses the Project.name property to print the name of the project:

Example 1. Access a Project property
build.gradle.kts

    println(name)
    println(project.name)

build.gradle

    println name
    println project.name

Output of `gradle -q check`

    > gradle -q check
    project-api
    project-api

Both `println` statements print out the same property. The first uses the top-level reference to the `name` property of the `Project` object. The other statement uses the `project` property available to any build script, which returns the associated `Project` object.

### Standard project properties

The `Project` object exposes a standard set of properties in your build script. The following table lists a few commonly used properties:

Table 1. Project Properties
Name | Type | Default Value
--- | --- | ---
`project` | Project | The `Project` instance
`name` | `String` | The name of the project directory.
`path` | `String` | The absolute path of the project.
`description` | `String` | A description for the project.
`projectDir` | `File` | The directory containing the build script.
`buildDir` | `File` | `projectDir/build`
`group` | `Object` | `unspecified`
`version` | `Object` | `unspecified`
`ant` | AntBuilder | An `AntBuilder` instance

| Script with other targets The build scripts described here target `Project` objects. There are also settings scripts and init scripts that respectively target Settings and Gradle objects.

## The Script API

When Gradle executes a Groovy build script (`.gradle`), it compiles the script into a class that implements Script. As a result, builds scripts have access to all of the properties and methods declared by the `Script` interface.

When Gradle executes a Kotlin build script (`.gradle.kts`), it compiles the script into a subclass of KotlinBuildScript. As a result, builds scripts have access to all visible properties and functions declared by the `KotlinBuildScript` type.

## Declare Variables

Build scripts can declare two kinds of variables: local variables and extra properties.

### Local Variables

Declare local variables with the `val` keyword. Local variables are only visible in the scope where they have been declared. They are a feature of the underlying Kotlin language.

Declare local variables with the `def` keyword. Local variables are only visible in the scope where they have been declared. They are a feature of the underlying Groovy language.

Example 2. Declare a local variable
build.gradle.kts

    val dest = "dest"

    tasks.register<Copy>("copy") {
        from("source")
        into(dest)
    }

build.gradle

    def dest = 'dest'

    tasks.register('copy', Copy) {
        from 'source'
        into dest
    }

### Extra Properties

All of Gradle’s enhanced objects, including projects, tasks, and source sets, can hold user-defined properties.

Add, read, and set extra properties via the owning object’s `extra` property. Alternatively, you can access extra properties via Kotlin delegated properties using `by extra`.

Add, read, and set extra properties via the owning object’s `ext` property. Alternatively, you can use an `ext` block to add multiple properties at once.

Example 3. Use extra properties
build.gradle.kts

    plugins {
        id("java-library")
    }

    val springVersion by extra("3.1.0.RELEASE")
    val emailNotification by extra { "build@master.org" }

    sourceSets.all { extra["purpose"] = null }

    sourceSets {
        main {
            extra["purpose"] = "production"
        }
        test {
            extra["purpose"] = "test"
        }
        create("plugin") {
            extra["purpose"] = "production"
        }
    }

    tasks.register("printProperties") {
        val springVersion = springVersion
        val emailNotification = emailNotification
        val productionSourceSets = provider {
            sourceSets.matching { it.extra["purpose"] == "production" }.map { it.name }
        }
        doLast {
            println(springVersion)
            println(emailNotification)
            productionSourceSets.get().forEach { println(it) }
        }
    }

build.gradle

    plugins {
        id 'java-library'
    }

    ext {
        springVersion = "3.1.0.RELEASE"
        emailNotification = "build@master.org"
    }

    sourceSets.all { ext.purpose = null }

    sourceSets {
        main {
            purpose = "production"
        }
        test {
            purpose = "test"
        }
        plugin {
            purpose = "production"
        }
    }

    tasks.register('printProperties') {
        def springVersion = springVersion
        def emailNotification = emailNotification
        def productionSourceSets = provider {
            sourceSets.matching { it.purpose == "production" }.collect { it.name }
        }
        doLast {
            println springVersion
            println emailNotification
            productionSourceSets.get().each { println it }
        }
    }

Output of `gradle -q printProperties`

    > gradle -q printProperties
    3.1.0.RELEASE
    build@master.org
    main
    plugin

This example adds two extra properties to the `project` object via `by extra`. Additionally, this example adds a property named `purpose` to each source set by setting `extra["purpose"]` to `null`. Once added, you can read and set all of these properties via `extra`.

This example adds two extra properties to the `project` object via an `ext` block. Additionally, this example adds a property named `purpose` to each source set by setting `ext.purpose` to `null`. Once added, you can read and set all of these properties just like predefined properties.

Gradle requires special syntax for adding a property so it can fail fast. For example, this allows Gradle to recognize when a script attempts to set a property that does not exist. You can access extra properties anywhere where you can access their owning object. This gives extra properties a wider scope than local variables. Subprojects can access extra properties on their parent projects.

For more information about extra properties, see ExtraPropertiesExtension in the API documentation.

## Configure Arbitrary Objects

Configure arbitrary objects with `configure()`:

Example 4. Configure arbitrary objects
build.gradle.kts

    class UserInfo(
        var name: String? = null,
        var email: String? = null
    )

    tasks.register("configure") {
        val user = UserInfo().apply {
            name = "Isaac Newton"
            email = "isaac@newton.me"
        }
        doLast {
            println(user.name)
            println(user.email)
        }
    }

build.gradle

    class UserInfo {
        String name
        String email
    }

    tasks.register('configure') {
        def user = configure(new UserInfo()) {
            name = "Isaac Newton"
            email = "isaac@newton.me"
        }
        doLast {
            println user.name
            println user.email
        }
    }

Output of `gradle -q configure`

    > gradle -q configure
    Isaac Newton
    isaac@newton.me

### Configure Objects in an External Script

You can also configure arbitrary objects using an external script:

| Not supported in Kotlin The Kotlin DSL does not support arbitrary object configuration using an external script. For more information, see gradle/kotlin-dsl#659.

Example 5. Configure arbitrary objects using a script
build.gradle

    class UserInfo {
        String name
        String email
    }

    tasks.register('configure') {
        def userInfo = new UserInfo()
        // Apply the script
        apply from: 'other.gradle', to: userInfo
        doLast {
            println userInfo.name
            println userInfo.email
        }
    }

other.gradle

    // Set properties.
    name = "Isaac Newton"
    email = "isaac@newton.me"

Output of `gradle -q configure`

    > gradle -q configure
    Isaac Newton
    isaac@newton.me

## Helpful Groovy Syntax

Groovy provides many features to help create DSLs. These features can help you write more idiomatic build scripts, plugins, and tasks.

| Looking for helpful Kotlin syntax? Check out the Kotlin reference documentation and Kotlin Koans.

### Convenience Methods

Groovy adds convenience methods to the standard Java classes. For example, `Iterable` gets an `each` method, which iterates over the elements of the `Iterable`:

Example 6. Groovy JDK methods
build.gradle

    // Iterable gets an each() method
    configurations.runtimeClasspath.each { File f -> println f }

For more information, see the GDK documentation.

### Automatic Property Accessors

Groovy automatically converts property references into getter or setter method calls:

Example 7. Property accessors
build.gradle

    // Using a getter method
    println project.buildDir
    println getProject().getBuildDir()

    // Using a setter method
    project.buildDir = 'target'
    getProject().setBuildDir('target')

### Optional Parentheses on Method Calls

Groovy doesn’t require parentheses for method calls:

Example 8. Method call without parentheses
build.gradle

    test.systemProperty 'some.prop', 'value'
    test.systemProperty('some.prop', 'value')

### List and Map Instantiation Shortcuts

Groovy provides shortcuts to define `List` and `Map` instances. For example, consider the “`apply`” method, which accepts a map parameter. When you apply a plugin (`apply plugin:'java'`), you don’t use a map literal. Plugin application uses "named parameters" instead. Named parameters and map literals use similar syntax, but named parameters don’t use wrapping brackets. When you call `apply`, Groovy converts the named parameter list to a map.

Example 9. List and map literals
build.gradle

    // List literal
    test.includes = ['org/gradle/api/**', 'org/gradle/internal/**']

    List<String> list = new ArrayList<String>()
    list.add('org/gradle/api/**')
    list.add('org/gradle/internal/**')
    test.includes = list

    // Map literal.
    Map<String, String> map = [key1:'value1', key2: 'value2']

    // Groovy will coerce named arguments
    // into a single map argument
    apply plugin: 'java'

### Last Closure Parameter Syntax

The Gradle DSL uses closures in many places. You can find out more about closures here. When the last parameter of a method is a closure, you can place the closure after the method call:

Example 10. Closure as method parameter
build.gradle

    repositories {
        println "in a closure"
    }
    repositories() { println "in a closure" }
    repositories({ println "in a closure" })

### Closure Delegates

Each closure has a `delegate` object. Groovy uses this delegate to look up variable and method references to nonlocal variables and closure parameters. Gradle uses this for configuration closures, where the `delegate` object refers to the object being configured.

Example 11. Closure delegates
build.gradle

    dependencies {
        assert delegate == project.dependencies
        testImplementation('junit:junit:4.13')
        delegate.testImplementation('junit:junit:4.13')
    }

## Default Imports

To make build scripts more concise, Gradle automatically adds a set of import statements to scripts. As a result, instead of writing `throw new org.gradle.api.tasks.StopExecutionException()`, you can write `throw new StopExecutionException()` instead.

Gradle implicitly adds the following imports to each script:

Gradle default imports

    import org.gradle.*
    import org.gradle.api.*
    import org.gradle.api.artifacts.*
    import org.gradle.api.artifacts.component.*
    import org.gradle.api.artifacts.dsl.*
    import org.gradle.api.artifacts.ivy.*
    import org.gradle.api.artifacts.maven.*
    import org.gradle.api.artifacts.query.*
    import org.gradle.api.artifacts.repositories.*
    import org.gradle.api.artifacts.result.*
    import org.gradle.api.artifacts.transform.*
    import org.gradle.api.artifacts.type.*
    import org.gradle.api.artifacts.verification.*
    import org.gradle.api.attributes.*
    import org.gradle.api.attributes.java.*
    import org.gradle.api.attributes.plugin.*
    import org.gradle.api.cache.*
    import org.gradle.api.capabilities.*
    import org.gradle.api.component.*
    import org.gradle.api.credentials.*
    import org.gradle.api.distribution.*
    import org.gradle.api.distribution.plugins.*
    import org.gradle.api.execution.*
    import org.gradle.api.file.*
    import org.gradle.api.flow.*
    import org.gradle.api.initialization.*
    import org.gradle.api.initialization.definition.*
    import org.gradle.api.initialization.dsl.*
    import org.gradle.api.initialization.resolve.*
    import org.gradle.api.invocation.*
    import org.gradle.api.java.archives.*
    import org.gradle.api.jvm.*
    import org.gradle.api.launcher.cli.*
    import org.gradle.api.logging.*
    import org.gradle.api.logging.configuration.*
    import org.gradle.api.model.*
    import org.gradle.api.plugins.*
    import org.gradle.api.plugins.antlr.*
    import org.gradle.api.plugins.catalog.*
    import org.gradle.api.plugins.jvm.*
    import org.gradle.api.plugins.quality.*
    import org.gradle.api.plugins.scala.*
    import org.gradle.api.provider.*
    import org.gradle.api.publish.*
    import org.gradle.api.publish.ivy.*
    import org.gradle.api.publish.ivy.plugins.*
    import org.gradle.api.publish.ivy.tasks.*
    import org.gradle.api.publish.maven.*
    import org.gradle.api.publish.maven.plugins.*
    import org.gradle.api.publish.maven.tasks.*
    import org.gradle.api.publish.plugins.*
    import org.gradle.api.publish.tasks.*
    import org.gradle.api.reflect.*
    import org.gradle.api.reporting.*
    import org.gradle.api.reporting.components.*
    import org.gradle.api.reporting.dependencies.*
    import org.gradle.api.reporting.dependents.*
    import org.gradle.api.reporting.model.*
    import org.gradle.api.reporting.plugins.*
    import org.gradle.api.resources.*
    import org.gradle.api.services.*
    import org.gradle.api.specs.*
    import org.gradle.api.tasks.*
    import org.gradle.api.tasks.ant.*
    import org.gradle.api.tasks.application.*
    import org.gradle.api.tasks.bundling.*
    import org.gradle.api.tasks.compile.*
    import org.gradle.api.tasks.diagnostics.*
    import org.gradle.api.tasks.diagnostics.configurations.*
    import org.gradle.api.tasks.incremental.*
    import org.gradle.api.tasks.javadoc.*
    import org.gradle.api.tasks.options.*
    import org.gradle.api.tasks.scala.*
    import org.gradle.api.tasks.testing.*
    import org.gradle.api.tasks.testing.junit.*
    import org.gradle.api.tasks.testing.junitplatform.*
    import org.gradle.api.tasks.testing.testng.*
    import org.gradle.api.tasks.util.*
    import org.gradle.api.tasks.wrapper.*
    import org.gradle.api.toolchain.management.*
    import org.gradle.authentication.*
    import org.gradle.authentication.aws.*
    import org.gradle.authentication.http.*
    import org.gradle.build.event.*
    import org.gradle.buildinit.*
    import org.gradle.buildinit.plugins.*
    import org.gradle.buildinit.tasks.*
    import org.gradle.caching.*
    import org.gradle.caching.configuration.*
    import org.gradle.caching.http.*
    import org.gradle.caching.local.*
    import org.gradle.concurrent.*
    import org.gradle.external.javadoc.*
    import org.gradle.ide.visualstudio.*
    import org.gradle.ide.visualstudio.plugins.*
    import org.gradle.ide.visualstudio.tasks.*
    import org.gradle.ide.xcode.*
    import org.gradle.ide.xcode.plugins.*
    import org.gradle.ide.xcode.tasks.*
    import org.gradle.ivy.*
    import org.gradle.jvm.*
    import org.gradle.jvm.application.scripts.*
    import org.gradle.jvm.application.tasks.*
    import org.gradle.jvm.tasks.*
    import org.gradle.jvm.toolchain.*
    import org.gradle.language.*
    import org.gradle.language.assembler.*
    import org.gradle.language.assembler.plugins.*
    import org.gradle.language.assembler.tasks.*
    import org.gradle.language.base.*
    import org.gradle.language.base.artifact.*
    import org.gradle.language.base.compile.*
    import org.gradle.language.base.plugins.*
    import org.gradle.language.base.sources.*
    import org.gradle.language.c.*
    import org.gradle.language.c.plugins.*
    import org.gradle.language.c.tasks.*
    import org.gradle.language.cpp.*
    import org.gradle.language.cpp.plugins.*
    import org.gradle.language.cpp.tasks.*
    import org.gradle.language.java.artifact.*
    import org.gradle.language.jvm.tasks.*
    import org.gradle.language.nativeplatform.*
    import org.gradle.language.nativeplatform.tasks.*
    import org.gradle.language.objectivec.*
    import org.gradle.language.objectivec.plugins.*
    import org.gradle.language.objectivec.tasks.*
    import org.gradle.language.objectivecpp.*
    import org.gradle.language.objectivecpp.plugins.*
    import org.gradle.language.objectivecpp.tasks.*
    import org.gradle.language.plugins.*
    import org.gradle.language.rc.*
    import org.gradle.language.rc.plugins.*
    import org.gradle.language.rc.tasks.*
    import org.gradle.language.scala.tasks.*
    import org.gradle.language.swift.*
    import org.gradle.language.swift.plugins.*
    import org.gradle.language.swift.tasks.*
    import org.gradle.maven.*
    import org.gradle.model.*
    import org.gradle.nativeplatform.*
    import org.gradle.nativeplatform.platform.*
    import org.gradle.nativeplatform.plugins.*
    import org.gradle.nativeplatform.tasks.*
    import org.gradle.nativeplatform.test.*
    import org.gradle.nativeplatform.test.cpp.*
    import org.gradle.nativeplatform.test.cpp.plugins.*
    import org.gradle.nativeplatform.test.cunit.*
    import org.gradle.nativeplatform.test.cunit.plugins.*
    import org.gradle.nativeplatform.test.cunit.tasks.*
    import org.gradle.nativeplatform.test.googletest.*
    import org.gradle.nativeplatform.test.googletest.plugins.*
    import org.gradle.nativeplatform.test.plugins.*
    import org.gradle.nativeplatform.test.tasks.*
    import org.gradle.nativeplatform.test.xctest.*
    import org.gradle.nativeplatform.test.xctest.plugins.*
    import org.gradle.nativeplatform.test.xctest.tasks.*
    import org.gradle.nativeplatform.toolchain.*
    import org.gradle.nativeplatform.toolchain.plugins.*
    import org.gradle.normalization.*
    import org.gradle.platform.*
    import org.gradle.platform.base.*
    import org.gradle.platform.base.binary.*
    import org.gradle.platform.base.component.*
    import org.gradle.platform.base.plugins.*
    import org.gradle.plugin.devel.*
    import org.gradle.plugin.devel.plugins.*
    import org.gradle.plugin.devel.tasks.*
    import org.gradle.plugin.management.*
    import org.gradle.plugin.use.*
    import org.gradle.plugins.ear.*
    import org.gradle.plugins.ear.descriptor.*
    import org.gradle.plugins.ide.*
    import org.gradle.plugins.ide.api.*
    import org.gradle.plugins.ide.eclipse.*
    import org.gradle.plugins.ide.idea.*
    import org.gradle.plugins.signing.*
    import org.gradle.plugins.signing.signatory.*
    import org.gradle.plugins.signing.signatory.pgp.*
    import org.gradle.plugins.signing.type.*
    import org.gradle.plugins.signing.type.pgp.*
    import org.gradle.process.*
    import org.gradle.swiftpm.*
    import org.gradle.swiftpm.plugins.*
    import org.gradle.swiftpm.tasks.*
    import org.gradle.testing.base.*
    import org.gradle.testing.base.plugins.*
    import org.gradle.testing.jacoco.plugins.*
    import org.gradle.testing.jacoco.tasks.*
    import org.gradle.testing.jacoco.tasks.rules.*
    import org.gradle.testkit.runner.*
    import org.gradle.util.*
    import org.gradle.vcs.*
    import org.gradle.vcs.git.*
    import org.gradle.work.*
    import org.gradle.workers.*

## Groovy Script Variables

Groovy has two types of script variables:

- Variables declared with a type modifier or `def` are visible within closures but not visible within methods.

- Variables declared without a modifier are visible anywhere in the script.

Prefer declaring variables with `def` to make their scope explicit.

scope.groovy

    String localScope1 = 'localScope1'
    def localScope2 = 'localScope2'
    scriptScope = 'scriptScope'

    println localScope1
    println localScope2
    println scriptScope

    closure = {
        println localScope1
        println localScope2
        println scriptScope
    }

    def method() {
        try {
            localScope1
        } catch (MissingPropertyException e) {
            println 'localScope1NotAvailable'
        }
        try {
            localScope2
        } catch(MissingPropertyException e) {
            println 'localScope2NotAvailable'
        }
        println scriptScope
    }

    closure.call()
    method()

Output of `groovy scope.groovy`

    > groovy scope.groovy
    localScope1
    localScope2
    scriptScope
    localScope1
    localScope2
    scriptScope
    localScope1NotAvailable
    localScope2NotAvailable
    scriptScope

| For more information about Groovy syntax, see the Groovy documentation.