Fix “compile against version 36 or later”: Flutter's compileSdk Error, Explained
If your Flutter Android build just died on :app:checkDebugAarMetadata (or its checkReleaseAarMetadata twin) with a message like “Dependency 'androidx.core:core:x.y.z' requires libraries and applications that depend on it to compile against version 36 or later of the Android APIs” — the fix is one line: raise compileSdk to 36 in android/app/build.gradle. It will not drop older devices — that is minSdk's job, not compileSdk's. The rest of this page explains why the error appears out of nowhere, and the two situations where the one-liner is not enough.
What the AAR metadata check actually verifies
Every Android library (an .aar) carries metadata declaring the minimum API level it was compiled against. The Android Gradle Plugin's checkAarMetadata tasks read those declarations for every dependency in the graph and compare them with your module's compileSdk. If any dependency demands a higher level than yours, the build stops before compilation even starts. It is a contract check, not a compiler error — which is why the message names the dependency, not a line of your code.
The important nuance: compileSdk is about the API surface visible at compile time. Raising it does not change your minSdk (which devices can install) or your targetSdk (which behavior era Android applies at runtime). Treating those three as one number is the single most common reason people fear this fix.
Why it broke this week and not last week
Your code did not change — your dependency graph did. As androidx libraries and Flutter plugins ship releases compiled against API 36, their AAR requirements rise with them, and the first build that resolves a new release trips the check. You can compare dependency versions between the successful and failed runs. A committed pubspec.lock helps preserve Dart resolution; it does not pin every dynamic Android dependency. A dependency upgrade can change the graph. A fresh checkout or cache miss by itself is not proof that the locked versions changed.
The one-line fix
In android/app/build.gradle (or .gradle.kts), inside the android {} block:
android {
compileSdk = 36
// minSdk and targetSdk stay as they are
}Many Flutter templates write compileSdk = flutter.compileSdkVersion, inheriting whatever your installed Flutter SDK defaults to. That indirection is fine — until a plugin runs ahead of your Flutter version's default. If the error persists after “raising” it, check you replaced the indirection with the explicit number rather than editing a value that gets overridden.
The messy case: a plugin module pins its own compileSdk
Here is the shape that eats an afternoon. Your app module says 36, but the failing module is a plugin — the error path reads :some_plugin:checkDebugAarMetadata instead of :app:. Plugin modules carry their own build scripts, and some pin an older compileSdk that your app-level setting does not touch. For example, a plugin module pinned to 34 can fail when one of its Android dependencies starts requiring 36.
Prefer updating the plugin to a compatible release. A root-level override can be a temporary workaround, but its timing depends on your Gradle/AGP versions. This older Groovy pattern illustrates the intent, not a universal drop-in fix:
// android/build.gradle (project root)
subprojects {
afterEvaluate {
if (project.hasProperty("android")) {
def androidExt = project.android
if (androidExt.compileSdk != null && androidExt.compileSdk < 36) {
androidExt.compileSdk = 36
}
}
}
}Do not use this unchanged if AGP reports that compileSdk is already finalized: the override must run earlier using an API compatible with that plugin version. Kotlin DSL also needs different syntax. Verify the effective value in the failing module and rebuild with a compatible SDK/AGP/JDK combination.
If you'd rather not maintain the toolchain at all
Managed builds remove the local SDK installation step, not responsibility for compatible source and dependencies. Upload your Flutter project on Builder or Pro; source compiles spend bundled credits, with 20 Android source builds per calendar month on Builder. The free Preview APK offer is for a live website URL, not a Flutter ZIP. Platform/network failures refund credits actually charged; customer compile errors do not. Read the logs and the current pricing. For the broader picture of building Flutter APKs without a local Android setup, start with our Flutter APK online build guide — or the old-Flutter-project guide if your app predates null safety.
Frequently asked questions
What does “compile against version 36 or later of the Android APIs” mean?
One of your dependencies was built against Android API level 36 and declares that requirement in its AAR metadata. Gradle's checkDebugAarMetadata / checkReleaseAarMetadata task compares that declaration with your app module's compileSdk and stops the build if yours is lower. The fix is raising compileSdk to 36 — it does not change which devices your app supports.
Is raising compileSdk to 36 safe? Will it drop older devices?
Raising compileSdk alone does not raise minSdk or drop older devices. It changes the API surface available to the compiler. You still need compatible Android Gradle Plugin, JDK and SDK versions, and should test the resulting app. Google Play's target-API policy is a separate requirement.
I raised compileSdk in android/app/build.gradle but the error is still there. Why?
Check the effective value and the failing module. Your app may still inherit flutter.compileSdkVersion, or a plugin module may pin its own lower compileSdk. Prefer a compatible plugin update; if you maintain a root override, apply it before the Android Gradle Plugin finalizes the module configuration. A late afterEvaluate override is not reliable across Gradle/AGP versions.
Why did this suddenly start failing when my code didn't change?
Because dependencies move underneath you. When a plugin you use (or a transitive androidx library) ships a release compiled against API 36, its AAR metadata requirement rises, and the next build that resolves the new version fails the metadata check. Lockfiles delay this but any dependency refresh reintroduces it.
Can a cloud build fix this automatically?
A managed toolchain can handle some supported configuration mismatches, but it cannot guarantee to repair your project. Check the logs for the actual dependency, module and SDK requirement. Code2Native source builds require Builder or Pro and spend bundled credits; platform/network failures refund credits actually charged, while customer compile errors do not.
Code2Native Engineering
Engineering team
Written by the Code2Native engineering team — the people who build and operate the cloud build pipeline.