Android Build Variants: One Codebase, Many Apps

Think of build variants as a matrix for your app builds, combining build types (like debug/release) with product flavors (like free/paid). This lets you manage different API endpoints or features for various versions from a single codebase.
WHY IT EXISTS: Apps often need multiple versions. You need a debug version for development and a release version for the Play Store. You might also have a free version with ads and a paid version without. Managing these as separate projects would be a nightmare of copy-pasting code. Build variants solve this by letting you define these differences within a single project.
THE MENTAL MODEL: A build variant is the result of a cross-product. Imagine a grid: the rows are your Build Types (e.g., 'debug', 'release'), and the columns are your Product Flavors (e.g., 'demo', 'full'). Each cell in that grid, like 'demoDebug' or 'fullRelease', is a unique build variant you can assemble and run. This lets you mix and match packaging rules with feature sets.
HOW IT WORKS: In your app's build.gradle file, you define buildTypes and productFlavors. Gradle then automatically creates variants for every possible combination. For each variant, you can provide specific code or resources (like layouts, strings, or icons) in dedicated source sets, such as src/demo/java or src/release/res/values. When you build a specific variant, Gradle intelligently merges the code and resources from the main, build type, and product flavor source sets.
WHEN TO USE IT: Use build variants when you need to produce different versions of your app from one codebase. This is ideal for managing environments (development, staging, production), monetization strategies (free vs. paid), or white-labeling (custom branding for different clients). It centralizes configuration and prevents code duplication.
WHEN NOT TO USE IT: Avoid creating too many product flavors or build types. If you have 3 build types and 10 product flavors, you get 30 variants. This significantly slows down Gradle project sync and can make the project difficult to navigate. For very distinct apps that share little logic, separate modules or even separate projects might be a cleaner approach.
ONE CANONICAL EXAMPLE: A common setup is having debug and release build types. You then add product flavors for staging and production. The staging flavor points to a test backend URL, while the production flavor points to the live one. This results in four variants: stagingDebug, stagingRelease, productionDebug, and productionRelease. A developer can easily build stagingDebug to test new features against the test server without affecting the production app.
Read the original → developer.android.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.