Upgrading your dependencies gives you access to their latest features, bug fixes, and improvements. To upgrade your dependencies, you need to understand how Gradle resolves the versions you request, the risks that are involved, and steps you can take to mitigate those risks.
Consider your upgrade strategy
The most important step to any upgrade is risk analysis. Determine how comfortable you are with each dependency you upgrade. There are many considerations when defining your upgrade strategy, including:
Build a library |
Are you building an application that users download and run on a device? Or are you building a library to assist other developers build their applications? If you're building an application, your focus should be keeping your application up-to-date and stable. If you're building a library, your focus should be on other developers' applications. Your upgrades affect your consumers. If you upgrade one of your dependencies, that version becomes a candidate for Gradle's dependency resolution, possibly breaking the application's use of that dependency. First - minimize your library's dependencies where possible. The fewer dependencies you have, the lower the impact on your consumer's dependency resolution. Be sure to follow semantic versioning to help indicate the types of changes you're making. For example, AndroidX follows semantic versioning and adds a pre-release versioning scheme. Try to avoid Consider creating a release-candidate (RC) of your library for users to test early. See Backward compatibility guidelines for library authors for details on keeping your library's Application Binary Interface (ABI) compatible. Use integration tests and tools like Binary compatibility validator to ensure your ABI changes match your intended version change. If you release fixes in a If your library upgrade requires breaking changes that may be particularly painful for your consumers, consider releasing them as a new artifact so the old and new versions can coexist and allow a more gradual rollout. Note: If an upgrade to one of your dependencies contains a major API change, you'll probably want to upgrade it in a |
Release cycle |
How often do you release your application or library? Shorter development and release cycles
Longer development and release cycles
|
Keep up with the latest features |
Do you prefer to use the latest available features and APIs, or only upgrade when you need a feature or bug fix? Consider the tradeoffs of frequent upgrades. Future upgrades are easier (fewer changes to integrate), but you're taking upgrade risks more often. Testing upgrades to pre-release (alpha, beta, release candidate) versions of libraries can help readiness when stable releases are available. |
New dependency |
If you're adding a new dependency, consider a strong review process that examines that library for all risk criteria to ensure they have been properly evaluated. Don't allow new dependencies to be added without review. |
Dedicated team |
Do you have a dedicated build team? Do your software engineers maintain the build? A dedicated team often can spend more time analyzing upgrade risks and testing out new versions to ensure the build works properly before engineers use the new versions. |
Type of upgrade |
Some upgrades are more important than others. Think about which are most important to you. Build tool upgrades, such as Gradle and Gradle plugins, typically have lower impact to your users, and much of the risk is internal to your build. The build itself helps validate these changes. Library and SDK upgrades are more difficult to validate, and they present a higher risk to your users. Android Gradle Plugin (AGP) — the tooling used to build your Android application or library. This is the most critical upgrade you can make, as it often includes or enables performance improvements, bug fixes, new lint rules, and support for new Android platform versions. Gradle — you'll often need to upgrade Gradle when you upgrade AGP or another Gradle plugin. Other Gradle plugins — Sometimes Gradle's plugin API changes. When you upgrade Gradle, check for upgrades to plugins that you use. Kotlin and Java — Some libraries and plugins require minimum versions of Kotlin or Java, or you want to take advantage of new language features, APIs, or performance improvements. Android Platform — Play Store requires regular Android SDK upgrades. You should test new versions of the Android SDK as soon as possible. Some SDK upgrades require changes to your application, such as new permissions or use of new APIs. Libraries — Do you want to prioritize libraries based on their closeness to your overall architecture?
Android Studio — keeping Android Studio up to date gives you access to the latest features and bug fixes in the underlying IntelliJ IDEA platform and tools to work with the latest Android SDKs. |
Available tooling |
There are many tools and plugins available to assist with your upgrades. Tools like Dependabot and Renovate automatically upgrade library versions in your build, but be sure to analyze the results to check for risks. |
Strategies for specific types of upgrades
Upgrading some types of dependencies might have a cascading effect, requiring other types of dependencies to be upgraded. We discuss relationships between build elements in Tool and library interdependencies.
When upgrading each type of component, consider how the upgrade impacts other components in the build.
Android Gradle Plugin (AGP) |
Android Studio includes an AGP upgrade assistant that can assist with these tasks. If you use the assistant or perform the upgrade manually, consider the following: Look at the AGP release notes. Upgrade Gradle to at least the version listed. Upgrade Android Studio to a version that supports the chosen AGP version. Use versions of Android Studio and AGP that support the Android SDK you want to use. Check compatibility with SDK Build Tools, NDK, and JDK. If you develop a Gradle plugin (for internal or public use) that extends or uses data from AGP, check whether you need to upgrade your plugin. Sometimes AGP deprecates and later removes APIs, causing incompatibilities with previous plugins. |
Kotlin compiler, language and runtime |
Check the Kotlin release notes for known issues and incompatibilities. If you use Jetpack Compose:
If you use Kotlin Symbol Processing (KSP), see KSP Quickstart for setup and KSP Releases for available versions. Note that you must use a version of KSP that matches the Kotlin version. For example, if you're using Kotlin 2.0.21, you can use any version of the KSP plugin that starts with 2.0.21, such as 2.0.21-1.0.25. You usually won't need to upgrade the KSP processors (such as the Room compiler, which appears as a Upgrade all other Kotlin Compiler Plugins that you're using. The Kotlin Compiler Plugin API often changes between releases, and the plugins must use a compatible API. If the plugin is listed in Compiler plugins, you must use the same version as the Kotlin compiler. For any other compile plugins, check their documentation for the appropriate mapping. Note that compiler plugins that are not maintained alongside the Kotlin compiler itself often experience release delays as they wait for the compiler plugin API to stabilize. Before upgrading Kotlin, check that all compiler plugins you use have matching upgrades available. Finally, on some occasions, the Kotlin language changes, requiring you to update your code. This most often happens if you're trying out experimental features. If your code doesn't build properly after upgrading the Kotlin compiler, check for language changes or runtime library breakage in the Kotlin release notes. |
Kotlin Compiler Plugins |
If you need to upgrade a Kotlin compiler plugin, upgrade to the matching version of Kotlin being used. Most Kotlin compiler plugins either use the same version as the Kotlin compiler, or they start with the required version of the Kotlin compiler. For example, if the plugin version is 2.0.21-1.0.25, you must use version 2.0.21 of the Kotlin compiler. Changing the Kotlin compiler version sometimes requires other changes. |
Libraries |
Libraries are the most commonly upgraded dependency in your build. You'll see available upgrades in the Android Studio editor, or if you use some dependency tools and plugins. Some libraries specify a minimum Some libraries also specify a minimum Kotlin version for use. Update the version of Kotlin in your build files to be at least the specified version. |
Gradle |
Sometimes new versions of Gradle deprecate existing APIs, removing those APIs in a future release. If you develop a Gradle plugin, upgrade your plugin as soon as possible, especially if that plugin is public. Some Gradle upgrades require locating new versions of plugins that you use. Note that these plugins can lag in their development as they upgrade the plugins to match the latest Gradle plugin APIs. To upgrade Gradle:
|
Gradle plugins |
Upgraded Gradle plugins sometimes use new or changed Gradle APIs, which in turn require a Gradle upgrade or possibly changes to their configuration in your build files. In either case, you'll see build warnings or errors to indicate incompatibility. Whenever upgrading plugins, upgrade Gradle. |
Android SDK |
Android Studio includes an Android SDK upgrade assistant that can help with these tasks. If you use the assistant or perform the upgrade manually, consider the following: Each release of the Android SDK contains new features and APIs, bug fixes and behavior changes. The Play Store requires updating your Before upgrading the Android SDK, carefully read the release notes. Pay close attention to the behavior changes section, which includes:
The behavior changes section can be quite long, but pay close attention as it often contains critical changes you need to make to your application. You must upgrade To take advantage of new SDK features during development and ensure compatibility during your build, upgrade the Android Gradle plugin (AGP) and Android Studio. These include new and improved tools for new SDKs. See Minimum versions of tools for Android API level. When upgrading the Android SDK, upgrade any AndroidX libraries that you use. AndroidX often uses new and updated APIs for better compatibility and performance across Android SDK versions. |
Android Studio |
You can generally upgrade Android Studio at any time. You might see messages prompting you to upgrade AGP or upgrade the Android SDK. These upgrades are strongly recommended but not required. If you later want to use Android Studio to upgrade AGP or the Android SDK, you can find these options on the Tools menu: |
Java |
If you have Java source code in your Android application, you may want to take advantage of newer Java APIs. Each Android SDK version supports a subset of Java APIs and language features. AGP provides compatibility for lower Android SDK versions using a process called desugaring. Android SDK release notes specify which Java level is supported and potential issues. Some of these issues may impact Kotlin source code as well, because Kotlin has access to the same Java APIs. Be sure to pay close attention to JDK API sections that appear in the behavioral changes section of the release notes, even if you have no Java source code. JDK usage is specified in several places in your build scripts. See Java versions in Android build for more information. |
Upgrade analysis
Upgrading a dependency can introduce risks in the form of API and behavior changes, new requirements for use, new security issues, or even license changes. For example, do you need to:
- Change code for API changes?
- Add new permission checks?
- Create additional tests or modify existing tests for behavior changes?
Consider that the dependency you've upgraded has upgraded the versions of its dependencies. This can quickly spider into a massive set of changes.
If you use a tool such as Renovate or Dependabot to automate your upgrades, be aware that they don't do any analysis for you; they upgrade to the latest library versions. Don't assume that everything will work properly after these types of automatic upgrades.
The key to successful upgrades is upgrade analysis:
- Determine dependency differences from before and after your upgrades.
- Examine each change and determine the risks involved.
- Mitigate risks, or accept or reject changes.
Determine dependency differences
The first step in your upgrade analysis is to determine how your dependencies change. Take advantage of version control (VCS, such as Git) and the Dependency Guard plugin to quickly see changes. Your goal is to create a before and after snapshot and compare them.
Set up and create your first baseline
Before starting your upgrade, make sure your project builds successfully.
Ideally, resolve as many warnings as possible, or create baselines to track which warnings you've already seen.
- Lint: Examine your existing lint warnings and create an Android lint baseline.
- Kotlin compiler:
- Enable
-Werror
to treat all warnings as errors. See How to define options. - Consider using plugins such as Kotlin Warning Baseline or Kotlin Warnings Baseline Generator.
- Enable
- Other tools: If you use other static analysis tools (like Detekt) that support baseline tracking, set up their baselines.
These warning baselines make it easier to see new warnings introduced as you upgrade your dependencies.
Create a dependency baseline by setting up and running Dependency Guard. In your gradle/libs.versions.toml version catalog, add:
[versions]
dependencyGuard = "0.5.0"
[plugins]
dependency-guard = { id = "com.dropbox.dependency-guard", version.ref = "dependencyGuard" }
And add the following to your app's build file:
Kotlin
plugins { alias(libs.plugins.dependency.guard) } dependencyGuard { configuration("releaseRuntimeClasspath") }
Groovy
plugins { alias(libs.plugins.dependency.guard) } dependencyGuard { configuration('releaseRuntimeClasspath') }
The releaseRuntimeClasspath
configuration is a likely target, but if you want
to use a different configuration, run ./gradlew dependencyGuard
without a
listed configuration in your build file to see all available configurations.
After setup, run ./gradlew dependencyGuard
to generate a report in
app/dependencies/releaseRuntimeClasspath.txt
. This is your baseline report.
Commit this to your version control system (VCS) to save it.
Keep in mind that Dependency Guard only captures the list of library dependencies. There are other dependencies in your build files, like the Android SDK and JDK versions. Committing to your VCS before your dependency changes allows your VCS diff to highlight those changes as well.
Upgrade and compare against your baseline
Once you have a baseline, upgrade dependencies and other build changes you wanted to test. Don't upgrade your source code or resources at this point.
Run ./gradlew lint
to see new lint warnings or errors. Address any important
issues and then update your warning baseline by running ./gradlew lint
-Dlint.baselines.continue=true
. If you have used other tools to capture warning
baselines, such as Kotlin Warning Baseline or Kotlin Warnings
Baseline Generator, address new warnings and update
their baselines as well.
Run ./gradlew dependencyGuard
to update your baseline report. Then run your
VCS diff to see nonlibrary changes. It's likely to include many more library
upgrades than you thought.
Analyze risks
Once you know what has changed, consider the possible risks of each upgraded library. This helps focus your testing or deeper investigation of changes. Define a set of risks to analyze for your project to ensure consistent analysis.
Some considerations:
Major version bumps |
Did the major version number change? When you see this, pay extra attention to the affected libraries when looking at any of the following considerations. If your code uses any experimental APIs (which often require you to opt-in using annotations or build-file specifications), even minor or patch version changes, such as upgrading from 1.2.3 to 1.3.1 or 1.2.3 to 1.2.5, might present additional risks. |
Nonstable API |
Some library releases may include nonstable APIs. These are usually APIs that are works in progress or depend on another unstable API. While typically limited to previews, such as alpha, dev, or experimental releases, some libraries include APIs marked experimental or unstable. If possible, avoid such APIs. If you need to use them, be sure to record your usage and watch for changes or removals in later releases. |
Dynamic behavior |
Some libraries behave differently based on external factors. For example, a library that communicates with a server depends on changes in that server.
|
Manifest merging |
Libraries published as Android Archives (AARs) can contain resources and manifests that are merged into your application. These can add new permissions and Android components, such as activities or broadcast receivers, that run indirectly. |
Runtime updates |
Some libraries use features that can be updated outside your application's control. A library might use Play Services, which is upgraded independently of the Android SDK. Other libraries may bind to services in independently updated external applications (often using AIDL). |
How many versions are you skipping? |
The longer you wait to upgrade a library, the more potential risks. If you see a version changing significantly, such as 1.2.3 to 1.34.5, pay extra attention to this library. |
Migration guides |
Check whether the library has a migration guide. This can significantly reduce your risk analysis and mitigation planning. Note that the presence of such a guide is a good indicator that the developer has focused on compatibility and considered your upgrade mitigation. |
Release notes |
See the release notes (if provided) for each changed library. Look for indications of breaking changes or new requirements, such as added permissions. |
READMEs |
Some README files for a library note potential risks, especially if the library doesn't provide release notes. Look for _known issues_, especially known security concerns. |
Check known vulnerabilities |
The Play SDK Index tracks vulnerabilities for many popular SDKs. The Play Console reports whether you use one of the listed SDKs with known vulnerabilities. When editing build files in Android Studio, the IDE checks the SDK index and flags use of vulnerable library versions. The National Institute of Standards and Technology (NIST) maintains a large National Vulnerability Database (NVD). The Dependency Check Gradle plugin checks your used dependencies against the NVD. To use Dependency Check, request an NVD API key, set up the Gradle plugin, and run |
Version conflicts |
Are versions resolving as expected? Look for conflicts, especially major version differences. See Gradle dependency resolution for details on how you can look for conflicts. In particular, search for When possible, work with the authors of a dependency to deconflict their dependencies. If your company allows, contribute changes to the library (upstreaming) to help improve the library's compatibility. |
Check licenses |
Look for changes in licenses when upgrading a library. The library itself could change to a license that's no longer compatible with your application or library. New transitive dependencies could also introduce incompatible licenses. See Validate licenses for details on checking the current set of licenses across your dependencies. |
Maintenance and |
For libraries with public repositories:
|
Open versus closed source |
If a library is open source, it'll be easier to debug issues than with closed source, whether the issues are in your code or the library code. Minimize closed source dependencies and apply additional scrutiny during their evaluation. Are there good alternatives that fit your use case? What service-level agreements are available for closed source libraries? If you choose to use a closed source dependency, be prepared to write additional test cases to help limit risks. |
Run a build
Build your project. Look for new errors or warnings. If you can identify which library is causing them, note that as a risk for upgrading that library.
If you see any new depreciation warnings, add those as specific risks for the library producing them. These can be removed in later releases. If you want to continue using that library, dedicate time to convert from using deprecated APIs to their replacements, or note the deprecations to keep an eye on those functions and whether they are later removed.
Use lint to detect API issues
Android lint can catch many issues in your application, including some
that are the result of changing versions of dependencies or the Android SDK. For
example, if you upgrade your compileSdk
and use its new APIs, lint
reports those that aren't available in prior SDK versions.
Lint runs in the Android Studio editor, reporting issues as you make changes.
But it's not normally run as part of your build in Studio or when you run a
command-line build unless you use the build
or lint
targets.
If you use Continuous Integration (CI), run gradlew
build
or gradlew lint
during your CI builds (or at least on your nightly
builds) to catch these types of errors.
If you don't use CI, be sure to at least occasionally run gradlew lint
.
Pay particular attention to lint errors and warnings. Some libraries are shipped with their own lint checks, helping ensure proper use of their API. Some new versions of a library include new lint warnings and errors, resulting in new reports when you build.
Mitigate risks
After determining upgrade risks, decide how you want to mitigate them:
- Accept some risks as is. Some risks are low enough to be acceptable, especially when upgrade time and resources are limited.
- Reject some risks outright. Some upgrades might feel too risky, especially if you have limited time or resources to mitigate them at this point. If you need to triage, focus on upgrades that are necessary for bugs you have encountered or new features you need.
- Mitigate remaining risks
- Consider batching your upgrades into smaller, independent sets of changes. This reduces overall risk and allows partial rollback.
- Investigate the changes in detail.
- Test your app to check for unexpected changes. Add new tests where needed to build confidence in the upgrade.
- Look at the source (if available) when something questionable is found.
- Make required changes in your source or build.
Document your decisions. If risks from an upgrade become issues when running your application, documentation of your risk analysis can reduce the necessary error analysis.
Validate licenses
Library developers license the libraries for your use. You are required to adhere to the terms of the license or you cannot use the library. Some licenses are very permissive, often requiring only attribution of the library and surfacing the text of its license to end users. Some are considered viral; if you use those libraries, you must apply the same license to your application or library.
Licenses can change with any release. Whenever you upgrade, you should verify that the dependencies you're using are licensed in a compatible way with your application or library.
If a license is not compatible (or has changed to be no longer compatible), you cannot use that version of the library. You can:
- Reach out to the library owner and request continuation of the existing license or dual licensing to keep allowing the old license.
- Work with your legal team to determine if you can change your license to be compatible.
- Find another library with a compatible license and modify your application as needed.
- Fork the last compatible version of the library (if that license allows derivatives and the changes are not retroactive) and make your own changes.