Docker Compose — Service DNS Naming

2 minute read

One of Docker Compose’s most powerful features is automatic DNS. Every service name becomes a hostname that other services can use to connect. No IP addresses to manage, no manual network configuration.


How Service DNS Works

When Compose creates a network, it runs an embedded DNS server. Each service name becomes a DNS entry:

services:
  api:
    image: node:20
    environment:
      DB_HOST: db           # ← Use service name as hostname
      REDIS_HOST: cache     # ← Use service name as hostname

  db:
    image: postgres:16

  cache:
    image: redis:7
┌────────────── Compose DNS ──────────────┐
│                                          │
│  Service Name → IP Address               │
│  ─────────────────────────               │
│  api   → 172.18.0.2                     │
│  db    → 172.18.0.3                     │
│  cache → 172.18.0.4                     │
│                                          │
│  api container can:                      │
│    ping db         → 172.18.0.3         │
│    ping cache      → 172.18.0.4         │
│                                          │
│  db container can:                       │
│    ping api        → 172.18.0.2         │
│    ping cache      → 172.18.0.4         │
└──────────────────────────────────────────┘

Practical Example

A Node.js API connecting to PostgreSQL and Redis:

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      # Use service names as hostnames
      DATABASE_URL: postgres://admin:secret@db:5432/myapp
      REDIS_URL: redis://cache:6379
    depends_on:
      - db
      - cache

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: admin
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp

  cache:
    image: redis:7-alpine

The api service connects to db:5432 and cache:6379 — using the service names as hostnames.


Testing DNS Resolution

You can verify DNS resolution inside a container:

# Shell into the api container
docker compose exec api sh

# Inside the container — ping other services
ping -c 1 db
# PING db (172.18.0.3): 56 data bytes
# 64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.098 ms

ping -c 1 cache
# PING cache (172.18.0.4): 56 data bytes
# 64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.085 ms

DNS Naming Rules

Rule Example
Service name = hostname db service → hostname db
Case-sensitive db ≠ DB
Only within same network Services on different networks can’t resolve each other
container_name doesn’t affect DNS DNS uses the service name, not the container name

Common Connection Strings

Database/Service Connection String
PostgreSQL postgres://user:pass@db:5432/dbname
MySQL mysql://user:pass@db:3306/dbname
Redis redis://cache:6379
MongoDB mongodb://user:pass@mongo:27017/dbname
Elasticsearch http://elasticsearch:9200
RabbitMQ amqp://user:pass@rabbitmq:5672

Summary

Concept Detail
DNS resolution Service name = hostname
No IP management Compose handles it automatically
Scope Within the same Compose network
Testing docker compose exec <service> ping <other-service>

Quick Reference

Item Detail
Service name = hostname db service → hostname db
Connection string postgres://user:pass@db:5432/mydb
Test DNS docker compose exec api ping db
Scope Same Compose network only
DNS server Embedded in Docker network
Case sensitive Service names are case-sensitive