Back to blog

Blog

Docker Compose Network Diagram: Map the Real Topology

Build a Docker Compose network diagram that shows what can really talk: map networks, ports and depends_on, then catch the exposure your YAML hides.

docker compose network diagramUpdated 11/6/2026Shafi Khan

Docker Compose Network Diagram: Map the Real Topology

Docker Compose network diagram, the short version: draw one zone per network, put each service inside the networks it joins, then add published ports as entry points from the host. Arrows come from real connections like env vars and app config, not from depends_on. That one swap is the difference between a startup-order chart and a topology you can review.

Every Compose stack starts cute. Two services, one database, life is good. Eighteen months later there are nine services, three override files, and a compose.yaml that only one person dares to touch.

So someone generates a diagram, it looks great, and it's quietly wrong. The arrows show who starts first, while the actual risks sit in lines nobody drew.

Here's how to map what's really there, using a stack we validated with Docker Compose v5.7.0.

What a Docker Compose network diagram should show

A Docker Compose network diagram answers one question: what can reach what? Not who boots first, and not which images you pulled.

Compose has several keys that look like they answer that. Only some of them do:

Compose keyWhat it really tells youHow to draw it
networksWho can connect to whomA zone around services
portsWhat's published on the hostAn entry arrow from outside
exposeA declared container port, not publishedA label on the service, never an entry
depends_onStart and stop orderA dashed note, or leave it out
environmentReal connection targets, like db:5432A solid arrow, once confirmed
volumesShared or persistent stateA storage node
profilesServices that only run sometimesA dotted box

Solid arrows should mean "this connection happens". If an arrow means something else, label it or lose it.

→ Turn your compose file into a dependency map with the free Docker Compose Diagrammer

Docker Compose networks, explained in 90 seconds

If your file declares no networks, you already have one. Compose sets up a single network for your app, named <project-name>_default, and every service joins it. Each service registers its name with an internal DNS server, so web can reach postgres://db:5432 by name.

That default is convenient and flat. Every service can try to connect to every other service, so your diagram gets exactly one zone.

Declare networks and the picture changes. The Compose networks reference spells out the rule with a classic example: a proxy on frontend, a database on backend, and an app on both. The proxy and database are isolated because they share no network.

A few special cases deserve their own markings:

  • internal: true creates an externally isolated network. Draw it with a thick border.
  • external: true means the network's lifecycle is managed outside this application, and Compose errors if it doesn't exist. Draw it crossing the edge of your stack, because something else is on it.
  • network_mode: host shares the host's network stack. Port mapping doesn't apply and service-name DNS doesn't work, so the service sits outside your zones.

Those last two are where "isolated" stops being true without anybody noticing. Hunt for them first.

→ Try a shared network layout in the Docker Compose Diagrammer

Docker Compose networks example: a stack with two surprises

Here's a realistic stack. Read it and spot the problems before scrolling on:

services:
  proxy:
    image: nginx:1.27
    ports:
      - "80:80"
    networks: [frontend]
    depends_on: [api]

  api:
    build: ./api
    expose:
      - "8000"
    environment:
      DATABASE_URL: postgres://app:${DB_PASSWORD:?set DB_PASSWORD}@db:5432/app
      REDIS_URL: redis://cache:6379
    networks: [frontend, backend]
    depends_on:
      db:
        condition: service_healthy
      cache:
        condition: service_started

  worker:
    build: ./worker
    environment:
      DATABASE_URL: postgres://app:${DB_PASSWORD:?set DB_PASSWORD}@db:5432/app
      REDIS_URL: redis://cache:6379
    networks: [backend]
    depends_on: [cache]

  cache:
    image: redis:7
    networks: [backend]

  adminer:
    image: adminer:5
    profiles: [debug]
    ports:
      - "8080:8080"
    networks: [backend]

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: app
      POSTGRES_DB: app
      POSTGRES_PASSWORD: ${DB_PASSWORD:?set DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app -d app"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks: [backend]

networks:
  frontend:
  backend:

volumes:
  pgdata:

The two-network split looks tidy. Now write the real topology as an edge list, which is the fastest draft of any diagram:

host   --:80----> proxy    published, intended entry point
host   --:5432--> db       published, REVIEW THIS
proxy  --:8000--> api      frontend (confirm in nginx.conf)
api    --:5432--> db       backend
api    --:6379--> cache    backend
worker --:5432--> db       backend, not in depends_on
worker --:6379--> cache    backend

Surprise one: worker uses the database, but depends_on never mentions it. A diagram built from depends_on draws no line there.

Surprise two: db lives on the "private" backend network and is also published on the host. That single ports entry walks around your careful segmentation.

FromToShared networkConnects?In depends_on?
proxyapifrontendYesYes
apidbbackendYesYes
workercachebackendYesYes
workerdbbackendYesNo
proxydbNoneNoNo
hostdbPublished portYesNo

→ Threat-model this kind of exposure with the free STRIDE checklist

Docker Compose depends_on vs networks

This mix-up causes most bad Compose diagrams, so here it is plainly: depends_on is about time, and networks are about space.

Per Docker's startup order docs, Compose starts and stops containers in dependency order, and on startup it waits until a container is running, not until it's ready. If you need readiness, use condition: service_healthy with a healthcheck, as api does above. service_completed_successfully is for one-shot jobs such as migrations.

None of this creates or restricts a connection. Which leads to two failure modes:

  • Missing arrows: services talk with no depends_on, like worker and db.
  • Phantom arrows: depends_on exists for ordering, but there's no meaningful traffic, as with a migration job that finishes before the app starts.

Direction can trip you up too. Here proxy depends on api, and traffic happens to flow the same way. Don't count on that for every edge, because a dependency only tells you what must start first.

→ Show request order properly with a sequence diagram in Flow IQ

Docker Compose ports vs expose

ports publishes. expose declares. Only one of them puts your service on the host.

Docker's docs on publishing ports are blunt about it: a published port goes to all network interfaces by default, so any traffic reaching your machine can reach the app. The same page says to be mindful of publishing databases. Fair warning, and it applies directly to our db.

On a laptop, that port is handy for a local SQL client. On a shared VM or cloud host, it's a very different conversation. Two fixes:

# Option 1: keep it on this machine only
ports:
  - "127.0.0.1:5432:5432"

# Option 2: remove ports entirely, services still connect via db:5432

Option 2 works because service-to-service traffic uses the container port. Your host port mapping never enters into it, which also means 8001:5432 on the host still means db:5432 inside the network. Label the container port on internal edges and the host port on entry arrows.

→ Run your design through Threat Analyzer before it reaches production

How to visualize Docker Compose services: 3 ways

Pick based on what you need next. Each option gives you a starting point, and the review layer stays yours.

OptionBest forOutputWatch out for
docker compose configChecking the effective modelYAML or JSONText only, and it resolves variables
docker compose alpha vizA quick graph in a terminalGraphviz DOTExperimental, arrows show dependencies
Docker Compose DiagrammerSharing a map in docsMermaid, Markdown, JSONManual layer needed for ports and app edges

Start with config. It merges your files, resolves variables and expands shorthand into canonical form, so overrides stop hiding from you:

docker compose config --services
docker compose config --networks
docker compose --profile debug config --services
docker compose config --no-interpolate > effective.yaml

Profiles matter here. In our stack, adminer only shows up in that third command, so a default run makes it invisible. If it runs in staging, it belongs on the diagram.

Use --no-interpolate for anything you'll share. Plain config writes resolved values into the output, including passwords in connection strings.

Then generate a quick graph. Docker ships an experimental Graphviz generator:

docker compose alpha viz --networks --ports --image | dot -Tsvg > compose.svg

You'll need Graphviz installed and your required variables set. It lists networks and ports inside each node, which is great for inventory, while the arrows still come from dependencies. On our stack, worker to db doesn't appear. Experimental also means it can change or vanish between releases, so don't wire it into anything important.

Or skip the terminal. Paste your source compose.yaml into the Docker Compose Diagrammer and you get a Mermaid map of services, depends_on links, networks and volumes, plus exports for your docs. Use the source file with short-syntax volumes, not expanded config output. It parses what you paste, so it won't apply override files, and published ports and env-var connections still need adding by hand.

→ Generate your Mermaid topology with the Docker Compose Diagrammer

A 6-step checklist for your Compose diagram

Use this on any stack, from a side project to a pre-migration inventory:

  • Validate the model. Run docker compose config -q so you're drawing a file that parses.
  • List every profile and override. Note which combination you're drawing, in the diagram title.
  • Draw network zones first. One box per network, and service boxes go inside. Services on two networks straddle the line.
  • Add entry points. One arrow from the host for every entry in ports, labelled with its bind address.
  • Add real connections. Search environment, env files and app config for hostnames and ports. Confirm each one.
  • Mark the weird stuff. external, internal, network_mode, shared volumes and anything else that breaks the simple story.

Then ask a reviewer one question: "Which of these arrows surprises you?" If one does, the diagram has already paid for itself.

Compose stacks are often the most honest record of an older system, so this pairs well with reverse engineering architecture from code when the docs have gone missing.

→ Document the request flows around this map in Flow IQ

From Compose to a production architecture diagram

A Compose file usually describes a stack on one Docker host. Your production design usually has more to say, so treat the Compose map as your current-state input, not your target.

In ComposeRough production equivalentQuestion to answer
Network zonesSubnets, security groups or network policiesWhich boundaries must be enforced?
Published portsLoad balancer, ingress or gatewayWhat's public, and who terminates TLS?
Named volumesManaged storage or persistent volumesWho owns backups and recovery?
healthcheckReadiness and health probesWhat should traffic wait for?
depends_onApplication retriesWhat happens when a dependency disappears?

If Kubernetes is next, the network policy explainer is a good bridge from Compose-style zones, and the Kubernetes YAML Visualizer gives you a system view of the manifests that follow.

For a cloud target, describe the stack and your constraints to Architect AI. It generates a structured topology that you can refine on a canvas and pass into cost, threat and documentation workflows.

→ Generate your target architecture from a prompt with Architect AI

Key takeaways

  • networks decide reachability. depends_on decides order, and it's not a topology.
  • Real connections live in config. Env vars and app config reveal edges Compose can't see.
  • ports can undo your segmentation. A published database is reachable from the host, whatever its network says.
  • Profiles and overrides hide services. Check them before you trust any generated map.
  • Generated diagrams are a first draft. Add entry points, real connections and a human review.

→ Map your stack now with the free Docker Compose Diagrammer

FAQ

How do I create a network diagram from a Docker Compose file?

Run docker compose config to validate the file and see the model Compose will really use. Draw one zone per network, place each service inside the networks it joins, add published ports as entry points from the host, and add the real connections from environment variables and app config. Finally, flag anything published on the host and review the result.

Does depends_on mean two Docker Compose services can talk to each other?

No. depends_on controls start and stop order. Connectivity comes from sharing a network. A service can connect to another service with no depends_on entry at all if they share a network, and depends_on doesn't create a network path between services that don't.

Can Docker Compose services on different networks communicate?

Not directly. Docker's Compose reference describes a proxy being isolated from a database because the two have no network in common. A service attached to both networks can talk to each side, which is why it's the natural place for a gateway or API tier.

What is the difference between ports and expose in Docker Compose?

ports publishes a container port on the host, so traffic reaching the machine can reach the service. expose declares a container port without publishing it to the host. Traffic between services on a shared network uses the container port, so it doesn't need ports at all.

Is there a built-in Docker Compose visualizer?

There is an experimental one. docker compose alpha viz generates a Graphviz graph from your Compose file, with flags for networks, ports and images. It's marked experimental, so it may change or disappear between releases, and its arrows show dependencies rather than traffic.

→ Compare Architecto with Lucidchart for technical diagrams

Stop trusting the pretty version

Your Compose file already knows a lot about your system. The job is separating what it proves from what it merely implies, then drawing the rest on purpose.

Start with the free tool, spend ten minutes on the checklist, and take the result into your next review. When it's time to move from a single-host stack to a real cloud design, bring that context with you.

→ Start free and design your next architecture in Architecto

→ See how Architect AI turns a prompt into a reviewable topology

FAQ

Questions readers ask before they act on this page.

How do I create a network diagram from a Docker Compose file?

Run docker compose config to validate the file and see the model Compose will really use. Draw one zone per network, place each service inside the networks it joins, add published ports as entry points from the host, and add the real connections from environment variables and app config. Finally, flag anything published on the host and review the result.

Does depends_on mean two Docker Compose services can talk to each other?

No. depends_on controls start and stop order. Connectivity comes from sharing a network. A service can connect to another service with no depends_on entry at all if they share a network, and depends_on doesn't create a network path between services that don't.

Can Docker Compose services on different networks communicate?

Not directly. Docker's Compose reference describes a proxy being isolated from a database because the two have no network in common. A service attached to both networks can talk to each side, which is why it's the natural place for a gateway or API tier.

What is the difference between ports and expose in Docker Compose?

ports publishes a container port on the host, so traffic reaching the machine can reach the service. expose declares a container port without publishing it to the host. Traffic between services on a shared network uses the container port, so it doesn't need ports at all.

Is there a built-in Docker Compose visualizer?

There is an experimental one. docker compose alpha viz generates a Graphviz graph from your Compose file, with flags for networks, ports and images. It's marked experimental, so it may change or disappear between releases, and its arrows show dependencies rather than traffic.

Related reading

Keep moving through the architecture workflow.

Free tool

Docker Compose Diagrammer

Quickly explain local platform topologies, integration stacks, and migration candidates by turning compose files into a visual dependency map.

docker compose visualizercompose file diagramcontainer topology mapper

Free tool

Kubernetes YAML Visualizer

Read Deployments, Services, Ingresses, StatefulSets, and ConfigMaps as one system view instead of a folder full of YAML files.

kubernetes manifest visualizerk8s yaml diagramkubernetes topology tool

Free tool

STRIDE Threat Checklist

Walk through spoofing, tampering, repudiation, information disclosure, denial of service, and elevation risks using a deterministic system model.

threat modeling checkliststride templatesecurity review checklist

Guide

What network policy means in Kubernetes and Cloud Native

What network policy means in Kubernetes and Cloud Native with technical review guidance, practical artifacts, and a workflow path into diagrams, documentation, and architecture governance.

kubernetes architecturenetwork policycloud native architecture

Guide

What current-state mapping means in Hybrid, Multi-Cloud, and Migration

What current-state mapping means in Hybrid, Multi-Cloud, and Migration with technical review guidance, practical artifacts, and a workflow path into diagrams, documentation, and architecture governance.

hybrid cloud migration architecturecurrent-state mappingmulti cloud migration plan

Comparison

Architecto vs Lucidchart

Architecto vs Lucidchart with a workflow-first comparison across diagrams, architecture review, technical documentation, and code-adjacent implementation evidence.

lucidchart alternativearchitecto vs lucidchartbrand comparison
Docker Compose Network Diagram: Map the Real Topology | Architecto