Same Commands, Different Engine Room
If you’ve spent any time on a k3s node or inside a Rancher Desktop install, you’ve probably typed nerdctl and thought, “wait, this is just Docker.” And honestly? You’re mostly right.
nerdctl — the nerdctl container launcher — is a Docker-compatible CLI that talks directly to containerd instead of going through the Docker daemon. Same verbs, same flags, same general vibe. The whale is just not involved.
# These do the same thing on their respective toolchainsdocker run -d -p 8080:80 nginxnerdctl run -d -p 8080:80 nginxSo why does this exist, and should you care? Let’s find out.
A Brief Word on Why Docker’s Own CLI Isn’t Always the Answer
Here’s the thing: Docker Inc had a bit of a licensing moment in 2022 when they started charging for Docker Desktop in commercial environments. Then there was the whole “we’re changing the terms” saga. Nothing apocalyptic, but it reminded a lot of infrastructure people that maybe tightly coupling their toolchain to a single commercial entity’s daemon was not the galaxy-brain move they thought it was.
containerd, meanwhile, is the actual container runtime that Docker itself uses under the hood. It’s graduated CNCF, it ships with Kubernetes, and it has been running your containers in production for years — Docker was just the chatty middleman you were talking to.
nerdctl removes the middleman.
The 90% Drop-In Case
Honestly, for most daily container work, alias docker=nerdctl just works. Here’s what maps cleanly:
nerdctl run -it ubuntu bashnerdctl ps -anerdctl imagesnerdctl pull alpine:3.19nerdctl push myrepo/myimage:latestnerdctl logs -f my-containernerdctl exec -it my-container shnerdctl stop my-containernerdctl rm my-containernerdctl network create mynetnerdctl volume create myvolnerdctl inspect my-containernerdctl statsnerdctl build works too — and this is actually where nerdctl has a quiet advantage. It uses BuildKit natively. No DOCKER_BUILDKIT=1 env var incantation required, no legacy builder fallback to worry about. BuildKit is the default, full stop.
# Mount cache for your package manager? Just works.nerdctl build --build-arg BUILDKIT_INLINE_CACHE=1 -t myapp:latest .Multi-stage builds, cache mounts, SSH forwarding in builds — all native.
Where It Diverges
Image Storage Location
Docker stores images in /var/lib/docker/. nerdctl stores them in /var/lib/containerd/. These are completely separate. An image you pulled with Docker is invisible to nerdctl and vice versa.
# Docker imagesdocker images # reads from /var/lib/docker/image/
# nerdctl images — completely separate storenerdctl images # reads from /var/lib/containerd/This trips people up constantly on hybrid setups. If you’re migrating a server, you need to push and re-pull, or use docker save / nerdctl load.
# Migrate an image from Docker to nerdctldocker save myapp:latest | nerdctl loadCompose Support
nerdctl bundles nerdctl compose which is Compose v2 compatible. Standard docker-compose.yml files work fine for the basics:
nerdctl compose up -dnerdctl compose logs -fnerdctl compose downWhat you lose: Swarm mode. deploy: blocks with replicas, placement, constraints — all silently ignored or errored out. If your Compose files have swarm-isms, nerdctl is not your tool. Swarm is Docker-specific and containerd doesn’t speak it.
services: web: image: nginx deploy: # nerdctl will either ignore or choke on this replicas: 3 placement: constraints: - node.role == workerIf you’re still running Swarm in 2026, godspeed. nerdctl won’t save you.
Docker Hub Login
Registry auth works but the flow is slightly different. nerdctl uses ~/.docker/config.json (same as Docker), but the login command syntax is the same:
nerdctl login docker.ionerdctl login ghcr.ionerdctl login registry.example.comDocker credential helpers work too. Where things get weird is with some GUI tools and CI systems that hardcode the Docker socket path (/var/run/docker.sock). containerd exposes a different socket (/run/containerd/containerd.sock). Tools that inject the Docker socket into containers for DinD setups will not work without reconfiguration.
Rootless: Actually Better Than Docker’s Version
This is the part that gets genuinely interesting.
Rootless Docker exists and works, but it has friction. You need newuidmap, newgidmap, subuid/subgid config, and sometimes things just break in mysterious ways that make you want to run everything as root like it’s 2015.
nerdctl + containerd rootless is cleaner. The rootless containerd setup follows a more coherent model and integrates better with systemd user services:
# Install rootless containerd (ships with the nerdctl-full bundle)containerd-rootless-setuptool.sh install
# Verify rootlessnerdctl run --rm alpine whoami# Output: root (inside the container, but you're not root on the host)
# Check the process — running as your userps aux | grep containerdYou get proper user namespace mapping, and since nerdctl was built with rootless as a first-class use case (not retrofitted), the rough edges are smoother. For home lab setups where you don’t want to hand root to a container runtime, this matters.
Lazy Pulls via eStargz
Here’s a nerdctl perk you won’t find in vanilla Docker: lazy image fetching with stargz / eStargz format.
Normally when you pull an image, you download and decompress the entire thing before the container starts. With lazy pulling, the container can start while the image is still being fetched in the background — only the layers actually needed for the startup path get pulled first.
# Enable stargz snapshotter (installed with nerdctl-full bundle)nerdctl --snapshotter stargz run -d --name fast-start ghcr.io/stargz-containers/ubuntu:20.04-esgzIn practice you need images in eStargz format for this to work, and most public images aren’t converted yet. But for internal registries serving large ML images or fat application layers, lazy pulling can cut your container cold-start time significantly. Docker has no equivalent.
OCI Image Encryption
nerdctl supports running encrypted OCI images — a feature Docker CLI has never exposed:
# Encrypt an image for a specific recipientnerdctl image encrypt \ --recipient jwe:mypubkey.pem \ myimage:latest \ myimage:encrypted
# Run with decryption keynerdctl run \ --decryption-keys /path/to/privkey.pem \ myimage:encryptedIs this something most home lab folks need? No. But if you’re distributing container images across untrusted infrastructure and need to ensure only authorized hosts can run them, this is a real feature with no Docker equivalent. Enterprise and regulated environments, take note.
Multi-Arch and Buildx Parity
nerdctl ships with buildx-compatible behavior. You can build multi-arch images without installing the buildx plugin separately, because again — BuildKit is native:
# Build for multiple architecturesnerdctl build \ --platform linux/amd64,linux/arm64 \ -t myrepo/myapp:latest \ --push \ .The nerdctl build --platform flag works the same as docker buildx build --platform. If you’re building images on an ARM Mac or Raspberry Pi that need to run on x86, this just works.
Performance: Mostly a Non-Issue
You’ll see benchmarks online claiming nerdctl is faster because it cuts out the Docker daemon. In practice, the delta is real but not meaningful for most workloads.
Container start time: slightly faster with nerdctl on cold starts because there’s one fewer IPC hop. Container runtime performance (actual CPU, memory, I/O): identical — both are running runc under the hood.
If you’re starting tens of thousands of containers per minute in a CI environment, maybe you’ll care. On a home server or small cluster, you won’t notice.
When NOT to Switch
Let’s be honest about the cases where you should leave Docker alone.
Docker Desktop on Mac/Windows. Docker Desktop handles the VM layer, file sharing, Kubernetes integration, and a GUI that non-sysadmins can use. nerdctl doesn’t have a Desktop equivalent — Lima or Rancher Desktop can get you there, but it’s more work and less polished.
Third-party tools hardcoded to /var/run/docker.sock. Portainer, Watchtower, some CI systems, and a long tail of dev tools assume the Docker socket exists at that path. Some support configuring an alternate socket; many don’t. If your workflow depends on these, switching to nerdctl means dealing with breakage.
Swarm users. Both of you. You know who you are.
Teams where “docker” is muscle memory and institutional knowledge. Honestly, if you’re running a Docker Engine setup that’s working fine, the upside of switching is mostly philosophical. “I’m not using the Docker daemon” is a cool fact to share at parties, but it doesn’t improve your uptime.
Where to Get nerdctl
Three main install paths:
If you have k3s or any Kubernetes distro using containerd: nerdctl is often already available or installable:
# k3s ships with its own CLI, but you can add nerdctlwget https://github.com/containerd/nerdctl/releases/latest/download/nerdctl-full-2.0.3-linux-amd64.tar.gzsudo tar Cxzvvf /usr/local nerdctl-full-*.tar.gzRancher Desktop: nerdctl is the default container CLI. You get the full stack (containerd, BuildKit, nerdctl) with a nice GUI on top. This is probably the best Docker Desktop alternative on Mac/Linux desktops right now.
Lima (macOS): Ships nerdctl in its default VM template. limactl start and you’re running containers without Docker Desktop.
The nerdctl-full bundle is the one you want — it bundles containerd, CNI plugins, BuildKit, and stargz snapshotter. The minimal bundle assumes you already have containerd running.
The Verdict
If you’re already on containerd — running k3s, k8s nodes, or using Rancher Desktop — nerdctl is the right CLI. It’s native, it’s maintained by the containerd project itself, and features like rootless mode and lazy pulls are genuinely better than Docker’s equivalents.
If you’re running Docker Engine on servers that are working fine, the upside is mostly philosophical. The real gains are rootless mode and lazy pulls, and if you’re not actively using either of those, switching is churn for the sake of it.
The one place Docker CLI still wins outright is the desktop ecosystem. Docker Desktop is a polished, integrated product. nerdctl has no equivalent — Lima and Rancher Desktop are close but require more patience.
The alias trick (alias docker=nerdctl) works for ~90% of daily commands. The other 10% will bite you when you’re debugging something at 2 AM and forget which runtime you’re actually talking to. Go in with eyes open, and you’ll be fine.
Quick Reference
| Feature | Docker CLI | nerdctl |
|---|---|---|
| Container run/stop/rm | Yes | Yes |
| Image pull/push/build | Yes | Yes |
| Compose | v2 | v2 (no Swarm deploy) |
| BuildKit native | Optional | Always |
| Rootless mode | Yes (rough) | Yes (cleaner) |
| Lazy pulls (stargz) | No | Yes |
| OCI image encryption | No | Yes |
| Multi-arch builds | Via buildx plugin | Native |
| Swarm mode | Yes | No |
| Docker socket | /var/run/docker.sock | /run/containerd/containerd.sock |
| Docker Desktop | Yes | No (use Rancher Desktop) |