Build Lifecycle
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:

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:
rootProject.name = "basic"
println("This is executed during the initialization phase.")
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.")
}
rootProject.name = 'basic'
println 'This is executed during the initialization phase.'
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:
-
Gradle looks for a
settings.gradle(.kts)
file in parent directories. -
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. -
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
:
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")
}
}
}
}
extra["hasTests"] = true
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"
}
}
}
}
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:
tasks.whenTaskAdded {
extra["srcDir"] = "src/main/java"
}
val a by tasks.registering
println("source dir is ${a.get().extra["srcDir"]}")
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:
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")
}
}
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.