By default, R8 makes a lot of optimizations to improve performance and size, but the optimizations might not work for your app immediately. If you're turning on R8 (or enabling[full mode](https://developer.android.com/topic/performance/app-optimization/adopt-optimizations-incrementally#use-compat)) in a big app for the first time, try to adopt optimizations incrementally: temporarily turn off obfuscation and enable R8 for portions of code at a time, rather than for all the code in your app. We recommend taking this incremental approach during local development, but you can also use it during internal QA testing or even in production as a gradual rollout. The exact steps you take depend on your desired timeline and confidence in your pre-release testing coverage.

## Limit the optimizations

R8 does many types of optimizations including removing code, rewriting code, and removing resources. Here are some high-level descriptions of the optimization types:

- Code shrinking (or tree shaking): removes unreferenced code
- Obfuscation (or identifier minification): shortens the names of classes and methods
- Optimization: rewrites code, for example inlining

To reduce the chance of errors, you can start by enabling only some of these optimizations.

### Enable tree shaking only

Code shrinking, also known as tree shaking, removes code that appears to be unreferenced. We recommend starting with just tree shaking, since it's the most straightforward.

To enable tree shaking only, add the following to your`proguard-rules.pro`file to turn off the other types of optimizations. Turning off obfuscation is key because it makes stack traces much easier to read.  

    -dontobfuscate // Use temporarily to turn off identifier minification
    -dontoptimize // Use temporarily to turn off optimization

In the end, you wouldn't want to ship this configuration, since it drastically limits the ability for R8 to optimize code, but it's a great starting point when adopting R8 for the first time in a large codebase with problems to fix.

### Use compat mode

By default, R8 runs in[*full mode*](https://r8.googlesource.com/r8/+/refs/heads/master/compatibility-faq.md#r8-full-mode). Full mode imparts significantly improved performance and size savings, but you can temporarily disable it and use*compat mode*instead when enabling minification for the first time.
| **Note:** R8 runs in compat mode by default for Android Gradle plugin versions 7.0 and lower.

To use compat mode, use the following setting in your`gradle.properties`file:  

    android.enableR8.fullMode = false // Use temporarily to disable full mode

### Enable the rest of the optimizations

When you've confirmed that tree shaking works for your app, you can remove the preceding settings to re-enable obfuscation, optimization, and R8 full mode. Note that obfuscation can make debugging more difficult, which is why we recommend addressing tree shaking issues first.

For more information about deobfuscating stack traces, see[Recover the original stack trace](https://developer.android.com/topic/performance/app-optimization/test-and-troubleshoot-the-optimization#recover-original-stack-trace).

## Limit the optimization scope

A fully optimized build optimizes all code across every library and package, so it's common to encounter issues with R8 when you first turn it on. If you find a problem with optimization in one part of the app, don't turn off R8 completely or you'll lose out on benefits everywhere else. Instead, temporarily disable R8 only in the parts of your app that are causing problems.

### Use package-wide keep rules

We recommend using package-wide keep rules as a way to temporarily disable R8 in parts of your app. You should always come back to fix these optimization issues later; this is generally a stop-gap solution to work around problem areas.

For example, if part of your app uses Gson heavily and is causing problems with optimization, the ideal fix is to add more[targeted keep rules](https://developer.android.com/topic/performance/app-optimization/add-keep-rules)or move to a codegen solution. But to unblock optimizing the rest of the app, you can place the code defining your Gson types in a dedicated subpackage, and add a rule like this to your`proguard-rules.pro`file:  

    -keep class com.myapp.json.** { *; }

If some library you're using has[reflection](https://en.wikipedia.org/wiki/Reflective_programming)into internal components, you can similarly add a keep rule for the entire library. You'll need to inspect the library's code or JAR/AAR to find the appropriate package to keep. Again, this isn't recommended to maintain long term, but can unblock the optimization of the rest of the app:  

    -keep class com.somelibrary.** { *; }

| **Note:** Never write a keep rule that keeps all of your app, for example -`keep **`or -`keep com.myapp.**`. These rules prevent optimization across such a wide portion of the app that you'll pay the build cost of R8 with effectively none of the benefit. Instead, always start with library- or package- based keep rules, and try to remove them gradually over time.

### Remove package-wide keep rules

Once your app functions correctly with package-wide keep rules, you should go back and either add[targeted keep rules](https://developer.android.com/topic/performance/app-optimization/add-keep-rules), or remove the reflection usage or library which necessitates the keep rule in the first place.

For example, keeping all rules which extend a certain class is extremely common in AndroidX to keep only relevant classes. Generally, reflection should only target classes or methods which either extend certain abstract classes, implement certain interfaces, or into classes with a specific runtime annotation. Each of these are supported ways to define keep rules so that you don't need package-wide keep rules in your final, fully optimized app.