.NET Core 3.1 .NET Standard 1.1 .NET Framework 4.5
dotnet add package ImpromptuNinjas.ZStd --version
NuGet\Install-Package ImpromptuNinjas.ZStd -Version
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ImpromptuNinjas.ZStd" Version="" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ImpromptuNinjas.ZStd --version
#r "nuget: ImpromptuNinjas.ZStd,"
#r directive can be used in F# Interactive, C# scripting and .NET Interactive. Copy this into the interactive tool or source code of the script to reference the package.
// Install ImpromptuNinjas.ZStd as a Cake Addin
#addin nuget:?package=ImpromptuNinjas.ZStd&version=

// Install ImpromptuNinjas.ZStd as a Cake Tool
#tool nuget:?package=ImpromptuNinjas.ZStd&version=

ZStd for .NET ZStd for .NET

NuGet Build & Test Sponsor

ZStd is a multi-platform .NET binding of Facebook's Zstandard library.

Supported platforms:

  • Windows
    • x64
    • x86
  • Linux
    • GNU flavors (Debian, Ubuntu, ...)
    • Musl flavors (Alpine, Void, ...)
    • Intel x86
    • AMD64 / Intel x86-64
    • ARMv8-64 / AArch64
    • ARMv7-HF / AArch32
  • Apple OSX
    • 64-bit only

Note: ARM support is currently hard-float only, no soft-float platform support unless requested.

Note: In the not too distant future support for 32-bit architectures will likely be dropped.


  • Compression and decompression
    • Dictionary support
    • Managed streams into streams of frames
    • Byte arrays and spans into frames
    • Byte arrays and spans into blocks (without frames)
  • Generation of dictionaries from a collection of samples
  • Loading and saving of dictionaries to and from streams, arrays and spans
  • Helpers for collection of dictionary samples and training
  • Training will automatically tune unspecified dictionary parameters

Take a look at the unit tests to explore its behavior in different situations.

This is in the later stages of development, and features are less likely to be added over time.

Known Issues:

  • Currently the native dependencies are shipped with this NuGet package for all platforms. Separate NuGet runtime packages should be created to provide each specific platform dependency.
  • Coverage currently stands at 50%. Critical path coverage is high. Coverage of non-critical path operations is low.
  • The GC is not yet automatically made aware of unmanaged memory usage.


Official documentation

This project is heavily inspired by ZstdNet, but shares very little in the way of implementation.


Basic usage examples

// pick a compression level or use 0, considered 'auto' in most cases
var compressionLevel = 3;
//var compressionLevel = ZStdCompressor.MinimumCompressionLevel; // probably 1
// Note: negative levels do exist as per zstd documentation, but this just calls ZSTD_minCLevel
//var compressionLevel = ZStdCompressor.MaximumCompressionLevel; // probably 22

// allocate a 32kB buffer to build a new dictionary
var dict = new ZStdDictionaryBuilder(32 * 1024);
// or load from some external data
//var dict = new ZStdDictionaryBuilder(someBytes);
//var dict = new ZStdDictionaryBuilder(someBytes, someSize);

// train the dictionary, and retrieve tuned training parameters for future training
var trainedParams = dict.Train(async () => {
  // sample your data by returning ArraySegment<byte>s of regions you expect to occur often
  // refer to Facebook's Zstd documentation for details on what should be sampled
  yield return ArraySegment<byte>(trainingData, 7, 42);
}, compressionLevel);

// optionally save the dictionary to a file somehow
using (var fs = File.Create(path))
  dict.WriteTo(fs); // preferred
//  fs.Write(dict); // implicitly casts to ReadOnlySpan<byte>
//File.WriteAllBytes("saved_dictionary", ((ArraySegment<byte>)dict).ToArray());

// create an unmanaged reference for use with compression
using var cDict = dict.CreateCompressorDictionary(compressionLevel);

// create an unmanaged reference for use with decompression
using var dDict = dict.CreateDecompressorDictionary();

// be sure to dispose of your compressors/decompressors before your dictionary references

// create a context
using var cCtx = new ZStdCompressor();

// specify the dictionary you want to use, or don't

// figure out about how big of a buffer you need
var compressBufferSize = CCtx.GetUpperBound((UIntPtr) inputData.Length);

var compressBuffer = new byte[compressBufferSize];

// set the compressor to the compression level (it may inherit it from the dictionary)
cCtx.Set(CompressionParameter.CompressionLevel, compressionLevel);

// actually perform the compression operation
var compressedSize = cCtx.Compress(compressBuffer, inputData);

// retrieve your compressed frame
var compressedFrame = new ArraySegment<byte>(compressBuffer, 0, (int) compressedSize);

// create a context
var dCtx = new ZStdDecompressor();

// specify the dictionary you want to use, or don't

// figure out about how big of a buffer you need
var decompressBufferSize = DCtx.GetUpperBound(compressedFrame);

var decompressBuffer = new byte[decompressBufferSize];

// actually perform the decompression operation
var decompressedSize = dCtx.Decompress(decompressBuffer, compressedFrame);

// retrieve your decompressed frame
var decompressedFrame = new ArraySegment<byte>(decompressBuffer, 0, (int) decompressedSize);

Stream Compression
// have somewhere to put the compressed output, any stream will do
using var compressed = new MemoryStream();

// create a compression context over the output stream
using var compressStream = new ZStdCompressStream(compressed);

// ZStdCompressStream.Compressor is just a ZStdCompressor, so you can set parameters and use dictionaries
compressStream.Compressor.Set(CompressionParameter.CompressionLevel, compressionLevel);

// write some data into it

// if you're done writing data and you're not at the end of a frame, it'd be wise to flush

Stream Decompression
// consume the compressed input stream with the stream decompressor
using var decompressStream = new ZStdDecompressStream(compressedInput);

// you can access ZStdCompressStream.Decompressor, it's a ZStdDecmpressor, to specify a dictionary and such

// decompress some data..
var decompressed = new byte[someDataSize];

decompressStream.Read(decompressed, 0, decompressed.Length);

Product Versions
.NET net5.0 net5.0-windows net6.0 net6.0-android net6.0-ios net6.0-maccatalyst net6.0-macos net6.0-tvos net6.0-windows net7.0 net7.0-android net7.0-ios net7.0-maccatalyst net7.0-macos net7.0-tvos net7.0-windows
.NET Core netcoreapp1.0 netcoreapp1.1 netcoreapp2.0 netcoreapp2.1 netcoreapp2.2 netcoreapp3.0 netcoreapp3.1
.NET Standard netstandard1.1 netstandard1.2 netstandard1.3 netstandard1.4 netstandard1.5 netstandard1.6 netstandard2.0 netstandard2.1
.NET Framework net45 net451 net452 net46 net461 net462 net463 net47 net471 net472 net48
MonoAndroid monoandroid
MonoMac monomac
MonoTouch monotouch
Tizen tizen30 tizen40 tizen60
Universal Windows Platform uap uap10.0
Windows Phone wpa81
Windows Store netcore netcore45 netcore451
Xamarin.iOS xamarinios
Xamarin.Mac xamarinmac
Xamarin.TVOS xamarintvos
Xamarin.WatchOS xamarinwatchos
Compatible target framework(s)
Additional computed target framework(s)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated 64,093 7/31/2020 348 7/21/2020 379 3/15/2020