Creating User-Defined Bridge Networks
Create Docker bridge networks with docker network create — automatic DNS between containers, scoped isolation, driver options, and IPv6.
Published on • October 18, 2026
AI Assistant

When you start a container without --network, it lands on the default bridge network — a legacy default that Docker itself says is not recommended for production. A user-defined bridge network takes a minute to create and gives you name-based DNS between containers, scoped isolation from unrelated containers, and per-network configuration. Everything below follows the bridge driver documentation.
Why user-defined beats the default bridge
The docs are blunt: user-defined bridge networks are superior to the default bridge network. Four reasons:
- Automatic DNS resolution. On the default bridge, containers reach each other only by IP (or via the legacy
--linkflag, which needs links in both directions and falls apart past two containers). On a user-defined network, containers resolve each other by name or alias —webconnects todb, whichever host the stack runs on. - Real isolation. Everything without an explicit
--networkattaches to the default bridge, so unrelated stacks can talk to each other by accident. A user-defined network is a scope: only containers you attach can communicate. - Hot attach/detach. You can
docker network connectanddisconnecta running container. Moving a container off the default bridge requires stopping and recreating it. - Per-network configuration. The default bridge’s MTU and
iptablessettings are global, edited outside Docker indaemon.jsonwith a daemon restart. Each user-defined network is configured at creation time, independently.
The one thing the default bridge gives that user-defined networks don’t is --link-style environment variable sharing — and volumes, Compose environment:, or Swarm secrets are the better answers to that anyway.
Create and inspect a network
docker network create my-net
That’s the whole thing — bridge is the default driver, so no --driver flag is needed. Be explicit if you prefer:
docker network create --driver bridge alpine-net
docker network ls
NETWORK ID NAME DRIVER SCOPE
e9261a8c9a19 alpine-net bridge local
17e324f45964 bridge bridge local
6ed54d316334 host host local
7092879f2cc8 none null local
docker network inspect alpine-net shows the gateway (something like 172.18.0.1), the subnet, and the connected containers. Need addressing control? Add --subnet, --ip-range, --gateway, and the rest documented under docker network create --help.
Attach containers
Create a container directly on the network, publishing port 80 to the host:
docker create --name my-nginx \
--network my-net \
--publish 8080:80 \
nginx:latest
Or attach something already running:
docker network connect my-net my-nginx
docker network disconnect my-net my-nginx
Containers on the same user-defined bridge expose all ports to each other with no -p needed. Publishing with -p/--publish is only for access from outside that network — from other networks or from the host.
Prove DNS and isolation work
Create four Alpine containers — three on alpine-net, one left on the default bridge — then bridge one of them across both:
docker run -dit --name alpine1 --network alpine-net alpine ash
docker run -dit --name alpine2 --network alpine-net alpine ash
docker run -dit --name alpine3 alpine ash
docker run -dit --name alpine4 --network alpine-net alpine ash
docker network connect bridge alpine4
Attach to alpine1 and test:
docker container attach alpine1
# ping -c 2 alpine2
PING alpine2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms
# ping -c 2 alpine3
ping: bad address 'alpine3'
Name resolution succeeds for alpine2 (same network) and fails for alpine3 (different network — it fails by name and by its 172.17.x.x IP). alpine4, attached to both, can reach everything but must use IPs to talk to containers on the other network. Two caveats from the docs: automatic service discovery resolves only custom container names, not Docker’s generated ones, and Docker manages the bridge devices and iptables rules for you — those are implementation details you shouldn’t touch.
Driver options
Pass --opt at creation time to tune the bridge:
| Option | Default | Purpose |
|---|---|---|
com.docker.network.bridge.name | — | Interface name for the Linux bridge |
com.docker.network.bridge.enable_icc | true | Inter-container communication on/off |
com.docker.network.bridge.enable_ip_masquerade | true | Outbound masquerading |
com.docker.network.bridge.host_binding_ipv4 | all addresses | Default bind address for published ports |
com.docker.network.driver.mtu | 0 (no limit) | Container MTU |
com.docker.network.container_iface_prefix | eth | Interface name prefix |
For example, an isolated test network with no east-west traffic and a sane MTU for an overlay-underlay with smaller frames:
docker network create \
--opt com.docker.network.bridge.enable_icc=false \
--opt com.docker.network.driver.mtu=1400 \
--opt com.docker.network.bridge.host_binding_ipv4=127.0.0.1 \
isolated-net
That last option is worth stealing: it makes every -p on this network bind to 127.0.0.1 by default instead of 0.0.0.0.
IPv6 and IPv6-only networks
Enable IPv6 explicitly; without a --subnet, Docker picks a Unique Local Address prefix automatically:
docker network create --ipv6 --subnet 2001:db8:1234::/64 my-net
An IPv6-only network drops IPv4 configuration entirely — note this is impossible on the default bridge:
docker network create --ipv6 --ipv4=false v6net
Use them from Compose
Compose creates a project-scoped bridge for you when a service needs one. Declaring networks: at the top level and referencing them per service is the same mechanism, automated:
services:
web:
image: nginx
networks:
- front
db:
image: postgres:18
networks:
- back
networks:
front: {}
back: {}
The web service reaches db by service name only if they share a network — and here they deliberately don’t.
Limits and cleanup
Two practical constraints: bridge networks go unstable around 1000+ containers on a single network (a Linux kernel limitation, moby/moby#44973), and removal requires disconnecting containers first:
docker network disconnect my-net my-nginx
docker network rm my-net
docker network prune clears unused networks in bulk.