mrkeyoor.com_
Tue 08 Sept 16:08 UTC
Dev Toolsevaluationupdated 08 Sept 2026

buildkit review

BuildKit is the build engine used by modern Docker builds, and it can also run as a standalone daemon with its own client. It turns Dockerfiles or other frontends into a dependency graph, executes independent work concurrently, and moves build results or caches to registries, local storage, and cloud backends.

Verdict

Our BuildKit checkout built in 100 seconds, but 13 of 104 package tests failed in the worker area on fresh unprivileged Debian, so a green source build does not finish the evaluation. Run standalone BuildKit when remote workers, LLB frontends, or controlled cache exports justify operating a privileged builder service. Ordinary Docker users should stay with Buildx, while platform teams should pin v0.33.0, require mutual TLS, and test the exact worker and cache paths they deploy.

We ran it

Lab card: what happened when we ran buildkitScreenshot of buildkit (github.com/moby/moby/issues/34227)
Install✓ · 75s0 packages
Build✓ · 100s
Tests✗ · 378s91 passed · 13 failed of 104 (go test)
Repo1364 files~279,069 lines of source · 8.3 MB · 12 CI workflows · Dockerfile

Answers from our run

Does buildkit build from source?

Dependencies installed in 75 seconds (0 packages), and the build succeeded in 100 seconds. We cloned commit ab362ca into a clean Debian container with 3 CPUs and no project-specific setup.

Do buildkit's tests pass?

Not all of them: 91 of 104 passed and 13 failed when we ran the project's own test command (go test). Some failures need services or credentials a bare container does not have.

Who should not use buildkit?

Most developers who only run docker build: the README says Docker Engine 23.0 uses Buildx and BuildKit by default.

What are the alternatives to buildkit?

Docker Buildx, Buildah, Earthly. Our BuildKit checkout built in 100 seconds, but 13 of 104 package tests failed in the worker area on fresh unprivileged Debian, so a green source build does not finish the evaluation.

Setup3/5100-second build passed; 13 of 104 package tests failed
Docs5/5Detailed workers, cache, rootless, TLS, and integration guidance
Community5/510,244 stars, current pushes, v0.33.0, and active issue triage
Maturity4/5Docker's default engine, with current cache and checksum bugs

Who it’s for

Platform teams that need remote builders, shared caches, or workers spread across machines.
CI operators who want registry, local, GitHub Actions, S3, or Azure cache exports.
Tool authors building custom frontends on BuildKit's LLB graph.
Container teams that can manage daemon privileges, TLS, storage cleanup, and worker backends.

Who it’s NOT for

Most developers who only run docker build: the README says Docker Engine 23.0 uses Buildx and BuildKit by default.
Mac users expecting a native local daemon: the macOS client needs a Linux VM such as Lima for buildkitd.
Locked-down hosts that cannot run a privileged container, install RootlessKit, or change user-namespace and security settings.
Operators planning an unauthenticated TCP endpoint: the README says executor containers can call the BuildKit API and recommends mutual TLS.
Builds that currently trust ADD --checksum to reject changed remote content in every cached case: open issue 7108 reproduces stale cached content across matching basenames.
Contributors requiring a clean default package run on fresh unprivileged Debian: our test command reported 91 passed and 13 failed of 104.

Setup reality

Our sandbox install completed in 75 seconds with 0 additional system packages, and the build passed in 100 seconds. Tests ran for 378 seconds and failed with exit 1: 91 packages passed and 13 failed of 104. The visible log tail named failures in worker/containerd and worker/runc but showed no cause.

Standalone use needs buildkitd, buildctl, an OCI runtime such as runc or crun, and optional containerd. Registry pushes use Docker credentials; remote cache exporters can require GitHub, S3, or Azure credentials. A TCP daemon needs client and server TLS material.

The daemon runs on Linux and currently Windows; macOS needs a VM. Root mode starts as root, while rootless mode adds RootlessKit, kernel and snapshotter conditions, and host networking. Container examples use --privileged or relax seccomp, AppArmor, and system-path protections.

Docker Engine 23.0 already covers the common case

Docker Engine 23.0 and later use Buildx and BuildKit by default, according to the project README. That single fact changes the buying decision. Developers who only want faster Dockerfile builds, cache mounts, build secrets, or multi-platform output can usually stay inside docker buildx. Standalone BuildKit is for teams that need direct control over the daemon, its workers, cache stores, networking, or the low-level build graph. Operating it separately should solve a platform problem you can name.

BuildKit's range is much wider than a Dockerfile parser. LLB represents a build as a dependency graph, so independent steps can run concurrently and cache records can move between backends. The checkout at commit ab362ca contained 1,364 files and roughly 279,069 source lines in 8.3 MB. Its API supports custom frontends and several output types, including images, OCI archives, local directories, and containerd's image store. That explains both its utility and the size of its operational surface.

What happened when we ran it

Our sandbox install step completed in 75 seconds and added 0 system packages. The Go build then succeeded in 100 seconds on a fresh Debian container with 3 CPUs, 8 GB of RAM, no secrets, and no elevated privileges. That is a good result for a repository of this size. It proves the checked-out source compiled in the stated environment; it does not prove that a daemon can execute container builds under the same unprivileged constraints.

The test command ran for 378 seconds and returned exit code 1. Go reported 91 passed packages and 13 failed packages out of 104. The visible log tail specifically named worker/containerd and worker/runc, then ended with FAIL; it did not show the underlying assertions or errors. Guessing that privileges caused them would go beyond the log. The finding is simpler: our default package run did not pass, and the worker implementations need a targeted rerun before adoption.

A 100-second build is easier than running the daemon

Source compilation uses the usual make path, and the repository has a Dockerfile plus 12 CI workflow files. Running the result adds runc or crun, with containerd required for the containerd worker. The default OCI worker starts buildkitd as root and listens on a Unix socket. Build results stay inside BuildKit unless the caller specifies an output, which is easy to miss when first using buildctl. Registry output also reads credentials from Docker's client configuration.

The contribution guide puts full integration, gateway, and Dockerfile tests inside its own harness. It can exercise OCI, rootless OCI, and containerd workers, and it advises using a separate public-read token rather than mounting a personal Docker configuration. Our 91-of-104 result came from the supplied lab command, so it should not be confused with that privileged integration matrix. Teams changing worker or exporter code need the project harness on machines where its binaries, images, and permissions are available.

Rootless mode still needs host cooperation

Rootless BuildKit requires RootlessKit and changes behavior by kernel version. OverlayFS needs kernel 5.11 or an Ubuntu kernel; older supported kernels fall back to fuse-overlayfs or the native snapshotter. Rootless networking always uses host mode unless the operator adds the documented network isolation. Troubleshooting may involve /etc/subuid, user-namespace limits, AppArmor settings, a FUSE device, or a writable BuildKit state volume. This is a real deployment mode, with host prerequisites that belong in infrastructure code.

Containerizing the rootless daemon does not remove every security choice. The documented command disables seccomp, AppArmor, and system-path restrictions, or uses --privileged. Another fallback disables the process sandbox, which the guide discourages because build containers can signal or inspect daemon-container processes under some configurations. An exposed TCP daemon has a separate warning: executor containers can reach the BuildKit API, so the README recommends mutual TLS for the server and client on port 1234.

Concurrent cache reset can invalidate an exported tag

Open issue 7102 reports that 2 concurrent local cache exports using reset=true can leave an index pointing to a deleted manifest blob. The author reproduced it on BuildKit v0.32.2 and says the affected tag then needs a full re-export. This is narrow, but CI systems are exactly where shared directories and parallel targets occur. Use separate destinations or avoid that reset pattern until the issue is resolved, and treat cache state as disposable acceleration rather than the only copy of an artifact.

Issue 7108 is more serious for reproducibility checks. Its reproducer shows ADD --checksum accepting stale cached content when 2 URLs have the same final filename and the declared digest remains old. The report covers BuildKit v0.20.2 and v0.32.2. Teams that depend on remote URL inputs should pin immutable URLs, verify output provenance outside the build cache, or confirm the eventual fix in their deployed version. A checksum clause alone does not cover the reported cache-key collision.

v0.33.0 is active, with 831 open issues

BuildKit v0.33.0 was released on September 2, 2026, and the repository was pushed on September 8. GitHub showed 10,244 stars and 920 combined open issues and pull requests. Search results separated that queue into 831 issues and 87 pull requests. The latest release updates the Dockerfile frontend to v1.27.0 and includes fixes around cache, credentials in progress output, Windows paths, and remote execution. Current commits and triage indicate active maintenance, while the queue demands precise searches before assuming a new problem is unique.

Buildx is the sensible interface for most Docker users because it already drives BuildKit. Buildah is a better fit for teams committed to daemonless OCI workflows and Podman, while Earthly adds a project-level build language over lower-level machinery. Our 100-second successful build shows BuildKit is approachable as Go source. The 13 failed package results and its privilege model show why production evaluation must use the same worker backend, kernel, rootless settings, cache exporter, and network boundary as the intended service.

Alternatives

ProjectWhat it isPick it when
Docker BuildxDocker's CLI plugin for driving BuildKit without operating its client by hand.pick this instead when Docker users need multi-platform or remote builds but do not need a custom BuildKit service interface.
BuildahA daemonless tool for building OCI images, commonly paired with Podman.pick this instead when daemonless OCI image construction and Podman integration matter more than BuildKit's LLB and cache system.
EarthlyA higher-level build framework that uses familiar container syntax and can use BuildKit underneath.pick this instead when developers want a project build language and reproducible targets rather than a low-level builder daemon.

What people are saying

  1. [github-trending] moby/buildkit

Sources

  1. BuildKit README
  2. BuildKit contribution and test guide
  3. BuildKit rootless mode guide
  4. BuildKit v0.33.0 release
  5. Issue 7102: concurrent local cache reset
  6. Issue 7108: stale content with ADD checksum

More dev tools reviews

validator · teamai-cli · rustlings · zstd · styled-components · ILSpy · the whole board →