Skip to content
Blog

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 --link flag, 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 — web connects to db, whichever host the stack runs on.
  • Real isolation. Everything without an explicit --network attaches 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 connect and disconnect a running container. Moving a container off the default bridge requires stopping and recreating it.
  • Per-network configuration. The default bridge’s MTU and iptables settings are global, edited outside Docker in daemon.json with 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:

OptionDefaultPurpose
com.docker.network.bridge.name—Interface name for the Linux bridge
com.docker.network.bridge.enable_icctrueInter-container communication on/off
com.docker.network.bridge.enable_ip_masqueradetrueOutbound masquerading
com.docker.network.bridge.host_binding_ipv4all addressesDefault bind address for published ports
com.docker.network.driver.mtu0 (no limit)Container MTU
com.docker.network.container_iface_prefixethInterface 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.

Sources