.NET MAUI applications have traditionally used Mono as the runtime for mobile platforms.
That changes significantly with .NET 11.
As of .NET 11 Preview 6, CoreCLR is the only runtime for .NET MAUI mobile applications targeting Android, iOS, and Mac Catalyst. Microsoft has been moving the mobile workloads toward the same CoreCLR runtime used by ASP.NET Core, cloud services, desktop applications, and other .NET workloads.
This is more than an implementation detail.
Changing the runtime can affect:
Microsoft's own guidance is clear that developers should measure their applications rather than assume that every application will improve equally. The .NET MAUI team specifically recommends comparing startup and package size against a .NET 10 baseline using real devices and Release builds.
This makes CoreCLR migration an excellent opportunity for a controlled benchmark.
What Changed in .NET MAUI?
Previously, the runtime architecture for mobile applications was different from the server and desktop .NET ecosystem.
The simplified model was:
.NET MAUI Android/iOS
|
v
Mono
while many other .NET workloads used:
ASP.NET Core
|
v
CoreCLR
.NET 11 brings the mobile platforms onto CoreCLR.
The current .NET 11 Preview 6 architecture is:
.NET MAUI
|
+---- Android
|
+---- iOS
|
+---- Mac Catalyst
|
v
CoreCLR
Microsoft also clarifies that Blazor WebAssembly is not affected by this change and continues to use Mono.
Why CoreCLR Matters
Runtime unification provides several potential benefits.
CoreCLR brings technologies such as:
Tiered JIT
ReadyToRun
Profile-Guided Optimization
Shared runtime implementation
Common .NET diagnostics tooling
Microsoft describes CoreCLR as providing a stronger foundation for runtime performance and future NativeAOT work on mobile platforms.
However, these capabilities do not guarantee that every application will automatically become faster.
Application startup depends on much more than the runtime:
Startup
|
+-- Runtime initialization
+-- JIT / native code
+-- Dependency loading
+-- DI registration
+-- XAML loading
+-- Database initialization
+-- Network calls
+-- Image loading
+-- Third-party SDKs
That is why measurement is essential.
Define the Benchmark Before Migrating
A useful benchmark compares the existing application with the migrated version.
For example:
Baseline
.NET 10 + existing runtime
|
v
Measurements
Candidate
.NET 11 + CoreCLR
|
v
Measurements
Comparison
|
v
Decision
Do not change several unrelated application components at the same time.
If you simultaneously:
then you will not know which change caused a performance difference.
Benchmark Environment
A reproducible benchmark should document:
.NET SDK version
.NET MAUI version
Target platform
Device model
OS version
CPU architecture
Build configuration
Linker/trimming settings
AOT configuration
Application build
Network state
Database state
For mobile benchmarks, real devices are especially important.
An emulator can be useful for development, but it should not be the only source of production-performance conclusions.
Microsoft explicitly recommends measuring .NET 11 MAUI applications on target devices and comparing them with the .NET 10 baseline.
Create a .NET 10 Baseline
Before migrating, build the existing application in Release mode.
For example:
dotnet publish \
-f net10.0-android \
-c Release
The exact target framework depends on the project and installed SDK.
Record at least:
Cold startup
Warm startup
Package size
Memory usage
CPU usage
Time to first screen
Time to usable application
Do not rely only on stopwatch measurements.
Automated instrumentation provides more consistent results.
Measure Cold Startup
Cold startup means the application is not already running.
A simplified test looks like:
Force Stop
|
v
Launch Application
|
v
Runtime Starts
|
v
Application Initializes
|
v
First Usable Screen
Measure the interval between launch and a clearly defined application-ready event.
For example:
var startupTimer =
Stopwatch.StartNew();
InitializeApplication();
startupTimer.Stop();
logger.LogInformation(
"Application startup: {ElapsedMs} ms",
startupTimer.ElapsedMilliseconds);
The exact location of the timer matters.
If you stop the timer too early, you may measure only framework initialization rather than the time users actually experience.
Define "Startup Complete"
This needs to be explicit.
Possible definitions include:
Application process started
|
v
Main page created
|
v
Navigation initialized
|
v
Initial data loaded
|
v
First interactive screen
For a user-facing benchmark, the last meaningful event is often more useful than process creation.
However, the definition should remain consistent between the baseline and migrated builds.
Measure Warm Startup
Warm startup is different.
The operating system may retain application-related resources after the first launch.
A benchmark should therefore distinguish:
Cold Start
Application not running
Warm Start
Application restarted with some resources cached
Run each test multiple times rather than relying on one measurement.
For example:
Cold:
Run 1
Run 2
Run 3
Run 4
Run 5
Warm:
Run 1
Run 2
Run 3
Run 4
Run 5
Then report the distribution.
Avoid publishing a single number without explaining how it was obtained.
Measure Package Size
Runtime changes can also affect application size.
For Android, measure the resulting APK or AAB.
For iOS, measure the resulting IPA or relevant packaged application artifact.
Microsoft specifically recommends comparing package size between the .NET 10 baseline and .NET 11 CoreCLR builds.
Record:
Raw package size
Compressed distribution size where relevant
Architecture-specific size
Be consistent between builds.
Do not compare an Android APK from one configuration with an Android AAB from another and treat the difference as a runtime effect.
Measure Memory Usage
Startup time is only one part of the benchmark.
Measure memory after defined application states.
For example:
Launch
|
v
Main Screen
|
v
Load Data
|
v
Navigate
|
v
Open Detail Screen
|
v
Return
|
v
Measure
This helps detect memory growth caused by application behavior rather than startup alone.
Useful measurements include:
Use .NET Diagnostics
One advantage of CoreCLR on mobile is the availability of familiar .NET diagnostics.
Microsoft states that tools such as dotnet-trace and dotnet-counters can now be used with .NET MAUI mobile applications running on CoreCLR.
That makes it easier for teams already familiar with server-side .NET diagnostics to investigate mobile runtime behavior.
Conceptually:
MAUI Application
|
v
CoreCLR
|
+---- dotnet-trace
|
+---- dotnet-counters
|
+---- Runtime Metrics
The exact connection and collection workflow varies by platform and development environment.
Monitor Runtime Counters
Runtime counters can help identify whether an observed slowdown is related to:
CPU utilization
GC
Allocation
Threading
Exceptions
The important point is correlation.
For example:
Startup slower
|
+-- CPU high?
+-- Allocation high?
+-- GC activity high?
+-- Dependency loading slow?
A benchmark result becomes much more useful when you can explain why it changed.
Benchmark Memory After Navigation
A mobile application may appear efficient during startup but accumulate memory as users navigate.
Create a repeatable workflow:
Home
|
v
List
|
v
Details
|
v
Back
|
v
List
|
v
Details
|
v
Back
Repeat the workflow several times.
Measure memory after each cycle.
If memory continuously increases, investigate whether the application has:
Event-handler leaks
Unreleased subscriptions
Cached images
Retained pages
Native resource leaks
Long-lived references
Do not automatically attribute memory growth to CoreCLR.
The runtime is only one part of the application.
Compare Equivalent Builds
The baseline and candidate should be as similar as possible.
For example:
| Variable | .NET 10 Baseline | .NET 11 Candidate |
|---|
| Application source | Same | Same |
| Device | Same | Same |
| OS | Same | Same |
| Build mode | Release | Release |
| Data | Same | Same |
| Network | Same | Same |
| Test workflow | Same | Same |
| Runtime | Baseline | CoreCLR |
This makes the runtime migration the primary experimental variable.
Test Real Application Flows
A benchmark based only on:
Launch -> Exit
is not enough for a complex application.
Microsoft recommends exercising the complete application flow, including navigation, data loading, and platform-specific integrations.
A realistic workflow might be:
Launch
|
v
Authentication
|
v
Dashboard
|
v
Load API data
|
v
Open list
|
v
Open detail
|
v
Perform action
|
v
Return to dashboard
This exposes issues that a startup-only benchmark cannot detect.
Test Platform-Specific Integrations
.NET MAUI applications frequently use platform-specific capabilities.
Examples include:
Camera
Location
Notifications
Bluetooth
Files
Sensors
Media
Native SDKs
Test them separately.
For example:
CoreCLR Migration
|
+-- Android API
+-- iOS API
+-- Mac Catalyst API
+-- Third-party native SDK
A runtime migration can expose compatibility problems in libraries that depend on reflection, dynamic code generation, or runtime-specific behavior.
Microsoft specifically calls out third-party libraries using reflection, dynamic code generation, or Mono-specific APIs as areas that should be validated during the transition.
Review Reflection-Heavy Libraries
Reflection can be important for:
Dependency injection
Serialization
ORMs
Plugin systems
Dependency discovery
Native bindings
Audit libraries that dynamically inspect types.
For example:
var type =
Type.GetType(typeName);
The code may work under one runtime configuration but behave differently when trimming, AOT, or runtime assumptions change.
Do not assume a successful startup proves that all dynamically discovered types remain available.
Test the actual feature.
Review Dynamic Code Generation
Some libraries rely on:
Expression Trees
Reflection.Emit
Dynamic Methods
Runtime-generated proxies
These areas deserve additional testing when moving between runtime and compilation configurations.
If a third-party component documents runtime-specific requirements, follow the vendor's compatibility guidance.
CoreCLR and ReadyToRun
CoreCLR can use ReadyToRun (R2R) images to reduce some runtime compilation work.
Microsoft describes partial R2R and packaged PGO profiles as part of the .NET 11 mobile performance work.
Conceptually:
Application Assembly
|
v
ReadyToRun Code
|
v
Runtime
|
v
Reduced JIT Work
This can affect startup behavior, but the actual result depends on the application.
Therefore, measure startup rather than assuming R2R will produce a specific percentage improvement.
CoreCLR and PGO
Profile-Guided Optimization can use runtime behavior to improve generated code.
The simplified concept is:
Application Execution
|
v
Profile Information
|
v
Optimization
|
v
Application Build/Runtime
Again, the correct engineering approach is measurement.
If your application has a different execution profile from the workload used to produce an optimization profile, the results may differ.
Compare Memory Under Load
Do not only measure memory immediately after launch.
Create defined checkpoints:
T0 = After launch
T1 = After login
T2 = After initial data load
T3 = After navigation
T4 = After repeated workflow
T5 = After idle period
Then compare:
.NET 10
vs
.NET 11 CoreCLR
The resulting graph or table can reveal whether memory stabilizes or continually increases.
Do not claim a memory improvement unless the measurements support it.
Example Benchmark Table
A final article or engineering report can use a table such as:
| Metric | .NET 10 | .NET 11 CoreCLR | Difference |
|---|
| Cold startup | Measure | Measure | Calculate |
| Warm startup | Measure | Measure | Calculate |
| Package size | Measure | Measure | Calculate |
| Initial memory | Measure | Measure | Calculate |
| Memory after workflow | Measure | Measure | Calculate |
| Allocation rate | Measure | Measure | Calculate |
The numbers should come from your actual test environment.
For example, if baseline startup is 1,000 ms and the candidate is 900 ms:
Improvement =
(1000 - 900) / 1000 * 100
= 10%
Do not substitute hypothetical values into a production benchmark.
Automate the Benchmark
Manual measurements are useful for initial validation, but automation improves repeatability.
A benchmark harness can record:
{
"runtime": "net11.0",
"platform": "android",
"device": "test-device",
"build": "Release",
"coldStartupMs": 0,
"warmStartupMs": 0,
"packageSizeBytes": 0,
"memoryBytes": 0
}
The actual values should be populated by the measurement system.
Then compare baseline and candidate builds automatically.
Test on Multiple Devices
Mobile hardware varies significantly.
A single device cannot represent every target.
Where practical, test representative device classes:
Older / lower-end
|
v
Mid-range
|
v
High-end
For iOS, similarly test the device generations relevant to the application's supported deployment range.
The objective is not to benchmark every device.
It is to identify whether runtime behavior changes significantly across the supported hardware range.
Test Android and iOS Separately
Do not combine platform results.
Use:
Android
.NET 10 -> .NET 11
iOS
.NET 10 -> .NET 11
Mac Catalyst
.NET 10 -> .NET 11
Microsoft reports different performance characteristics across platforms during the CoreCLR transition. Its Preview 6 update states that iOS and Mac Catalyst are generally faster than Mono, while Android was within 10 percent of Mono for startup and app size in Microsoft's reported validation. These are Microsoft's observations, not a universal benchmark for every application.
Your application's results can differ.
Common Migration Problems
Startup Gets Worse
Do not immediately revert the migration.
Profile startup first.
Look at:
Dependency loading
JIT
R2R
PGO
Reflection
Third-party libraries
Network calls
Database initialization
Microsoft has acknowledged reports of startup and package-size regressions in some larger Android applications during the preview transition.
Package Size Increases
Compare the complete packaged artifact.
Then inspect:
Runtime
Native libraries
Managed assemblies
Resources
Architecture-specific binaries
Determine whether the increase comes from the runtime or another dependency.
A Third-Party Library Stops Working
Check whether the library depends on:
Mono-specific APIs
Reflection
Dynamic code generation
Native bindings
Runtime assumptions
Then check the library's compatibility information.
Hot Reload Behaves Differently
Hot Reload and debugging have been actively evolving during the CoreCLR mobile transition.
Microsoft reports substantial progress in Preview 6 while noting that some scenarios remain in progress.
Do not use development-time tooling behavior as the only reason to reject a Release build migration.
Common Benchmarking Mistakes
Comparing Different Devices
Always use the same device when comparing two builds.
Comparing Debug With Release
Use Release builds for production-oriented performance measurements.
Measuring Only Startup
Startup is important, but it is only one part of mobile performance.
Measuring Only Memory
Memory should be evaluated alongside allocations, GC behavior, application state, and native resources.
Using One Run
One measurement can be affected by background processes, caches, thermal conditions, and other variables.
Changing Application Code During the Experiment
If you optimize the application between baseline and candidate measurements, the runtime is no longer the only variable.
Publishing Microsoft's Numbers as Your Own
Microsoft's published observations are useful context, but they should not be presented as a benchmark of your application.
A Practical Migration Benchmark Workflow
Use this sequence:
Build .NET 10 Baseline
|
v
Release to Test Device
|
v
Measure Startup
|
v
Measure Memory
|
v
Measure Package Size
|
v
Run Full App Workflow
|
v
Migrate to .NET 11
|
v
Repeat Identical Tests
|
v
Compare Results
|
v
Investigate Regressions
This approach produces evidence rather than assumptions.
Best Practices
Create a .NET 10 baseline before migration.
Use .NET 11 Release builds for comparison.
Test on real target devices.
Keep the test workload identical.
Measure cold and warm startup separately.
Measure package size.
Measure memory at multiple application states.
Use runtime diagnostics when investigating differences.
Test third-party libraries explicitly.
Test complete application flows.
Separate Android, iOS, and Mac Catalyst results.
Do not assume CoreCLR produces the same improvement for every application.
Record the exact SDK, runtime, device, and build configuration.
Do not publish benchmark numbers that you did not actually measure.
Frequently Asked Questions
Is CoreCLR now the default for .NET MAUI in .NET 11?
More precisely, as of .NET 11 Preview 6, CoreCLR is the only runtime for .NET MAUI mobile apps targeting Android, iOS, and Mac Catalyst. The previous Mono selection path has been removed for those targets in that preview.
Does this affect Blazor WebAssembly?
No.
Microsoft explicitly states that Blazor WebAssembly continues to use Mono and is not affected by this .NET 11 MAUI runtime transition.
Will CoreCLR automatically make my MAUI application faster?
No universal guarantee should be made.
Microsoft reports positive results in its validation, but also acknowledges application-specific regressions, particularly in some Android scenarios. The recommended approach is to measure your own application against its .NET 10 baseline.
What should I benchmark first?
Start with:
Cold startup
Warm startup
Package size
Initial memory
Memory after a representative workflow
Then investigate any meaningful differences with runtime diagnostics.
Should I benchmark an emulator?
An emulator can be useful for development and repeatable functional tests.
For production performance conclusions, prioritize real devices that represent your supported hardware.
Can I continue using Mono with .NET 11 Preview 6?
Microsoft's Preview 6 announcement states that CoreCLR is now the only runtime for .NET MAUI mobile applications on Android, iOS, and Mac Catalyst and that the previous Mono selection path has been removed.
Conclusion
The move from Mono to CoreCLR is one of the most significant runtime changes for .NET MAUI mobile applications.
As of .NET 11 Preview 6, CoreCLR is the only runtime for .NET MAUI Android, iOS, and Mac Catalyst applications. Microsoft has positioned the change around runtime unification, performance foundations, diagnostics, and the longer-term NativeAOT direction.
But the correct migration strategy is not:
.NET 10
|
v
.NET 11
|
v
Assume Faster
It should be:
.NET 10 Baseline
|
v
Measure
|
v
.NET 11 CoreCLR
|
v
Measure Again
|
v
Compare
|
v
Profile
|
v
Optimize
The most important metrics are not limited to startup time.
A meaningful CoreCLR migration benchmark should examine:
Startup
+
Memory
+
Package Size
+
Allocations
+
GC Behavior
+
Application Workflow
+
Third-Party Compatibility
+
Platform Integrations
The key principle is simple:
Do not migrate to CoreCLR because a benchmark says mobile applications are faster. Migrate with evidence that CoreCLR works correctly and delivers acceptable behavior for your application, devices, and production workload.
The .NET 11 preview window provides an opportunity to establish that evidence before the final release. Microsoft is explicitly asking developers to test their applications now and report reproducible results, making application-specific benchmarking particularly valuable during this transition.