Docker Compose Network Aliases Tutorial
Network aliases let containers reach each other under multiple names. Learn how aliases work in Compose, when to use them, and the gotchas to avoid.
What you'll learn
- ✓What a network alias is in Docker Compose
- ✓How DNS resolution works inside a Compose network
- ✓When aliases simplify multi-service setups
- ✓Combining aliases with multiple networks
- ✓Common pitfalls and production tips
Prerequisites
- •Familiar with shell and YAML
By default, every service in a Docker Compose file gets a DNS name equal to its service name. The api service is reachable from other containers as http://api:3000. That covers most needs, but sometimes a service should answer to a different name, or to several names at once. That is what network aliases are for.
What and Why
A network alias is an extra DNS hostname attached to a container on a specific network. Compose lets you declare aliases per network, so the same container can be redis on one network and cache.internal on another. Aliases are scoped to the network, not the container, which matters once you have more than one.
Why use them? Three common reasons. First, drop-in compatibility: if a legacy service expects to connect to a host called mysql.prod, you can alias your local MySQL container with that name without changing client code. Second, multi-version testing: run two versions of a service and alias one as api-canary. Third, friendly internal names: keep service names short for the file, but expose readable hostnames to clients.
Mental Model
Each Compose network gets its own embedded DNS server. When a container queries a name, the DNS server checks the network for any container with that service name or alias. The first match wins. Aliases are just additional A records pointing at the same container.
+-------- network: backend ---------+
| |
| db api |
| | | |
| alias: alias: |
| mysql.prod api.local |
| api-canary |
| |
+-----------------------------------+
DNS lookup "mysql.prod" -> db
DNS lookup "api.local" -> api
DNS lookup "api-canary" -> api Hands-on Example
Below is a Compose file with two networks and aliases on both. The api is reachable as api, api.local, and api-canary from the backend network, and as public-api from the edge network.
services:
db:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: example
networks:
backend:
aliases:
- mysql.prod
- primary-db
api:
image: myorg/api:1.4.2
networks:
backend:
aliases:
- api.local
- api-canary
edge:
aliases:
- public-api
worker:
image: myorg/worker:1.4.2
environment:
DB_HOST: mysql.prod
API_URL: http://api.local:3000
networks:
- backend
gateway:
image: nginx:alpine
ports:
- "80:80"
networks:
- edge
networks:
backend:
edge:
Bring it up and verify resolution from inside a container:
docker compose up -d
docker compose exec worker getent hosts mysql.prod
docker compose exec worker getent hosts api.local
docker compose exec gateway getent hosts public-api
Each command should print the container’s IP. Notice worker cannot resolve public-api because it is on a different network. Aliases respect network boundaries.
Common Pitfalls
The first pitfall is duplicate aliases across containers on the same network. If two services both alias themselves as cache, Compose accepts the file but DNS becomes ambiguous: one client may reach service A and another service B. Keep aliases unique per network.
The second pitfall is assuming aliases work without a user-defined network. The default bridge network in standalone Docker does not have automatic name resolution. Compose creates a project network for you, so this is rarely an issue in Compose itself, but it is a frequent surprise when porting docker run examples.
The third pitfall is mixing service names and aliases inconsistently. If half your environment variables say db and the other half say mysql.prod, debugging connection failures is harder than it needs to be. Pick one canonical name per service per network and stick with it.
The fourth pitfall is forgetting alias scope across depends_on. depends_on checks the service, not its aliases. If worker depends on db, you cannot rewrite the dependency line to use the alias mysql.prod. Service names live in the Compose file; aliases live in the runtime DNS.
Production Tips
In real environments, prefer aliases that look like the names you will use elsewhere. If production code talks to auth-service.svc.cluster.local, alias the local container as auth-service.svc.cluster.local so your configuration stays identical between local and prod. Differences in hostnames are a frequent source of “works on my machine” bugs.
Use aliases to model blue/green or canary topologies locally. Two services, one aliased api-blue and the other api-green, lets a gateway flip targets without rebuilding anything. It also makes load balancing experiments easy: round-robin between two aliases pointing at different versions.
For testing failure modes, you can temporarily detach a container from a network with docker network disconnect. Aliases go with the network attachment, so the name will stop resolving for that subset of clients. Useful for chaos experiments without tearing down the stack.
When integrating with external services that expect specific hostnames, aliases are usually cleaner than editing /etc/hosts inside containers. They survive container restarts and they are visible in docker network inspect, which is easier to audit.
Avoid putting secrets or environment identifiers into alias names. Aliases show up in inspect output and in DNS replies. Reserve them for stable, semantic names.
Wrap-up
Network aliases turn Compose’s simple service-name DNS into a flexible naming system. Use them to match production hostnames, to support multiple versions of a service, or to give friendly names to internal endpoints. Keep aliases unique per network, scope them deliberately, and they will make your multi-service setups easier to reason about.
Related articles
- Docker Docker Compose vs Kubernetes: When to Use Which
A pragmatic comparison of Docker Compose and Kubernetes covering scope, operational cost, and the signals that tell you it is time to graduate.
- Docker Docker Healthchecks and Restart Policies Explained
Healthchecks tell Docker if a container is alive. Restart policies tell it what to do when it is not. Together they keep your services running.
- Docker Docker Networking: Bridge, Host, and Overlay Networks Explained
A clear guide to Docker's three most common network drivers, when to pick each one, and how packets actually flow between containers in real deployments.
- Docker Docker vs Podman: A Practical Comparison
Docker and Podman both run OCI containers, but their daemons, security models, and workflows differ. Here is when and why each one fits.