# \[ANN\] ozstd 0.1

**URL:** <https://discuss.ocaml.org/t/ann-ozstd-0-1/18538>\
**Category:** Community\
**Tags:** zstd, bindings, streaming, compression, announce\
**Created:** [September 17, 2026, 7:28pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538 "2026-09-17T19:28:24Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [September 17, 2026, 7:28pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/1 "2026-09-17T19:28:24Z")

</div>

Yo!

I am happy to announce the first release of [**ozstd**](https://github.com/dx3mod/ozstd) library! The is a small, modern OCaml binding to [Zstandard](https://github.com/facebook/zstd). It wraps the common one-shot and streaming C APIs in a simple, idiomatic interface.

![](https://i.ibb.co/LXfsM8S3/logos-001-2.png)

**Features**

- One-shot and streaming compression/decompression for strings and bigstrings.
- Reusable compression and decompression contexts.
- Low-level `Stream` API for manual buffers, and high-level `State` API for slice handling.

This is a **hard fork** of the unmaintained [zstd](https://github.com/ygrek/ocaml-zstd) OCaml bindings. It has been **fully rewritten** and is released separately because the original maintainers do not merge pull requests.

The main goal of creating this library was to provide a way to incrementally compress and decompress features for my [Bytream](https://github.com/dx3mod/bytream) library, which is used in my other library, [Rpmfile](https://github.com/dx3mod/rpmfile), to decode a package’s payload as a compressed cpio archive.

However, for regular use, you can use the one-shot API.

```ocaml
let source = 
  "Contrary to popular belief, Lorem Ipsum is not simply random text."

let compressed = 
  Ozstd.Compressor.compress_string ~level:3 source

let decompressed =
  Ozstd.Decompressor.decompress_string compressed

```

Or also streaming API (the `State` module is the high-level API: feed it input slices and emit output slices).

```ocaml
let compress_sequence_into_channel seq oc =
  let state = Ozstd.Compressor.State.create () in

  let output Slice.{ buf; off; len } = 
    Out_channel.output_bigarray oc buf off len 
  in

  let aux slice =
    Ozstd.Compressor.State.feed state slice `Continue |> output
  in

  Seq.iter aux seq;
  Ozstd.Compressor.State.finish state |> output

```

An example of usage in the Bytream context.

```ocaml
let uncompressed_payload =
  Rpmfile.Payload.to_incoming_bytes compressed_payload 
  |> Bytream_zstd.In.of_stream
in

```

For more details see [README](https://github.com/dx3mod/ozstd) and other docs.

**Limitations**. These bindings cover a large part of the Zstandard C API, but not all of it! Pull requests are welcome.

If you encounter any issue with these releases, please [report it on the github repository](https://github.com/dx3mod/ozstd/issues).  
Feedback and contributions are welcome.

---

<div class="post-metadata">

**Author:** ![Khady](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/khady/32/469_2.png) [@Khady](https://discuss.ocaml.org/u/Khady)\
**Post date:** [September 18, 2026, 1:22am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/2 "2026-09-18T01:22:28Z")

</div>

> [@dx3mod](#):
>
> This is a **hard fork** of the unmaintained [zstd](https://github.com/ygrek/ocaml-zstd) OCaml bindings.

Those are very much maintained and used heavily in production.

> [@dx3mod](#):
>
> the original maintainers do not merge pull requests.

This isn’t true either.

---

<div class="post-metadata">

**Author:** ![amongonz](https://avatars.discourse-cdn.com/v4/letter/a/a88e4f/32.png) [@amongonz](https://discuss.ocaml.org/u/amongonz)\
**Post date:** [September 18, 2026, 6:31am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/3 "2026-09-18T06:31:20Z")

</div>

> [@dx3mod](#):
>
> This is a **hard fork** of the unmaintained [zstd](https://github.com/ygrek/ocaml-zstd) OCaml bindings. It has been **fully rewritten**

That’s not a fork at all? You’ve just written a new library, even changed the license. (I just noticed a license file is missing from [zstd](https://github.com/ygrek/ocaml-zstd), but it’s stated in the opam file.)

Which by itself is fine, perhaps yours is truly better, but you announce it by being weirdly adversarial to the previous library: You dumped a +2165 -758 PR on a ~700 line project (replaced all their code), didn’t wait for a day for a reply, which you knew would be negative, before giving up, and came here telling us that project is unmaintained?

---

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [September 18, 2026, 7:12am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/4 "2026-09-18T07:12:38Z")

</div>

At first, I only intended to make minor changes, but I ended up having to rewrite the entire project; there was no other way. Not a single line of the original code remains. Of course, I would have liked to merge my changes into the main branch, but I don’t have time to wait six months only to be rejected—whether because of a broken API or because I’m told, “We already have enough as it is.”

I don’t know what you find offensive about the word “unmaintained,” but to me it describes [open PRs](https://github.com/ygrek/ocaml-zstd/pull/12) that have neither been discussed nor rejected and have been sitting since the beginning of the year, along with a complete lack of development.

If you’re satisfied with the primitive functionality the original project offers, then you can consider Ozstd a nasty knockoff—and you don’t need it. Otherwise, you can keep working on the original project and deal with everything that comes with it.

I called it a fork out of respect for the original authors, but the code is entirely mine. Therefore, the license and authorship are mine, not anyone else’s.

---

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [September 18, 2026, 7:29am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/5 "2026-09-18T07:29:47Z")

</div>

> [@Khady](#):
>
> very much maintained

If that’s how you see it, so be it. But all I see is a project that solved someone’s problem, then got abandoned in the ecosystem, and it doesn’t even have a README.

---

<div class="post-metadata">

**Author:** ![Khady](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/khady/32/469_2.png) [@Khady](https://discuss.ocaml.org/u/Khady)\
**Post date:** [September 18, 2026, 7:53am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/6 "2026-09-18T07:53:06Z")

</div>

That’s not “how I see it”. I work at the company which is maintaining this project and using it at VERY large scale. The open PR (no s here) is also from someone working in the company. There’s development for features that people need. Obviously you are right it doesn’t have much doc or presentation and that could be improved. But things don’t have to be fancy and moving all the time to be alive.

To be clear, I am not saying that it makes your development uninteresting or illegitimate. I totally understand that you can have your own constraints like not waiting for us to respond or preferring a specific api or just owning your code. It might even inspire some improvements in our code. But I have to point out that the original repo is still maintained to avoid confusing humans and AI that might rely on it.

Your PR description claims to fix a leak. I’m curious to know where that leak is so that we can solve it if you have the info available. From what I could gather it’s actually a leak that appeared and was fixed during your development. But if I’m wrong I’d like to fix our code.

---

<div class="post-metadata">

**Author:** ![dinosaure](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dinosaure/32/16_2.png) [@dinosaure](https://discuss.ocaml.org/u/dinosaure)\
**Post date:** [September 18, 2026, 7:53am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/7 "2026-09-18T07:53:56Z")

</div>

I just want to point out that a README.md isn’t a good metric for gauging the health of a software project. I myself might forget to create README.md files or stop maintaining them even though the project is still active. For example, there’s a 6-year gap between the two commits that update the README.md for [ocaml-tls](https://github.com/mirleft/ocaml-tls/blame/main/README.md) (and God knows a lot has changed in those 6 years…).

---

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [September 18, 2026, 8:09am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/8 "2026-09-18T08:09:23Z")

</div>

> [@Khady](#):
>
> Your PR description claims to fix a leak

My implementation uses hand-written C stubs; yours uses ctypes. Because of that, I could set a custom finalizer for external values and avoid calling `free_*` from OCaml code. This lets users create and use their own contexts more freely with the matching API.

---

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [September 18, 2026, 7:10pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/9 "2026-09-18T19:10:25Z")

</div>

@Khady Okay, I have removed the mention of this being a fork and the reasons behind its creation. This is now a standalone project. Is everyone happy with this?

---

<div class="post-metadata">

**Author:** ![Khady](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/khady/32/469_2.png) [@Khady](https://discuss.ocaml.org/u/Khady)\
**Post date:** [September 22, 2026, 10:57pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/10 "2026-09-22T22:57:30Z")

</div>

Yes that should avoid some confusion. Thank you

---

<div class="post-metadata">

**Author:** ![aryx](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/aryx/32/2356_2.png) [@aryx](https://discuss.ocaml.org/u/aryx)\
**Post date:** [October 2, 2026, 10:53pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/11 "2026-10-02T22:53:08Z")

</div>

What’s the point of writing bindings … we can now automatically generate the OCaml code for the format, without depending on any C library: [ocaml-elm-playground/libs/compression/Zstd.ml at master · aryx/ocaml-elm-playground · GitHub](https://github.com/aryx/ocaml-elm-playground/blob/master/libs/compression/Zstd.ml)

---

<div class="post-metadata">

**Author:** ![dbuenzli](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dbuenzli/32/18_2.png) [@dbuenzli](https://discuss.ocaml.org/u/dbuenzli)\
**Post date:** [October 2, 2026, 11:58pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/12 "2026-10-02T23:58:40Z")

</div>

The point is to rely on code that is understood by those who provide it.

---

<div class="post-metadata">

**Author:** ![aryx](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/aryx/32/2356_2.png) [@aryx](https://discuss.ocaml.org/u/aryx)\
**Post date:** [October 3, 2026, 6:24am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/13 "2026-10-03T06:24:20Z")

</div>

I agree Daniel, and I was being a bit provocative. But if you think about it, this ozstd binding is 1900 LOC (mostly OCaml and a bit of C stubs) when the whole from-scratch implementation in the ocaml-elm-playground is just 900 LOC! The whole zstd C github repo contains 140 000 LOC! Granted, the playground implem is just the decompressor, and the zstd repo contains a fuzzer, some kernel contribs, tests, etc, but still 900 LOC is definitely easier to understand than the big amount of C code in the zstd and those 1900 LOC in ozstd. A big argument is speed; The C implementation is for sure faster, but 140 000 LOC is a big price on understandability.

---

<div class="post-metadata">

**Author:** ![dinosaure](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dinosaure/32/16_2.png) [@dinosaure](https://discuss.ocaml.org/u/dinosaure)\
**Post date:** [October 3, 2026, 7:17am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/14 "2026-10-03T07:17:26Z")

</div>

We can do better, [a flight simulator in only 58 LOC](https://www.ioccc.org/1998/banks/index.html)!

---

<div class="post-metadata">

**Author:** ![aryx](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/aryx/32/2356_2.png) [@aryx](https://discuss.ocaml.org/u/aryx)\
**Post date:** [October 3, 2026, 8:15am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/15 "2026-10-03T08:15:08Z")

</div>

Well let’s not provoke our future masters. I’m sure they can even beat that!

---

<div class="post-metadata">

**Author:** ![dbuenzli](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dbuenzli/32/18_2.png) [@dbuenzli](https://discuss.ocaml.org/u/dbuenzli)\
**Post date:** [October 3, 2026, 8:31pm UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/16 "2026-10-03T20:31:12Z")

</div>

> [@aryx](#):
>
> The C implementation is for sure faster, but 140 000 LOC is a big price on understandability.

This misses my point. The day you have a bug in your “automatically generated” implementation, you are alone with something you do not fully understand – if at all.

---

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [October 7, 2026, 5:20am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/17 "2026-10-07T05:20:39Z")

</div>

Yes, it’s a bit of a shame that the only attention my library has received has come from a single confusing paragraph, leaving many users confused. Instead, we would like to focus on the benefits that our library provides to OCaml users, giving them more options for working with zstd.

---

<div class="post-metadata">

**Author:** ![dx3mod](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/dx3mod/32/6740_2.png) [@dx3mod](https://discuss.ocaml.org/u/dx3mod)\
**Post date:** [October 9, 2026, 5:54am UTC](https://discuss.ocaml.org/t/ann-ozstd-0-1/18538/18 "2026-10-09T05:54:19Z")

</div>

By the way, ozstd had another minor release not too long ago. It brought an API for both bigstring and bytes, typed exceptions instead of Failure, and dictionary string as a private type so values don’t get mixed together.

Honestly, I think that’s more than enough for most use cases that don’t need zstd tuning itself. But if anyone wants something, I’d be happy to make it happen. Just let me know!
