---
title: "SkiaSharp on Linux and Docker"
url: https://recursiveai.org/oneimage/articles/skiasharp-linux-docker/
description: "Fix “Unable to load shared library 'libSkiaSharp'” on Linux, Docker and Alpine: which NativeAssets package to add, fontconfig, and a no-native alternative."
date: 2026-10-23
author: OneImage team
---

# 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.

October 23, 2026 · OneImage team

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.Linux.NoDependencies`, 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 `SkiaSharp` referenced:** `/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.Linux.NoDependencies`:** no error. The program printed `800x800`.

The runtime lists every path it tried, so read the first specific line. SkiaSharp’s own [troubleshooting guide](https://github.com/mono/SkiaSharp/blob/main/documentation/dev/packages.md#troubleshooting-native-loading) 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](https://www.nuget.org/packages/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](https://github.com/mono/SkiaSharp/blob/main/documentation/dev/packages.md) 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.

*Terminal · NuGet*

```
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 `SkiaSharp` package. 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:

*Program.cs · SkiaSharp 4.153.1 · .NET 10*

```
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:

*Dockerfile · SkiaSharp + NoDependencies*

```
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:

*Dockerfile · Ubuntu / Debian*

```
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:

*Dockerfile · 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.Linux` is winning. SkiaSharp’s docs suggest checking for that conflict and running `ldd` on the deployed `libSkiaSharp.so`. `dotnet nuget why <project> SkiaSharp.NativeAssets.Linux` shows where it comes from.
- **Trimming.** The docs list trimming among the causes and recommend the same fix: a direct `PackageReference` to 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/`. With `dotnet publish -r linux-x64 --self-contained false` it was 13 MB, with one `libSkiaSharp.so`. Use `linux-musl-x64` for Alpine and the `arm64` variants 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. Our [SkiaSharp migration guide](https://recursiveai.org/oneimage/articles/migrate-from-skiasharp/) maps the common calls one by one.

*Terminal · NuGet*

```
dotnet add package RecursiveAI.OneImage
```

*Program.cs · OneImage 1.6.0 · .NET 10*

```
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:

*Dockerfile · OneImage*

```
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#](https://recursiveai.org/oneimage/articles/resize-image-csharp/). For drawing-heavy code, SkiaSharp stays the better tool. Our [comparison of .NET image libraries](https://recursiveai.org/oneimage/articles/imagesharp-alternatives/) says where each one fits, and the [SkiaSharp license](https://recursiveai.org/oneimage/articles/skiasharp-license/) page covers what you agree to when you ship it.
