How does the default bridge network provide container-to-container communication, and why is it usually not the best choice?

6 minintermediatedefault-bridgedocker0networking

Quick Answer

The default bridge network (docker0) lets containers reach each other by IP address, and gives outbound internet access via NAT. But it does not support DNS-based service discovery by container name, unlike a user-defined bridge network. So containers on the default bridge must be hardcoded to reach each other by IP, which can change on restart. This is why Docker recommends always creating a custom, user-defined bridge network instead.

Detailed Answer

What happens without specifying a network

docker run -d --name web nginx
docker run -d --name api myapi:1.0

Without an explicit --network flag, both containers attach to Docker's default bridge network — visible as the docker0 interface on the host. Each gets its own private IP address on this virtual network, and can reach the internet through NAT via the host.

The critical limitation: no built-in DNS resolution by name

docker exec web ping api
# ping: api: Name or service not known

On the default bridge network, containers cannot resolve each other by container name. You'd have to look up api's current IP manually with docker inspect api, then hardcode that IP into web's configuration. This is fragile — a container's IP on the default bridge can change if it's stopped and restarted.

The fix: a user-defined bridge network

docker network create my-app-network
docker run -d --network my-app-network --name web nginx
docker run -d --network my-app-network --name api myapi:1.0
docker exec web ping api
# PING api (172.20.0.3): 56 data bytes    <- resolves correctly by name!

A user-defined bridge network, created with docker network create, includes Docker's embedded DNS server automatically. Containers on that network can resolve each other by container name, or by any --network-alias assigned. This is the single biggest reason the default bridge is discouraged for real multi-container apps.

Additional benefits of user-defined networks over the default

  • Better isolation. You can create multiple separate user-defined networks. Containers only see or reach others explicitly attached to the same network. For example, you could set up a "frontend" network and a "backend" network, with only specific containers bridging both. The shared default bridge can't do this.
  • Dynamic reconnection. A running container can be connected to or disconnected from a user-defined network on the fly, with docker network connect/disconnect, without a restart. The default bridge is more rigid about this.
  • This is exactly what Docker Compose does automatically. Every docker-compose.yml project gets its own user-defined bridge network by default. That's why Compose services can reference each other by service name out of the box, with no manual network setup.

The default bridge is really only useful for the simplest case: a single container with no inter-container communication, or a legacy setup. Anything with more than one container talking to each other should use a user-defined network instead.