Every estimate I have ever seen for mobile app maintenance is wrong in the same direction, and for the same reason.
The estimate is built as a support retainer. Bug fixes, some analytics, a designer on call. Fifteen percent of the original build cost, annually, because that is the number everyone repeats.
The actual invoice is generated by something else entirely: a stack of externally-imposed deadlines that you do not control, cannot negotiate, and did not put in your Gantt chart. Google sets them. Apple sets them. Your SDK vendors set them. Your certificate authority sets them. None of them care about your roadmap.
This is a post-mortem on where the money actually goes.
-
The annual platform tax
Google Play's target API level policy is not a suggestion. As of August 31, 2025, new apps and app updates must target Android 15 (API level 35) or higher to be submitted at all. Existing apps must target at least API 34 to remain available to new users on devices running a newer OS than the app targets. Fall below that and your app quietly stops appearing for new installs on modern devices — no removal email, just a gradual disappearance from the funnel.
Apple runs the same cadence with less ceremony. Submissions must be built with a recent Xcode and SDK; the minimum floor moves annually, and privacy manifest requirements for third-party SDKs have been enforced since 2024.
Here is what makes this expensive: bumping targetSdkVersion is a one-line change, and the one-line change is never the work.
gradle
android {
compileSdk = 35
defaultConfig {
targetSdk = 35 // <- 15 seconds
}
}
Targeting API 35 activates Android 15 behaviour changes for your process. Edge-to-edge display is enforced by default, so every screen with a hardcoded status bar assumption now has content sliding under the system bars. Predictive back requires OnBackInvokedCallback migration. Non-SDK interface restrictions tighten, so that reflection hack from 2021 throws at runtime instead of at compile time.
The 15-second change generates two to six engineer-weeks of regression work. Nobody budgets the six weeks.
The 16 KB page size problem
If you ship native code — and if you use almost any media, ML, database or crypto library, you do — Android's move to 16 KB memory page sizes requires recompiling every .so in your APK against a compatible NDK.
bashFind out whether you have a problem
unzip -o app-release.apk -d /tmp/apk
find /tmp/apk/lib -name ".so" | while read f; do
echo "$f: $(objdump -p "$f" | grep -m1 LOAD | awk '{print $NF}')"
done
If a .so shows 2*12 alignment, it needs rebuilding. If that .so came from a third-party AAR whose vendor has stopped shipping updates, you are not rebuilding anything. You are replacing the dependency, and the replacement has a different API surface.
That is not maintenance. That is a small feature project wearing maintenance's coat. Dependency drift is compound interest
A typical React Native or Flutter app carries several hundred transitive dependencies. Each one has a maintainer who may or may not still care.
Run this on any app older than eighteen months:
bash
npm outdated --long
npm audit --audit-level=high
Then run it again with the honest question: how many of these have a breaking major version between me and the fix?
Deferring dependency upgrades feels free because nothing breaks today. It is not free. It is a loan, and the interest compounds. Upgrading a library across one major version is a contained task. Upgrading it across four, while three other libraries in the graph also need upgrading and two of them have peer-dependency conflicts with each other, is a multi-week untangling exercise with a nontrivial chance of a rewrite.
The team that spends four hours a month on dependency hygiene pays roughly 48 hours a year. The team that defers pays a 200-hour migration in year three, plus the opportunity cost of the feature that was not shipped while three engineers untangled the graph.
The most expensive line in any mobile app maintenance budget is the one that reads "we'll deal with it next quarter."Third-party SDK end-of-life
You do not control the lifecycle of your analytics SDK, your payment SDK, your push provider, your crash reporter, or your auth library.
When a payment SDK announces it will not support API 35, you have three options: wait for the vendor, fork and patch, or migrate to a competitor. All three cost money. The third costs the most, and it is frequently the only real option, because the deadline is Google's and the vendor's timeline is the vendor's.
I have watched a fintech client discover, six weeks before a Play Store deadline, that their KYC SDK's Android 15 support was "on the roadmap." The migration to a replacement provider consumed a full quarter, and none of it appeared on any product roadmap. It was, on the ledger, maintenance.
Audit your SDKs annually against a simple question: if this vendor disappeared tomorrow, what is my exit cost? Any dependency where the answer exceeds four weeks is a strategic risk, not a technical one.The invisible operational baseline
These items never appear in maintenance quotes and always appear in maintenance costs.
Certificate and provisioning expiry. Apple distribution certificates expire. Push notification certificates expire. Someone has to notice before your users do, and the person who set them up has usually left.
Backend scaling under changing client behaviour. An OS update changes background execution rules. Suddenly your sync logic fires differently, your API traffic pattern shifts, and your cloud bill moves without a single line of app code changing.
CI/CD maintenance. Build agents drift. Xcode versions on hosted runners get deprecated. Your pipeline that worked in March fails in September because GitHub retired the macOS 13 image.
Crash-rate regression. A crash-free session rate that slips from 99.7% to 99.1% is invisible on a dashboard and catastrophic in reviews. Investigating a 0.6% regression across device fragmentation is genuinely difficult engineering work.
Store policy changes. Data safety declarations, permission justifications, account deletion requirements. Each one is a form, a code change, and a resubmission.
What the number actually looks like
The 15–20% rule is not wrong. It is just misattributed. People hear it and imagine a support desk. It is really:
Cost driver Share of annual maintenance
Platform/OS compliance (target SDK, behaviour changes, NDK) 25–35%
Dependency and SDK upgrades 20–30%
Bug fixes and crash regression 15–20%
Backend, infrastructure and CI 10–20%
Store policy and compliance overhead 5–10%
Note what is missing: new features. Those are not maintenance, and the moment they get billed as maintenance, your maintenance budget becomes a fiction and your feature roadmap becomes a lie.
The one practice that changes the number
Treat platform deadlines as scheduled work, not incidents.
Every year, Google announces the target API deadline months ahead. Every year, Apple announces the SDK floor at WWDC. Every year, teams find out in August.
Put both on the engineering calendar in January. Allocate the sprint. Run the target SDK bump on a branch in February, on the beta SDK, and find the breakage while the deadline is seven months away and the fix is cheap. Audit your native libraries for page alignment before the vendor deadline, not after Play Console flags you.
Maintenance is expensive because it is treated as an interruption. It is not an interruption. It is the recurring, forecastable cost of operating on someone else's platform. The only genuinely optional part is whether you pay for it on your schedule or on Google's.
Top comments (0)