How to Minify Godot's Build Size (93MB -> 6.4MB exe)
Table of Contents
- Intro
- Default Export (92.8MB Windows, 42.0MB Web)
- Setting optimize="size" (53.6MB Windows, 39.1MB Web)
- Disabling 3D (44.0MB Windows, 31.5MB Web)
- Disabling the Advanced Text Server (41.9MB Windows, 29.5MB Web)
- Disabling Advanced GUI Objects (39.7MB Windows, 27.8MB Web)
- Disabling Unnecessary Features (33.6MB Windows, 27.1MB Web)
- Disabling Unwanted Modules (29.8MB Windows, 24.8MB Web)
- Using Godot's Engine Compilation Configuration (21.0MB Windows, 17.4MB Web)
- Using UPX on the Windows Build (6.36MB* Windows)
- Running Wasm-Opt on the Web Build (16.0MB Web)
- Using Brotli on the Web build (2.7MB Web Compressed)
- Conclusion
Intro
This was an article I wanted to do for ages. Godot's default file size for web exports is quite massive, and there weren't a lot of guides on how to reduce it aside from the official documentation - which gives general information without any numbers or details, leaving people to figure out how effective any of the solutions really are. It also doesn't mention some more advanced tricks we can use which I'll mention here. Hopefully this guide can save you the hassle of discovering all this nonsense yourself!
In order to reduce the build size of our Godot project, we have to compile the export templates ourselves, so this guide is a bit more advanced than what most people are used to. tibaverus made an excellent tutorial on how to compile Godot's export templates on Windows, so I recommend checking that out if you're a beginner. Just ignore the parts about using encryption.
Compiling export templates with full link-time optimization takes anywhere from 5-15 minutes on my Ryzen 7 7735HS, and you'll have to do it again every single time you change something, so this'll need some patience. Obligatory xkcd comic:

Default Export (92.8MB Windows, 42.0MB Web)
Let's start with a default export that Godot gives us. I have here a tiny project where a CharacterBody bounces around the screen like a DVD logo, with a Label attatched to it. This'll show a best-case scenario for compressing our project and allow us to disable features without worrying about breaking everything. It also gives us a project with a sort-of real usecase: 2D physics, sprites, and text rendering.
I'll be making Windows & Web exports throughout this post to compare file sizes. I'll also be showing uncompressed and zipped file sizes using a compression level of 9 with Deflate, which is pretty standard. Using the default export settings, we get these numbers:
- Windows: 92.8MB Uncompressed / 30.6MB .zip
- Web: 42.0MB Uncompressed / 8.72MB .zip
The windows build being 93MB is fine. Not great, but fine considering the vast majority of games will have assets larger than the engine itself. The web build though... That needs work. Even at 9 megabytes compressed, that's quite big.
Setting optimize="size" (53.6MB Windows, 39.1MB Web)
Let's start with the low-hanging fruit. Setting the build to prefer optimizing for size will reduce performance, but that isn't a big deal for simpler 2D games. Note that Web builds by default set optimize to size, so you shouldn't see much change there.
Instead of writing scons platform=windows target=template_release debug_symbols=no optimize=size lto=full
and slowly adding stuff to the command, I'll be using a Python build script to keep things organized. Now I can just write scons platform=windows profile=custom.py
.
#custom.py
target="template_release"
debug_symbols="no"
optimize="size"
lto="full"
- Windows: 53.6MB Uncompressed / 18.5MB .zip
- Web: 39.1MB Uncompressed / 8.66MB .zip
The Windows build sees a huge reduction to build size, shaving almost 40MB in size. The web build surprisingly shaves off almost 3MB in size, which is odd because the official release build already does optimize for size. Maybe they use a different compiler or thin LTO rather than full.
Disabling 3D (44.0MB Windows, 31.5MB Web)
Very straightforward option, it just disables the 3D part of the engine. All you have to do is add disable_3d="yes"
to the python build profile.
- Windows: 44.0MB Uncompressed / 15.0MB .zip
- Web: 31.5MB Uncompressed / 6.76MB .zip
Very good gains from disabling 3D, as expected. The web build is now approaching what I'd say is acceptable territory in terms of file size. Let's keep going!
Disabling the Advanced Text Server (41.9MB Windows, 29.5MB Web)
Godot actually has two text servers: the advanced text server, and the fallback text server. The advanced is the default one, it provides support for Right-to-Left languages and complex scripts. It also provides support for font ligatures and OpenType features.
Since my tiny game is English-only and doesn't do anything fancy with fonts, we can disable the advanced text server use the fallback one instead. I'll add this to custom.py
:
[...]
module_text_server_adv_enabled="no"
module_text_server_fb_enabled="yes"
- Windows: 41.9MB Uncompressed / 14.2MB .zip
- Web: 29.5MB Uncompressed / 6.25MB .zip
The official documentation says disabling the advanced text server saves more space than disabling 3D. This is definitely not the case, and while shaving off 2MB is respectable, I wouldn't consider it "high" in savings like it's written. Moving on...
Disabling Advanced GUI Objects (39.7MB Windows, 27.8MB Web)
This disables advanced Control nodes like RichTextLabels, SpinBoxes, TextEdits, etc. You can see everything it disables in the docs. I'm not using any of these, so let's add disable_advanced_gui="yes"
to my custom.py
. I'm curious of this build flag needs to exist anymore since you can manually choose which nodes to disable in Godot's build configuration profile (which we'll do later).
- Windows: 39.7MB Uncompressed / 13.5MB .zip
- Web: 27.8MB Uncompressed / 6.01MB .zip
Another 2MB shaved off, which is nice. I'm honestly not a big fan of this option, as I feel most games make use of RichTextLabels. Sacrificing text effects and potentially important UI nodes for two megabytes might not be worth it depending on the project. If you aren't using any of those, then sure, you might as well disable them.
Disabling Unnecessary Features (33.6MB Windows, 27.1MB Web)
Godot has a number of features you can disable that aren't mentioned specifically in the docs. You can see all the build flags with scons --help
. Before we dive into modules, we can safely disable some features I'm sure we don't need in this simple project. Let's add more stuff to custom.py
:
[...]
deprecated="no" # Disables deprecated features
vulkan="no" # Disables the Vulkan driver (used in Forward+/Mobile Renderers)
use_volk="no" # Disables more Vulkan stuff
openxr="no" # Disables Virtual Reality/Augmented Reality stuff
minizip="no" # Disables ZIP archive support
- Windows: 33.6MB Uncompressed / 11.7MB .zip
- Web: 27.1MB Uncompressed / 5.76MB .zip
Since I'm using the Compatibility renderer (which uses OpenGL), removing Vulkan from the export template is totally safe. We got a whopping 6.1MB cut from the Windows executable, but only a modest 0.7MB improvement on web builds. It's possible most of these were already excluded in web builds since they can't run Vulkan anyway.
It's interesting how close the Web and Windows builds are getting in terms of size as we approach a limit for how many features we can disable while keeping the base runtime intact. There's still more we can do, though!
Disabling Unwanted Modules (29.8MB Windows, 24.8MB Web)
We're entering the danger zone. You can disable modules that aren't used in our game, but be aware that if you accidentally disable something you might be using, it'll just crash your game. Tread carefully; you wouldn't want to keep re-compiling export templates all day to find out which module you disabled that's causing issues.
That said, rather than disable everything you don't need one-by-one like the official documentation suggests, you can just disable everything by default and enable only what you need. Again, you can see what modules exist with scons --help
. Since my game is simple, I'll only need a few modules. I'll also need 2D physics to bounce on touching the edge of the screen, which likely uses a decent amount of space.
[...]
modules_enabled_by_default="no"
module_gdscript_enabled="yes"
module_text_server_fb_enabled="yes"
module_freetype_enabled="yes"
module_svg_enabled="yes"
module_webp_enabled="yes"
module_godot_physics_2d_enabled="yes"
- Windows: 29.8MB Uncompressed / 10.0MB .zip
- Web: 24.8MB Uncompressed / 4.92MB .zip
The web build now being under 5MB compressed is nice. The Windows build is also on the cusp of being under 10MB when compressed, making it easy to share small apps. This is essentially where Godot's documentation ends, but there's one more thing we can do...
Using Godot's Engine Compilation Configuration (21.0MB Windows, 17.4MB Web)
This isn't a very advertised feature since it's still a work-in-progress, but Godot actually has a built-in feature to let you include/exclude things you want to compile. This includes general features like Vulkan and physics engines, but more notably, it lets you disable nodes and resources one-by-one! You can access it inside Godot itself by going to Project>Tools>Engine Compilation Configuration Editor
. From here, you can toggle options then save your settings as a .build
file.
By exporting the custom.build
file and putting it next to the custom.py
file, we can compile only the nodes and resources used in our project with this command: scons platform=windows profile=custom.py build_profile=custom.build
.
The good news is that there's an autodetect feature to quickly disable everything you don't use. The bad news is that it's pretty unreliable and disables classes that Godot needs to run. In my case, it disabled MainLoop
, StyleBox
, KinematicCollision2D
, TextServer
, and TextServerManager
. All of those are needed to run the game. The other good news is that the build file is human-readable, so I just opened it up and removed their names from the list of disabled classes.
How did I know those classes were needed, you say? The answer is the game will crash on launch if you don't have them, printing errors in the console shouting that a specific class is missing. Yup, you'll need a bit of trial and error if you're using the autodetect feature... But it's better than manually disabling ~400 classes yourself.
Now that everything is fixed, let's look at the build sizes:
- Windows: 21.0MB Uncompressed / 7.25MB .zip
- Web: 17.4MB Uncompressed / 3.70MB .zip
Now that's good savings! We removed 9 megabytes on the Windows build and over 7 megabytes on the Web build. Godot's build configuration is a bit janky and can break a lot of games, but when it works, it can strip out a ton of useless code.
That's it for the Godot-specific savings we can make. Now I'll go through a bit more advanced techniques specifically on desktop and web, which can be a hassle in most use cases. Whether they're worth doing is up to you.
Using UPX on the Windows Build (6.36MB* Windows)
⚠ Warning ⚠ Executables packed with UPX can sometimes be flagged as malicious by antiviruses, since it was also used by malware. Antiviruses have gotten pretty good at ignoring UPX, but I would avoid using this on serious projects so you don't get issues down the line!
UPX is a program that can pack your executables and reduce its file size by a ridiculous amount. You might be wondering: what's the catch? Aside from sometimes being flagged as a virus, it essentially compresses the exe then decompresses it when you open it. Think of it like a zip file that extracts itself when run.
The bad news is that it stores that decompressed data in your RAM, increasing the memory used by the game. Without UPX, my game uses ~53MB of RAM. With UPX, it's up to ~74MB. A 20 megabyte RAM increase isn't the end of the world, but then again, neither is an extra 20 megabytes on your hard drive. Any modern system wouldn't care either way.
There's also a tiny startup time increase, but it's negligible on small executables. According to the official site, it can decompress "more than 500MB/s on any reasonably modern machine". In my project, I didn't even notice a difference in how quickly my project opens since my exe was already small.
Anyway, in order to use UPX, just grab the project from GitHub and extract it next to your game files. Now run ./upx.exe <game-name.exe>
. It'll replace your exe with the UPX'd version. That gives us...
Windows: 6.36MB Uncompressed* / 6.21MB .zip
Sure, using UPX is kind of cheating, but you can't argue with the results if your goal is a small binary. I sometimes use it for sharing small games and software, not necessarily because saving a dozen megabytes is important nowadays, but just to make it a little easier to download and share (blast you, Discord 8mb file size limit).
That's all we can do for our desktop builds, so let's finish this off with a trick or two on our web builds.
*Technically the .exe is compressed by UPX, but most people can't tell the difference anyway.
Running Wasm-Opt on the Web Build (16.0MB Web)
Courtesy of dustdfg, you can use Binaryen to compress the WebAssembly file. Extract Binaryen, add the bin folder to your PATH, then run wasm-opt <original.wasm> -o <optimized.wasm> -all --post-emscripten -Oz
on your exported game. This is pretty slow and can take a few minutes, just don't close the terminal window.
Web: 16.0MB Uncompressed / 3.64MB .zip
This shaves off 1.4 megabytes on the uncompressed build, but disappointingly only removed 0.06 megabytes from the zip file. It seems most of the optimizations made by wasm-opt were already covered by zip file compression. It's better than nothing, I suppose.
Using Brotli on the Web build (2.7MB Web Compressed)
This only works if the website you're hosting the game on supports decompressing Brotli files. Check the serving files part of the documentation for more info. Unfortunately, most websites including itch.io don't allow it, so this is an option only in specific cases.
Flametime on GitHub found a way to de-compress your Brotli files in Godot without relying on the server or browser, but there are two problems with it...
- You have to add a 1MB wasm file to decompress it, which kind of ruins the point and brings the zip file back up to roughly the same file size.
- I couldn't get it to work in the end on my project after following the steps, not sure why.
So it's not a great solution and I wouldn't bother in most cases, but it was worth mentioning since I'm sure somebody will bring it up.
Compressing the wasm and pck files using Brotli then packing it all into a zip, our final size is...
Web: 2.70MB .zip!
Conclusion
In short...
- The Windows build went from...
- 93MB --> 21MB Uncompressed (or 6.36MB with UPX)
- 30.6MB --> 7.25MB Compressed (or 6.21MB with UPX)
- The Web build went from...
- 42MB --> 16MB Uncompressed
- 8.72MB --> 3.64MB Compressed (or 2.70MB if you can use Brotli)
Recompiling export templates ~30 times to make sure everything works was certainly an experience, but I got there in the end! Hopefully this guide can give you an idea of which settings are worth doing, and how effective each one is.
I'd say optimizing for size is worthwhile if your assets are already small, but if you already have hundreds of megabytes of assets in your .pck file, then it's probably not worth the effort. For people making web games, it's usually worth doing if you care about having your game load quickly - which you should because not everyone has fast internet.
Also, shoutout to the Godot contributors that are working on the build system. While the default export size has gone up, they've slowly made it easier and more effective to get rid of unwanted parts of the engine to save space, like this PR that already got merged and is coming to Godot 4.5 where you can save an extra ~0.5MB when compiling without XR. Good stuff.
You can find the final builds here: Windows - Web

This post took some effort, if you found it useful and want to see more please consider donating.