
This image was generated using AI
Whether your build.gradle is written in Groovy or if you already made the jump to Kotlin, there will come a time where you will need to migrate to Gradle version catalogs.
When, you ask?
It will happen when you will want to update your Kotlin compiler version to be 2.0.0 or above. This is because the Jetpack Compose compiler has been moved to the Kotlin repository [Reference]. Due to this, a new plugin was released, the Compose Compiler Gradle plugin. Usually, with every release of the Compose library, you had a specific kotlinCompilerExtensionVersion you would have to use:
composeOptions { kotlinCompilerExtensionVersion '1.5.13' }
But you can see here, that for Kotlin versions 2 and above, you will need to use the Compose Compiler Gradle plugin.

In this article, we will lay out the (possible) path you may need to take:
- Your build configuration is in Groovy
- Your build configuration is in Kotlin
- You don’t have a libs.versions.toml file
- You have a libs.versions.toml file
Migrating build configuration to Kotlin
There are two choices if your build configuration is in Groovy:
- You can migrate your build configuration to Kotlin
- You can migrate your build configuration directly to Gradle Version Catalog
If you choose the first option, it is a longer route to take, but not by much. If you choose the second option, you can skip this section and go right ahead to the next one.
❗️ Be aware that this article is written assuming the build configuration is in Kotlin so you may need to make the necessary adjustments for Groovy
First, we will need to migrate the project to work with Kotlin in the build.gradle files. There is an article that covers all the needed steps, but here I’d like to showcase a full example of how the build.gradle file looks like before and after the migration.
build.gradle (app level) before the migration:
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' android { compileSdkVersion 34 defaultConfig { applicationId "com.tomerpacific.laundry" minSdkVersion 21 targetSdkVersion 34 versionCode 25 versionName "2.4.8" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" dataBinding { enabled = true } } kotlinOptions { jvmTarget = 17 } buildFeatures { compose true viewBinding = true } composeOptions { kotlinCompilerExtensionVersion '1.5.10' } buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' ndk { debugSymbolLevel 'SYMBOL_TABLE' } } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } packagingOptions { resources.excludes.add("META-INF/*") } namespace 'com.tomerpacific.laundry' } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "androidx.fragment:fragment-ktx:1.4.0" implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'androidx.activity:activity-compose:1.8.2' implementation 'androidx.compose.ui:ui-viewbinding:1.6.2' implementation 'com.google.android.material:material:1.8.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.2' implementation 'com.google.android.play:app-update:2.1.0' implementation 'com.google.android.play:app-update-ktx:2.1.0' implementation "androidx.compose.material3:material3:1.2.1" implementation "androidx.compose.material3:material3-window-size-class:1.2.1" implementation "androidx.compose.material3:material3-adaptive-navigation-suite:1.3.0-rc01" testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.1.0' debugImplementation 'androidx.compose.ui:ui-test-manifest:1.6.2' }
The key changes you should pay attention to are:
- Using double quotation marks(“) instead of single quotation marks(‘)
- Using the equals operator (=) for any setting
- Any property that has a Boolean value should be prefixed with the is word
- Plugins block instead of the apply plugin commands
- Removal of implementation”org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version”
build.gradle after the migration:
plugins { id("com.android.application") id("org.jetbrains.kotlin.android") id("kotlin-kapt") } android { namespace = "com.tomerpacific.laundry" compileSdk = 34 defaultConfig { applicationId = "com.tomerpacific.laundry" minSdk = 21 targetSdk = 34 versionCode = 25 versionName = "2.4.8" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" buildFeatures { dataBinding = true } } kotlinOptions { jvmTarget = "17" } buildFeatures { compose = true viewBinding = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.10" } buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) ndk { debugSymbolLevel = "SYMBOL_TABLE" } } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } packaging { resources { excludes += "META-INF/*" } } } dependencies { implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.jar")))) implementation("androidx.fragment:fragment-ktx:1.4.0") implementation("androidx.appcompat:appcompat:1.4.0") implementation("androidx.activity:activity-compose:1.8.2") implementation("androidx.compose.ui:ui-viewbinding:1.6.2") implementation("com.google.android.material:material:1.8.0") implementation("androidx.constraintlayout:constraintlayout:2.1.2") implementation("com.google.android.play:app-update:2.1.0") implementation("com.google.android.play:app-update-ktx:2.1.0") implementation("androidx.compose.material3:material3:1.2.1") implementation("androidx.compose.material3:material3-window-size-class:1.2.1") implementation("androidx.compose.material3:material3-adaptive-navigation-suite:1.3.0-rc01") testImplementation("junit:junit:4.12") androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.1.0") debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.2") }
As for the your project level build.gradle file and the settings.gradle file, here is how they look like after the changes:
build.gradle.kts:
// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { id("com.android.application") version "8.0.2" apply false id("org.jetbrains.kotlin.android") version "1.9.22" apply false }
settings.gradle.kts:
pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } } rootProject.name = "laundry" include(":app")
Migrating To Gradle Version Catalog
If you don’t have a libs.versions.toml file, then before you migrate to the Compose Compiler Gradle plugin, you need to migrate your build to Gradle Version Catalog. This means creating a libs.versions.toml file in your project’s gradle folder:

This file includes three sections:
- versions – In this section you will have the names of your dependencies with their associated version in the format of version = “x.y.z”
- libraries – In this section you will have key value pairs indicating the name of the library with an object representing the group, name and version reference of the library
- plugins – Similar to the libraries section, but having only an id and version reference fields
Each dependency or plugin that you migrate from your build.gradle.kts file will be broken up into two parts:
- A line under the versions/plugins section, indicating the library name and it’s version
- A line under the libraries section, indicating the name of the library followed by an object that contains three keys: group, name and version.ref
For example, if we have the following dependency:
implementation "androidx.fragment:fragment-ktx:1.4.0"
We will break it into three parts and use those parts in our libs.versions.toml file:
- fragment-ktx:1.4.0 will be used under the versions section
- androidx.fragment-ktx will be used as the key under the libraries section
- group = “androidx.fragment”, name = “fragment-ktx”, version.ref = “fragment-ktx” will be the object for the key in step #2
It looks like this:
[versions] fragment-ktx = "1.4.0" [libraries] androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragment-ktx" } [plugins]
⚠️ Pay attention that the key you use under the libraries section is the value you will need to use in your build.gradle.kts file
And in our build.gradle.kts file, under the dependencies block, we will use:
implementation(libs.androidx.fragment.ktx)
It is recommended to make sure your project compiles and runs properly after each dependency you migrate
When you migrate one of the plugins you use, you will have to add lines under the versions and plugins section. Let’s show how to do this with an example below:
classpath 'com.android.tools.build:gradle:8.0.2'
Above is the line you have in your project level build.gradle, so you will need to add these lines in the corresponding versions and plugins sections to represent it:
[versions] androidGradlePlugin = "8.0.2" ... [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" }
Then in your project level build.gradle, replace the original line with this one:
plugins { alias(libs.plugins.android.application) apply false }
and in your application level build.gradle, replace the line there:
plugins { id("com.android.application") // <--- This line should be removed alias(libs.plugins.android.application) }
⚠️ If you are using a Gradle version below 8.1, you will need to add an annotation above your plugins block in both build.gradle files:
@file:Suppress("DSL_SCOPE_VIOLATION") // <---- This plugins { alias(libs.plugins.android.application) apply false }
And in your application level build.gradle:
@file:Suppress("DSL_SCOPE_VIOLATION") // <---- This plugins { alias(libs.plugins.android.application) }
Migrating to Compose Compiler Gradle
Whether you got here after going through all of the steps, or just jumped to this one, the migration here is rather simple.
- Remove any reference you might have in your build.gradle.kts to the Compose Compiler, I.E.
composeOptions { kotlinCompilerExtensionVersion '1.5.10' }
2. Alter the Kotlin version you have and add this dependency in the libs.versions.toml file:
[versions] kotlin = "2.0.0" [plugins] kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
3. Inside your project level build.gradle.kts, add this line:
plugins { id(libs.plugins.compose.compiler) apply false }
4. Inside your application level build.gradle.kts, add this line:
plugins { id(libs.plugins.compose.compiler) }
Job Offers
If you would like to see a complete example of how this migration was done, you can view it here:
References:
- Android Blog Post about Jetpack Compose Compiler Migration
- Developer Documentation about Compose Compiler Gradle Plugin
- Official Android GitHub PR showing Jetpack Compose Compiler Migration
If you would like to read others articles I have written, you can find them here:
This article was previously published on proandroiddev.com.