El problema con las recetas mágicas
Buscás “Gradle slow build” y enseguida aparecen listas de mandamientos: activá configuration cache, activá build cache, pasate a KSP, dividí en módulos, actualizá AGP, desactivá esto, habilitá aquello. Algunas recomendaciones son buenas. El problema es que tomadas como receta pueden servirte poco o nada si no entendés dónde se está yendo realmente el tiempo.
Una build lenta no siempre significa lo mismo. A veces el problema es la fase de configuración. A veces el costo está en compilación incremental que dejó de ser incremental. A veces el cuello está en KAPT, en demasiadas variantes, en dependencias demasiado visibles o en una mezcla de todo eso.
Primero: medir
Antes de tocar flags o reorganizar medio proyecto, medí. Ese paso parece obvio, pero es donde más equipos fallan. Sin una línea base, cualquier cambio se siente como mejora porque hiciste algo, no porque haya mejorado de verdad.
./gradlew assembleDebug --scan
./gradlew assembleDebug --profile
./gradlew :app:tasks
./gradlew :app:dependencies
Los build scans y los reports de perfil no reemplazan el criterio técnico, pero sí te muestran dónde está el costo: configuración, compilación, tasks custom, annotation processing, tests, packaging o resolución de dependencias.
Punto claveNo optimices por intuición. Primero descubrí si el dolor principal está en configurar el build o en ejecutar tareas concretas.
Demasiado trabajo en configuración
Muchos proyectos se vuelven lentos incluso antes de compilar porque hacen demasiado trabajo durante la fase de configuración. Scripts Gradle con lógica pesada, lectura de archivos innecesaria, tareas registradas de forma costosa o plugins que inicializan demasiado hacen que cualquier comando tarde más de lo necesario.
Eso afecta no solo al build completo: también afecta sync de Android Studio y experiencia de desarrollo diaria. A veces el proyecto no “compila lento”; en realidad “arranca lento”.
AtenciónSi cada módulo evalúa demasiada lógica en configuración, el problema escala con el tamaño del proyecto aunque compiles una tarea pequeña.
Dependencias y acoplamiento
La forma en que declarás dependencias impacta en recompilación y tamaño del classpath. Si usás api de más entre módulos, exponés demasiadas cosas y hacés que cambios locales se propaguen mucho más de lo necesario.
Lo mismo pasa cuando módulos compartidos arrastran librerías pesadas que media app termina viendo aunque no las necesite. A veces el problema no es Gradle: es un diseño de dependencias que obliga a recompilar demasiado.
dependencies {
implementation(project(":core:model"))
// usar api solo cuando realmente forma parte de la API pública
}
Procesadores y generación de código
KAPT, KSP y otros mecanismos de generación de código pueden influir mucho en tiempos de build. No porque sean “malos” en sí mismos, sino porque agregan trabajo extra, a veces en varios módulos y a veces de forma no incremental.
Eso no significa eliminar toda generación de código. Significa entender qué procesadores tenés, dónde están, cuánto cuestan y si están en módulos donde realmente aportan valor.
En muchos proyectos, una parte visible del tiempo se va en Hilt, Room, serialización o procesadores similares. Medir eso evita discutir en abstracto.
Variantes de build y combinaciones
Build types y product flavors son útiles, pero cada combinación suma trabajo potencial. Si el proyecto tiene varias dimensiones de flavors, branding, entornos y distribución, la cantidad de variantes crece rápido. Y con eso crece el costo mental y técnico del build.
No todo debería modelarse como flavor. A veces una diferencia puede resolverse con feature flags o configuración runtime. Meter todo al sistema de variantes hace que Gradle tenga que contemplar más escenarios de los necesarios.
Flags útiles, sin fetiche
Hay propiedades que suelen ayudar, pero no son una religión. Sirven cuando el proyecto y sus plugins son compatibles, no por el simple hecho de activarlas.
# gradle.properties
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
kotlin.incremental=true
parallel, caching y configuration-cache pueden mejorar bastante un build. Pero también pueden no mover la aguja si el cuello real está en otra parte. Lo mismo con migrar de KAPT a KSP o actualizar versiones: suele ayudar, pero no siempre ataca la causa principal.
Regla prácticaLas flags son multiplicadores de una base razonable. No reemplazan una buena estructura de módulos, dependencias y scripts.
Cierre
Las builds Gradle lentas casi nunca se arreglan con una sola palanca. El camino sano es medir, entender en qué fase se va el tiempo y recién ahí decidir si el problema es de configuración, dependencias, variantes, procesadores o tooling. Gradle mejora mucho cuando dejás de tratarlo como una caja negra y empezás a mirar el build como un sistema con costos concretos.