A registry engine with 620 files, not a registry product
Distribution implements the server side of the OCI Distribution Specification, the HTTP contract container tools use to push and pull images and other artifacts. The repository says its registry code sits under services including Docker Hub, GitHub Container Registry, GitLab Container Registry, DigitalOcean Container Registry, and Harbor. That pedigree matters, but it can also mislead a buyer about the package in front of them. This project is the engine room. It does not arrive with the policy, scanning, replication controls, and operator interface many teams picture when they hear "private registry."
The checkout we measured contained 620 files, about 56,148 lines of source, and 10.2 MB of code. Its main deliverable is the registry server, accompanied by Go libraries and documentation. The README warns that the library interfaces are unstable. It also says the included client is deprecated in favor of containerd's implementation and will not receive new features. Running the server is the safer center of gravity. Embedding its packages means accepting more change than the OCI HTTP interface exposes.
The prebuilt image is the documented path for most users
Distribution's build guide tells casual users to choose a prebuilt Registry image. Source builds are aimed at contributors and people making a custom image. Release v3.1.2 raises that source requirement to Go 1.26 or newer, while make validate also expects Docker with the Buildx plugin. Those are reasonable development requirements, but they are work you can avoid when the published image already matches the deployment.
A minimal configuration listens on port 5000, stores blobs under /var/lib/registry, caches blob descriptors in memory, and can use htpasswd authentication. A production service needs more decisions: TLS termination, persistent storage, access control, health checks, upload cleanup, and a shared HTTP secret if several instances handle uploads. Cloud storage brings provider credentials and failure modes. The local S3 development recipe alone adds a Compose-compatible runtime, MinIO, a bucket, region settings, and access credentials.
What happened when we ran it
Our sandbox install succeeded in 52 seconds and added 0 packages. The build completed in 86 seconds in a fresh unprivileged Debian container with 3 CPUs and 8 GB of RAM. That is a clean result for compiling the registry itself, and the repository includes both a Dockerfile and 10 CI workflow files. The checked-out commit was 3220848, so these figures describe that source snapshot rather than every v3 image.
The test step did not pass. It ran for 419 seconds, then reported 74 passed and 3 failed out of 77. The final package summary shows the failure under registry/storage/driver/inmemory, which took 360.780 seconds; nearby filesystem, Azure, GCS, S3, and middleware packages passed. The supplied tail does not name the three assertions or establish a cause. We can say the full suite failed in our container, and no more.
That distinction changes the trial plan. A successful 86-second compile proves that the source is buildable in the stated Go image. It does not clear the in-memory driver or prove a chosen object store behaves correctly under interruption, concurrency, or garbage collection. Before production, run the relevant driver tests on the exact release, storage service, credentials, and network path you intend to use.
Garbage collection needs backups and a post-run check
Open issue 4939 reports that garbage-collect --delete-untagged on registry v3.1.1 sometimes removed a blob still referenced by 9 repositories. The reporter describes several incidents over about 2 weeks and says restoring the blob from backup made the affected tags pull again. There is no minimal reproduction in the issue, so it is not proof that every deployment is exposed. It is enough reason to avoid treating destructive collection as routine housekeeping without a dry run, backup, and manifest-to-blob verification.
Pull-through caches have a separate warning. Issue 4957 traces blob TTL expiry on v3.1.1 to a Delete method that returns ErrUnsupported, leaving the cleanup path before it removes the cached blob. The reporter says the behavior remained in main when filed. That is a specific report, not a substitute for checking v3.1.2 or a later commit. If disk limits depend on TTL, measure reclaimed bytes and alert on growth instead of trusting the configured duration.
September 2026 activity is current, while operations remain yours
GitHub recorded 10,627 stars, 518 open issues and pull requests, and a last push on September 26, 2026. Release v3.1.2 arrived on September 24 with a digest-verification security fix, storage and pagination fixes, dependency updates, and the Go 1.26 requirement. Recent issue discussion covers configuration isolation, cache expiry, and garbage collection. This is active maintenance around software that handles persistent content, not a dormant repository coasting on its name.
Distribution is the right choice when the OCI registry protocol is the product boundary you want. It stays close to the storage and transport job, and its Apache-2.0 license leaves room for custom services around it. That narrowness also writes the operator's checklist: put authentication and TLS in place, pin the release, back up the blobs, test the chosen driver, and verify cleanup. If your team wants those choices packaged into an administrative product, start with Harbor or Quay instead.

