How do AGP build types, flavors, and variants relate to Gradle core concepts like source sets, configurations, and tasks?
answer
- Gradle core: source sets, configurations, tasks
- AGP: types/flavors/variants on top
- <variant>Implementation extendsFrom implementation+flavor+type
- AGP variant ≠ Gradle component variant
- BuildTypeAttr attribute matches lib to app
basics
~10 sBuild types, flavors, and variants are AGP-only abstractions. AGP implements them by generating Gradle source sets, dependency configurations (like <variant>Implementation), and tasks (assemble<Variant>) — Gradle core itself has no variant concept.
solid answer
~40 sGradle core knows only **source sets, configurations, tasks, and the dependency graph**. AGP layers an Android-specific model on top: a *build type* (how) and a *product flavor* (what) combine into a *variant*, the real build unit. AGP realizes each variant by generating: a chain of Gradle **source sets** that merge (`main` → flavors → buildType → combo); per-variant **configurations** such as `freeDebugImplementation` (extending `implementation`); and a per-variant **task graph** (`compileFreeDebug…`, `mergeFreeDebugResources`, `assembleFreeDebug`). So when you write `paidImplementation(...)`, you're using a Gradle configuration AGP created for you. The interview point: variants/flavors/buildTypes are *not* Gradle primitives — they're AGP DSL that compiles down to Gradle primitives. For depth on the variant lifecycle, the manifest merger, or R8, you bridge out to the Android/AGP docs; Gradle docs won't cover them.
code
kotlin · 7 lines// 'paidDebugImplementation' is a Gradle Configuration AGP generated.
// You can inspect the extension chain:
configurations.matching { it.name == "paidDebugImplementation" }
.configureEach {
println(extendsFrom.map { it.name })
// -> [implementation, paidImplementation, debugImplementation]
}go deeper
Just know variants/flavors/types are Android-specific, not plain Gradle.
Map each AGP concept to its generated source set, configuration, and task.
Explain the extendsFrom chain, disambiguate AGP build variant vs Gradle component variant, and know where the doc/debug boundary lies.
Reason about how attribute-based variant publishing (BuildTypeAttr) lets multi-module/library ecosystems resolve matching artifacts, and standardize the abstraction boundary across teams.
## The two layers There's a clean separation worth holding in your head: **Gradle core primitives** (project-type agnostic): - *Source sets* — named groups of inputs (sources, resources). - *Configurations* — buckets of dependencies with roles (`resolvable`, `consumable`, declarable), e.g. `implementation`, `api`. - *Tasks* — units of work in the DAG. - *Attributes & variants-of-a-component* — Gradle's own notion of component variants for dependency resolution (distinct from AGP build variants!). **AGP abstractions** (Android only), all defined under the `android { }` extension: - *Build type* (how) and *product flavor* (what) → combine into an *AGP build variant*. ## How AGP maps onto Gradle core For a project with flavors `free`/`paid` and types `debug`/`release`, AGP generates: | AGP concept | Gradle-core realization | |---|---| | build type `debug` | source set `src/debug`, config `debugImplementation`, suffix in tasks | | flavor `free` | source set `src/free`, config `freeImplementation` | | variant `freeDebug` | merged source-set chain, config `freeDebugImplementation`, tasks `compileFreeDebugKotlin`, `mergeFreeDebugResources`, `assembleFreeDebug` | So `freeDebugImplementation` is just a normal Gradle `Configuration` that `extendsFrom` `implementation` + `freeImplementation` + `debugImplementation`. The `assembleFreeDebug` task is a normal Gradle `Task`. Nothing here is magic at the Gradle level — AGP is *registering* these via the same `tasks.register`, `configurations.create`, source-set APIs any plugin uses. ## A subtle naming collision Gradle has its **own** word "variant" — the *variant of a published component* used during dependency resolution (selected via attributes like `org.gradle.usage`). AGP's **build variant** is a different thing. Senior candidates should disambiguate: AGP build variants are about which app you assemble; Gradle component variants are about which artifact/configuration a consumer resolves. AGP actually *does* publish Gradle variants (with attributes like `com.android.build.api.attributes.BuildTypeAttr`) so that an app consuming an Android library picks the matching `debug`/`release` artifact — that's the bridge between the two worlds. ## Why the boundary matters Knowing the boundary tells you *where to debug*: a missing `paidImplementation` dependency is a Gradle configuration issue; a manifest-merge conflict or resource overlay is AGP behavior. It also tells you *which docs to read*. This leaf is an **overview** — for the AGP variant lifecycle, manifest merger, or resource merge order, bridge to the Android/AGP documentation.
- Is an AGP build variant the same as a Gradle component variant?No. A Gradle component variant is a publishable configuration selected via attributes during dependency resolution. An AGP build variant is a buildable app combination. AGP does map build types onto Gradle attributes (BuildTypeAttr) so a consuming app resolves the matching library artifact.
- Where does `freeDebugImplementation` come from?AGP creates it as a Gradle Configuration that extendsFrom `implementation`, `freeImplementation`, and `debugImplementation`, so variant-specific deps merge correctly.
- If a resource overlay isn't applying, is that a Gradle or AGP problem?AGP — resource merging/overlay priority across source sets is AGP behavior; you'd consult the AGP docs, not Gradle core.
Gradle core is the alphabet (source sets, configs, tasks); AGP build variants are words spelled from those letters. New words, same letters.
saying these in an interview costs you the question
- Calling build types/flavors Gradle-core features
- Conflating AGP build variants with Gradle component variants
- Assuming you must hand-create the `<variant>Implementation` configurations