If you have been using SkiaSharp for custom rendering in a .NET MAUI app, a Blazor canvas, or a headless image pipeline, you have probably noticed the release cadence slow to a crawl. The last major version shipped in early 2024, and upstream Skia kept moving without it. That gap is now closing. On 28 April 2026 the team released SkiaSharp 4.0 Preview 1, jumping from Skia milestone 133 all the way to milestone 147 — two and a half years and 28 milestones of rendering, performance, and security work landing in a single package update.

This is not just a Skia engine bump, though. The release introduces a proper variable font API, makes SKPath immutable under the hood, adds colour font palette support, and brings Uno Platform on board as a co-maintainer. If SkiaSharp is anywhere in your dependency graph, this preview deserves a close look.

What the engine upgrade gives you for free

The Skia milestone jump from 133 to 147 delivers improvements that apply automatically — no code changes, no new API calls. You install the updated package and your existing rendering gets better.

The headline gains:

// TIP

If you have manual Exif rotation code in your image loading pipeline, test whether it double-rotates after upgrading. The codec now handles orientation automatically, so your manual rotation may need to be removed.

Variable fonts: a long-awaited API

Variable fonts have been the most requested SkiaSharp feature for years. The underlying Skia engine supported them, but SkiaSharp never exposed the API. Developers resorted to P/Invoke hacks against the native Skia symbols to set font weight or width axes — fragile, undocumented, and painful to maintain.

SkiaSharp 4.0 Preview 1 adds first-class variable font support with a clean, allocation-aware API. Several new types make this work.

Querying font axes

SKTypeface gains properties and methods for inspecting which variation axes a font supports:

Services/FontInspector.cs
using var stream = File.OpenRead("fonts/InterVariable.ttf");
using var typeface = SKTypeface.FromStream(stream);

foreach (var axis in typeface.VariationDesignParameters)
{
    Console.WriteLine($"{axis.Tag}: {axis.Min} .. {axis.Default} .. {axis.Max}");
}

Each SKFontVariationAxis exposes Tag, Min, Default, Max, and IsHidden. The Tag is an SKFourByteTag — a struct that wraps the standard four-character OpenType axis tags like wght, wdth, and slnt.

Creating font variants

To create a typeface at a specific weight or width, clone it with the desired axis positions:

Services/FontVariantFactory.cs
public static SKTypeface CreateVariant(
    SKTypeface baseTypeface,
    float weight,
    float width = 100f)
{
    Span<SKFontVariationPositionCoordinate> coordinates = stackalloc[]
    {
        new SKFontVariationPositionCoordinate
        {
            Axis = SKFourByteTag.Parse("wght"),
            Value = weight
        },
        new SKFontVariationPositionCoordinate
        {
            Axis = SKFourByteTag.Parse("wdth"),
            Value = width
        }
    };

    return baseTypeface.Clone(coordinates);
}

The Clone method accepts a ReadOnlySpan<SKFontVariationPositionCoordinate>, so you can use stackalloc to avoid heap allocations entirely. There is also an overload that takes SKFontArguments for full control over variation position and collection index (useful for TTC font collections).

Reading current positions

If you need to inspect the current variation state of a typeface:

Example.cs
var positions = typeface.VariationDesignPosition;
foreach (var pos in positions)
{
    Console.WriteLine($"Axis {pos.Axis} is set to {pos.Value}");
}

For hot paths, a span-based GetVariationDesignPosition(Span<SKFontVariationPositionCoordinate>) overload avoids the array allocation.

HarfBuzz integration

The variable font API extends to HarfBuzzSharp as well. Face gains HasVariationData, VariationAxisInfos, and TryFindVariationAxis. Font gains SetVariations, SetVariationCoordsDesign, and named instance selection via SetVariationNamedInstance. This means your text shaping pipeline can work with variation axes end-to-end.

// NOTE

Variable font rendering has always worked if you loaded the correct static instance of a font file. What is new here is programmatic axis control — loading one variable font file and creating multiple weight or width variants at runtime without separate font files.

Colour font palettes

Colour fonts — think emoji fonts, icon sets with built-in colours, or branded glyph sets — use the OpenType CPAL (Colour Palette) table to store multiple colour schemes. SkiaSharp 4.0 exposes this for the first time.

You can now switch between palettes or override individual glyph colours, which is useful for rendering icon fonts in different themes (light/dark) or adjusting emoji styles programmatically. Previously this required either multiple font files or custom rendering logic.

SKPathBuilder: the path construction shift

This change has the biggest migration implications. SKPath is now immutable under the hood — its geometry cannot be modified after construction. The familiar MoveTo/LineTo/CubicTo methods on SKPath still compile and work (they delegate internally), but the intended construction pattern going forward is SKPathBuilder.

Before: mutable SKPath

Example.cs
// Bad — works today but relies on mutable path internals
var path = new SKPath();
path.MoveTo(10, 10);
path.LineTo(100, 10);
path.LineTo(100, 100);
path.Close();

canvas.DrawPath(path, paint);

After: SKPathBuilder

Example.cs
// Good — explicit builder, immutable result
var builder = new SKPathBuilder();
builder.MoveTo(10, 10);
builder.LineTo(100, 10);
builder.LineTo(100, 100);
builder.Close();

using var path = builder.Snapshot();
canvas.DrawPath(path, paint);

SKPathBuilder provides the same fluent API (MoveTo, LineTo, QuadTo, CubicTo, ArcTo, Close) plus static factory methods for common shapes:

Example.cs
// One-call shape construction — no builder needed
using var rect = SKPath.Rect(SKRect.Create(0, 0, 200, 100));
using var oval = SKPath.Oval(SKRect.Create(0, 0, 200, 100));
using var circle = SKPath.Circle(100, 100, 50);
using var roundRect = SKPath.RRect(new SKRoundRect(SKRect.Create(0, 0, 200, 100), 12));

// WARNING

If you are mutating paths after construction — for example, calling Transform or AddPath on an existing path — review those call sites. The path is immutable after it leaves the builder. Transform operations return new paths rather than modifying in place.

Why immutable paths matter

Immutable paths let the rendering engine cache and share path data more aggressively. When a path cannot change after construction, the rasteriser can skip defensive copies and reuse tessellation results across frames. For apps that redraw the same shapes repeatedly — chart lines, UI chrome, game sprites — this can reduce per-frame allocation and improve render throughput.

SKSamplingOptions for surface drawing

A smaller but welcome fix: SKCanvas.DrawSurface and SKSurface.Draw now accept SKSamplingOptions. Previously, drawing one surface onto another used default sampling with no way to control the filtering. If you were compositing multiple render targets — say, drawing an off-screen surface onto the main canvas with specific interpolation — you had to work around this limitation. The fix brings these methods in line with the rest of the canvas drawing API.

Platform additions

SkiaSharp 4.0 Preview 1 adds native builds for two new targets:

These are niche targets, but they reflect the broader push to keep SkiaSharp viable anywhere .NET runs.

Uno Platform as co-maintainer

SkiaSharp has historically been maintained primarily by Matthew Leibowitz at Microsoft. That single-maintainer model created a bottleneck — issues piled up, upstream Skia updates lagged, and features like variable fonts sat in the backlog for years.

Starting with 4.0, Uno Platform formally joins as co-maintainer. This is not just a sponsorship badge. Uno engineers contributed several of the headline features in this preview: the major Skia engine upgrade (PRs #3560 and #3702), the variable font implementation (#3703), an Android API 36 typeface crash fix (#3730), and cross-platform generator tooling for Linux (#3714).

The partnership makes sense when you consider that SkiaSharp is the rendering backbone of Uno Platform's cross-platform UI stack. Having Uno engineers with commit access and release authority means faster triage, a more predictable release cadence, and direct representation of cross-platform rendering concerns in the project's direction.

Migration considerations

This is a preview, so the API surface may still shift. But a few things are worth planning for now:

  1. Package name stays the same. The NuGet package is still SkiaSharp, versioned 4.147.0-preview.1.1. No package renames or splits to worry about.

  2. Path construction. The SKPath mutation methods still work, but start moving new code to SKPathBuilder or the static SKPath factory methods. The mutation methods are likely to be deprecated in a future preview.

  3. Exif orientation. If you have manual Exif rotation logic, test it against the new codecs. You may be double-rotating images.

  4. Variable fonts. If you had P/Invoke workarounds for variable font axes, you can replace them with the new managed API. The SKFontArguments ref struct and span-based overloads are designed for hot paths.

  5. Target framework. SkiaSharp 4.0 adds C# 13 support on older target frameworks via PolySharp. No need to upgrade your TFM just for SkiaSharp.

The release roadmap

The team has published a clear timeline through the GitHub tracking issue:

Milestone Target date Focus
Preview 1 28 April 2026 Version bump, sample validation
Preview 2 5 May 2026 Skia engine update, dependency changes
Preview 3 19 May 2026 API deprecation review, new APIs
RC 1 & RC 2 June 2026 Final stabilisation
Stable (4.x GA) 30 June 2026 General availability

A launch event is scheduled for 30 June 2026, hosted by Uno Platform.

Common pitfalls

Assuming path mutation still works long-term. The MoveTo/LineTo methods on SKPath are compatibility shims. They work in this preview, but the direction is clear: SKPathBuilder is the future. Do not write new code that depends on mutating paths after construction.

Ignoring the Exif auto-rotation. This is the most likely source of visual regressions. Any custom orientation handling needs to be tested against the new codec behaviour.

Mixing SkiaSharp 3.x and 4.x in the same solution. If you have transitive dependencies that pin SkiaSharp 3.x (some MAUI libraries do), you will get binding redirect conflicts. Check your dependency graph before upgrading.

Expecting stable API from a preview. The Preview 2 and Preview 3 milestones explicitly include API deprecation review and new API additions. Pin to specific preview versions in experimental branches, not in production builds.

Summary