Docker Networking Modes: Bridge, Host, and Overlay
Docker's default bridge network isolates containers with NAT; host mode shares the host's network stack; overlay connects containers across hosts.
Docker containers don’t share the host’s network stack by default — each one gets its own virtual network interface, and how that interface connects to the host and other containers depends on which network driver it’s attached to. The driver you pick — bridge, host, overlay, or none — determines whether a container is isolated behind NAT, shares the host’s networking directly, or spans multiple physical machines.
Bridge: the default
When you run a container without specifying --network, Docker attaches it to a default bridge network. Docker creates a virtual bridge interface (docker0) on the host, and each container gets a virtual ethernet pair connecting it to that bridge — effectively a private, host-local network with its own IP range.
Containers on the same bridge can reach each other by IP, but not by container name unless you create a user-defined bridge network instead of using the default one:
docker network create app-net
docker run --network app-net --name api my-api-image
docker run --network app-net --name worker my-worker-image
On a user-defined bridge, Docker runs an embedded DNS server so containers can resolve each other by name (worker can reach api at the hostname api) — a capability the default bridge network doesn’t provide. This is why most docker compose setups implicitly create a dedicated bridge network per project; see Docker Compose explained for how that mapping works.
To reach a bridged container from outside the host, you publish a port with -p hostPort:containerPort, which sets up a NAT rule forwarding traffic from the host’s interface into the container’s private IP.
Host: no isolation, no NAT
Host networking removes the network namespace boundary entirely — the container shares the host’s network stack directly, with no virtual interface, no NAT, and no port mapping:
docker run --network host my-image
A process listening on port 8080 inside the container is listening on port 8080 on the host, exactly as if it were running natively. This eliminates NAT overhead, which matters for network-intensive workloads, but it also means the container can bind to any host port and see the host’s network interfaces directly — a meaningfully larger blast radius than bridge isolation, and one reason host networking is used sparingly and deliberately rather than as a default.
None: fully isolated
The none driver gives a container a network namespace with only a loopback interface — no bridge, no external connectivity at all. It’s used for containers that do purely local computation and shouldn’t be able to reach the network under any circumstance, or as a base to attach custom networking to by hand.
Overlay: networking across hosts
Bridge networking is confined to a single host — it can’t connect a container on one machine to a container on another. Overlay networks solve that by building a virtual network that spans multiple Docker hosts, encapsulating container traffic (typically over VXLAN) so it can traverse the underlying physical network transparently.
Overlay networks are what Docker Swarm uses to let services on different nodes communicate as if they were on the same local network, and they’re the conceptual ancestor of the pod networking every Kubernetes cluster relies on — though Kubernetes implements its own cross-node networking through a CNI plugin rather than Docker’s overlay driver directly. In either system, the goal is the same: give every container or pod a routable identity that doesn’t depend on which physical machine it happens to be scheduled on.
Comparison
| Bridge | Host | Overlay | |
|---|---|---|---|
| Scope | Single host | Single host | Multiple hosts |
| Isolation | NAT-isolated, own IP | None — shares host stack | Isolated, own virtual network |
| Container-to-container DNS | Yes, on user-defined bridges | N/A (shared namespace) | Yes |
| Port publishing needed | Yes (-p) | No — ports bind directly on host | Depends on service configuration |
| Typical use | Default for standalone containers and Compose | Performance-sensitive, trusted workloads | Swarm services, multi-node clusters |
Inspecting a network
A few commands cover most day-to-day troubleshooting. docker network ls lists every network Docker knows about on the host, including the default bridge, host, and none that exist regardless of whether you’ve created anything yourself. docker network inspect <name> shows the containers currently attached to a network along with their assigned IPs and the subnet the network is using — useful for confirming two containers that should be able to reach each other are actually on the same network, a surprisingly common source of “connection refused” errors when a docker compose service list grows and a new service is accidentally left off a shared network. docker network connect and docker network disconnect attach or detach a running container from a network without restarting it, which is handy for temporarily bridging two otherwise-separate Compose projects during debugging.
A common pitfall: multiple bridge networks
A container attached to two different bridge networks can talk to services on both, but its embedded DNS resolution only reliably covers the networks it’s explicitly connected to — a container on network-a can’t resolve a container that’s only on network-b by name, even if both happen to be reachable through some other routing path. This trips people up most often in larger Compose files where services are split across multiple networks for isolation (say, a “frontend” network and a “backend” network, with only the API gateway attached to both) — the isolation is the point, but it’s easy to forget which services need to bridge both sides when adding a new one.
Choosing a mode
For most local development and single-host deployments, a user-defined bridge network is the right default — it gives containers name-based discovery and keeps them isolated from the host’s own network surface, with published ports as the deliberate, explicit exception rather than the default state. Host networking is worth reaching for only when NAT overhead is measurably a problem and the trust model allows it. Overlay networking (or a Kubernetes CNI equivalent) only becomes necessary once containers need to talk to each other across more than one physical or virtual machine — at that point you’re also likely to want a proper service mesh or load balancer in front of the resulting fleet rather than relying on raw container-to-container networking alone.
Whatever the network mode, remember it’s orthogonal to storage — see Docker volumes vs bind mounts for the equivalent decision on the data side, and Docker vs Podman for how these networking concepts carry over to Podman’s daemonless model.
The takeaway
Docker’s network drivers trade off isolation against convenience and reach. Bridge is the sensible default — NAT-isolated, with container-name DNS available on user-defined networks. Host networking drops isolation for raw performance and should be used deliberately, not by default. None gives a container no network at all. Overlay extends container networking across multiple hosts, the mechanism Swarm services (and, in spirit, Kubernetes pods) rely on to make multi-node clusters behave like one flat network.
Tagged
Keep reading
Chisato · · 4 min read Docker vs Podman: Container Runtimes Compared
Docker runs containers through a persistent root daemon; Podman runs them daemonless and rootless by default. What that architectural split changes.
The Lycoris Team · · 4 min read Docker Multi-Stage Builds Explained
Multi-stage builds let a Dockerfile use one stage to compile code and a separate, minimal stage to ship it — cutting image size and attack surface.
Chisato · · 5 min read Docker Volumes vs Bind Mounts: What's the Difference
Docker volumes are managed by Docker and portable; bind mounts map a host path directly into a container. When to use each for persistent data.