Xamarin.Forms to .NET MAUI Migration

Delivered in slices, each one shippable.

The failure mode of this migration is well established: a branch is cut, the UI layer is rewritten screen by screen, production carries on changing, and four months later the two are reconciled by hand under time pressure. We do not work that way, because the app in production is usually carrying revenue or carrying a field team.

How the work is sequenced

1. Pin the behaviour that must not change. Before the UI layer is touched, shared view models and business logic get characterization tests: tests that assert what the code does now, not what it should do. They are the only reliable way to know that a migrated screen still calculates the same total.

2. Restructure the project. The Xamarin.Forms shared project and its two head projects become a .NET MAUI project with platform folders. Target frameworks, resource handling, splash and icon generation, and the app lifecycle all move at this step, and nothing about the UI changes yet.

3. Get it running on the compatibility layer. .NET MAUI can host most Xamarin.Forms renderers through its compatibility layer. Standing the app up that way first separates "does it build and launch" from "is every control right", which are two different weeks of work.

4. Convert renderers to handlers, in priority order. Custom renderers become handlers, starting with the controls that appear on the most screens. The renderer-to-handler walkthrough is the same method we use. Controls whose behaviour is now built in stop being custom code entirely.

5. Replace what has no successor. Third-party controls and NuGets with no maintained .NET MAUI package get replaced, reimplemented, or removed with the screen that needed them. We inventory this before it becomes urgent.

6. Move the platform code. Native bindings, DependencyService registrations, platform effects, notifications, background work, and anything that reached around the framework into the platform.

7. Verify parity, screen by screen. Against the production app, not against the specification. Differences are either fixed or written down and signed off by name.

What "releasable slices" means in practice

Each slice ends at a build you could submit. In most engagements the app does ship during the migration, at least once, because a store requirement or a bug fix will not wait for the port to finish. That is a design goal of the sequencing, not an accident of it.

Working with your team

Most of the apps we migrate have one to three .NET developers who maintain them part-time and have never done a mobile migration. Where those developers want to work on it, the engagement is structured so they do: paired slices, reviewed pull requests, and the handler conversions done together rather than delivered finished. It takes slightly longer and it is the only way the maintenance phase is ever cheap.

What we will tell you not to do

Screens that should be retired rather than migrated. Flows that exist because of a process that changed. Custom renderers that were written to work around a framework bug that no longer exists. These are listed in the assessment and re-checked during the migration; a port is the cheapest opportunity you will get to delete things.

Billed hourly, staffed by senior US engineers, scoped in an initial conversation.

Tell us what the app does, which Xamarin version it is on, and what is forcing the change: a store rejection, an OS upgrade, or a security review. A senior engineer replies within one business day.
Talk to an engineer