After moving a Flutter Android app to Android Gradle Plugin 9, what do android.builtInKotlin and android.newDsl in gradle.properties do, and what migration does the app need?
answer
- AGP 9 makes built-in Kotlin default
- kotlin-android plugin must go
- kotlinOptions becomes kotlin.compilerOptions
- flags are temporary escape hatches
- all plugins must migrate first
basics
~10 sAGP 9 compiles Kotlin itself and knows only its new DSL; Flutter's android.builtInKotlin=false and android.newDsl=false are temporary escape hatches. Migrating removes kotlin-android and kotlinOptions and adds kotlin { compilerOptions { ... } }.
solid answer
~40 sAndroid Gradle Plugin 9 makes **built-in Kotlin** the default and uses only its new DSL interfaces, so apps still applying the `kotlin-android` plugin fail to build. Flutter 3.44 added support for keeping the old Kotlin Gradle Plugin with `android.builtInKotlin=false`, and the Flutter tool's migrator writes that flag and `android.newDsl=false` into `gradle.properties` when they are missing. To migrate an app, remove `id("kotlin-android")` and the `kotlinOptions` block from `android/app/build.gradle.kts` and add `kotlin { compilerOptions { jvmTarget = JvmTarget.JVM_17 } }`. Flutter 3.47 supports `android.builtInKotlin=true` once the app and all its plugins have migrated. Separately, product flavors using `resValue` fail under AGP 9 by default; move those values into flavor `strings.xml` files.
code
kotlin · 17 linesplugins {
id("com.android.application")
// id("kotlin-android") removed: AGP 9 compiles Kotlin itself
id("dev.flutter.flutter-gradle-plugin")
}
android {
namespace = "com.example.plantcare"
compileSdk = flutter.compileSdkVersion
// kotlinOptions { jvmTarget = ... } removed
}
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}go deeper
Recall that AGP 9 compiles Kotlin itself, so the kotlin-android plugin has to come out of the app's Gradle file eventually.
Explain the two gradle.properties flags, what the Flutter migrator writes, and the three edits to build.gradle.kts.
Sequence the migration across app and plugins, handle add-to-app hosts by hand, and fix flavor resValue failures before they block releases.
Plan platform migrations across teams: track plugin readiness, budget for the announced removal of KGP support, and avoid permanent escape hatches.
## What changed in AGP 9 The **Android Gradle Plugin (AGP)** is the Gradle plugin that builds every Android app, including a Flutter app's Android shell. AGP 9 brought two changes that affect Flutter projects: 1. **Built-in Kotlin is the default.** AGP now compiles Kotlin itself. Projects that also apply the separate **Kotlin Gradle Plugin** (KGP, applied as `kotlin-android` or `org.jetbrains.kotlin.android`) fail to build without migration. 2. **Only the new AGP DSL interfaces.** Build scripts and plugins using old DSL types are not recognised. Many Flutter apps created before these releases apply `kotlin-android` in `android/app/build.gradle.kts`, and many plugins do too. ## The escape hatches To keep projects building during the transition, Flutter provides two `gradle.properties` flags: - `android.builtInKotlin=false` — keep using KGP under AGP 9 (support added in Flutter 3.44); - `android.newDsl=false` — keep the legacy DSL types working. The Flutter tool includes **migrators** that append these lines to `gradle.properties` when they are missing, the next time you run `flutter run` or `flutter build apk`; new project templates contain them too. Add-to-app host projects are pure Android projects where the migrator does not run, so they must add both lines by hand. These flags are **temporary**: the Flutter docs state that support for applying KGP and for the old DSL will be removed in a future version. ## Migrating the app In `android/app/build.gradle.kts`: 1. **Remove** `id("kotlin-android")` from the `plugins {}` block. 2. **Remove** the `kotlinOptions { jvmTarget = ... }` block inside `android {}`. 3. **Add** a top-level `kotlin` block: ```kotlin kotlin { compilerOptions { jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 } } ``` The Flutter guide warns that this migration applies only to apps that **already apply KGP**; an app that never applied `kotlin-android` needs only `android.newDsl=false` and no further steps. ## When to flip `builtInKotlin` to `true` Flutter 3.47 added support for **enabling** built-in Kotlin with `android.builtInKotlin=true` once the **app and all of its plugins** have migrated. A single plugin still applying KGP keeps the flag at `false`, so the practical order is: - migrate the app's own Gradle file; - upgrade plugins to versions that have migrated (plugin authors have their own guide); - only then set `android.builtInKotlin=true` and build every flavor. ## A related AGP 9 break: `resValue` in flavors Flavored apps often set the launcher name with `resValue("string", "app_name", "...")` in each product flavor. The Flutter flavor guide notes that builds with AGP 9 or later fail by default with an error saying the product flavor contains custom resource values but the feature is disabled. The fix is to delete those `resValue` calls and define `app_name` in `android/app/src/<flavor>/res/values/strings.xml`. ## What a new project looks like A project created with Flutter 3.47's template already reflects the new layout: `settings.gradle.kts` pins AGP 9.1.0, the app's `build.gradle.kts` applies only `com.android.application` and the Flutter Gradle plugin and uses `kotlin { compilerOptions { ... } }`, and `gradle.properties` carries the two flags set to `false`. | Item | Before AGP 9 | After migration | |---|---|---| | Kotlin compilation | `kotlin-android` plugin | AGP built-in Kotlin | | JVM target | `kotlinOptions { jvmTarget }` | `kotlin { compilerOptions { jvmTarget } }` | | Transitional flags | none | `android.builtInKotlin`, `android.newDsl` | | Flavor app names | `resValue` in the flavor | flavor `strings.xml` | ## Checking readiness A practical sequence for a real app: 1. Run `flutter build apk` once after upgrading Flutter so the migrators add the two flags if missing. 2. Search `android/` for `kotlin-android` and `kotlinOptions` and migrate the app module. 3. For each plugin in `pubspec.lock`, check whether its latest version has moved off KGP; upgrade the ones that have. 4. Try `android.builtInKotlin=true` on a branch and build every flavor and build mode; any plugin still applying KGP fails loudly there. 5. Keep `android.newDsl=false` until Flutter's own Gradle plugin and your plugins no longer need the old DSL. ## Interview angle The question tests whether a candidate can read a platform migration rather than paste flags: the flags buy time, the plugin ecosystem decides when `builtInKotlin=true` is safe, and the removal of KGP support is already announced.
- Why can't an app set android.builtInKotlin=true as soon as its own Gradle file is migrated?Plugins are Gradle subprojects built with the same setting. If any plugin still applies the Kotlin Gradle Plugin, built-in Kotlin breaks that plugin's build. Flutter 3.47 supports `true` only once the app and all its plugins have migrated.
- An add-to-app Android host fails under AGP 9 while the Flutter module builds. What is missing?The host is a pure Android project, so the Flutter migrator never runs there. Add `android.builtInKotlin=false` and `android.newDsl=false` to the host's `gradle.properties` by hand, then migrate its Kotlin setup when ready.
saying these in an interview costs you the question
- Treats android.builtInKotlin=false as the permanent fix
- Sets builtInKotlin=true while plugins still apply kotlin-android
- Migrates an app that never applied the Kotlin Gradle Plugin
- Keeps resValue app names in flavors under AGP 9
- Expects the Flutter migrator to update add-to-app host projects