← All posts

6 min read

Maintaining a Mobile App After Launch: What Founders Should Plan For

What maintaining a mobile app after launch really involves: OS releases, store SDK deadlines, expiring keys, dependency updates, monitoring, triage and a sane rhythm.

  • Maintenance
  • App Updates
  • Product
Cover illustration for Maintaining a Mobile App After Launch: What Founders Should Plan For

An app that nobody touches doesn’t stay the same. It gets worse.

That surprises a lot of founders. A website can sit untouched for years and mostly keep working. A mobile app lives on platforms that change underneath it every year, inside stores that keep raising the bar for what they’ll accept. Leave it alone long enough and one day you can’t ship an update at all, usually right when you need to fix something urgent.

A fair share of my work is picking up apps in exactly that state. I’ve written about taking over an existing Flutter app, and almost every takeover starts with the same catch-up list. This post is about avoiding that list in the first place.

Why apps need ongoing work

None of the following is caused by bad code. It’s just the environment apps live in.

Apple and Google ship major OS releases every year. New versions change permission prompts, background behavior, notification rules and UI details. Sometimes an existing feature keeps working. Sometimes a screen suddenly renders under the status bar or a background task stops firing.

The stores enforce target SDK deadlines. Google Play requires apps to target a recent Android API level, and the bar moves up on a yearly schedule. Apple periodically requires builds to be made with a recent Xcode and SDK. Miss the deadline and you can’t publish updates. On Play, an app that falls far enough behind can also become harder for users on newer devices to find.

Third-party SDKs get deprecated. Payment, analytics, ads, maps and login SDKs all retire old versions. When they do, the old version may stop working on their servers, which is a much ruder surprise than a compile error.

Security patches arrive constantly. Packages you depend on fix vulnerabilities. Your backend framework does too. Staying a few versions behind is normal; staying years behind is how you end up with a known hole and no easy path to close it.

Certificates and keys expire. Apple push certificates, distribution certificates, provisioning profiles, API keys with expiry dates, SSL certificates on your backend, and sometimes your Apple Developer membership itself. Each one has a date on it, and the app breaks quietly when that date passes.

Dependencies drift. Flutter, Dart and the packages your app uses move fast. Updating a little every couple of months is boring and cheap. Updating everything at once after two years is a project of its own.

Monitoring: know before your users tell you

You can’t maintain what you can’t see. Before launch, I make sure every app has:

  • Crash reporting with readable stack traces, so a crash on a specific device shows up as a fixable issue rather than a one-star review. (I cover my setup in crash reporting and monitoring in Flutter.)
  • Basic analytics on the main flows, so you notice when sign-ups or checkouts drop after a release.
  • Backend monitoring and alerts for errors, slow endpoints and service quotas.
  • Store dashboards checked regularly. Both App Store Connect and Play Console show crash and performance data, and Play Console has its own vitals with thresholds that affect visibility.

The point isn’t to stare at dashboards. It’s to set alerts that wake someone up only when something genuinely changes.

Bug triage without panic

After launch, bug reports come from everywhere: store reviews, support emails, your cousin’s phone. Not all of them are equally urgent, and treating them all as emergencies burns money and attention.

I sort issues into a few levels:

  1. Critical. Crashes on launch, payments failing, data loss, security problems. Fix now, ship a hotfix.
  2. Major. A key flow is broken for some users or devices. Fix in the next release.
  3. Minor. Cosmetic issues, rare edge cases, confusing copy. Batch them.
  4. Not a bug. Feature requests in disguise. Move them to the product list.

Every report gets a level, a reproduction note and an owner. That alone turns “everything is on fire” into a list someone can work through.

A sensible maintenance rhythm

Here’s the rhythm I recommend for most small and mid-size apps. Adjust it to how actively the app is being developed.

Weekly (light touch): check crash reports and alerts, triage new issues.

Monthly: update minor dependency versions, review analytics for anything unusual, ship accumulated minor fixes if there are any.

Quarterly: update Flutter and major packages, review upcoming store deadlines, check every expiry date on certificates and keys, run the full regression test on real devices.

Yearly (around the big OS releases): test the app on beta versions of the new iOS and Android before they launch publicly, update the target SDK, and review store policy changes that affect your category.

Having a release checklist makes each of these updates boring, which is exactly what you want.

Automated tests and a CI pipeline make this rhythm cheaper too. If building and testing a release takes one click, small regular updates stop feeling like a risk.

What a maintenance agreement should cover

If you’re working with a freelancer or agency after launch, put the maintenance arrangement in writing. Prices vary too much to be useful here, but the contents shouldn’t. A good agreement answers:

  • What’s included. OS and SDK updates, dependency updates, security patches, store compliance changes, certificate renewals, monitoring.
  • What isn’t. New features are usually separate. Say so explicitly, so nobody argues about whether a “small change” is maintenance.
  • Response times. How fast critical issues are acknowledged and worked on, versus minor ones. Be realistic, especially across time zones.
  • How issues are reported. One channel, with enough detail to act on.
  • Who holds the accounts. The developer accounts, repositories, signing keys and cloud services should belong to you, with the developer given access. This matters most when the agreement ends.
  • Reporting. A short summary of what was updated and what’s coming up, so you can see the work being done.
  • Ending the agreement. Handover notes, credentials returned, access removed cleanly.

The most common mistake I see isn’t a bad agreement. It’s no agreement, followed by a year of silence, followed by an urgent message when the app can’t be updated.

What skipping maintenance actually costs

When an app has been left alone for a long time, the work to bring it back usually looks like this:

  • Upgrading Flutter across several major versions, often with breaking changes along the way
  • Replacing packages that were abandoned in the meantime
  • Updating native Android and iOS project files to current tooling
  • Fixing whatever broke on the newer OS versions
  • Regenerating or recovering expired certificates and keys
  • Re-testing everything, because nothing has been tested in a while

All of that has to happen before the actual fix you needed. Regular maintenance spreads the same work across small, predictable steps.

Takeaways

  • Apps degrade without changes because the OS, stores and SDKs keep moving.
  • Store target SDK deadlines can block you from shipping updates if you fall behind.
  • Track every expiry date: certificates, profiles, keys and memberships.
  • Set up crash reporting, analytics and backend alerts before launch, not after.
  • Triage bugs by severity so only real emergencies get emergency treatment.
  • Put maintenance in writing, and make sure you own the accounts and keys.

If you have an app that’s been quiet for a while, or you want a maintenance plan before it gets that way, let’s talk.

Comments

Questions, corrections or your own experience — leave a comment below (GitHub sign-in).