Flutter ships new stable releases several times a year, and Apple and Google raise their own requirements on a regular schedule too. An app that sits untouched for a year or two rarely breaks all at once. It drifts, until one day a routine update turns into a week of build errors.
The good news is that the warning signs show up early. If you recognize more than one of these, it’s time to plan an upgrade instead of waiting for a deadline to force one.
1. Packages won’t resolve
You try to add or update a single package and get a version solving failure. Newer releases of the packages you need depend on a newer Dart SDK, and your project’s SDK constraint won’t allow it. Every workaround — pinning, dependency overrides, forks — adds more debt.
2. Android builds break when you touch anything
Flutter’s Android build setup has changed a lot over the years, including how Gradle plugins are applied. Older projects end up with Gradle, Android Gradle Plugin, Kotlin and Java versions that no longer agree with each other or with newer plugins. Fixing one mismatch exposes the next.
3. You’re close to Google Play’s target API deadline
Google Play requires apps to target a recent Android API level before you can publish updates, and the required level moves up every year. Raising targetSdkVersion often means upgrading Flutter, plugins and native build tooling at the same time — exactly the upgrade you’ve been postponing.
4. App Store Connect rejects your build
Apple requires uploads to be built with a recent version of Xcode and the iOS SDK, and publishes these changes on its upcoming requirements page. New Xcode releases also regularly drop support for old toolchains and project settings, and Apple has introduced requirements such as privacy manifests for commonly used SDKs. An outdated project can fail on any of these before review even starts.
5. Packages you depend on are discontinued
pub.dev marks packages as discontinued when their authors stop maintaining them, often pointing to a replacement. Discontinued plugins stop receiving fixes for new OS versions, and they can block you from upgrading everything else.
6. Your code predates null safety
Dart 3 only supports sound null safety. If your app, or one of its dependencies, was written before null safety, it won’t compile on current Flutter without a real migration.
7. Nobody wants to be the one who upgrades it
This one isn’t technical, but it’s the most reliable sign. If previous attempts ended in a rollback, or the developer who understood the build has moved on, the upgrade won’t get easier with time.
How to approach an upgrade safely
- Take inventory first. Record your current Flutter and Dart versions, run
flutter pub outdated, and list your native dependencies and any custom platform code. - Upgrade in stages. Jumping several major versions at once makes it hard to tell which change broke what. Moving in steps keeps each problem small.
- Let the tooling help.
dart fix --applyhandles many API migrations automatically, and Flutter documents breaking changes together with migration guides. - Decide what to do with abandoned packages. Replace, fork or re-implement them deliberately, not as a side effect of fixing a build error.
- Test release builds on real devices. Debug builds on a simulator hide problems that only appear in release mode or on older hardware.
- Work on a branch. Keep shipping fixes from your main branch until the upgrade is verified.
When to get help
If your app is more than a few versions behind, relies on custom native code, or has already resisted one upgrade attempt, an experienced second pair of eyes saves time. We start every Flutter upgrade with a free assessment: we review your project, show you what’s blocking the upgrade and give you a fixed price to fix it.