# Ocibuild - Build OCI compliant images from your releases

**URL:** <https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330>\
**Category:** Libraries\
**Tags:** rebar3, releases, containers\
**Created:** [December 20, 2025, 12:02am UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330 "2025-12-20T00:02:06Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![rhblind](https://erlangforums.com/user_avatar/erlangforums.com/rhblind/32/3087_2.png) [@rhblind](https://erlangforums.com/u/rhblind)\
**Post date:** [December 20, 2025, 12:02am UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/1 "2025-12-20T00:02:06Z")

</div>

Hello,

I have been working on a rebar3 plugin/library for the last few days that allows you to build OCI compliant container images from Erlang and Elixir releases. At my company we’re using quite a few different languages, and some of them (C# and Golang are quite popular) have the ability to build container images directly without having to go through Docker. This results in incredibly fast build times on CI/CD pipelines.

I was a bit jealous of this for my Elixir projects, so I looked into if it was possible to do so for BEAM languages. With a lot of help from my good friend Claude we made fast progress, and tonight I released the first v0.1.0 release to Hex.pm.

Disclaimer: I’ve not written much Erlang before, but I decided to write this in Erlang instead of Elixir in order to make it easier for all BEAM languages to take advantage of this.

If this sounds interesting, please give it a spin 🙂

> **[ocibuild](https://hex.pm/packages/ocibuild)**
>
> Build and publish OCI container images from the BEAM

> **[GitHub - intility/erlang-oci-builder: Build and publish OCI container images from the...](https://github.com/intility/erlang-oci-builder)**
>
> Build and publish OCI container images from the BEAM

---

<div class="post-metadata">

**Author:** ![rhblind](https://erlangforums.com/user_avatar/erlangforums.com/rhblind/32/3087_2.png) [@rhblind](https://erlangforums.com/u/rhblind)\
**Post date:** [December 25, 2025, 6:25pm UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/2 "2025-12-25T18:25:48Z")

</div>

Hi, friends!

During the last few days I’ve implemented quite a few new features from my roadmap for  
this library. I just released v0.5.0 which includes the following new features.

- Multi-Platform Images

- Non-Root containers by default

- Automatic OCI Annotations

- Reproducable Builds

- Automatic Software Bill of Materials (SBOM) support

- Smart Dependency Layering

There’s probably still a few rough edges and the code-base needs a bit refactoring in certain places, but I have implemented most of my planned features and would be very happy for feedback (both positive and negative)!

As stated earlier, I’m, quite fresh in Erlang (even though I have been coding Elixir for quite some time), so there might be conventions and other things that could use some polish.

---

<div class="post-metadata">

**Author:** ![rhblind](https://erlangforums.com/user_avatar/erlangforums.com/rhblind/32/3087_2.png) [@rhblind](https://erlangforums.com/u/rhblind)\
**Post date:** [January 9, 2026, 9:49am UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/3 "2026-01-09T09:49:59Z")

</div>

Hello again!

Just a small update on the latest work on this library. I’ve now implemented all planned features and made significant improvements on the code base, both in terms of code organization, test coverage and security measures.

The library now has the following feature table.

| Feature | Status | Description |
| --- | --- | --- |
| **No Docker required** | ✅ | Builds images directly without container runtime. |
| **OCI compliant** | ✅ | Produces standard OCI image layouts. |
| **OCI annotations** | ✅ | Add custom annotations to image manifests. Automatically populate source URL, revision, version from VCS. |
| **Push to any registry** | ✅ | Docker Hub, GHCR, ECR, GCR, and any OCI-compliant registry. |
| **Build system integration** | ✅ | Native rebar3 and Mix task support. |
| **Non-root by default** | ✅ | Run as non-root (UID 65534) by default; override with `--uid`. |
| **Layer caching** | ✅ | Base image layers cached locally for faster rebuilds. |
| **Tarball export** | ✅ | Export images for podman, skopeo, crane, buildah, etc. |
| **Multi-platform images** | ✅ | Build for multiple architectures (amd64, arm64) from a single command. |
| **Reproducible builds** | ✅ | Identical images from identical inputs using `SOURCE_DATE_EPOCH`. |
| **Smart dependency layering** | ✅ | Separate layers for ERTS, dependencies, and application code. |
| **SBOM generation** | ✅ | SPDX 2.2 SBOM embedded at `/sbom.spdx.json` and attached via referrers. |
| **Image signing** | ✅ | Sign images with ECDSA keys (cosign-compatible format). |
| **Zstd compression** | ✅ | Automatic zstd on OTP 28+ (20-50% smaller, faster). Falls back to gzip on OTP 27. |

\*_Disclaimer: The claim about pushing to “any” registry is theoretical. I’ve actually only tested it with [ghcr.io](http://ghcr.io)._

The library should be on par (or better) feature-wise with comparable libraries from other eco-systems (`ko` for Golang, `Microsoft.NET.Build.Containers` for .NET and `jib` for Java). It will remain in v0.x.x for a while to gather real-world experience and fixing bugs that certainly will pop up, but it should be in a pretty good shape.

Hopefully someone will find it useful 🙂

---

<div class="post-metadata">

**Author:** ![LostKobrakai](https://erlangforums.com/user_avatar/erlangforums.com/lostkobrakai/32/453_2.png) [@LostKobrakai](https://erlangforums.com/u/LostKobrakai)\
**Post date:** [January 10, 2026, 7:30am UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/4 "2026-01-10T07:30:44Z")

</div>

This looks interesting. Given you‘re not running any container this won’t help with compiling NIFs for the target architecture though I guess. So just like ERTS they would need to be handled out of band. This still looks like a great option for where that‘s not needed.

---

<div class="post-metadata">

**Author:** ![rhblind](https://erlangforums.com/user_avatar/erlangforums.com/rhblind/32/3087_2.png) [@rhblind](https://erlangforums.com/u/rhblind)\
**Post date:** [January 10, 2026, 12:12pm UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/5 "2026-01-10T12:12:57Z")

</div>

That’s correct. If you’re building images for another platform you’ll need to either have to cross-compile your NIFs with a toolchain for that platform, or use a custom base image which contains ERTS and your NIFs already in place. The upside is that you’ll only have to build this base image once instead of on every build.

---

<div class="post-metadata">

**Author:** ![zabrane](https://erlangforums.com/letter_avatar_proxy/v4/letter/z/7ba0ec/32.png) [@zabrane](https://erlangforums.com/u/zabrane)\
**Post date:** [January 10, 2026, 1:17pm UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/6 "2026-01-10T13:17:03Z")

</div>

@rhblind Thanks for sharing.

Could you please explain?

> **Zstd compression** ✅ Automatic zstd on OTP 28+ (20-50% smaller, faster). Falls back to gzip on OTP 27.

---

<div class="post-metadata">

**Author:** ![rhblind](https://erlangforums.com/user_avatar/erlangforums.com/rhblind/32/3087_2.png) [@rhblind](https://erlangforums.com/u/rhblind)\
**Post date:** [January 10, 2026, 1:25pm UTC](https://erlangforums.com/t/ocibuild-build-oci-compliant-images-from-your-releases/5330/7 "2026-01-10T13:25:04Z")

</div>

`zstd` support is not available in OTP27 (as far as I know), thus we’re falling back to compressing the image using `gzip` instead.
