Build Type in Android development is a Gradle configuration that determines how the application is built: with or without debugging, with or without code optimization, and with which signing certificate. Android Gradle Plugin provides two standard Build Types — debug and release, and developers can add custom ones, such as staging or benchmark. According to Google Android Developers, 2025, proper Build Type configuration reduces APK size by up to 60% through minification and resource shrinking. Each Build Type is combined with Product Flavors to form a Build Variant.
Key Takeaways
Build Type is an element of Gradle configuration in Android projects that describes the compilation and packaging parameters of the application. Each Build Type is a named set of options: debuggable (enable debugging), minificationEnabled (enable code shrinking), shrinkResources (enable resource shrinking), proguardFiles (ProGuard rule files), signingConfig (signing certificate), and others. Build Types are declared in the android.buildTypes block of the build.gradle file of the app module.
The main purpose of Build Type is to separate development workflow (fast build, detailed logs, debugging) from production release (optimized code, minimal size, security). A debug build should compile in seconds and provide maximum information to the developer. A release build should be as fast and compact as possible for users. Build Type is an infrastructure setting, not related to the application's functionality.
Android Gradle Plugin automatically creates a source set for each Build Type — the src/<buildType>/ directory (e.g., src/debug/, src/release/). Resources, code and manifest files placed in this source set apply only to that build type. For example, src/debug/ can contain an AndroidManifest.xml with ADB installation permission, while src/release/ does not. The Build Type source set has priority over the Product Flavor source set.
The key difference: Build Type answers the question "how to build?", while Product Flavor answers "what to build?". Build Type can be debug, release, staging. Product Flavor can be free, paid, enterprise. Build Type does not change the application's functionality (it does not add or remove screens), Product Flavor does. Build Type can disable the debugger and enable obfuscation, Product Flavor can change applicationId and resources. Both work together: each Build Type is combined with each Product Flavor to form a Build Variant.
Debug is the default Build Type created by AGP. It has debuggable=true, allowing debugger attachment, viewing Log.d logs, and using the Android Studio profiler. Minification is disabled, so the build is fast. In a debug build, the applicationId gets the ".debug" suffix (if not overridden), allowing the debug version to be installed alongside the release version on the same device. The debug build is signed with a certificate from debug.keystore, which is automatically created by Android SDK.
Release is the Build Type for publishing the application. debuggable=false, minificationEnabled=true (by default), shrinkResources=true. The developer must specify a signingConfig with a production certificate — otherwise the build will not be considered a release build. The release build uses ProGuard or R8 for obfuscation, optimization and code shrinking. Android Studio cannot attach a debugger to a release build (if debuggable=false). All Log.d and Log.v calls are removed from the code during minification if the appropriate ProGuard rules are configured.
Important: debug builds do not test release behavior. Minification can change code behavior — reflection, serialization, Gson/SQLite, and other libraries often require ProGuard rules. Therefore, always build and test a release build before publishing. Google Play Console and Firebase Test Lab allow uploading release builds for automated testing on real devices before publishing.
android {
buildTypes {
debug {
debuggable true
minification false
signingConfig signingConfigs.debug
versionNameSuffix "-debug"
}
release {
debuggable false
minification true
shrinkResources true
proguardFiles "proguard-rules.pro"
signingConfig signingConfigs.release
ndk { abiFilters "arm64-v8a", "x86_64" }
}
}
}
In addition to debug and release, you can create custom Build Types — for example staging (intermediate environment) or benchmark (for performance testing). A custom Build Type is declared in the buildTypes block just like debug and release. The name can be anything, but it is recommended to use semantically clear names in English. For staging, debuggable=true is typically set (for diagnosing issues in the staging environment) and minification=true (to test obfuscation before production).
A custom Build Type automatically gets a corresponding source set (src/staging/) and generates tasks like assembleStaging. AGP does not impose limits on the number of custom types, but each new type multiplies the number of Build Variants. The practical limit is 4–5 Build Types: debug, staging, benchmark, release, and possibly debugMinified (debug with minification enabled for testing ProGuard rules).
For a custom Build Type, you can inherit debuggable from debug using initWith. The initWith keyword copies all parameters from the specified Build Type, after which they can be overridden. This is convenient for creating staging based on debug: initWith debug + additionally enable minification. Without initWith, you would have to manually list all parameters of the base type.
android {
buildTypes {
staging {
initWith debug
minification true
shrinkResources true
proguardFiles "staging-proguard-rules.pro"
versionNameSuffix "-staging"
}
benchmark {
initWith release
signingConfig signingConfigs.debug
matchingFallbacks = ["release"]
}
}
}
// matchingFallbacks — for libraries that do not have a benchmark type
// if the library only has release — AGP uses it
SigningConfig determines which certificate is used to sign the APK or AAB. Android requires all installable applications to be signed — without it, the system will not allow installation. For debug builds, AGP uses debug.keystore — a pre-installed certificate with a known password generated by Android SDK Tools. For release builds, you must create your own certificate through Android Studio (Build → Generate Signed Bundle/APK) or via the keytool command line.
Storing signing keys is a critical security concern. It is recommended not to store release keys in the source code repository. Instead, use a keystore.properties file (added to .gitignore), CI/CD environment variables, or Android Studio's encrypted storage. In CI/CD (GitHub Actions, GitLab CI), signing keys are stored in secrets and passed to build.gradle through system properties. Example: storePassword = System.getenv("KEYSTORE_PASSWORD").
Each Build Type can reference its own signingConfig. For release — a production certificate, for debug — debug.keystore, for staging — a separate staging certificate. The signing configuration directly affects the ability to install the application: if you sign debug with debug.keystore and staging with a production key, staging cannot be installed over the debug version due to mismatched signatures. The applicationId must also differ — use applicationIdSuffix for this.
android {
signingConfigs {
debug {
storeFile file("debug.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
release {
storeFile file("release-key.jks")
storePassword System.getenv("KEYSTORE_PASS")
keyAlias "my-key"
keyPassword System.getenv("KEY_PASS")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
Minification is the process of removing unused code and renaming classes, methods, and fields to short names. AGP performs minification using ProGuard (legacy) or R8 (recommended, built into AGP starting from version 3.4). R8 performs four operations: shrinking (removing unused classes), optimization (simplifying code), obfuscation (renaming), and preverify (adding compatibility information). The result is a smaller APK that is harder to decompile.
Minification rules are defined in ProGuard rules files — text files with syntax including -keep, -dontwarn, -keepclassmembers. Without rules, R8 will remove or rename classes used through reflection (Gson, Retrofit, Room, Kotlin serialization). The Android Studio project template creates a proguard-rules.pro file where rules for specific libraries are added. Libraries may also contain built-in rules — they are automatically included from jar/aar.
Shrink resources (shrinkResources=true) removes unused resources from the APK. R8 first determines which resources are not used in the code (checks R.java and manifest references), then removes them from the final build. For resources used through getIdentifier() or by third-party libraries, you need to add tools:keep="@layout/my_layout" in the resources. Combined with minification, resource shrinking can reduce APK size by 40–60%.
# proguard-rules.pro — mandatory rules
# Gson: keep classes for serialization
-keepclassmembers class com.example.** {
<fields>;
}
# Retrofit: keep API interfaces
-keep,allowobfuscation interface com.example.api.*
# Room: keep DAO and Entity
-keep class * extends androidx.room.RoomDatabase
-keep @interface androidx.room.** { *; }
# Kotlin Coroutines: prevent removal of Continuation
-keepnames class kotlinx.coroutines.internal.*
# OkHttp: preserve service loader
-keep class okhttp3.** { *; }
BuildConfig is an automatically generated Java/Kotlin class that contains constants defined in defaultConfig, productFlavors, and buildTypes. Using buildConfigField, you can add custom fields: buildConfigField "String", "API_URL", '"https://api.example.com"'. A BuildConfigField declared in a buildType is available in all variants of that type. Values in buildType override values from productFlavor, which in turn override defaultConfig.
For debug builds, it is convenient to set API_URL to localhost or a staging server, and for release — to production. BuildConfig.FLAVOR and BuildConfig.BUILD_TYPE are also generated automatically and contain the current flavor and build type names. In code, you can use: if (BuildConfig.DEBUG) { /* logs */ } — the DEBUG constant is true only for the debug build type. BuildConfig.DEBUG is a standard field that AGP adds to every BuildConfig.
Resources for Build Type are defined via the src/<buildType>/res/ source set. For example, src/debug/res/values/strings.xml can contain the string "Server: Dev", while src/release/res/ can contain "Server: Prod". Manifest resources are also overridden through the source set: src/debug/AndroidManifest.xml can include <uses-permission android:name="android.permission.INTERNET" /> only for debug builds. This is cleaner than checking BuildConfig in code and works even for attributes that cannot be set programmatically (such as networkSecurityConfig).
// src/debug/kotlin/.../DebugConfig.kt
object DebugConfig {
val apiUrl = "http://localhost:8080/api"
val enableLogging = true
val enableCrashReporting = false
}
// src/release/kotlin/.../ReleaseConfig.kt
object ReleaseConfig {
val apiUrl = "https://api.production.com/v2"
val enableLogging = false
val enableCrashReporting = true
}
// Usage: the main class loads Config via reflection
fun getConfig(): AppConfig = when (BuildConfig.BUILD_TYPE) {
"debug" -> DebugConfig
else -> ReleaseConfig
}
Frequently Asked Questions
Yes, create a custom Build Type like debugMinified with initWith debug and enable minification: debugMinified { initWith debug; minification true }. This is useful for testing ProGuard rules without building a full release version.
Run apksigner from Android SDK: apksigner verify --print-certs app-release.apk. If the certificate matches the one uploaded to Google Play Console, the signature is correct. You can also verify using jarsigner for older formats.
matchingFallbacks specifies which Build Type of a library to use if it does not have the required type. For example, if the app has a "staging" type but the library only has "release", AGP uses release for the library. It is specified as a list: matchingFallbacks = ["release", "debug"].
In ProGuard rules, use -keep for the library's classes. For example: -keep class com.some.library.** { *; }. To completely disable minification for all libraries, specify -dontobfuscate and -dontoptimize in proguard-rules.pro.
Build Type itself does not change minSdk or targetSdk. However, you can set minSdk for a specific Build Type: debug { minSdk 21 }. This is useful for debug builds — you can support only API 21+ to speed up building, while release builds use minSdk 26.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also