Compose services talk over a shared network using service names as hostnames. Connection failures mean you are on different networks or using the wrong name.
docker-compose creates a default network per project directory. Two compose projects do not share one unless you define an external network.
The hostname is the service key (the name under services:), not the container_name, not the image name.
depends_on only orders startup, it does not wait for the database to accept connections. The app crashes on first boot.
docker network inspect <project>_default | grep -B2 Container
docker compose exec app getent hosts db
networks:
shared:
name: shared
external: true
db:
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
app:
depends_on:
db:
condition: service_healthy
Never point one compose service at another using localhost — inside a container, localhost is the container itself.
They're on different networks, or you're using the wrong name: compose service names are only resolvable within a shared user-defined network. Same compose file defaults to one network; separate compose projects need an explicit shared network.
Each container has its own network namespace: localhost inside container A is container A, never container B. Use the service name (http://api:3000) — Docker's embedded DNS maps it to the right container IP.
A production-shaped compose stack: healthchecks, resource limits, log rotation. Never debug a boot race again.
Docker Production Starter — $19 →One-time. Yours to modify. Instant download from the NinjaOps template store.