Relationship Status of minSdk, compileSdk, targetSdk

Posted on 2026/02/13

It is year 2026 and yet Android developers continue to be mystified about minSdk, compileSdk, and targetSdk. There are some myths and false claims floating in the community that I would like to clear up.

minSdk represents the oldest version of Android your application or library wants to support. For example, if you only want to support Android Marshmallow (API 23) and newer, you set your minSdk { version = release(23) }. This informs build tools such as R8 on what code optimizations are safe to make and Android Lint on what API level your code will run on, so NewApi checks can work correctly. Generally minSdk <= compileSdk. minSdk has no relationship to targetSdk. Bumping minSdk version does not generally force any tooling upgrades for library consumers, but they might be forced to bump their application minSdk version.

compileSdk represents the version of Android APIs you want to be able to use in your application or library. Android APIs are generally additive, but in some rare cases we remove APIs, for example android.hardware.fingerprint.FingerprintManager that was removed in API 36. This additive property means that if you pick a compileSdk { version = release(36) } then you have access to APIs added in 36 and all the previous versions of Android (except for removals). compileSdk used for an application has no effect on the runtime behavior of this application, in other words if you build your app with compileSdk 35 vs 36 your application will behave in the exact same way. compileSdk has no direct relationship with targetSdk besides the fact that new APIs and new behaviors in the OS used to ship at the same cadence. However, even this is no longer true, as minor SDK releases (e.g. 36.1) have no behavior changes and thus no matching targetSdk. Bumping compileSdk version forces library consumers to upgrade their Android Gradle Plugin version (compileSdk to minimum AGP version mapping) as new SDK releases frequently come with changes that are not compatible with old tools.

targetSdk represents the version the Android runtime behavior of your application. As Android evolves, we try very hard to avoid breaking existing applications already in the Play Store and as a result we sometimes gate runtime behavior changes behind an explicit opt-in by the application and this mechanism is targetSdk. When your application goes from targetSdk { version = release(35) } to targetSdk { version = release(36) } you are telling the OS that you acknowledge that your app will now get the new behaviors. As noted above, there is no relationship with between targetSdk and compileSdk or targetSdk and minSdk, namely your targetSdk can be a higher number than compileSdk and that is a completely reasonable state if you are happy with the new runtime behaviors and no access to the APIs. targetSdk has no meaning for a library, because only the final value set by the application has impact on the behavior. However, in a library case, you want to set lint.targetSdk and testOptions.targetSdk to the latest API version to make sure that your library behaves correctly when the consumers pick that version in their application.

Why might you change one of these values?

minSdk - either your team no longer cares about supporting old Android versions or a library you depend on no longer does and forces you to change your minSdk version. For example, AndroidX libraries moved from minSdk 21 to 23 in 2025.

compileSdk - either your team wants access to new shiny Android APIs or a library you depend on does and forces you to change your compileSdk version. For example, androidx.compose adopted compileSdk 35 in 2025.

targetSdk - either your team wants a new runtime behavior or Google Play Store is no longer allowing you to publish an application targeting that targetSdk. Libraries have no effect on your targetSdk version.