Android applications are typically built using the [Gradle](https://gradle.org/) build
system. Before we dive into the details of how to configure your build, we'll
explore the concepts behind the build so you can see the system as a whole.

## What is a build?

A build system transforms your source code into an executable application.
Builds often involve multiple tools, to analyze, compile, link, and package your
application or library. Gradle uses a task-based approach to organize and run
these commands.

[Tasks](https://docs.gradle.org/current/userguide/more_about_tasks.html) encapsulate commands that translate their inputs into
outputs. [Plugins](https://docs.gradle.org/current/userguide/custom_plugins.html) define tasks and their configuration. Applying
a plugin to your build registers its tasks, and wires them together using their
inputs and outputs. For example, applying the [Android Gradle Plugin](https://developer.android.com/build/releases/gradle-plugin) (AGP)
to your build file will register all the tasks necessary to build an APK, or an
Android Library. The `java-library` plugin lets you build a jar from Java source
code. Similar plugins exist for Kotlin, and other languages, but other plugins
are meant to extend plugins. For example, the `protobuf` plugin is meant to add
protobuf support to existing plugins like AGP or `java-library`.

Gradle prefers convention over configuration so plugins will come with good
default values out of the box, but you can further configure the build through a
declarative [Domain-Specific Language](https://docs.gradle.org/current/dsl) (DSL). The DSL is designed
so you can specify *what* to build, rather than *how* to build it. The logic in
the plugins manages the "how". That configuration is specified across several
[build files](https://developer.android.com/build/android-build-structure) in your [project](https://docs.gradle.org/current/userguide/multi_project_builds.html) (and subprojects).

Task inputs can be files and directories as well as other information encoded as
Java types (integer, strings, or custom classes). Outputs can only be directory
or files as they have to be written on disk. Wiring a task output into another
task input, links the tasks together so that one has to run before the other.

While Gradle supports writing arbitrary code and task declarations in your build
files, this can make it more difficult for tooling to understand your build and
for you to maintain. For example, you can write tests for code inside plugins
but not in build files. Instead, you should restrict build logic and task
declarations to plugins (that you or someone else define) and declare how you
want to use that logic in your build files.

## What happens when a Gradle build runs?

Gradle builds run in three phases. Each of these phases executes different parts
of code that you define in your build files.

- **Initialization** determines which projects and subprojects are included in the build, and sets up classpaths containing your build files and applied plugins. This phase focuses on a settings file where you declare projects to build and the locations from which to fetch plugins and libraries.
- **Configuration** registers tasks for each project, and executes the build file to apply the user's build specification. It's important to understand that your configuration code won't have access to data or files produced during execution.
- **Execution** performs the actual "building" of your application. The output of configuration is a [Directed Acyclic Graph](https://en.wikipedia.org/wiki/Directed_acyclic_graph) (DAG) of tasks, representing all required build steps that were requested by the user (the tasks provided on the command line or as defaults in the build files). This graph represents the relationship between tasks, either explicit in a task's declaration, or based on its inputs and outputs. If a task has an input that is the output of another task, then it must run after the other task. This phase runs out-of-date tasks in the order defined in the graph; if a task's inputs haven't changed since its last execution, Gradle will skip it.

For more information see the Gradle [Build lifecycle](https://docs.gradle.org/current/userguide/build_lifecycle.html).

## Configuration DSLs

Gradle uses a [Domain-Specific Language](https://docs.gradle.org/current/dsl) (DSL) to configure
builds. This declarative approach focuses on specifying your data rather than
writing step-by-step (imperative) instructions. You can write your build files
using Kotlin or Groovy, but we strongly recommend using Kotlin.

DSLs attempt to make it easier for everyone, domain experts and programmers, to
contribute to a project, defining a small language that represents data in a
more natural way. Gradle plugins can extend the DSL to configure the data they
need for their tasks.

For example, configuring the Android part of your build might look like:  

### Kotlin

```kotlin
android {
    namespace = "com.example.app"
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}
```

### Groovy

```groovy
android {
    namespace = 'com.example.app'
    compileSdk {
        version = release(36) {
            minorApiLevel = 1
        }
    }
    // ...

    defaultConfig {
        applicationId = 'com.example.app'
        minSdk {
            version = release(23)
        }
        targetSdk {
            version = release(36)
        }
        // ...
    }
}
```

Behind the scenes, the DSL code is similar to:  

    fun Project.android(configure: ApplicationExtension.() -> Unit) {
        ...
    }

    interface ApplicationExtension {
        var namespace: String?

        fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
            ...
        }

        val defaultConfig: DefaultConfig

        fun defaultConfig(configure: DefaultConfig.() -> Unit) {
            ...
        }
    }

Each block in the DSL is represented by a function that takes a lambda to
configure it, and a property with the same name to access it. This makes the
code in your build files feel more like a data specification.
| **Note:** If you're interested in the details that make this work in Kotlin, see [Type-safe builders](https://kotlinlang.org/docs/type-safe-builders.html). For more details on DSLs in general, see the book [Domain Specific Languages](https://martinfowler.com/books/dsl.html), by Martin Fowler and Rebecca Parsons.

## External dependencies

The Maven build system introduced a [dependency](https://docs.gradle.org/current/userguide/declaring_dependencies.html) specification,
storage and management system. Libraries are stored in
[repositories](https://docs.gradle.org/current/userguide/declaring_repositories.html) (servers or directories), with metadata including
their version and dependencies on other libraries. You specify which
repositories to search, versions of the dependencies you want to use, and the
build system downloads them during the build.

Maven Artifacts are identified by group name (company, developer, etc), artifact
name (the name of the library) and version of that artifact. This is typically
represented as `group:artifact:version`.

This approach significantly improves build management. You'll often hear such
repositories called "Maven repositories", but it's all about the way the
artifacts are packaged and published. These repositories and metadata have been
reused in several build systems, including Gradle (and Gradle can publish to
these repositories). Public repositories allow sharing for all to use, and
company repositories keep internal dependencies in-house.

You can also [modularize](https://developer.android.com/topic/modularization) your project into [subprojects](https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:creating_multi_project_builds)
(also known as "modules" in Android Studio), which can also be used as
dependencies. Each subproject produces outputs (such as jars) that can be
consumed by subprojects or your top-level project. This can improve build time
by isolating which parts need to be rebuilt, as well as better separate
responsibilities in the application.

We'll go into more detail on how to specify dependencies in [Add build
dependencies](https://developer.android.com/build/dependencies).

## Build variants

When you create an Android application, you'll typically want to build multiple
[variants](https://developer.android.com/build/build-variants). Variants contain different code or are built with different
options, and are composed of build types and product flavors.

[Build types](https://developer.android.com/build/build-variants#build-types) vary declared build options. By default, AGP sets up "release"
and "debug" build types, but you can adjust them and add more (perhaps for
staging or internal testing).

A debug build doesn't minify or obfuscate your application, speeding up its
build and preserving all symbols as is. It also marks the application as
"debuggable", signing it with a generic debug key and enabling access to the
installed application files on the device. This makes it possible to explore
saved data in files and databases while running the application.

A release build optimizes the application, signs it with your release key, and
protects the installed application files.

Using [product flavors](https://developer.android.com/build/build-variants#product-flavors), you can change the included source and [dependency
variants](https://developer.android.com/build/build-variants#variant_aware) for the application. For example, you may want to create "demo"
and "full" flavors for your application, or perhaps "free" and "paid" flavors.
You write your common source in a "main" [source set](https://developer.android.com/build/build-variants#sourcesets) directory, and
override or add source in a source set named after the flavor.

AGP creates variants for each combination of build type and product flavor. If
you don't define flavors, the variants are named after the build types. If you
define both, the variant is named `<flavor><Buildtype>`. For example, with build
types `release` and `debug`, and flavors `demo` and `full`, AGP will create
variants:

- `demoRelease`
- `demoDebug`
- `fullRelease`
- `fullDebug`

## Next steps

Now that you've seen the build concepts, take a look at the [Android build
structure](https://developer.android.com/build/android-build-structure) in your project.