Self-hosted service
opencontainers/runc avatar
opencontainers/runc

runc 1.5.2: a Linux-only runtime whose default build compiles a Rust library first

CLI tool for spawning and running containers according to the OCI specification

13,556 stars2,352 forksGoApache-2.0

At a glance

What is it?
runc is the CLI that spawns and runs containers on Linux under the OCI specification. Its default build tags enable seccomp and libpathrs, so a stock build needs a Rust toolchain and a locally installed libpathrs before any container runs, and checkpoint/restore is the one capability a tag can switch off.
Who is it for?
Use runc when you are the runtime layer under a container engine or a build system and you control the host toolchain, because the feature set is a compile-time decision you have to keep track of. Step back if you need a runtime that runs anywhere but Linux, since that is not on offer here.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • opencontainers/runc13,556 ★ · +98
Star history
Repository2026-09-222026-11-14
opencontainers/runc13.5k13.6k

98 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Every verb is its own file at the repository root, and none of them fetch an image

runc has one sentence of purpose and a repository root that shows the whole command surface. The stated job is spawning and running containers on Linux according to the OCI specification. Each verb then has its own file at the top level: create.go, delete.go, exec.go, kill.go, list.go, pause.go, ps.go, run.go, start.go, state.go, update.go, events.go, spec.go, checkpoint.go, restore.go, init.go, tty.go, and signals.go. The framework behind them is urfave/cli/v3, pinned at v3.14.0 in go.mod, and the man/ directory holds the man pages that go with those commands. What this layout cannot tell you is where the container comes from. Nothing in the repository pulls an image, unpacks layers, or configures networking, so runc consumes a bundle prepared by something else and leaves those stages to a caller. The practical consequence is that a first meeting with the project is not a first meeting with containers: a bundle and a spec have to exist on disk before any of these files do anything, and the types that describe that spec come from a separate module, opencontainers/runtime-spec v1.3.0.

Linux only, Go 1.26.0, and a PIE flag that quietly depends on your race detector

The platform floor is stated in a single line: runc only supports Linux, and the header of go.mod holds the minimum Go version. That header reads go 1.26.0. The shape of the tree agrees, with rlimit_linux.go, rootless_linux.go, and utils_linux.go sitting beside their platform-neutral counterparts, and the build image is golang:1.26-trixie selected through an ARG. What cannot be done is build or run the runtime on macOS or Windows, so validating a bundle that another host produced has no answer here, and a developer on a Mac works inside a Linux container or a VM. The Makefile adds two more platform facts. Dynamic PIE executables are enabled on 386, amd64, arm, arm64, loong64, ppc64le, riscv64, and s390x, unless the string -race appears in EXTRA_FLAGS, in which case the build mode is dropped. And TRIMPATH defaults to -trimpath, with the comment noting it may be required on some platforms for reproducible builds while also stripping the build information some tools use to infer a version; the file shows an override written as make runc TRIMPATH=. The consequence is that a race-instrumented build and a normal build differ in more than instrumentation, and a reproducible build differs from a normal one in what a version tool can still read.

libpathrs is a default tag, so apt alone cannot produce a stock runc

The build tag table is where the real cost of a stock runc appears. seccomp is set by default and depends on libseccomp. libpathrs is also set by default, and it depends on a Rust library runc can optionally use for path safety. runc_nocriu is the odd one out: it is not set by default and it disables checkpoint/restore. Turning on libpathrs means Rust 1.63 or newer plus cargo, clang, and lld, and very few distributions ship libpathrs packages, so building it locally is the normal route:

sh
LIBPATHRS_VERSION=0.2.5
curl -o - -sSL https://github.com/cyphar/libpathrs/releases/download/v${LIBPATHRS_VERSION}/libpathrs-${LIBPATHRS_VERSION}.tar.xz | tar xvfJ -
cd libpathrs-${LIBPATHRS_VERSION}/
make release
sudo ./install.sh --prefix=/usr/local
sudo ldconfig

What the default feature set cannot do is come out of a package manager. The recipes given for Ubuntu and Debian, for CentOS and Fedora, and for Alpine install make, gcc, kernel headers, and libseccomp development files, and none of them install libpathrs. The consequence for a first build is a choice: add a Rust toolchain and a source build of libpathrs into /usr/local followed by ldconfig, or drop the tag and give up the path safety it exists to provide. The project also points at a CI shortcut, which is two commands:

sh
sudo ./script/build-libpathrs.sh "$LIBPATHRS_VERSION" /usr/local
sudo ldconfig

That script is described as completely unsupported and not really intended for general use, because it carries workarounds for CI issues that will no longer be necessary once libpathrs has distribution packages. Read it as a reference for a complicated host, not as something to depend on.

The tag table recognizes three names while three feature files cover two implementations

A version drift and a file naming mismatch sit next to each other in this repository, and both affect what you build. The minimum libpathrs stated for correct operation is 0.2.5. The development snippet sets LIBPATHRS_VERSION=0.2.5. go.mod requires cyphar.com/go-pathrs at v0.2.6, and the Dockerfile pins LIBPATHRS_VERSION=0.2.6. So the documented floor is one release below the pinned build. Alongside that, the tree carries three files for the same concern: features.go, features_libpathrs.go, and features_pathrslite.go. The build tag table recognizes seccomp, libpathrs, and runc_nocriu, and it does not name pathrslite, so the file names and the tag table do not line up one to one. What none of that tells you is which path-safety implementation a given binary ended up with, because the choice is fixed when it compiles. The consequence is that two binaries built from one commit with different RUNC_BUILDTAGS values can handle paths differently, so a bug report that omits the tag list leaves the reader guessing which implementation they are looking at.

RUNC_BUILDTAGS subtracts with a hyphen prefix, and four older tags now do nothing

Tag selection has its own small language. RUNC_BUILDTAGS is a make or shell variable in which entries prefixed with a hyphen are removed from the default set and everything else is added, and the Makefile implements exactly that over a base of seccomp libpathrs. One invocation both adds and subtracts:

bash
# Add runc_nocriu and remove seccomp tag.
make RUNC_BUILDTAGS="runc_nocriu -seccomp"

A second variable, EXTRA_BUILDTAGS, no longer works: the Makefile stops with an error when it is set, EXTRA_BUILDTAGS has been removed; use RUNC_BUILDTAGS instead. The same block carries a TODO to remove that check for runc 1.8, so a build script written against the older name already fails. Four earlier tags are listed as obsoleted, each with the version that retired it: runc_nodmz since v1.2.1, when the runc dmz binary was dropped; nokmem since v1.0.0-rc94, when kernel memory settings are ignored; apparmor and selinux since v1.0.0-rc93, when those features became always enabled. What that cannot do is fail loudly. Nothing in the tag table recognizes those four names, so passing one is filtered without complaint and the build proceeds as if it were valid. The consequence is that old packaging recipes keep setting flags that do nothing, and a reader has to know the version history to tell a missing feature caused by a tag from one caused by code.

The suite runs in Docker because the tests expect to write and remove anywhere

The test suite runs in a container, and the reason is stated rather than implied:

bash
make test

The Makefile sets CONTAINER_ENGINE to docker, and additional targets exist for running the tests outside a container, which the README says is not recommended because the tests are written with the expectation that they can write and remove anywhere. What that cannot do is leave your filesystem alone, so a contributor with real data on the machine has no sanctioned host path through the suite and needs the container. Two variables narrow the scope when a full run is not what you want: TESTFLAGS selects one test function, and TESTPATH selects one integration test file, with /checkpoint.bats given as the example. The dependency list in the Dockerfile shows how far the suite reaches, and it is long: CRIU from a dedicated repository, cargo, cargo-auditable, clang, lld, jq, gawk, gperf, iptables, kmod, sshfs, uidmap, and iproute2, plus cross toolchains for i386, armel, armhf, arm64, ppc64el, s390x, and riscv64 added through dpkg --add-architecture. The consequence is that the test image, not your workstation, is the environment the project supports.

Checkpoint and restore are the one capability a tag deletes, and EXTRA_VERSION is how you prove which build you have

Checkpoint and restore are the feature the build can switch off. checkpoint.go and restore.go sit at the repository root, the go-criu client is pinned at v8.4.0, and the build image installs the CRIU package from its own repository. The tag that removes the feature is runc_nocriu, and it is the only tag in the table left off by default, which is why one invocation can add it while dropping seccomp. One way to tell builds apart is the version string. `runc --version` prints it, and a build can append a marker through the EXTRA_VERSION make variable:

bash
make EXTRA_VERSION="+build-1"

The README asks that you include a separator for readability. Stamp tag variants that way, and a report that quotes the version output alongside the RUNC_BUILDTAGS value tells a reader which binary produced the behavior instead of leaving them to infer it from symptoms. The same goes for the Go version and the libpathrs version: three inputs decide what a runc binary can do, and none of them are visible in a container listing.

Signed releases and a Cure53 audit cover upstream tags, not the binary a distro compiles

Release integrity is handled in two visible places. Official releases live on the release page, and every release is signed by one of the keys listed in the runc.keyring file at the repository root, so verification has a published set of keys to check against instead of one exchanged privately. A third party security audit by Cure53 has its full report in docs/Security-Audit.pdf, and the process for reporting a new issue is outlined in SECURITY.md. The release titles each carry a quoted phrase: v1.6.0-rc.1 in Spanish, v1.5.2 in Russian, v1.5.1 in Spanish. What none of that reaches is the binary a distributor compiles from source, since the signing story attaches to tagged releases rather than to every build. The audit is a point-in-time document too, and the README does not date it. The consequence for anyone running a distro package is that the keyring and the audit tell you about upstream, while the build actually on your host is defined by its build tags, its Go version, and its libpathrs, which is why those belong in any incident report.

Editorial conclusion

Use runc when you are the runtime layer under a container engine or a build system and you control the host toolchain, because the feature set is a compile-time decision you have to keep track of. Step back if you need a runtime that runs anywhere but Linux, since that is not on offer here. Before you rely on a binary, check its RUNC_BUILDTAGS value, confirm the libpathrs version it was built against, and stamp it with EXTRA_VERSION so the artifact identifies itself.

Frequently asked questions

What is runc in Docker?

runc is the CLI tool that spawns and runs containers on Linux according to the OCI specification. In this repository Docker appears as the test harness rather than as a runtime dependency: the Makefile sets CONTAINER_ENGINE to docker for make test.

Why are people moving away from Docker?

The project does not address that question, because it is a runtime rather than an engine. It does not pull images, unpack layers, or configure networking, so any engine-versus-runtime argument belongs to the calling project, not here.

Is Apple's container runtime better than Docker?

Nothing in the repository compares runc with any other runtime, and there is no mention of Apple's. What the project does state is that runc only supports Linux, with the minimum Go version given in the header of go.mod.

Is Crun better than Runc?

The repository names no alternative runtime, so there is no comparison to read here. The decision it does put in front of a builder is which build tags a binary carries, since seccomp and libpathrs are on by default and runc_nocriu removes checkpoint and restore.

Official sources

  1. License: Apache-2.0
  2. opencontainers/runc on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/opencontainers-runc.svg)](https://hysenlabs.com/projects/opencontainers-runc)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/opencontainers-runc.svg)](https://hysenlabs.com/projects/opencontainers-runc)

Was this useful?