November 11, 2025·6 min read·engineeringdockercontainerdnetworking

Docker Engine 29 changes storage defaults without migrating existing hosts

Engine 29 defaults new installations to containerd image storage, adds experimental nftables support, and changes the client compatibility boundary.

A new storage default and a storage migration are different operations. Docker Engine 29 makes the containerd image store the default for new installations while leaving existing installations on their current backend. That boundary lets Docker change its preferred architecture without treating an ordinary version upgrade as a conversion of stored content.

The 29.0.0 release notes date the release to November 10. Docker's November 11 explanation describes why it is moving image management toward containerd and makes the new-installation scope explicit. The release also introduces experimental native nftables support and raises the minimum Engine API version.

I value Docker's repeatable artifact model, so consolidating its image handling around containerd is interesting. The useful question is what changes for an operator's existing content. A default for a new host does not establish that an old host's images have moved or that two hosts now use the same storage arrangement.

Container execution and image storage had separate histories

Docker's explanation distinguishes container execution from image layer management. Engine had already used containerd for execution while retaining the graph driver backend for images. Containerd developed its own content store and snapshotter framework alongside that arrangement.

Engine 29 brings the preferred storage path closer to the execution path. Docker describes the goal as reducing duplication and aligning with the wider containerd ecosystem. That is an architectural argument about the components responsible for content and layers.

The distinction matters because saying Docker now uses containerd would omit its existing role. The new default concerns the image store. It does not describe the first introduction of containerd into every part of Engine.

Docker also describes possibilities enabled by the architecture, including lazy content retrieval and remote stores. Those are motivations and future opportunities in the announcement. They should not be reported as a guarantee that installing 29 automatically enables every proposed storage feature.

The storage backend remains relevant even when the application image is unchanged. An image describes the artifact being retrieved and executed. The backend determines how the host manages its content and filesystem representation. The same application-level reference does not imply identical host storage implementation.

Existing installations keep their current store

The announcement states that existing users are not forced onto containerd. They may opt in, while a migration guide for moving existing content is still being developed. That is a materially different promise from an automatic in-place conversion.

The release notes also identify an exception for daemons configured with user namespace remapping. The containerd image store is temporarily unavailable in that arrangement as a workaround for a tracked issue. A description of the default needs to preserve that qualification.

This makes installation history relevant to comparing machines. A newly installed Engine 29 host and an upgraded host can legitimately use different image stores. The version number alone is not a complete statement of the storage configuration.

It also changes how a default should be documented in automation. A configuration that relies on defaults can produce different arrangements depending on whether it provisions a new host or upgrades an existing one. Recording an explicit storage choice removes that ambiguity when uniformity is required.

My preference for small runtime images does not make host storage unimportant. Intermediate build content and locally retained images still exist around the final artifact. The choice of image store belongs to the system maintaining those inputs and outputs.

Docker says legacy graph drivers remain available but are deprecated. That identifies the intended direction without making immediate removal part of this release. Existing users have a supported continuity path while the project moves its preferred implementation elsewhere.

Platform selection can retain more than one variant

Engine 29 also extends platform filtering for image load and save. The release notes describe selecting multiple platforms through a single --platform flag. This expands the earlier ability to select one member of a multi-platform image.

The documented import example makes the operation concrete. The archive must contain the variants requested by the caller.

docker image load --platform linux/amd64,linux/arm64 -i image.tar

This is useful when a transfer should retain a selected set rather than every available member or only one. The archive remains a distribution artifact, while the flag states which platform members the receiving store should load.

The change also fits the broader distinction between artifact identity and local representation. A multi-platform image can contain several manifests. The local operation needs to express which members it intends to preserve, independently of the host architecture on which the command runs.

Native nftables support is an opt-in experiment

Docker's announcement explains that Engine has historically generated iptables and ip6tables rules. On many systems those commands already translate rules into nftables through compatibility tools. Native nftables support changes who creates the nftables rules directly.

The new backend is opt-in. Docker documents the daemon setting used to select it, which is separate from the storage default.

{
  "firewall-backend": "nftables"
}

The announcement explicitly calls this initial support experimental. It also says it cannot be enabled on a node with Swarm enabled. Swarm support remains planned work, so the release does not establish native nftables as a replacement for every existing Docker network deployment.

There are differences for hosts using the iptables DOCKER-USER chain. Docker says that policy needs migration when switching backends. The native rules use separate nftables tables and base chains, which also changes the relationship with firewalld's older direct interface.

Forwarding configuration is another explicit responsibility. The release notes say the nftables backend does not enable IP forwarding on the host. If a bridge network needs forwarding and it is disabled, daemon startup or network creation fails unless the relevant check is disabled.

Disabling the check does not supply forwarding functionality. The notes warn that some bridge features, including port forwarding, may then fail. That distinction separates a configuration acceptance option from the host behavior the network actually needs.

Client compatibility changes independently of storage

The daemon now requires API version 1.44 or later. Docker's announcement associates that minimum with version 25 of the Engine API generation. A client that insists on an older API can fail before any image or container operation reaches its ordinary implementation.

That makes API compatibility a separate part of an Engine upgrade. Existing containers and stored images do not prove that every external management client can communicate with the upgraded daemon. The protocol version negotiated or requested by that client matters.

Go consumers also have a packaging change. The release notes deprecate github.com/docker/docker in favor of the public client and API modules under github.com/moby/moby. They identify those supported modules separately from Moby's internal implementation.

These are different compatibility boundaries. An HTTP client needs an accepted API version. A Go program importing the SDK also needs supported module paths and types. Treating both as merely a CLI upgrade would miss integrations that do not invoke the CLI.

The runtime security update remains independently important

Engine 29 includes runc 1.3.3. The runc release, published November 5, fixes CVE-2025-31133, CVE-2025-52565, and CVE-2025-52881. Its maintainers describe all three as paths to container breakout through bypasses of restrictions on writes to procfs files.

The release explains one defect through masked paths. Replacing the container's /dev/null with a symlink could cause a bind mount to target a procfs file read-write. Another concerns the bind mount for the console. These defects affect runtime setup, independently of which image store manages the input image.

The third runc issue revisits the handling of Linux security module process labels. The release describes it as a more sophisticated variant of CVE-2019-19921. An earlier mitigation checked that writes of those labels targeted procfs files, but that check was insufficient. This history explains why the presence of an older mitigation cannot establish that the new bypass is blocked. The fixed runtime version is the relevant supplied correction.

That security update should therefore retain its own significance within the architectural release. A storage default concerns how a host manages artifacts. A runtime repair concerns the restrictions applied when creating container execution state.

Engine 29 combines those changes without making them one migration. Existing hosts retain their storage choice, new hosts receive the containerd default subject to the stated exception, and native nftables remains an explicit experiment. The API minimum and runc update apply their own compatibility and security requirements to the resulting installation.