We assumed our assets were most of the build. They were 9.11%.
We were about to spend a weekend shrinking textures. The kart racer we ship had grown to about 146 MiB on Windows, and the obvious story was the obvious one: too many models, too many textures, the usual. Before touching anything we did the thing we keep telling ourselves to do first, which is to measure. Unity writes a full report of every build to Library/LastBuild.buildreport. We wrote a small Editor tool to read it, attribute packed bytes to the source asset that produced them, and group the rest by role.
The number that came back for "everything under Assets/" was 13,986,213 bytes, or 9.11% of the build. Ninety percent of what we were about to optimise was not ours to optimise.
What an empty build is made of
To see the floor, we built a near-empty project: Unity 6000.0.78f1, one scene, and a single 1 MB .bytes file so the asset column would not be zero. The macOS player came out at 104,921,186 bytes.
| Role | Bytes | Share |
|---|---|---|
| dylib | 70,455,488 | 67.15% |
| dll (130 files) | 26,687,488 | 25.44% |
| resS | 3,320,528 | 3.16% |
| unity default resources | 1,699,492 | 1.62% |
| assets | 1,154,692 | 1.10% |
Our own content under Assets/ was 1,048,592 bytes, 1.00% of the player. The single largest file was UnityPlayer.dylib at 61,203,888 bytes, 58.33% on its own. Among the 130 DLLs, a project with no code of its own still ships System.Data.dll (2,105,344 bytes) and System.Xml.dll (3,160,064 bytes).
The 1 MB test file is worth a footnote because it kept us honest about compression. It was random data, 1,048,576 bytes on disk, and it packed to 1,048,592 bytes: the original plus a 16-byte header. Incompressible input does not shrink, and the tool reports the packed size, which is the number that matters for the build.
The kart racer
Then we pointed the same tool at the real thing: the last Windows64 build of our kart racing game, built on 2026-09-01. Total 153,510,191 bytes (146.40 MiB), with 5,201 packed entries across 2,326 unique source paths.
The five largest assets:
| # | Asset | Type | Bytes | Share |
|---|---|---|---|---|
| 1 | Assets/TextMesh Pro/Fonts/HiraginoSans.ttc |
Font | 7,864,062 | 5.12% |
| 2 | Built-in Texture2D "Splash Screen Unity Logo" | Texture2D | 2,796,408 | 1.82% |
| 3 | LiberationSans SDF.asset |
Texture2D | 1,078,500 | 0.70% |
| 4 | Resources/unity_builtin_extra |
Cubemap | 538,180 | 0.35% |
| 5 | LiberationSans.ttf |
Font | 352,734 | 0.23% |
The largest asset in a racing game is a Japanese font. The second largest is Unity's own splash logo, which we do not draw anywhere in the game. By type, fonts total 8,298,398 bytes (5.41%), textures 6,450,651 (4.20%), and every mesh in the game together comes to 1,875,889 bytes (1.22%). One kart is about 170 KB. The karts, the track, the audio, all of it, adds up to that 9.11%.
The rest is runtime. UnityPlayer.dll is 34,421,168 bytes (22.42%). Then two files we had not looked at closely: EOSSDK-Win64-Shipping.dll at 19,531,704 bytes (12.72%) and EOSSDK-Win64-Shippingarm64.dll at 18,058,240 bytes (11.76%). Together the online SDK is 24.5% of the build.
That second DLL is the one finding in the whole exercise that is real, removable waste. It is the arm64 build of the SDK. A Windows x64 player cannot load it under any circumstances. It is 18 MB that ships to every player and is never read. The texture weekend would not have touched it, because it is not a texture, and it does not show up in the Project window as something that looks heavy.
What we changed
We stopped guessing from the Project window and made the report reading a step we run before builds. The tool reads BuildReport, attributes packed bytes to source assets, groups by type and by role, and diffs two builds so a size regression shows up as a named asset rather than a bigger number. In CI it can fail the build when growth crosses a threshold, in bytes or in percent, which is how we intend to catch the next 18 MB before it ships.
We also corrected our own README. It used to say that a 40 MB PSD packs down to 2 MB, as an illustration of why packed size is the number to watch. That figure was an example, not a measurement, and after this exercise we are not comfortable leaving an unmeasured number next to measured ones. It now reads as an example, and the measured pair above (1,048,576 in, 1,048,592 out) is the one we cite.
Limits
Everything here is measured on macOS (StandaloneOSX) with Unity 6000.0.78f1, plus the one Windows64 report from the kart game. Other platforms read the same BuildReport format and are expected to work, but we have not measured them and will not claim otherwise. Percentages are of TotalSize, which includes the engine and runtime. Final store compression, the second pass an APK or IPA gets when packaged, is not modelled; the packed sizes here are what Unity reports, not what a store serves.