SkiaSharp on Linux and Docker
Fix “Unable to load shared library 'libSkiaSharp'” on Linux, Docker and Alpine: which NativeAssets package to add, fontconfig, and a no-native alternative.
SkiaSharp runs on Linux, but the SkiaSharp package doesn’t bring the Linux native library with it. On Linux, Docker or Alpine you have to add a native-assets package to your application project yourself. For containers that’s SkiaSharp.NativeAssets., which needs nothing installed in the image. SkiaSharp.NativeAssets.Linux also works but needs fontconfig in the image. This page shows each error, the fix for each, and the Dockerfiles we tested with SkiaSharp 4.153.1 on .NET 10. It ends with OneImage, a pure C# image library with no native binary to deploy.
The errors
We published one small SkiaSharp program (below) three ways and ran it in Microsoft’s stock mcr.microsoft.com/dotnet/runtime:10.0 (Ubuntu 24.04) and runtime:10.0-alpine images. Every failure starts with TypeInitializationException: “The type initializer for 'SkiaSharp.SkiaApi' threw an exception”, and then a DllNotFoundException: “Unable to load shared library 'libSkiaSharp' or one of its dependencies.” The lines after that tell you which problem you have:
- Only
SkiaSharpreferenced:/app/libSkiaSharp.so: cannot open shared object file: No such file or directory. On Alpine:Error loading shared library /app/libSkiaSharp.so: No such file or directory. - Plus
SkiaSharp.NativeAssets.Linux, with no fontconfig in the image:libfontconfig.so.1: cannot open shared object file: No such file or directory. On Alpine:Error loading shared library libfontconfig.so.1: No such file or directory (needed by /app/runtimes/linux-musl-x64/native/libSkiaSharp.so). - Plus
SkiaSharp.NativeAssets.: no error. The program printedLinux. NoDependencies 800x800.
The runtime lists every path it tried, so read the first specific line. SkiaSharp’s own troubleshooting guide makes the same split. If libSkiaSharp.so itself wasn’t found, the native-assets package is missing. If a library it needs, like libfontconfig.so.1, wasn’t found, the binary is there but the image lacks one of its dependencies.
Why SkiaSharp doesn’t include Linux
The SkiaSharp 4.153.1 listing shows its dependencies for net10.0: SkiaSharp.NativeAssets.macOS and SkiaSharp.NativeAssets.Win32, and no Linux package. SkiaSharp’s package documentation says the Linux, WebAssembly, Nano Server and WinUI assets “must be added manually”. The README explains why: “Because there are multiple distros of Linux, and we cannot possibly support them all, we have a separate NuGet package”. The published app confirms it. With only SkiaSharp, its runtimes folder held osx, win-arm64, win-x64 and win-x86, and nothing for Linux.
Fix 1: add the NoDependencies native assets
For Docker, this is the package SkiaSharp’s documentation recommends. It describes it as having “No fontconfig, no third-party deps” and being “Designed for minimal containers”. It covers glibc and musl (Alpine) on x64, x86, arm, arm64, riscv64 and loongarch64.
dotnet add package SkiaSharp.NativeAssets.Linux.NoDependencies --version 4.153.1
Two details matter:
- Add it to the application project, the one that builds the executable. A reference that exists only in a class library may not copy the native binary to the output. SkiaSharp’s docs say so, and it is the most common reason the fix “doesn’t work”.
- Match the version to your
SkiaSharppackage. Both are 4.153.1 here.
This is the program we tested. It loads a 3000×3002 JPEG, resizes it to 800 px wide with the documented Resize(SKImageInfo, SKSamplingOptions) overload and saves a JPEG:
using SkiaSharp; using SKBitmap input = SKBitmap.Decode("photo.jpg"); int height = input.Height * 800 / input.Width; using SKBitmap resized = input.Resize(new SKImageInfo(800, height), new SKSamplingOptions(SKCubicResampler.Mitchell)); using SKData jpeg = resized.Encode(SKEncodedImageFormat.Jpeg, 85); File.WriteAllBytes("photo-800.jpg", jpeg.ToArray()); Console.WriteLine($"{resized.Width}x{resized.Height}");
With NoDependencies it ran unchanged in the plain Ubuntu image, the Alpine image and the distroless runtime:10.0-noble-chiseled image. A Dockerfile needs nothing SkiaSharp-specific:
FROM mcr.microsoft.com/dotnet/runtime:10.0 WORKDIR /app COPY publish/ . ENTRYPOINT ["dotnet", "SkiaResize.dll"]
For the chiseled image, use FROM mcr.microsoft.com/dotnet/runtime:10.0-noble-chiseled and COPY --chown=app:app publish/ .. Chiseled images run as a non-root user, so the app needs to own any folder it writes to.
The tradeoff is fonts. Without fontconfig, SkiaSharp can’t enumerate installed fonts. Its documentation says that with NoDependencies “Fonts must be loaded explicitly”. If you only decode, resize and encode images, that doesn’t matter. If you draw text, load the font files you ship.
Fix 2: add NativeAssets.Linux and install fontconfig
If your app needs the system’s fonts, use SkiaSharp.NativeAssets.Linux and install fontconfig in the image. SkiaSharp’s selection guide recommends this package for a “Standard Linux server/desktop” and whenever the “App needs system font enumeration”. On Debian or Ubuntu images:
FROM mcr.microsoft.com/dotnet/runtime:10.0
RUN apt-get update \
&& apt-get install -y --no-install-recommends libfontconfig1 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY publish/ .
ENTRYPOINT ["dotnet", "SkiaResize.dll"]On Alpine:
FROM mcr.microsoft.com/dotnet/runtime:10.0-alpine RUN apk add --no-cache fontconfig WORKDIR /app COPY publish/ . ENTRYPOINT ["dotnet", "SkiaResize.dll"]
Both printed 800x800. Running ldd on the libSkiaSharp.so from this package in the stock image shows the missing piece: libfontconfig.so.1 => not found. To see fonts in the output, the image also needs font files. The stock Ubuntu and Alpine .NET 10 runtime images we used have no /usr/share/fonts directory.
Still failing? Check these
- Two Linux packages at once. If you reference NoDependencies but the error mentions fontconfig, a transitive
SkiaSharp.NativeAssets.Linuxis winning. SkiaSharp’s docs suggest checking for that conflict and runninglddon the deployedlibSkiaSharp.so.dotnet nuget why <project> SkiaSharp.NativeAssets.Linuxshows where it comes from. - Trimming. The docs list trimming among the causes and recommend the same fix: a direct
PackageReferenceto the native-assets package. - A large publish folder. A framework-dependent publish without a runtime identifier carries native binaries for every platform. Our NoDependencies publish was 473 MB, almost all of it in
runtimes/. Withdotnet publish -r linux-x64 --self-contained falseit was 13 MB, with onelibSkiaSharp.so. Uselinux-musl-x64for Alpine and thearm64variants for ARM hosts.
Image processing without a native library
The fixes above work, but the native binary has to match every platform and image you deploy to, and the native-assets package is one more reference to keep in step with SkiaSharp. If your SkiaSharp code does image processing (decode, resize, crop, convert, encode) rather than 2D drawing, GPU rendering or UI, OneImage removes the native part entirely. It is pure C#, licensed MIT OR Apache-2.0, and targets .NET 10.
dotnet add package RecursiveAI.OneImage
using OneImage; Image resized = Image.Load("photo.jpg").Resize(width: 800); resized.Save("photo-800.jpg", new SaveOptions { EncoderOptions = new JpegEncoderOptions { Quality = 85 } }); Console.WriteLine($"{resized.Width}x{resized.Height}");
It printed 800x801, since OneImage rounds the derived height where the SkiaSharp sample truncates it. The same publish folder ran in the Ubuntu, Alpine and chiseled .NET 10 runtime images with nothing added. There was no runtimes/ folder and no .so file, and the whole publish output was 7.8 MB. No runtime identifier was needed, and this is the chiseled Dockerfile we used:
FROM mcr.microsoft.com/dotnet/runtime:10.0-noble-chiseled WORKDIR /app COPY --chown=app:app publish/ . ENTRYPOINT ["dotnet", "OneImageResize.dll"]
OneImage also applies EXIF orientation when it loads, decodes JPEGs at reduced scale when a thumbnail allows it, and checks size limits from the file headers before allocating, which matters for uploads. See our guide to resizing images in C#. For drawing-heavy code, SkiaSharp stays the better tool. Our comparison of .NET image libraries says where each one fits, and the SkiaSharp license page covers what you agree to when you ship it.