Rewrite, replace, or repair a mobile app

The rewrite question comes up in every legacy mobile app eventually. The codebase is aging, the original team is gone, new features take three times longer than they should, and someone suggests starting fresh. It is a tempting idea. It is also one of the most expensive decisions you can make, and getting it wrong in either direction costs real money and time.

Rewriting when you should have maintained means months of development with no new features for users, missed market opportunities, and a high risk of the new version shipping with fewer capabilities than the old one. Maintaining when you should have rewritten means throwing good money after bad, fighting an architecture that actively resists change, and watching your best engineers leave because they are tired of patching a system that should not exist anymore.

Here is the framework we use when advising teams on this decision.

Signs the App Needs a Rewrite

Not every painful codebase needs a rewrite. Pain alone is not a sufficient signal. But there are specific technical and organizational indicators that point clearly toward starting over.

The Framework Is End-of-Life

If the app is built on a framework or platform that is no longer supported, maintaining it becomes increasingly expensive. Examples include apps built with Xamarin.Forms (replaced by .NET MAUI), early React Native versions before the New Architecture, or Cordova-based apps that cannot meet current platform requirements. When the framework itself is not receiving security patches or compatibility updates, every OS release becomes a crisis.

Architecture Rot Has Gone Too Far

Architecture rot is the gradual accumulation of shortcuts, workarounds, and layering violations that make the codebase increasingly difficult to change. Warning signs include: circular dependencies between modules, God classes with thousands of lines that handle unrelated responsibilities, state management spread across dozens of singletons, and a dependency graph so tangled that changing one screen can break three others.

The critical question is whether the architecture can be improved incrementally. If you can refactor one module at a time without touching everything else, the architecture is salvageable. If every change requires understanding and modifying the entire system, you have passed the point where incremental improvement is practical.

You Cannot Hire for the Technology

If the app is written in Objective-C with no Swift, or uses a niche cross-platform framework that few developers know, your hiring pool shrinks dramatically. Maintenance costs rise because specialized talent commands higher rates. Onboarding takes longer because new developers need to learn an unfamiliar technology stack. This is a business problem as much as a technical one.

The Test Suite Is Nonexistent

An app with zero automated tests and no clear separation of concerns cannot be safely changed. Every modification is a gamble because there is no way to verify that existing functionality still works. If the app also lacks crash reporting and analytics, you are operating completely blind. Adding tests retroactively to a tightly coupled codebase is sometimes more effort than rebuilding with testability in mind from the start.

Signs You Should Keep Maintaining

Rewrites fail more often than they succeed. Joel Spolsky called rewriting from scratch "the single worst strategic mistake that any software company can make." While that is an overstatement, the bias should be toward maintenance unless the rewrite case is overwhelming.

The Core Architecture Is Sound

If the app follows a recognizable architecture pattern (MVVM, Clean Architecture, MVI) and the layers are reasonably well separated, the codebase can be improved incrementally. Ugly code that is well structured is dramatically easier to fix than pretty code with no structure.

The Technology Stack Is Current

An app written in Swift with UIKit or Kotlin with Jetpack components is on a supported, actively maintained technology stack. The fact that newer alternatives exist (SwiftUI, Compose) does not mean the current stack is obsolete. UIKit and the Android View system will be supported for many years. Rewriting to adopt the newest UI framework is rarely justified by business value alone.

Users Are Active and Revenue Is Flowing

A rewrite freezes feature development for months. If the app has active users and generates revenue, the opportunity cost of going dark on features is substantial. Competitors do not pause while you rewrite. Maintenance lets you continue shipping improvements while addressing technical debt incrementally.

The Strangler Fig Pattern

When the answer is not clearly "rewrite" or "maintain," the strangler fig pattern offers a middle path. Named after the strangler fig tree that grows around and eventually replaces its host tree, this approach lets you rebuild the app piece by piece while keeping the existing app running in production.

The pattern works like this:

  1. Identify a self-contained module in the existing app. A settings screen, a profile editor, or a secondary feature flow are good starting points.
  2. Build the replacement using the new architecture, framework, or technology stack. The replacement lives alongside the old code in the same project.
  3. Route users to the new module using a feature flag. Start with internal testers, then roll out to a percentage of users.
  4. Remove the old module once the replacement is stable and validated in production.
  5. Repeat with the next module.

On Android, this is particularly practical because you can introduce Jetpack Compose screens inside an existing View-based app using ComposeView. Each new screen can be Compose-based while existing screens remain untouched. On iOS, SwiftUI views can be wrapped in UIHostingController and presented within a UIKit navigation stack.

The strangler fig approach takes longer than a ground-up rewrite but carries far less risk. You ship continuously, validate each piece in production, and can pause or reprioritize at any point without losing progress.

Building the Business Case

Technical arguments alone rarely win the rewrite vs. maintain debate. Decision makers need to see the cost and timeline comparison in concrete terms.

Cost of Continued Maintenance

Calculate the current cost of maintaining the app. Include developer hours spent on bug fixes, OS compatibility updates, dependency upgrades, and the extra time required for new features due to technical debt. If a feature that should take one sprint consistently takes three, the overhead is quantifiable. Multiply the monthly maintenance cost by 24 months to get a two-year projection.

Cost of a Rewrite

Estimate from observed behavior and thin technical slices, not a universal multiplier. Inventory workflows, integrations, analytics, accessibility, offline states, operational tools, and store configuration. Include dual-running, migration, support, and the opportunity cost of work paused during replacement.

Risk Assessment

The rewrite carries execution risk (will it actually be better?), schedule risk (will it take longer than planned?), and feature parity risk (will users lose functionality they depend on?). Maintenance carries different risks: escalating costs, inability to meet future platform requirements, and developer attrition. Lay out both risk profiles clearly.

Evidence that supports replacement

A replacement case becomes credible when a thin slice proves that the current stack cannot meet a measured requirement, the limiting constraint cannot be isolated, and the new approach meets that requirement with an operable migration path. “The code is old” and “features feel slow to build” are reasons to investigate, not proof.

Evidence that supports incremental change

Maintenance is favored when the app has a reproducible release, observable production health, seams that let one module change at a time, and active users who depend on behavior a rewrite would need to rediscover. In that case, migrate at boundaries and compare delivery and quality before widening the effort.

There is no universal answer. But with a structured framework, honest cost analysis, and a clear understanding of both the risks and the rewards, you can make the right call for your specific situation.

DEVSFLOW Maintenance audits inherited codebases to document the evidence for continued maintenance, staged replacement, or a rewrite. Review the standard maintenance scope.