Gradle is an example of dependency based programming: you define tasks and dependencies between tasks. Gradle guarantees that these tasks execute in the order of their dependencies. Your build scripts and plugins configure this dependency graph. This page discusses the phases of the lifecycle Gradle passes through as it interprets those scripts. Additionally, this page explains how you can react to events of the lifecycle using notifications.

Task Graphs

Some build tools assemble a task graph as they execute tasks. Gradle builds the task graph before executing any task. With configuration avoidance, Gradle skips configuration for tasks that aren’t part of the current build.

Within each project, tasks form a Directed Acyclic Graph (DAG).

This diagram shows two example task graphs: one abstract and the other concrete. The diagram represents dependencies between tasks as arrows:

Example task graphs
Figure 1. Two examples of Gradle task graphs

Both plugins and your own build scripts contribute to the task graph via the task dependency mechanism.

Build Phases

A Gradle build has three distinct phases. Gradle runs these phases in order: first initialization, then configuration, and finally execution.

Initialization
  • Detects the settings file.

  • Evaluates the settings file to determine which projects and included builds participate in the build.

  • Creates a Project instance for every project.

Configuration
  • Evaluates the build scripts of every project participating in the build.

  • Creates a task graph for requested tasks.

Execution
  • Schedules and executes each of the selected tasks in the order of their dependencies.

Example

The following example shows which parts of settings and build files correspond to various build phases:

settings.gradle.kts
rootProject.name = "basic"
println("This is executed during the initialization phase.")
build.gradle.kts
println("This is executed during the configuration phase.")

tasks.register("configured") {
    println("This is also executed during the configuration phase, because :configured is used in the build.")
}

tasks.register("test") {
    doLast {
        println("This is executed during the execution phase.")
    }
}

tasks.register("testBoth") {
    doFirst {
        println("This is executed first during the execution phase.")
    }
    doLast {
        println("This is executed last during the execution phase.")
    }
    println("This is executed during the configuration phase as well, because :testBoth is used in the build.")
}
settings.gradle
rootProject.name = 'basic'
println 'This is executed during the initialization phase.'
build.gradle
println 'This is executed during the configuration phase.'

tasks.register('configured') {
    println 'This is also executed during the configuration phase, because :configured is used in the build.'
}

tasks.register('test') {
    doLast {
        println 'This is executed during the execution phase.'
    }
}

tasks.register('testBoth') {
	doFirst {
	  println 'This is executed first during the execution phase.'
	}
	doLast {
	  println 'This is executed last during the execution phase.'
	}
	println 'This is executed during the configuration phase as well, because :testBoth is used in the build.'
}

The following command configures and executes the test and testBoth tasks specified above. Because Gradle only configures requested tasks and their dependencies, the configured task never configures.

> gradle test testBoth
This is executed during the initialization phase.

> Configure project :
This is executed during the configuration phase.
This is executed during the configuration phase as well, because :testBoth is used in the build.

> Task :test
This is executed during the execution phase.

> Task :testBoth
This is executed first during the execution phase.
This is executed last during the execution phase.

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed
> gradle test testBoth
This is executed during the initialization phase.

> Configure project :
This is executed during the configuration phase.
This is executed during the configuration phase as well, because :testBoth is used in the build.

> Task :test
This is executed during the execution phase.

> Task :testBoth
This is executed first during the execution phase.
This is executed last during the execution phase.

BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 executed

Initialization

In the initialization phase, Gradle detects the set of projects and included builds participating in the build. Gradle first evaluates the settings file. Then, Gradle instantiates Project instances for each project.

Detect Settings File

When you run Gradle in a directory that contains a settings.gradle file, Gradle uses that settings.gradle file to initialize the build. You can run Gradle within any subproject of the build.[1] When you run Gradle in a directory that contains no settings.gradle file:

  1. Gradle looks for a settings.gradle(.kts) file in parent directories.

  2. If Gradle finds a settings.gradle(.kts) file, Gradle checks if the current project is part of the multi-project build. If so, Gradle builds as a multi-project.

  3. If Gradle does not find a settings.gradle(.kts) file, Gradle builds as a single project.

In the standard Gradle project layout, project paths match the physical subproject layout on disk. The automatic search for a settings file only works for multi-project builds with a standard project layout. To build projects that use a nonstandard layout, execute the build from the directory that contains settings.gradle(.kts).

Evaluate Settings File

During settings file evaluation, Gradle:

  • Adds libraries to your build script classpath.

  • Defines which included builds participate in a composite build.

  • Defines which projects participate in a multi-project build.

Gradle creates a Project for every project in the build. By default, each Project has a name equal to the name of its top level directory. Every project except the root project has a parent project. Any project may have child projects.

Configuration

In the configuration phase, Gradle adds tasks and other properties to the projects generated by the initialization phase. By the end of the configuration phase, Gradle has a complete task execution graph for the requested tasks.

Project Evaluation

During project evaluation, Gradle evaluates build scripts to build a task hierarchy within a Project. This hierarchy includes inputs, actions, and outputs for all tasks.

React to Project Evaluation

You can receive a notification immediately before and immediately after a project evaluates. These notifications work even when project evaluation fails. You can configure project evaluation notifications for all projects or a specific project. For example, you could use these notifications for:

  • additional configuration after applying all definitions in a build script

  • custom logging

  • custom profiling

The following example uses gradle.beforeProject() to add hasTests property to certain tests. Later, the example uses gradle.afterProject() to add a test task to each project where the hasTests property value is true:

build.gradle.kts
gradle.beforeProject {
    // Set a default value
    project.ext.set("hasTests", false)
}

gradle.afterProject {
    if (project.ext.has("hasTests") && project.ext.get("hasTests") as Boolean) {
        val projectString = project.toString()
        println("Adding test task to $projectString")
        tasks.register("test") {
            doLast {
                println("Running tests for $projectString")
            }
        }
    }
}
project-a.gradle.kts
extra["hasTests"] = true
build.gradle
gradle.beforeProject { project ->
    project.ext.set("hasTests", false)
}

gradle.afterProject { project ->
    if (project.ext.has("hasTests") && project.ext.get("hasTests") as Boolean) {
        def projectString = project.toString()
        println "Adding test task to $projectString"
        project.task('test') {
            doLast {
                println "Running tests for $projectString"
            }
        }
    }
}
project-a.gradle
hasTests = true
> gradle -q test
Adding test task to project ':project-a'
Running tests for project ':project-a'

To receive these events via a listener instead of a closure, add a ProjectEvaluationListener to a build’s Gradle instance.

Task Execution Graph Assembly

During project evaluation, Gradle assembles the task execution graph: a DAG representing the dependency relationships between tasks.

React to Task Execution Graph Assembly

You can receive a notification immediately after Gradle finishes populating a project’s task execution graph.

To receive these events, add a TaskExecutionGraphListener to a project’s TaskExecutionGraph.

Task Creation

During project evaluation, Gradle registers tasks and their configuration actions. The configuration actions define inputs, outputs, and actions for those tasks. They are evaluated if the task is part of the task graph for the requested tasks.

React to Task Creation

You can receive a notification immediately after Gradle adds a task to a project. For example, you could use these notifications to set some default values or methods.

The following example sets a srcDir value on each task in a project:

build.gradle.kts
tasks.whenTaskAdded {
    extra["srcDir"] = "src/main/java"
}

val a by tasks.registering

println("source dir is ${a.get().extra["srcDir"]}")
build.gradle
tasks.whenTaskAdded { task ->
    task.ext.srcDir = 'src/main/java'
}

tasks.register('a')

println "source dir is $a.srcDir"
> gradle -q a
source dir is src/main/java

To receive these events via a listener instead of a closure, add an Action to a TaskContainer.

Execution

In the execution phase, Gradle runs tasks. Gradle uses the task execution graphs generated by the configuration phase to determine which tasks to execute.

Task Execution

Task execution includes most of the work you normally associate with a build: downloading libraries, compiling code, reading inputs, and writing outputs.

React to Task Execution Notifications

Task execution events are not compatible with the configuration cache. You can use build services to receive information about task execution in a way compatible with the configuration cache.

You can receive a notification immediately before and after Gradle executes any task. These notifications work even when task execution fails. The following example logs the start and end of each task execution:

build.gradle.kts
tasks.register("ok")

tasks.register("broken") {
    dependsOn("ok")
    doLast {
        throw RuntimeException("broken")
    }
}

gradle.taskGraph.beforeTask {
    println("executing $this ...")
}

gradle.taskGraph.afterTask {
    if (state.failure != null) {
        println("FAILED")
    } else {
        println("done")
    }
}
build.gradle
tasks.register('ok')

tasks.register('broken') {
    dependsOn ok
    doLast {
        throw new RuntimeException('broken')
    }
}

gradle.taskGraph.beforeTask { Task task ->
    println "executing $task ..."
}

gradle.taskGraph.afterTask { Task task, TaskState state ->
    if (state.failure) {
        println "FAILED"
    }
    else {
        println "done"
    }
}
> gradle -q broken
executing task ':ok' ...
done
executing task ':broken' ...
FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':broken'.
> broken

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 0s
> gradle -q broken
executing task ':ok' ...
done
executing task ':broken' ...
FAILED

FAILURE: Build failed with an exception.

* Where:
Build file '/home/user/gradle/samples/build.gradle' line: 6

* What went wrong:
Execution failed for task ':broken'.
> broken

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 0s

To receive these events via a listener instead of a closure, add a TaskExecutionListener to a project’s TaskExecutionGraph.


1. Gradle supports partial multi-project builds (see Executing Multi-Project Builds).