Advanced

Non-Transitive R Classes in Android: Build Faster, Ship Smaller Apps

Android Gradle Plugin 4.2 introduced non-transitive R classes—a feature that lets each module's R class include only its own resources, not those from dependencies. If you're working on anything beyond a single-module app, this change is worth enabling.

At a Glance

  • Available in AGP 4.2 and later
  • Enable via android.nonTransitiveRClass=true in gradle.properties
  • Benefits: reduced APK/AAB size, faster incremental builds, clearer module dependencies
  • Android Studio includes an auto-refactor tool to assist migration

What Non-Transitive Means

In a multi-module project, Module A depends on Module B, which depends on Module C. Previously, Module A could reference resources from Module C through Module B—a transitive dependency that bloated the R class and increased build complexity.

With non-transitive R classes enabled, Module A can only reference its own resources and Module B's resources (via fully qualified package names). It cannot access Module C's resources directly. This mirrors how your code dependencies work: if you don't import a module, you can't use its code.

How to Enable It

Add this line to your /gradle.properties file:

Android.nonTransitiveRClass=true

The property was renamed from android.namespacedRClass in August 2020. If you see the old name in documentation, use the updated version instead.

Alternatively, Android Studio Arctic Fox (2020.3.1) and later includes an automatic refactor: navigate to Android Studio > Refactor > Move to Non-Transitive R Classes. This applies the setting and attempts to fix resource references automatically.

Migration Challenges

The auto-refactor isn't foolproof. It may add incorrect package names, miss necessary imports, or attempt to reference resources from modules your app doesn't depend on. Build errors typically surface in three patterns:

1. Missing package qualification.** Your code references a resource from another module without the fully qualified package name. Fix: use com.my.moduleB.R.string.example, import the R file, or (Kotlin only) use an alias.

2. Undeclared dependency.** Your code references a resource from a module you haven't declared as a dependency. Fix: add the dependency and update the reference.

3. Cross-module access you don't want to formalize.** You need a resource from an unrelated module but don't want to add that dependency. Fix: create a local resource with the same name or copy the definition into your module.

Who Should Care

Project Type Verdict
Large multi-module apps (5+ modules) High priority. The build speed and APK size gains are significant, and the migration effort pays for itself quickly.
Small multi-module apps (2-4 modules) Moderate priority. Gains are smaller but still worthwhile. The setting is simple to enable.
Single-module projects Low priority. Non-transitive has no effect when you have no transitive dependencies. Skip for now.
New projects Strong recommendation. Enable it from day one to avoid retrofitting later.

Our Analysis

The real value of non-transitive R classes isn't just build speed—it's architectural enforcement. When resources can't sneak in transitively, teams are forced to explicitly declare what each module depends on. This makes dependency graphs honest and easier to audit.

The trade-off is migration time. For mature projects with years of accumulated cross-module resource usage, the auto-refactor will catch the obvious cases, but expect to spend hours tracking down edge cases. Budget accordingly.

Watch for modules that have become "back doors" to other modules through transitive chains. These hidden dependencies will surface during migration and will need to be either formalized (add the dependency) or eliminated (create local resources). Either way, you'll end up with a cleaner architecture.

Key takeaways

  • Enable android.nonTransitiveRClass=true in gradle.properties for AGP 4.2+
  • Auto-refactor tools exist but manual fixes are often required for complex projects
  • Migration errors fall into three patterns: missing imports, missing dependencies, or cross-module resource references
  • The payoff is faster incremental builds, smaller distribution packages, and explicit module dependencies

Frequently asked questions

What are non-transitive R classes in Android?

Non-transitive R classes ensure each module's resource class contains only its own declared resources, not resources from transitive dependencies.

How do I enable non-transitive R classes?

Add android.nonTransitiveRClass=true to your project's gradle.properties file.

What are the benefits of enabling this feature?

Smaller APK/AAB files, faster incremental builds, reduced DEX field references, and clearer module dependency structures.

What happens if the auto-refactor makes mistakes?

Build errors will appear for incorrect resource references. Fix them by adding fully qualified package names, importing R files, or adding missing dependencies.

Which Android Studio version supports the auto-refactor?

The auto-refactor was added in Android Studio Arctic Fox (2020.3.1) under Android Studio > Refactor > Move to Non-Transitive R Classes.

Related