GODOTENGINE.ORG
Live from GodotCon Boston: Web .NET prototype
Hi there! I’m Adam Scott (@adamscott on GitHub), the Godot Engine Web team lead, live from the GodotCon Boston 2025!On May 6, during my State of Godot and the Web talk, I revealed a world premiere to the GodotCon attendees. It was something some thought impossible, and others were resigned to not seeing during their lifetime.Please note that the VOD isn’t available yet. The link to the recording will be added to the article once available. Meanwhile, you can access the slides of the presentation.The .NET team lead, Raul Santos (@raulsntos on GitHub), managed to create a prototype running C# on the Web.Click here to see the prototype!Wasn’t it impossible?We tried dotnet.js. It didn’t work.We tried NativeAOT-LLVM. It didn’t work.We (initially) tried statically linking Mono. It didn’t work.Well, Raul gave it another shot recently and managed to make it work. Here’s how he explains his accomplishment.As mentioned in my last update, the option of statically linking Mono seemed the most promising so we went ahead with that.I have opened a draft PR with the latest changes, but keep in mind it’s still a work in progress:[.NET] Add web export support #106125As a reminder, this approach still seems very brittle to me and has some limitations. The C# project must match the WASM features supported by the Godot template (this includes things like the threading model, exception handling, SIMD support, etc.). The TargetFramework version of the C# project must also match the one that was used to build the template.Additionally, since we currently don’t load any globalization data, we only support invariant mode. This is not a big problem because most users will likely rely on Godot’s localization features, so it’s not a blocker.On the last update the issue we run into was retrieving function pointers. We were able to workaround that by declaring stub C# methods on the project we use to retrieve the Mono runtime. When building the Godot templates, this ensures these methods are included in the generated table which seems to be enough to let us retrieve the function pointer at runtime.In a regular C# application built for the web platform you’d use dotnet.js which acts as a loader for the WASM file and other required assets. In Godot we have our own way of doing this, and as a result we’re currently missing a key part of the process.The Mono runtime exports some JavaScript functions but at the time of building the templates these are stubs. The dotnet.js loader takes care of replacing these stubs with their real implementation in dotnet.runtime.js. We’re currently missing this step so they remain stubs.This means some .NET APIs that rely on these exported JavaScript functions will not work, resulting in unexpected behavior. This includes things that must be implemented using browser APIs such as cryptography.Nonetheless, I think this is significant progress and has allowed us to build a demo running on the browser.What’s next for C#/.NET on the WebRaul has published his pull request as a draft so far. It means that there’s a lot of work and testing to do.We’re working as fast as we can to enable you to export C#/.NET to the Web, but we cannot commit to a specific timeline yet. If everything works great, it should be available in the next Godot release.What about file size? My .pck size has exploded!Currently, we do have to include some .dll files in your main .pck file in order to be able to run a C# project. For the simple prototype, the .pck file size is at an astounding 72 MiB. Fortunately, when Brotli-compressed, the file can be reduced to 23.8 MiB.It’s not perfect, as we often suggest targeting the smallest size when deploying to the Web. But the following announcement should help at least somewhat concerning this issue.Introducing built-in (pre)compressionI also revealed my upcoming built-in (pre)compression PR to the public.It will do the following:add an option to compress template files when compiling the engineadd export options to compress exported filesif the target server doesn’t support serving pre-compiled files, the preloading script will take over as a fallback, ensuring to download compressed files instead of non-compressed ones in order to save bandwidth.The future is brightC#/.NET support on the Web and file compression are two important features that will come to the platform. These features will push the limits of what can be done by Godot users on the Web. I do hope that you are as excited as we are!