|
1 | | -# .NET Container Image Size Report |
| 1 | +# .NET image size comparison |
2 | 2 |
|
3 | | -.NET offers a variety of deployment options for applications, which pair with container images that we offer. It's possible to produce very small container images. This document summarizes the available options to help you make the best choice for your apps and environment. |
| 3 | +.NET offers a variety of deployment options for applications which pair well |
| 4 | +with the container images that we publish. It's possible to produce very small |
| 5 | +container images. This document summarizes the available options to help you |
| 6 | +make the best base image choice for your apps and environment. |
4 | 7 |
|
5 | | -All images were produced from the ["releasesapi" sample](https://github.com/dotnet/dotnet-docker/tree/main/samples/releasesapi) using Ubuntu 22.04 ("jammy") images for amd64. |
6 | | -Alpine images will be similar. |
7 | | -The Baseline image is a standard [framework-dependent](https://learn.microsoft.com/dotnet/core/deploying/#publish-framework-dependent) deployment on the ASP.NET runtime image. |
8 | | -This is the largest image with the most functionality and flexibility. |
9 | | -However, the new [Ubuntu Chiseled](https://github.com/dotnet/dotnet-docker/blob/main/documentation/ubuntu-chiseled.md) .NET base images can provide significantly smaller and more secure deployments for your application as demonstrated below. |
| 8 | +The table below shows how base image choice and publish type affects typical |
| 9 | +image sizes and for a simple .NET minimal web API. These images were produced |
| 10 | +from the ["releasesapi" sample](../samples/releasesapi). |
| 11 | + |
| 12 | +| Base Image | Publish Type | Distroless | Globalization | Compressed Size | |
| 13 | +| ------------------------------------------ | ----------------------------- | ---------- | ------------- | --------------: | |
| 14 | +| [`aspnet:10.0`] | [Framework-dependent] | ✖️ No | ✅ Yes | 92.48 MB | |
| 15 | +| [`aspnet:10.0-noble-chiseled`] | [Framework-dependent] | ✅ Yes | ✖️ No | 52.81 MB | |
| 16 | +| [`aspnet:10.0-noble-chiseled-extra`] | [Framework-dependent] | ✅ Yes | ✅ Yes | 67.68 MB | |
| 17 | +| [`runtime-deps:10.0`] | [Self-contained] + [Trimming] | ✖️ No | ✖️ No | 61.53 MB | |
| 18 | +| [`runtime-deps:10.0`] | [Self-contained] + [Trimming] | ✖️ No | ✅ Yes | 61.63 MB | |
| 19 | +| [`runtime-deps:10.0-noble-chiseled`] | [Self-contained] + [Trimming] | ✅ Yes | ✖️ No | 21.86 MB | |
| 20 | +| [`runtime-deps:10.0-noble-chiseled-extra`] | [Self-contained] + [Trimming] | ✅ Yes | ✅ Yes | 36.82 MB | |
| 21 | +| [`runtime-deps:10.0`] | [Native AOT] | ✖️ No | ✖️ No | 51.27 MB | |
| 22 | +| [`runtime-deps:10.0`] | [Native AOT] | ✖️ No | ✅ Yes | 51.36 MB | |
| 23 | +| [`runtime-deps:10.0-noble-chiseled`] | [Native AOT] | ✅ Yes | ✖️ No | 11.60 MB | |
| 24 | +| [`runtime-deps:10.0-noble-chiseled-extra`] | [Native AOT] | ✅ Yes | ✅ Yes | 26.56 MB | |
| 25 | +| [`aspnet:10.0-alpine`] | [Framework-dependent] | ✖️ No | ✖️ No | 51.93 MB | |
| 26 | +| [`runtime-deps:10.0-alpine`] | [Self-contained] + [Trimming] | ✖️ No | ✖️ No | 20.95 MB | |
| 27 | +| [`runtime-deps:10.0-alpine-extra`] | [Self-contained] + [Trimming] | ✖️ No | ✅ Yes | 35.52 MB | |
| 28 | +| [`runtime-deps:10.0-alpine`] | [Native AOT] | ✖️ No | ✖️ No | 10.69 MB | |
| 29 | +| [`runtime-deps:10.0-alpine-extra`] | [Native AOT] | ✖️ No | ✅ Yes | 25.25 MB | |
10 | 30 |
|
11 | 31 | > [!NOTE] |
12 | | -> The recorded image sizes are a snapshot of deployment sizes at the time of .NET 8.0 GA. |
13 | | -> Image sizes will fluctuate over time due to base image updates and updated package installations. |
14 | | -> This document will not be updated over time. The key takeaway is the size *difference* between the different models. |
| 32 | +> Please note that these image sizes are a snapshot of deployment sizes from |
| 33 | +> November 2025. Image sizes will fluctuate over time due to base image and |
| 34 | +> package updates. |
15 | 35 |
|
16 | | -## Framework-Dependent Deployment |
| 36 | +Watch the [announcements page](https://github.com/dotnet/dotnet-docker/discussions/categories/announcements) |
| 37 | +for the latest information on new features and changes in .NET container images. |
17 | 38 |
|
18 | | -| Image Kind | Base Image | Uncompressed Image Size | Compressed Image Size | % Size Savings Over Baseline[^1] | |
19 | | -| --- | --- |--- | --- | --- | |
20 | | -| Baseline | [`aspnet:8.0-jammy`](https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/8.0/jammy/amd64/Dockerfile)| 217 MB | 90.9 MB | | |
21 | | -| [Chiseled](https://github.com/dotnet/dotnet-docker/blob/main/documentation/ubuntu-chiseled.md) | [`aspnet:8.0-jammy-chiseled`](https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/8.0/jammy-chiseled/amd64/Dockerfile)| 111 MB | 49.3 MB | 46% | |
22 | | -| [Chiseled](https://github.com/dotnet/dotnet-docker/blob/main/documentation/ubuntu-chiseled.md) + [ASP.NET Composite Runtime](https://github.com/dotnet/dotnet-docker/blob/main/documentation/image-variants.md#composite-net-80) | [`aspnet:8.0-jammy-chiseled-composite`](https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/8.0/jammy-chiseled-composite/amd64/Dockerfile)| 103 MB | 40.8 MB | 55% | |
| 39 | +## About Publishing Options |
23 | 40 |
|
24 | | -## Self-Contained + Trimming Deployment |
| 41 | +### .NET Image Variants |
25 | 42 |
|
26 | | -[Self-contained](https://learn.microsoft.com/dotnet/core/deploying/#publish-self-contained) deployments bundle the .NET Runtime with your app so that it's able to run without the full .NET Runtime installed. |
27 | | -[IL Trimming](https://learn.microsoft.com/dotnet/core/deploying/trimming/trim-self-contained) for self-contained apps removes unused code from the .NET Runtime and libraries to reduce application size. |
28 | | -And [Native AOT](https://learn.microsoft.com/dotnet/core/deploying/native-aot/) deployment produces an app that is completely compiled to native code at build time for the smallest deployment size that .NET allows for. |
| 43 | +- **[Ubuntu Chiseled] images** images are a type of [distroless container image](./distroless.md) |
| 44 | + that contain only a minimal set of packages with everything else removed - no |
| 45 | + shell, no package manager, and no globalization support by default. This |
| 46 | + results in a dramatically smaller deployment size and attack surface. |
| 47 | +- **`extra` images** add `icu` and `tzdata` to Alpine and Chiseled/distroless |
| 48 | + images for full globalization support in .NET apps. |
29 | 49 |
|
30 | | -| Image Kind | Base Image | Uncompressed Image Size | Compressed Image Size | % Size Savings Over Baseline[^1] | |
31 | | -| --- | --- |--- | --- | --- | |
32 | | -| [Self-contained](https://learn.microsoft.com/dotnet/core/deploying/#publish-self-contained) + [Trimming](https://learn.microsoft.com/dotnet/core/deploying/trimming/trim-self-contained) | [`runtime-deps:8.0-jammy`](https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/8.0/jammy/amd64/Dockerfile) | 146 MB | 57.9 MB | 36% | |
33 | | -| [Chiseled](https://github.com/dotnet/dotnet-docker/blob/main/documentation/ubuntu-chiseled.md) + [Self-contained](https://learn.microsoft.com/dotnet/core/deploying/#publish-self-contained) + [Trimming](https://learn.microsoft.com/dotnet/core/deploying/trimming/trim-self-contained) | [`runtime-deps:8.0-jammy-chiseled`](https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/8.0/jammy-chiseled/amd64/Dockerfile)| 39.3 MB | 16.4 MB | 82% | |
34 | | -| [Native AOT](https://learn.microsoft.com/dotnet/core/deploying/native-aot/) | [`runtime-deps:8.0-jammy-chiseled`](https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/8.0/jammy-chiseled/amd64/Dockerfile)| 27.7 MB | 12.4 MB | 86% | |
| 50 | +See [.NET Image Variants](https://github.com/dotnet/dotnet-docker/blob/main/documentation/image-variants.md) |
| 51 | +for more details. |
35 | 52 |
|
36 | | -For more information on .NET image variants and AOT images, please see the following documentation: |
| 53 | +### Publishing Types |
37 | 54 |
|
38 | | -- [.NET Image Variants](https://github.com/dotnet/dotnet-docker/blob/main/documentation/image-variants.md) |
39 | | -- [Announcement: .NET 10 AOT container images](https://github.com/dotnet/dotnet-docker/discussions/6312) |
40 | | -- [Announcement: New approach for differentiating .NET 8+ images](https://github.com/dotnet/dotnet-docker/discussions/4821) |
| 55 | +- **[Self-contained]** deployments bundle the .NET Runtime with your app so that |
| 56 | + it can run without the .NET Runtime installed. |
| 57 | +- **[Trimming]** for self-contained apps removes unused code from the .NET |
| 58 | + Runtime and libraries to reduce application size. |
| 59 | +- **[Native AOT]** deployment produces an app that is compiled ahead-of-time |
| 60 | + (AOT) for the smallest deployment size and startup time. |
41 | 61 |
|
42 | | -Watch the [announcements page](https://github.com/dotnet/dotnet-docker/discussions/categories/announcements) for the latest information on new features and changes in .NET contanier images. |
| 62 | +See [".NET Application Publishing Overview"](https://learn.microsoft.com/dotnet/core/deploying) |
| 63 | +for more details on all of the supported options for publishing .NET apps. |
43 | 64 |
|
44 | | -[^1]: Percentage of size savings is based on compressed image size. |
| 65 | +[Ubuntu Chiseled]: https://github.com/dotnet/dotnet-docker/blob/main/documentation/ubuntu-chiseled.md |
| 66 | +[Self-contained]: https://learn.microsoft.com/dotnet/core/deploying/#publish-self-contained |
| 67 | +[Trimming]: https://learn.microsoft.com/dotnet/core/deploying/trimming/trim-self-contained |
| 68 | +[Native AOT]: https://learn.microsoft.com/dotnet/core/deploying/native-aot/ |
| 69 | +[Framework-dependent]: https://learn.microsoft.com/dotnet/core/deploying/#publish-framework-dependent |
| 70 | +[`aspnet:10.0`]: https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/10.0/noble |
| 71 | +[`aspnet:10.0-noble-chiseled`]: https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/10.0/noble-chiseled |
| 72 | +[`aspnet:10.0-noble-chiseled-extra`]: https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/10.0/noble-chiseled-extra |
| 73 | +[`runtime-deps:10.0`]: https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/10.0/noble |
| 74 | +[`runtime-deps:10.0-noble-chiseled`]: https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/10.0/noble-chiseled |
| 75 | +[`runtime-deps:10.0-noble-chiseled-extra`]: https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/10.0/noble-chiseled-extra |
| 76 | +[`aspnet:10.0-alpine`]: https://github.com/dotnet/dotnet-docker/blob/main/src/aspnet/10.0/alpine3.22 |
| 77 | +[`runtime-deps:10.0-alpine`]: https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/10.0/alpine3.22 |
| 78 | +[`runtime-deps:10.0-alpine-extra`]: https://github.com/dotnet/dotnet-docker/blob/main/src/runtime-deps/10.0/alpine3.22-extra |
0 commit comments