containerd/nerdctl
contaiNERD CTL - Docker-compatible CLI for containerd, with support for Compose, Rootless, eStargz, OCIcrypt, IPFS, ...
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 2d ago
- ✓16 active contributors
- ✓Apache-2.0 licensed
Show all 6 evidence items →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 59% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/containerd/nerdctl)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/containerd/nerdctl on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: containerd/nerdctl
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/containerd/nerdctl shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 2d ago
- 16 active contributors
- Apache-2.0 licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 59% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live containerd/nerdctl
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/containerd/nerdctl.
What it runs against: a local clone of containerd/nerdctl — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in containerd/nerdctl | Confirms the artifact applies here, not a fork |
| 2 | License is still Apache-2.0 | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of containerd/nerdctl. If you don't
# have one yet, run these first:
#
# git clone https://github.com/containerd/nerdctl.git
# cd nerdctl
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of containerd/nerdctl and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "containerd/nerdctl(\\.git)?\\b" \\
&& ok "origin remote is containerd/nerdctl" \\
|| miss "origin remote is not containerd/nerdctl (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
&& ok "license is Apache-2.0" \\
|| miss "license drift — was Apache-2.0 at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "cmd/nerdctl/main.go" \\
&& ok "cmd/nerdctl/main.go" \\
|| miss "missing critical file: cmd/nerdctl/main.go"
test -f "cmd/nerdctl/compose/compose.go" \\
&& ok "cmd/nerdctl/compose/compose.go" \\
|| miss "missing critical file: cmd/nerdctl/compose/compose.go"
test -f "cmd/nerdctl/builder/builder.go" \\
&& ok "cmd/nerdctl/builder/builder.go" \\
|| miss "missing critical file: cmd/nerdctl/builder/builder.go"
test -f "Dockerfile" \\
&& ok "Dockerfile" \\
|| miss "missing critical file: Dockerfile"
test -f ".github/workflows/job-test-in-container.yml" \\
&& ok ".github/workflows/job-test-in-container.yml" \\
|| miss "missing critical file: .github/workflows/job-test-in-container.yml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/containerd/nerdctl"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
nerdctl is a Docker-compatible command-line interface for containerd that provides a Docker-like UX while exposing containerd's advanced capabilities. It's a non-core containerd sub-project that enables users to interact with containerd containers, images, and builds using familiar Docker commands, while adding support for features like rootless mode, lazy-pulling (Stargz/Nydus/OverlayBD), encrypted images (OCIcrypt), P2P distribution (IPFS), and Docker Compose orchestration. Monorepo structure: /cmd contains the main CLI implementation organized by command (compose, build, run, etc.); /pkg holds shared utilities (config, imageutils, clientutil, rootlessutil); /docs has comprehensive command reference and feature guides; /Dockerfile.d contains build artifacts and configuration templates for testing multiple scenarios (rootless, buildkit, stargz, IPFS, SOCI). Build/test orchestration via Makefile and .github/workflows/ with separate jobs for linting, unit tests, and integration tests across multiple environments.
👥Who it's for
DevOps engineers and container developers who want a drop-in Docker replacement for containerd environments (especially in Kubernetes debugging scenarios); infrastructure teams running rootless containers at scale; users needing advanced image pulling strategies or P2P distribution without full Docker overhead.
🌱Maturity & risk
Production-ready and actively maintained. The project has 3.7M+ lines of Go code, comprehensive CI/CD via GitHub Actions (multiple test workflows covering unit, integration, host, container, Lima, and Vagrant scenarios), and clear governance with MAINTAINERS file. Regular releases and consistent commit activity indicate active development, though as a non-core containerd sub-project it has a narrower upstream commitment than Docker itself.
Moderate risk from the breadth of optional integrations: the codebase depends on 20+ specialized snapshotter and encryption libraries (stargz-snapshotter, nydus-snapshotter, imgcrypt, IPFS plugins) that each add complexity and potential security surface area. Dependency churn is notable (gomodjail confinement tags suggest active vendoring concerns). Single-maintainer risk exists on some features; watch the MAINTAINERS file for coverage gaps.
Active areas of work
Active development targeting containerd v2.3.0 compatibility (per go.mod); integration testing expanded across multiple environments (native host, containers, Lima, Vagrant, FreeBSD via Vagrantfile); optional features like Nydus snapshotter and SOCI snapshotter being tested in CI; project tracks against compose-spec v2.10.2.
🚀Get running
Clone the repo and build: git clone https://github.com/containerd/nerdctl.git && cd nerdctl && make (Makefile-driven build). For development: make test-unit runs unit tests; make test-integration requires a full containerd setup. See BUILDING.md for detailed setup instructions including Go 1.26.2+ requirement and containerd daemon prerequisites.
Daily commands:
Development loop: (1) Ensure containerd daemon is running, (2) make to build the binary into ./bin/nerdctl, (3) ./bin/nerdctl run -it --rm alpine to test basic functionality. For Compose: ./bin/nerdctl compose -f examples/compose-wordpress/docker-compose.yaml up. Run full test suite with make test-unit and make test-integration (integration requires privileged container or host setup).
🗺️Map of the codebase
cmd/nerdctl/main.go— Entry point for the nerdctl CLI; defines root command and global flags that all subcommands inheritcmd/nerdctl/compose/compose.go— Docker Compose support orchestration; handles compose-spec parsing and multi-container workflowscmd/nerdctl/builder/builder.go— OCI image build abstraction layer; bridges containerd/buildkit and Docker-compatible build commandsDockerfile— Multi-stage build definition used in CI/CD workflows and containerd testing infrastructure.github/workflows/job-test-in-container.yml— Primary integration test pipeline; validates all nerdctl commands in containerd environmentgo.mod— Module dependencies including containerd/v2, compose-spec, and key extension points (IPFS, eStargz, OCI-crypt)
🛠️How to make changes
Add a new subcommand (e.g., nerdctl foo)
- Create a new directory under cmd/nerdctl/{subcommand}/ (
cmd/nerdctl/foo/) - Define the root command struct and NewFooCommand() in foo.go (
cmd/nerdctl/foo/foo.go) - Implement action handlers (e.g., FooRun, FooCreate) that call containerd APIs (
cmd/nerdctl/foo/foo_action.go) - Register the command in the main root command definition (
cmd/nerdctl/main.go) - Add integration tests in foo_linux_test.go following the pattern in compose or image tests (
cmd/nerdctl/foo/foo_linux_test.go)
Add a Docker Compose sub-action (e.g., nerdctl compose new-action)
- Create new file compose_newaction.go in cmd/nerdctl/compose/ (
cmd/nerdctl/compose/compose_newaction.go) - Parse compose spec fields and validate configuration (
cmd/nerdctl/compose/compose_newaction.go) - Implement service iteration and containerd client calls (
cmd/nerdctl/compose/compose_newaction.go) - Register the action in compose.go's NewComposeCommand() switch statement (
cmd/nerdctl/compose/compose.go) - Add integration test file compose_newaction_linux_test.go with test helpers (
cmd/nerdctl/compose/compose_newaction_linux_test.go)
Add support for a new image lazy-pull strategy or encryption method
- Check the builder_build.go to see how snapshotter options are passed to buildkit (
cmd/nerdctl/builder/builder_build.go) - Add new snapshotter flags or environment variable handling in the build command (
cmd/nerdctl/builder/builder_build.go) - Update containerd config parsing if new daemon-level settings required (
Dockerfile.d/etc_containerd_config.toml) - Add integration test in job-test-in-container.yml to validate the new feature in CI (
.github/workflows/job-test-in-container.yml)
Add a new platform-specific feature (Linux-only)
- Create cmd/nerdctl/{feature}/{feature}_linux.go for Linux implementation (
cmd/nerdctl/myfeature/myfeature_linux.go) - Create stub files for other platforms: myfeature_unix.go or myfeature_windows.go (
cmd/nerdctl/myfeature/myfeature_nolinux.go) - Register command in main.go and add help text (
cmd/nerdctl/main.go) - Add Linux-only integration tests with build tag // +build linux (
cmd/nerdctl/myfeature/myfeature_linux_test.go)
🔧Why these technologies
- containerd/v2 — Core container runtime; nerdctl is a CLI wrapper offering Docker compatibility without requiring full Docker daemon
- compose-spec/compose-go — Standards-compliant Docker Compose file parsing and orchestration; enables multi-container workflows
- BuildKit — Modern O
🪤Traps & gotchas
Containerd daemon must be running and properly configured for integration tests (see Dockerfile.d/test-integration-etc_containerd_config.toml for test config). CNI plugins must be installed in /opt/cni/bin/ for network tests. Rootless tests require unprivileged user namespace support in the kernel. Test output captures can be verbose; set VERBOSE=1 for debugging. BuildKit image building requires BuildKit daemon (buildkitd) accessible via socket, configured in test Dockerfile. Some tests are flaky and tracked separately (see .github/workflows/workflow-flaky.yml).
🏗️Architecture
💡Concepts to learn
- Snapshotter Interface — nerdctl's pluggable image pulling architecture depends on containerd snapshotter implementations (standard overlayfs, stargz, nydus, SOCI); understanding snapshot layers is key to debugging image pull failures and performance issues
- User Namespaces & Rootless Containers — nerdctl's rootless mode uses Linux user namespace isolation instead of requiring the container daemon to run as root; essential for understanding the
pkg/rootlessutilcode and testing rootless scenarios - Container Network Interface (CNI) — nerdctl bridges containerd to CNI plugins for container networking; the codebase uses go-cni library to invoke CNI implementations (bridge, host, none modes)
- OCI Image Spec & Container Spec — nerdctl translates Docker commands into OCI-compliant container and image structures; understanding OCI manifest layouts is critical for image pull, build, and export functionality
- Lazy Image Pulling (Stargz/Nydus) — nerdctl optionally supports eStargz and Nydus formats that stream image layers on-demand rather than pulling entire layers upfront; affects how snapshotter backends are configured and tested
- BuildKit Image Builder Protocol — nerdctl's
buildcommand delegates to BuildKit daemon via gRPC; understanding BuildKit's build request format and output handling is needed for implementing build flags and debugging build failures - gRPC for Container APIs — nerdctl communicates with containerd exclusively via gRPC (containerd/containerd/api); all container operations (create, start, exec, logs) use Protocol Buffer messages
🔗Related repos
containerd/containerd— Core container runtime that nerdctl wraps; you'll need to read containerd API docs and potentially contribute fixes upstreamdocker/cli— Docker's own CLI implementation that nerdctl emulates for compatibility; reference for UX and command argument patternscontainerd/stargz-snapshotter— Lazy image pulling snapshotter that nerdctl optionally integrates; needed to understand eStargz format and streaming behaviorcontainerd/nydus-snapshotter— Alternative lazy-pulling snapshotter that nerdctl supports; required for testing Nydus feature integrationcompose-spec/compose-go— Docker Compose specification parser that nerdctl uses fornerdctl composecommand implementation
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for apparmor subcommands
The apparmor module (cmd/nerdctl/apparmor/) has only one test file (apparmor_linux_test.go) covering the core functionality. Given that nerdctl supports apparmor profile inspection, loading, unloading, and listing via apparmor_inspect_linux.go, apparmor_load_linux.go, and apparmor_list_linux.go, there are missing integration tests for these individual operations. This is critical for a container CLI where security profiles are essential.
- [ ] Create cmd/nerdctl/apparmor/apparmor_inspect_linux_test.go with tests for profile inspection scenarios
- [ ] Create cmd/nerdctl/apparmor/apparmor_load_linux_test.go testing profile loading with valid/invalid profiles
- [ ] Create cmd/nerdctl/apparmor/apparmor_list_linux_test.go testing profile enumeration
- [ ] Add end-to-end test cases in .github/workflows/job-test-in-host.yml or similar for apparmor operations
Add GitHub Action workflow for FreeBSD testing
The repo contains Vagrantfile.freebsd indicating FreeBSD support, but the .github/workflows/ directory lacks a dedicated FreeBSD CI job. Currently there are workflows for Linux (job-test-in-host.yml, job-test-in-container.yml, job-test-in-lima.yml) and Windows, but FreeBSD testing appears to only happen locally via Vagrant. Adding a CI workflow would catch FreeBSD-specific regressions early.
- [ ] Create .github/workflows/job-test-freebsd.yml using GitHub's FreeBSD runner or native action
- [ ] Reference Vagrantfile.freebsd to identify required dependencies and test commands
- [ ] Configure the workflow to run on pull requests affecting core functionality (cmd/nerdctl/*, Makefile)
- [ ] Add the new workflow to workflow-test.yml as a dependency like the Linux/Lima/Vagrant tests
Create missing unit tests for checkpoint operations
The checkpoint module (cmd/nerdctl/checkpoint/) has only one test file (checkpoint_create_linux_test.go) despite having multiple command implementations (checkpoint.go, checkpoint_create.go, checkpoint_list.go). The checkpoint_list.go command lacks dedicated unit tests, and checkpoint.go (root command) likely needs tests for argument parsing and routing. This is a critical feature for container persistence.
- [ ] Create cmd/nerdctl/checkpoint/checkpoint_list_linux_test.go with tests for listing checkpoints with various filters and formats
- [ ] Add tests to checkpoint_create_linux_test.go for error cases (non-existent container, permission issues, invalid checkpoint names)
- [ ] Create cmd/nerdctl/checkpoint/checkpoint_test.go for the root command routing and help text
- [ ] Ensure tests cover both happy-path and error scenarios with mock containerd interactions
🌿Good first issues
- Add missing integration test coverage for the
nerdctl inspect --formatflag with Go template validation against actual container metadata (likely incmd/nerdctl/container/inspect_test.go) - Document the Nydus snapshotter lazy-pulling behavior in
docs/nydus.mdwith a worked example and performance comparison vs. standard pulling - Implement missing
nerdctl system prune --volumeflag by extending the prune logic incmd/nerdctl/system/prune.goto walk volume store and delete unreferenced volumes
⭐Top contributors
Click to expand
Top contributors
- @AkihiroSuda — 59 commits
- @dependabot[bot] — 17 commits
- @ChengyuZhu6 — 7 commits
- @haytok — 4 commits
- @shouhei — 2 commits
📝Recent commits
Click to expand
Recent commits
0b388bb— Merge pull request #4882 from ogulcanaydogan/docs/fix-security-opt-label-formatting (AkihiroSuda)a01031d— Merge pull request #4880 from containerd/dependabot/go_modules/github.com/containerd/containerd/v2-2.3.0 (AkihiroSuda)4e82d72— Merge pull request #4878 from ChengyuZhu6/fix-note (AkihiroSuda)ea64ff9— docs: fix missing list prefix for --security-opt label entry (ogulcanaydogan)e8e886f— build(deps): bump github.com/containerd/containerd/v2 (dependabot[bot])9667cae— Merge pull request #4876 from containerd/dependabot/go_modules/github.com/containerd/continuity-0.5.0 (ChengyuZhu6)cead61e— hack: update release note (ChengyuZhu6)2299ffb— build(deps): bump github.com/containerd/continuity from 0.4.5 to 0.5.0 (dependabot[bot])0280cf4— Merge pull request #4874 from ChengyuZhu6/add-gpg (fahedouch)065061d— MAINTAINERS: update ChengyuZhu6's gpg key (ChengyuZhu6)
🔒Security observations
The nerdctl project demonstrates reasonable security practices with checksum verification and security documentation references. However, there are concerns regarding unconfined dependencies in the module system, the use of pre-release versions in default builds, and reliance on privileged execution. The project would benefit from stricter dependency management policies, automated vulnerability scanning in CI/CD pipelines, and clearer documentation of security requirements. No hard
- High · Unconfined Dependencies in Go Module —
go.mod (multiple dependencies marked //gomodjail:unconfined). Multiple dependencies in go.mod are marked with //gomodjail:unconfined, indicating they bypass security confinement checks. This includes critical packages like containerd/v2, docker/cli, and compose-go. Unconfined dependencies may introduce supply chain risks and reduce visibility into transitive dependency behavior. Fix: Review and document the necessity of each unconfined dependency. Consider using gomodjail or similar tools to audit and confine dependencies where possible. Establish a security review process for unconfined packages. - High · Go Version at EOL or Near EOL —
go.mod (go 1.26.2). The project specifies Go 1.26.2, which appears to be a future/unrealistic version. This may indicate version management issues. Verify the actual Go version requirement, as older versions (1.20.x and earlier) have known security vulnerabilities in the crypto and net packages. Fix: Verify and correct the Go version to a currently supported release. Ensure Go version is regularly updated to receive security patches. Document the minimum supported Go version. - Medium · Privileged Docker Execution Required —
Dockerfile (comment: 'docker run -it --privileged'). The Dockerfile explicitly requires '--privileged' flag for execution (noted in comments). Privileged containers have elevated capabilities that increase the attack surface if the container is compromised. This is necessary for containerd but poses risks. Fix: Document the necessity of privileged mode clearly. Consider using capability-specific flags (--cap-add) instead of --privileged where possible. Implement container security scanning and runtime monitoring for privileged containers. - Medium · External Binary Dependency Integrity —
Dockerfile, Dockerfile.d/SHA256SUMS.d/ directory. The Dockerfile references external binaries (containerd, runc, etc.) with SHA256 checksums stored in separate files (Dockerfile.d/SHA256SUMS.d/). While checksums are present, the distribution and verification mechanism for these checksums could be vulnerable to MITM attacks if not properly secured. Fix: Ensure SHA256SUMs files are sourced from secure, authenticated channels. Consider using GPG-signed checksums or alternative verification methods. Document the source and verification process for all external binaries. - Medium · Beta/RC Dependencies in Production Build —
Dockerfile (ARG CONTAINERD_VERSION=v2.3.0-beta.2@...). The Dockerfile specifies containerd v2.3.0-beta.2, a beta release, as the default version. Using pre-release software in production builds introduces stability and security risks as beta versions may contain unpatched vulnerabilities. Fix: Use stable, released versions in default configurations. If beta versions are necessary for testing, clearly segregate them and document the risks. Establish a policy for upgrading to stable releases. - Low · Incomplete Dependency File Snippet —
go.mod (end of file). The provided go.mod file appears truncated at 'gi', suggesting incomplete information was provided for analysis. This limits the ability to assess all dependencies for known vulnerabilities. Fix: Provide complete dependency listings for comprehensive security analysis. Use 'go mod audit' and 'govulncheck' tools to scan for known vulnerabilities in all dependencies. - Low · Missing Security Policy Enforcement —
SECURITY.md, .github/workflows/. While a SECURITY.md file exists pointing to external security policy, there is no evidence of automatic security scanning in the CI/CD pipeline visible from the workflow files (though specific workflow content wasn't provided). Fix: Implement automated security scanning in CI/CD: enable Dependabot alerts, integrate SAST tools (golangci-lint is present but needs verification), and add SBOM generation. Run 'go mod audit' and govulncheck in CI.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.