How Did We Discover the Flutter AGP 9.1.0 Build Error in Production?
While working on a recent enterprise FinTech application, our engineering team was tasked with clearing out Play Store optimization warnings ahead of a major compliance release. To ensure maximum performance and meet Google’s latest Android ecosystem requirements, we initiated an upgrade to Flutter 3.47.0. This upgrade inherently pushed our Android Gradle Plugin (AGP) version to 9.1.0 and Kotlin (KGP) to 2.4.0.
Because enterprise applications rely heavily on environment separation, we utilize flavoring alongside Flutter Version Management (FVM). When we attempted to build our staging environment, the CI pipeline halted abruptly. An unexpected build exception derailed the deployment, blocking the QA cycle. This is a common hurdle when maintaining long lifecycle applications and it underscores the necessity of having experienced engineering teams at the helm. When companies hire app developer to create a mobile app, they often underestimate the maintenance complexity that arises from aggressive open-source release cycles.
This technical challenge inspired this article. By sharing our diagnostic process and resolution for this specific Kotlin Gradle Plugin conflict, we aim to help other CTOs and architects navigate similar modernization roadblocks.
Why Do Flutter 3.47.0 and AGP 9.1.0 Cause Kotlin Plugin Conflicts?
At an architectural level, the Android build system has undergone a fundamental shift with AGP 9.0+. Historically, whenever a project needed Kotlin support, engineers (and third-party package authors) had to explicitly declare and apply the Kotlin Gradle Plugin (KGP) via apply plugin: 'kotlin-android' in their build.gradle files.
Starting with AGP 9.0, Android introduced a streamlined approach via the android.builtInKotlin=true flag. This delegates Kotlin compilation directly to the Android Gradle Plugin, rendering the standalone org.jetbrains.kotlin.android plugin obsolete. In fact, declaring it manually alongside built-in Kotlin triggers a fatal conflict.
The core issue surfaced because the Flutter 3.47.0 migration script aggressively modernizes the host app’s configuration by enabling android.builtInKotlin=true. However, the wider Flutter package ecosystem on pub.dev does not always move at the same speed. Several critical packages in our dependency tree were still statically applying the legacy Kotlin plugin, resulting in a fractured build environment.
What Went Wrong When Applying the Kotlin-Android Plugin?
When initiating our standard staging build via fvm flutter run --flavor staging -t lib/main_staging.dart, the process failed in approximately 15 seconds. The terminal yielded a stark diagnostic error:
* What went wrong:
An exception occurred applying plugin request [id: 'kotlin-android']
> Failed to apply plugin 'kotlin-android'.
> Failed to apply plugin 'org.jetbrains.kotlin.android'
The 'org.jetbrains.kotlin.android' plugin is no longer required for Kotlin support since AGP 9.0.
Solution: Remove the 'org.jetbrains.kotlin.android' plugin from this project's build file: ~/.pub-cache/hosted/pub.dev/google_sign_in_android-7.2.11/android/build.gradle.kts.
See https://kotl.in/gradle/agp-built-in-kotlin for more details.
Further inspection of the build logs revealed a warning explicitly flagging our dependency tree. The system identified multiple essential plugins—such as firebase_remote_config, google_sign_in_android, shared_preferences_android and url_launcher_android—that were statically applying KGP.
Our gradle.properties file showed that the Flutter migrator had automatically configured the modern standard:
android.useAndroidX=true
android.enableJetifier=true
android.builtInKotlin=true
android.newDsl=false
The contradiction was clear: our root project demanded built-in Kotlin, while our foundational third-party packages demanded the legacy KGP injection. Since these packages reside in the local pub cache (or on CI runners), editing them directly is an anti-pattern that violates ephemeral build principles.
How Did We Approach Resolving the AGP Built-In Kotlin Issue?
Diagnosing an issue involving third-party supply chain bottlenecks requires a structured approach. Our immediate goal was to unblock the staging release, but our architectural goal was to ensure the CI/CD pipeline remained deterministic and secure. This is the caliber of problem-solving expected when organizations hire software developer teams for dedicated delivery.
What Alternative Workarounds Did We Consider for Gradle?
Before settling on our final implementation, we evaluated several technical paths to mitigate the build failure:
- Direct Cache Modification: We considered writing a pre-build shell script to execute a
sedreplacement across the~/.pub-cache/directory, stripping out theapply plugin: 'kotlin-android'line. We discarded this because modifying external caches introduces silent, flaky behaviors in remote CI/CD pipelines. - Git Forking and Dependency Overrides: We evaluated forking the offending repositories (like
google_sign_inandfirebase_remote_config), updating theirbuild.gradlefiles and using Flutter’sdependency_overridesin ourpubspec.yaml. While robust, maintaining forks for heavily updated Firebase libraries introduces severe technical debt and security patch lag. - Gradle Lifecycle Hook Injection: We investigated using Gradle’s
projectsEvaluatedhook within the rootbuild.gradleto intercept and dynamically strip the Kotlin plugin from subprojects. Unfortunately, AGP 9.0+ validates plugin requests very early in the configuration phase, making interception highly complex and brittle.
How Did We Finally Implement the Fix for Flutter Build Errors?
After weighing the architectural trade-offs, we determined that the safest, most deterministic path was to leverage a temporary feature toggle provided by the Android ecosystem, while enforcing strict version tracking for future package updates.
We deliberately disabled the built-in Kotlin feature by adjusting the android/gradle.properties file. Since the migration to AGP 9.0+ does not strictly mandate builtInKotlin=true until a future AGP 10+ release, setting it to false acts as a highly effective, non-destructive bridge.
Step 1: Reconfiguring Gradle Properties
We updated our android/gradle.properties to safely bypass the conflict:
# Temporarily disabled due to third-party plugin incompatibility with AGP 9.1
android.builtInKotlin=false
android.useAndroidX=true
android.enableJetifier=true
android.newDsl=false
Step 2: Dependency Monitoring & Technical Debt Tracking
Simply flipping a boolean is not an architectural solution—it is a deferral. To ensure this didn’t become permanent technical debt, we established a tracking epic in our project management system. We pinned our current package versions and utilized a CI scheduled job to notify us when upstream repositories (like Google’s Flutter packages) release patches explicitly resolving KGP AGP 9+ compatibility.
Step 3: Validating the Staging Build
After adjusting the property and running fvm flutter clean followed by our flavor-specific build command, the assembleStagingDebug task completed successfully within 45 seconds. The QA team resumed testing without facing optimization warnings on the Play Store, achieving the initial business objective.
What Are the Key Engineering Lessons for Upgrading Flutter Apps?
When you hire mobile developers for enterprise modernization, you expect proactive infrastructure management. Here are the actionable insights from this scenario:
- Never Blindly Trust Migration Scripts: Automated migrators (like Flutter’s AGP upgrade scripts) apply ideal-state configurations. They lack context regarding your specific dependency tree’s compatibility.
- Understand the Gradle Lifecycle: Knowing the difference between root project configuration and subproject evaluation is critical when dealing with transient dependency failures.
- Use Dependency Overrides Cautiously: Forking packages to fix build errors should be an absolute last resort due to the ongoing maintenance burden it shifts onto your team.
- Document Temporary Toggles: Setting a flag like
builtInKotlin=falsemust be heavily commented in the code and tracked as technical debt in Jira/Linear to prevent future build-breaking surprises when AGP 10 is eventually enforced. - Maintain Ephemeral CI Integrity: Resist the urge to patch local cache files. Your build must remain reproducible across any developer machine and CI runner.
How Can You Modernize Your Enterprise Mobile Architecture?
Upgrading foundational SDKs like Flutter and AGP is rarely a straight line. Modernization requires navigating complex dependency matrices, understanding deep Gradle build lifecycles and knowing when to apply strategic workarounds without compromising the long-term integrity of the codebase. By analyzing the root cause of the Kotlin plugin failure and systematically evaluating our options, we kept the delivery pipeline moving while safeguarding against future technical debt.
At WeblineGlobal, we provide structural delivery practices and pre-vetted dedicated teams who treat your product’s architecture with this level of scrutiny. If you need to augment your team with engineers capable of managing complex mobile infrastructures, contact us.
Social Hashtags
#Flutter #FlutterDev #AndroidDevelopment #AGP9 #Kotlin #Gradle #MobileAppDevelopment #FlutterDevelopment #AndroidDev #DevOps #CICD #SoftwareEngineering
Frequently Asked Questions
AGP 9.0+ introduced built-in Kotlin support. When android.builtInKotlin=true is set, the Android build tools handle Kotlin compilation natively. Manually applying the legacy kotlin-android plugin creates an unresolvable duplicate process in the Gradle build phase.
Yes, temporarily. It allows the older KGP pipeline to compile your code. However, it is a deprecated pathway. You must monitor your third-party packages and switch it back to true once the package maintainers release compatible updates.
The Flutter migrator only modifies files within your project's repository boundary (like your android/app/build.gradle). It cannot and should not, modify external packages residing in the global pub cache.
Running the Flutter build command will output a warning listing the specific packages. Alternatively, you can run ./gradlew app:dependencies --scan in the Android folder to trace the exact plugin resolution tree.
You should only fork a package if the issue is a critical security vulnerability or an absolute production blocker and the upstream maintainer has abandoned the repository. For transient build issues like AGP updates, relying on Gradle property toggles is significantly safer.
Success Stories That Inspire
See how our team takes complex business challenges and turns them into powerful, scalable digital solutions. From custom software and web applications to automation, integrations, and cloud-ready systems, each project reflects our commitment to innovation, performance, and long-term value.

US SaaS Platform Cut Manual Ops by 70% After Hiring WeblineGlobal’s n8n Automation Pod

California-based SMB Hired Dedicated Developers to Build a Photography SaaS Platform

















