skip to content

Google Play blocks your Flutter app's update for an old target API level; where does Flutter set targetSdk, and what does raising it risk?

level: middleimportance: should knowfreq 36%

answer

  1. Play's yearly target API requirement
  2. targetSdk = flutter.targetSdkVersion
  3. 36 in Flutter 3.47
  4. a hard-coded integer freezes it
  5. new target opts into behaviour changes

basics

~20 s

The app's build.gradle.kts sets targetSdk = flutter.targetSdkVersion, supplied by the Flutter Gradle plugin (36 in Flutter 3.47), so upgrading Flutter raises it. Raising it opts the app into that Android version's behaviour changes, such as enforced edge-to-edge, which you must test.

solid answer

~40 s

Google Play requires new apps and updates to target a recent Android API level and raises the bar each year, so an old `targetSdk` blocks publishing. In a Flutter project, `android/app/build.gradle.kts` sets `targetSdk = flutter.targetSdkVersion`, a value the Flutter Gradle plugin supplies (36 in Flutter 3.47, alongside `compileSdk` 36 and `minSdk` 24). Upgrading Flutter therefore usually fixes the block; a project that replaced the expression with a fixed integer stays frozen until someone edits it. Raising the target is not cosmetic: it opts the app into that Android version's behaviour changes. Targeting API 35, the default since Flutter 3.27, turns on edge-to-edge, and Android 16 removes the opt-out. Plugins must support the new level too, so upgrade them and test on the newest Android.

code

kotlin · 12 lines
kotlin
android {
    namespace = "com.example.pharmacy"
    compileSdk = flutter.compileSdkVersion

    defaultConfig {
        applicationId = "com.example.pharmacy"
        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName
    }
}

go deeper

for a junior

Recall that targetSdk lives in android/app/build.gradle.kts and normally reads flutter.targetSdkVersion.

for a middle

Explain compileSdk vs minSdk vs targetSdk, where the flutter. defaults come from and why a pinned integer freezes the target.

for a senior

Show you plan the yearly target bump: upgrade Flutter and plugins, test behaviour changes such as edge-to-edge, and ship through a test track.

for a principal

Treat SDK currency as a standing budget item so a store deadline never collides with an urgent release.

## Three SDK numbers, three meanings An Android app declares three API levels, and they are easy to mix up: | Setting | Meaning | Effect of raising it | |---|---|---| | `compileSdk` | the Android SDK the code is compiled against | newer APIs become callable; no runtime behaviour change by itself | | `minSdk` | the oldest Android version that can install the app | older devices can no longer install it | | `targetSdk` | the Android version the app declares it was designed and tested for | the OS applies that version's behaviour changes to the app | Google Play's requirement is about **`targetSdk`**. Each year Play raises the minimum target API level for new apps and for updates to existing ones; an app below it cannot publish updates until it is raised. The deadline itself is Play's policy, not something Flutter controls. ## Where Flutter sets it A project created with `flutter create` contains this in `android/app/build.gradle.kts`: - `compileSdk = flutter.compileSdkVersion` - `minSdk = flutter.minSdkVersion` - `targetSdk = flutter.targetSdkVersion` The `flutter.` values come from the **Flutter Gradle plugin**. In Flutter 3.47 they are `compileSdk` 36, `minSdk` 24 and `targetSdk` 36, and the tool's source notes that the target should always be the latest stable Android version. Two consequences follow: 1. **Upgrading Flutter raises the target** for projects that kept the expression, which is why a Flutter upgrade is usually the first step when Play blocks an update. 2. **A hard-coded integer freezes it.** Teams sometimes replace `flutter.targetSdkVersion` with a number to avoid surprises; that project stays on the old target, whatever Flutter version it uses, until someone edits the file. ## What raising the target changes Raising `targetSdk` tells Android the app is ready for that version's behaviour changes, so they start applying: - **Edge-to-edge.** Apps targeting Android 15 (API 35) draw behind the status and navigation bars by default. Flutter apps began targeting API 35 by default in **Flutter 3.27**, and on Android 16 the opt-out is gone, so layouts must handle system insets, for example through `SafeArea` or `MediaQuery` padding. - **Plugin compatibility.** Plugins run native code under the same target. An outdated plugin may rely on behaviour the new level removed, so run `flutter pub upgrade` and read plugin changelogs. - **Permissions and background work.** New Android versions tighten these; the plugins that wrap them usually handle it once updated. ## How to tell what the app targets today - Read `android/app/build.gradle.kts`; if it says `flutter.targetSdkVersion`, the Flutter SDK in use decides. - Check which Flutter version the project builds with, since that sets the value. - For certainty, inspect the merged manifest of the release bundle, which records the final `targetSdkVersion` after flavors and build types are applied. A product flavor can also set its own target, so check the variant you actually publish, not only `defaultConfig`. ## A safe sequence 1. Upgrade Flutter and plugins together on a branch. 2. Confirm the Gradle file still reads `targetSdk = flutter.targetSdkVersion`, or set the required integer deliberately. 3. Test on an emulator or device running the newest Android version, looking at insets, permission prompts, notifications and background tasks. 4. Ship through a testing track before production. ## Why deadlines still catch teams The requirement arrives once a year, and projects that pinned integers or skipped Flutter upgrades meet it as a surprise, often while an urgent fix waits to ship. Keeping Flutter reasonably current is the cheapest way to never see the block at all.

  • Why not raise minSdk to satisfy Google Play's target API requirement for a Flutter app?
    Play's rule concerns `targetSdk`, the version the app declares it was built for. `minSdk` only sets the oldest Android that can install the app; raising it drops older devices and does nothing for the target requirement.
  • After raising the target, a Flutter app's bottom buttons sit under the Android navigation bar. What happened?
    Targeting Android 15 turns on edge-to-edge, so the app draws behind the system bars. Content must respect the insets, for example by wrapping it in `SafeArea` or reading `MediaQuery` padding. On Android 16 the temporary opt-out is gone, so fixing the layout is the only path.

saying these in an interview costs you the question

  • Raising minSdk satisfies Play's target API requirement.
  • targetSdk only matters at compile time and changes no runtime behaviour.
  • A Flutter app's target API is fixed by the engine and cannot be changed.
  • Pinning targetSdk to an integer keeps it current across Flutter upgrades.
  • Raising targetSdk needs no testing if the app compiles.