Skip to content

.net 11 RC1 iOS and Android app Size is nearly double #134182

Description

@TedMobile

Description

We just built and deployed the app locally and noticed a huge increate in the size of the app - the same app now is quite large -it add at least 30mb to it see screenshots - the .net 10 is considerably smaller

Image Image

Hope the above helps to diagnose the issue .. this is a production app so obviously is not feasible to add as a repo.

thanks

Reproduction Steps

this is a production app so obviously is not feasible to add as a repo.

Expected behavior

deployed app should be same size

Actual behavior

it adds 30 mb to both ios and android

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

Activity

  1. huoyaoyuan commented on Sep 19, 2026

    @huoyaoyuan
    Member

    It's somehow expected because the implementation switched from Mono to CoreCLR (https://devblogs.microsoft.com/dotnet/dotnet-maui-moves-to-coreclr-in-dotnet-11/ https://devblogs.microsoft.com/dotnet/coreclr-progress-and-mono-timeline-dotnet-maui/).

    You can try with ReadyToRun, NativeAOT options to test with size, performance and compatibility, and track related issues at https://github.com/dotnet/android etc.

  2. TedMobile commented on Sep 19, 2026

    @TedMobile
    Author

    @huoyaoyuan thanks for your reply - my clients will be not pleased at all!! We are not talking about a few mb - it’s 40 mb increase on both platforms!!

    Can I use mono? Is the option still available?

    Whenever I heard David Ortinau and all the talks they said something like 10% android and iOS was smaller! I do hope we have the option for mono for this year because it’s not acceptable!!

    Will this be investigated? Because this is what people complained in earlier previews and then it was fixed!

    Let’s hope it’s a bug

  3. martincostello commented on Sep 19, 2026

    @martincostello
  4. MichalPetryka commented on Sep 19, 2026

    @MichalPetryka
    Contributor

    Can I use mono? Is the option still available?

    How to Opt Back to Mono

    This was removed.

  5. TedMobile commented on Sep 21, 2026

    @TedMobile
    Author

    @davidortinau can you help? I think this is worth investigating before .NET 11 GA because this appears very similar to a problem that was already identified earlier in the .NET 11 cycle.

    In #124212, Microsoft measured the MAUI sample at approximately 50 MB using Mono and 80 MB using CoreCLR — a ~30 MB increase. That issue resulted in several .NET 11 size improvements, including trimming changes, native symbol stripping (~36 MB reduction) and removal of debug libraries from Release builds (~3 MB). The issue was subsequently closed against the .NET 11 milestone.

    We are now seeing effectively the same ~30 MB regression again with .NET 11 RC1, and importantly we are seeing it on both iOS and Android with an existing production MAUI application. The application itself has not changed in a way that would account for this increase; the significant variable is the move from .NET 10 to .NET 11/CoreCLR.

    This matters because CoreCLR is becoming the default runtime. Even if a ~100 MB application remains within App Store/Google Play limits, an additional ~30 MB is a substantial regression for a mobile application: it affects initial downloads, every application update, mobile-data usage and storage, and becomes more significant for larger real-world applications.

    Because the earlier CoreCLR size regression was considered important enough to optimise during the .NET 11 development cycle, I think it would be valuable to confirm whether:

    • one of those size optimisations is no longer being applied in RC1;
    • this is an expected remaining CoreCLR/R2R overhead; or
    • there is a new regression affecting Release MAUI builds.

    I cannot provide the production application as a reproduction project, but the consistent increase across both iOS and Android, together with the very similar +30 MB previously identified in #124212, suggests this deserves investigation rather than being treated simply as expected application growth.

    Can the mono csproj switch be reinstated for .net 11?

    thanks

  6. dotnet-policy-service commented on Sep 21, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to 'os-ios': @vitek-karas, @kotlarmilos, @steveisok, @akoeplinger
    See info in area-owners.md if you want to be subscribed.

  7. dotnet-policy-service commented on Sep 21, 2026

    @dotnet-policy-service
    Contributor

    Tagging subscribers to 'arch-android': @vitek-karas, @simonrozsival, @steveisok, @akoeplinger
    See info in area-owners.md if you want to be subscribed.

  8. 16 remaining items

  9. vitek-karas commented on Sep 23, 2026

    @vitek-karas
    Member

    Also is this dotnet/android#12867 waiting approval has any impact on a positive outcome?

    Unlikely - you already tried that basically. Simon did an experiment with some runaway generics and found that in that specific case this would help keep the size reasonable while still getting similar perf - so it was motivated by this issue, but unlikely the same root cause.

  10. jonathanpeppers commented on Sep 23, 2026

    @jonathanpeppers
    Member

    @TedMobile I was reviewing this and one thing stuck out to me:

    • I don't see an indication that Mono+AOT was being used in your .NET 10 application.
    • Are there any (Mono) libaot-*.so files? There should be one per .NET assembly.

    So, is it possible you were using Mono (JIT only) and you moved to .NET 11, which is now using ReadyToRun? In theory, the libaot-*.so file size should get shuffled around into libassembly-store.so when you move to .NET 11 (but were there none?). So, disabling ReadyToRun entirely would be a better comparison to .NET 10?

    Let me know if I'm on the right track at all, thanks!

  11. vitek-karas commented on Sep 23, 2026

    @vitek-karas
    Member

    Thanks a lot for the command lines - from those it seems that on Android the problem is full R2R actually (even though it's not explicitly enabled). The root is likely that your project uses Microsoft.Maui.Controls version 10.0 which doesn't contain the necessary build changes and data files to enable partial R2R on CoreCLR (it does that only for mono). Could you please try upgrading Microsoft.Maui.Controls (and probably the whole MAUI) to 11.0.0-rc.1.26451.6 (this should be the version which belongs to .NET 11 RC1 release)?

    I was able to validate locally that on Android this has a big impact, but it's not clear as noted by Jonathan if your app was using AOT on Android at all - in which case updating MAUI would get you closer, but not fully there since it will do partial AOT, not no-AOT.

    For iOS the MAUI update should have an effect but much smaller based on my local testing. So for iOS we would need to check what was the configuration of the app before. Specifically do you set either UseInterpreter or MtouchInterpreter MSBuild properties - ideally check the value of these in the binlog as that should show the effective value used during the build.

  12. TedMobile commented on Sep 25, 2026

    @TedMobile
    Author

    @vitek-karas
    Hi, we have trying to build/deploy the app using everything .net 11 and we have encountered issues with android packages (dependency hell!!) what used to just work in net 10 , in net 11 android does not longer like packages like Xamarin.play.core ( we used the reviewmanager there ... looking into it..

    we do manage to build both ios and android and the appsize and results are identical to before .
    I have attached

    • an extract of our ios and android csproj.
    • commandlines

    Android_CommandLineArguments_CreateR2RImages.txt

    ios-csprojExtract.txt

    iOS-CommandLineArguments_R2R.txt

    Android-CSProj.txt

    basically the above is with the 2 properties set to false "MauiEnableFullReadyToRun=false and publishreadytorun=false too ,

    so no change at all - we also tried the other flags and they were both 100mb.. no changes there.

    there was no interpreter set on iOS.

    @jonathanpeppers please see the cs proj extract of what we actually set - and below is an image that shows what we get with net 11 with MauiEnableFullReadyToRun=false and publishreadytorun=false - there no Aot files as we have issues to sort out with AOT.

    Image

    is the above of any help?

  13. vitek-karas commented on Sep 25, 2026

    @vitek-karas
    Member

    @TedMobile thanks a lot for providing more data for us. Please bear with me as I have to admit I'm a bit lost in what config was used where... so I'll try to restate how I understand it and please correct me if I got it wrong.

    • The shared R2R command lines are from the matching csproj extract projects.

    • Were they collected without setting PublishReadyToRun=false? - if you have binlogs could you check what was the effective value of PublishReadyToRun (I'm pretty sure it had to be true otherwise it would not run the crossgen compiler)

    • Your .NET 10 project for Android (the baseline) has RunAOTCompilation=false in it. Could you confirm this please?

    • The picture of the size of the APK is from a .NET 11 Android project which specified PublishReadyToRun=false. If I read this correctly it shows size close to the baseline 61MB of final package size. If your baseline disabled all AOT on Android, then disabling it on CoreCLR should produce similar size (probably slightly larger, but only by a couple of MBs).

    • I have to admit I don't know what is the situation on iOS - the original issue description states that .NET 11 adds 30 MB to the app size - is that the packaged ipa? I think you said that if you disable R2R the .NET 11 size goes back to something similar to .NET 10, right? What I'm not clear on is what was the AOT configuration for the .NET 10 project.

    Could you please help us confirm the AOT configuration of your original .NET 10 iOS build?

    Collect a binlog from a clean Release device build (ios-arm64), using your original settings, and share these small extracts:

    • In MSBuild Structured Log Viewer, search for UseInterpreter and MtouchInterpreter. What is their effective values, or they're not set at all?
    • Search for $task AOTCompile and select AOTCompile under _AOTCompile. Under Parameters → Assemblies, could you copy the Arguments and ProcessArguments entries for your main application assembly and System.Private.CoreLib.dll? If your main assembly is not listed, please let us know.

    Side note: RunAOTCompilation has no effect on .NET 11 (CoreCLR). Similar property to that in CoreCLR is PublishReadyToRun.

    Out of curiosity (if it's not too much trouble): You seem to hint that the original .NET 11 setup (with 10.0 MAUI) and the new setup (with 11.0 MAUI) produce basically the same app size on Android. Is that correct? (The original one showed full R2R, the new one shows partial R2R in the command line). I also assume they were done with R2R enabled.

  14. TedMobile commented on Sep 29, 2026

    @TedMobile
    Author

    @vitek-karas
    My colleague who made the pipeline changes and carried out a number of the tests with the different flags is off this week, but let me try to summarise exactly what we did and hopefully remove some of the confusion.

    .NET 11 + MAUI 10
    Our initial migration was to the .NET 11 SDK/runtime, but we subsequently realised that we were still using the MAUI 10 workload.
    These were the results from that configuration ( both net 11 + Maui 10 or Maui 11 ) have the same result!.

    Image

    This is where we first noticed the significant package-size increase. Disabling R2R brought the packages back close to the sizes we were accustomed to before the migration.

    .NET 11 + MAUI 11
    Once we realised that we were still using the MAUI 10 workload, we upgraded to the proper MAUI 11 workload and controls and repeated the testing.
    We saw the same package-size behaviour: with R2R enabled the packages were significantly larger, while disabling R2R brought them back close to the previous sizes.
    I will provide the equivalent MAUI 11 numbers/configuration separately so that we have a clean comparison.

    Android
    For clarity, all of our Android projects, both .NET 10 and .NET 11, have been built with:
    <RunAOTCompilation>false</RunAOTCompilation>
    We have some existing Android AOT issues to resolve before we can enable it.

    iOS
    For both our .NET 10 and .NET 11 iOS Release builds, we are not using the interpreter.
    We haven't explicitly selected an iOS AOT configuration in the project; we have relied on the normal iOS Release/toolchain defaults. Our Release configuration also has:

    Let me see if I can reproduce what he did and extract the remaining information from the binlogs.

    In particular, I will try to provide the requested .NET 10 iOS Release AOTCompile details:

    • Arguments / ProcessArguments for our main application assembly
    • Arguments / ProcessArguments for System.Private.CoreLib.dll
      I will also confirm the effective PublishReadyToRun value for the relevant R2R-enabled build.

    Hopefully this clarifies the configurations and which results came from which setup

  15. vitek-karas commented on Sep 29, 2026

    @vitek-karas
    Member

    Thanks a lot for the information. On the Android side the RunAOTCompilation=false basically explains the behavior. .NET 11 doesn't react to that property (intentional breaking change on our end - maybe we should produce a warning or error though to guide people to the right place) - it will use R2R AOT by default and that's almost certainly why the app is larger. If you disable that via PublishReadyToRun=false it seems to get the app close to the .NET 10 size numbers.

    For iOS I don't have an explanation yet unfortunately - hopefully the arguments for the AOT compiler will help us there.

  16. TedMobile commented on Oct 6, 2026

    @TedMobile
    Author

    @vitek-karas hi we collected some data and find below hope is helpful and give you more of an insight..

    Build Comparison Matrix

    Test .NET MAUI Interpreter UseInterpreter effective MtouchInterpreter effective PublishReadyToRun MauiEnableFullReadyToRun AOTCompile checked APK IPA Confirmed
    NET10 baseline 10 10 ❌ No TBC / binlog TBC / binlog — — ✅ TRUE 66.4 MB 117 MB ✅ Size
    NET11 / MAUI10 / DEFAULT R2R 11 10 ❌ No* — — — — ❌ FALSE 100.0 MB 76.8 MB ✅ Size
    NET11 / MAUI10 / No R2R 11 10 ❌ No* — — ❌ FALSE ❌ FALSE ❌ FALSE 61.8 MB 76.8 MB ✅ Size
    NET11 / MAUI10 / Generic cycle 11 10 ❌ No* — — TBC / true TBC ❌ FALSE 100.0 MB 104.0 MB ✅ Size
    NET11 / MAUI11 / Default R2R 11 11 ❌ No* — — — — ❌ FALSE 64.6 MB 103.0 MB ✅ Size
    NET11 / MAUI11 / No R2R 11 11 ❌ No* — — ❌ false ❌ false ❌ FALSE 61.6 MB 76.8 MB ✅ Size

    Arguments.txt

    Image
  17. tannergooding commented on Oct 6, 2026

    @tannergooding
    Member

    @vitek-karas, did you note that the linker command has -a "System.Text.Json" All and -a "System.Net.Http" All, which is causing at the very least all of the following to be rooted/kept:

    Root Confirmed retention in a controlled build
    System.Net.Http Connection pools, HTTP/2, HTTP/3 despite Http3Support=false, QPACK, authentication and telemetry code. HTTP/3 references retain QUIC dependencies.
    System.Text.Json JSON schema export, F# converters, otherwise-unused reader/writer APIs, and reflection-based member-access machinery.

    So post trimming this also pulls in System.Net.Quic, System.Net.Security, System.Net.Sockets, System.Diagnostics.DiagnosticSource, etc. Which look to add up to around 14.7MB of combined cost for R2R codegen

    It also looks to cause it to ignore switches like Http3Support=false and we don't seem to have a way to balance those concepts here (allow rooting something that is generally used, but also trim out specific aspects that are explicitly unused)

  18. vitek-karas commented on Oct 7, 2026

    @vitek-karas
    Member

    @TedMobile, thanks a lot for the update!

    Size regressions after the upgrade

    Please correct me if I misunderstood anything. Here is my takeaway from the data you provided:

    Android

    • The new data shows .NET 10 at 66.4 MB and .NET 11 (with MAUI 11 and all other settings at their defaults) at 64.6 MB. These sizes are comparable.
    • The resolution for the originally reported regression is to upgrade MAUI to 11 as well, which enabled partial R2R and reduced the package size.
    • Disabling R2R completely only saves around 4 MB. I would not recommend doing this, as I expect a rather significant negative impact on startup time.
    • From my point of view, the Android issue is resolved. We're tracking improving the SDK to produce a warning when the version of MAUI and runtime are not matching: Warn when a MAUI app targets a newer .NET version than its resolved MAUI packages maui#39170.

    iOS

    • The new data shows .NET 10 at 117 MB and .NET 11 (with MAUI 11 and all other settings at their defaults) at 103 MB. This is, in fact, a small improvement.
    • Disabling R2R brings the size down considerably, to 77 MB. Again, I would not recommend this, as I expect a very significant impact on performance in general, not just startup.
    • There is no clear resolution for iOS, though, as some earlier comments also reported a ~30 MB regression on iOS, which is not shown in the latest data.
    • The logs you shared from the iOS AOT invocation on .NET 10 confirm the expected default behavior: a full LLVM AOT configuration. However, we can't fully confirm this, as the data only shows it explicitly for CoreLib.
    • If I rely on the newly reported data, I would consider this resolved for iOS as well.

    Please do let me know if you have different observations or if any of the new behavior is unexpected for your application.

    Rooting of JSON and HTTP assemblies

    @tannergooding, thanks a lot for pointing that out. I didn't notice it. It's definitely an interesting observation, and it likely affects the size of the application on both platforms.

    @TedMobile, we don't have enough data to tell why the System.Text.Json and System.Net.Http assemblies are fully rooted.
    Typically this is done by specifying TrimmerRootAssembly items in your project file, but there are other ways as well.

    This could be intentional, to work around problems with the partial trimming setup used by MAUI apps. If it's not, though, it might be a nice opportunity to reduce the size of the application.

    • If this was intentional, we would be very interested in the types of problems you ran into that motivated these workarounds. We would very much like to improve this going forward.

    • Could you search your project and shared/imported .props or .targets files for these assembly names and share any entries that preserve them, particularly TrimmerRootAssembly entries? You could also search the binlog for TrimmerRootAssembly; even knowing that it was set would help us diagnose this further.

    • Could you check whether the same assemblies are explicitly preserved in both the original .NET 10 Android baseline and the current .NET 11 / MAUI 11 Android build? In the binlog, the ILLink task's Parameters → RootAssemblyNames contains the effective list, including any RootMode metadata. It would also help to know whether you use equivalent preservation rules on iOS.

    This would help us understand whether these roots were added intentionally by the project configuration or somehow slipped in during the upgrade.

  19. added this to the 11.0.0 milestone on Oct 7, 2026
  20. TedMobile commented on Oct 7, 2026

    @TedMobile
    Author

    @vitek-karas

    Android
    I agree its solved! we have removed all the flags and with only a few mbs difference - its a win!

    iOS
    in net .10 we had the interpreter on because we were getting errors very difficult to debug! and our size was 77 - now it works in .net 11 but we gain 30mb but removing the interpreter. I wish it was less - but it is what it is I guess. I will have some explaining to do when our clients will see the app size a bigger.

    TrimmerRootAssembly
    thanks to @tannergooding for spotting it ! yes we have those in our csproj!

      <!-- Prevent trimming of critical assemblies -->
      <ItemGroup Condition="'$(Configuration)|$(TargetFramework)'=='Release|net10.0-android'">
        <TrimmerRootAssembly Include="System.Text.Json" RootMode="All" />
        <TrimmerRootAssembly Include="System.Net.Http" RootMode="All" />
      </ItemGroup>
    
    

    the reason we added the above was because we removed nuewtonsoft and fully replaced with System.Text.Json. however when the app was released it was crashing without telling us much what was going on and what the "culprit" was so we added the above! - given the gain we could make in reducing the size I.E 15/17 mb may be we are going to investigate it again , and any tips/tricks what to look for would be good.. binlog is a bit cryptic at times but may be any suggestion could help..

    PublishReadyToRun/MauiEnableFullReadyToRun
    As you suggested , we have decided to fully remove them! , however I have to say we noticed the start up being snappier for sure, but not yet everywhere else, but it does make the app bigger though!.. but lets see.

    thanks alot in taking the time, and we learned a lot about all these new flags.. I do wish though mono enabled could have been a fallback for .net 11 only though.

  21. vitek-karas commented on Oct 7, 2026

    @vitek-karas
    Member

    iOS size

    For the iOS I just want to clarify for my benefit: So you set either MtouchInterpreter=all or UseInterpreter=true in the .NET 10 project? The AOT invocation you shared about doesn't seem to be for a build where interpreter is enabled on everything.

    Regardless - if your app had AOT really disabled then we don't have a corresponding configuration on .NET 11 - the closest is PublishReadyToRun=false which might work, we just don't really test it and thus you might run into problems. Also the pure-interpreter execution is likely slower on .NET 11 than it was on .NET 10 (AOT is on the other hand faster).

    Trimming

    The best approach is to enable trim warnings, the compiler will tell you all the places in your code which do problematic reflection (or other patterns). But it works the opposite direction, it will likely point to places which try to do something problematic, it doesn't tell you if this touches code inside the two assemblies. But it might still be helpful to at least know which areas of your code might be the cause of the problems. https://learn.microsoft.com/en-us/dotnet/maui/ios/linking#suppress-analysis-warnings - you want to enable it (MAUI disables this by default).

    Full R2R

    It is expected that full R2R will speed up startup if you have some meaningful amount of code running during startup. For the rest of the app this is a bit more difficult to measure and the difference might not be observable.

    Mono

    I do wish though mono enabled could have been a fallback for .net 11 only though.

    I understand the concern here, I'm just curious where the real need comes from. My reasoning is that you can stay on .NET 10 for a while still. And even it was possible, it would just delay the change by 1 year... I'm honestly curious what is the aspect which makes it compelling (I can only theorize, you know the reality).

  22. TedMobile commented on Oct 8, 2026

    @TedMobile
    Author

    @vitek-karas
    iOS
    in net 10 we used only Interpreter true (as we were getting some errors we could not clear) all good in .net 11

    Trimming
    Giving a go now - would be nice if we managed at our end to remove those!

    Mono
    It was more of a safety net - but now that I know more - its fine I guess. We always move to latest avail version of .net as even though .net 10 is supported the maui team is very small and they will concentrate on .net 11 for bugs etc and only fix critical .net 10 once 11 is out.

    we are going AOT all the way.. just the iOS bump in size is a bummer...

  23. vitek-karas commented on Oct 8, 2026

    @vitek-karas
    Member

    @TedMobile

    we are going AOT all the way.. just the iOS bump in size is a bummer...

    If I understand it correctly on .NET 10 you were not using AOT on iOS. Unfortunately we don't really have an option to not have it in .NET 11.

    On a similar train of thought - have you considered NativeAOT - it has hard trimming and compat requirements, but it will make your app significantly smaller (and faster). But I don't know your dependencies, it might be very difficult to make it work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions