The situation
It's 2 AM and your app container is throwing this every few seconds:
dial tcp: lookup db on 127.0.0.1:53: no such host
Your docker-compose.yml has a service named db. Your app is clearly trying to reach it. The DB container is running โ you checked. So what's going on?
The short answer: your app container is using 127.0.0.1:53 as its DNS server. That's the host machine's loopback resolver โ not Docker's internal DNS. Docker's service name resolution runs through its own embedded DNS at 127.0.0.11. The host resolver has never heard of db, so it fails immediately.
This happens when a container isn't on a Docker-managed network, or when something broke its DNS config. Either way, it falls back to the system resolver โ and the system has no idea what db means.
Debug process
Step 1: Check if both containers are on the same network
Nine times out of ten, this is the problem. Run:
docker network ls
docker inspect <your_container_name> | grep -A 20 '"Networks"'
Look at the Networks section. App container on bridge (the default legacy network) but DB on myapp_default? They're isolated from each other โ service names won't resolve across different networks.
Step 2: Verify Docker's internal DNS is being used
Exec into the app container and check:
docker exec -it <app_container> cat /etc/resolv.conf
A healthy Docker container should show:
nameserver 127.0.0.11
options ndots:0
Seeing nameserver 127.0.0.1 or a public resolver like 8.8.8.8? Docker's DNS isn't wired up. This happens when containers run with --network host, or when they're not attached to a user-defined network.
Step 3: Test name resolution manually
docker exec -it <app_container> nslookup db
docker exec -it <app_container> ping db
nslookup fails but the DB container is running? Network attachment problem. Not an app config problem.
Solutions
Solution 1: Put both services on the same named network (Docker Compose)
Start here โ this resolves 90% of cases. In your docker-compose.yml:
services:
app:
build: .
networks:
- backend
environment:
DATABASE_URL: postgres://user:pass@db:5432/mydb
db:
image: postgres:15
networks:
- backend
networks:
backend:
driver: bridge
When both services live in the same Compose file without explicit network config, Docker Compose automatically creates a shared network named <project>_default and puts everything on it. Service names resolve automatically. No extra config needed.
The error creeps in when:
- You override
networks:on one service but forget the other - One container was started manually with
docker runinstead of through Compose - You have multiple Compose files with services on different project networks
Solution 2: Connect a manually-run container to the Compose network
Started your app with docker run while the DB lives in a Compose stack? Connect them:
# Find the network name
docker network ls
# Connect your standalone container
docker network connect myproject_default <app_container_name>
No restart needed. Service name resolution kicks in immediately after connecting.
Solution 3: Drop --network host
--network host makes a container share the host's network stack entirely. Docker's internal DNS doesn't apply. Service names won't resolve โ full stop.
Unless you actually need host networking (raw sockets, hardware access, very specific port binding scenarios), remove it:
# Wrong
docker run --network host myapp
# Right โ use a named network
docker run --network myproject_default myapp
Solution 4: Multiple Compose files โ create a shared external network
Running separate Compose stacks that need to talk? Define one shared network explicitly:
# In your DB stack (docker-compose.db.yml)
networks:
shared:
name: shared_backend
driver: bridge
# In your app stack (docker-compose.app.yml)
networks:
shared:
external: true
name: shared_backend
Both stacks now share the same network. Service names resolve across stacks without any extra tricks.
Verification
Run these checks to confirm the fix took effect:
# Check container is on the right network
docker inspect <app_container> | grep -A 5 '"Networks"'
# Confirm Docker DNS is active
docker exec -it <app_container> cat /etc/resolv.conf
# Should show: nameserver 127.0.0.11
# Test name resolution
docker exec -it <app_container> nslookup db
# Should resolve to an internal IP like 172.18.0.x
nslookup db returns an IP? You're good. Still seeing errors in the app? Restart the app container โ some runtimes (notably Go and Java apps) cache DNS failures in memory and won't retry until the process restarts.
Tip: Debugging subnet conflicts
DNS resolved but connections still fail? Check for subnet collisions. Docker picks CIDR ranges automatically โ sometimes they overlap with your VPN or office network and break routing entirely. Check your network's subnet:
docker network inspect <network_name> | grep Subnet
A common culprit: Docker defaulting to 172.17.0.0/16 while your VPN uses the same range. Pin a custom subnet in your Compose file to avoid the conflict:
networks:
backend:
driver: bridge
ipam:
config:
- subnet: 10.50.0.0/24
When sorting out which addresses fall in which subnet, I reach for the Subnet Calculator on ToolCraft โ browser-based, shows the broadcast address, usable range, and wildcard mask without phoning home.
Lessons learned
- Service name DNS only works on user-defined networks. The default
bridgenetwork doesn't support service discovery. Name your networks in Compose โ always. - Mixing
docker runanddocker composecauses this silently. A container started by hand won't automatically join a Compose network. You have to connect it manually withdocker network connect. --network hostis a sledgehammer. It bypasses Docker DNS entirely. Reach for it only when you genuinely need it, not as a quick fix for port binding issues.- The nameserver line in
/etc/resolv.conftells you everything.127.0.0.11means Docker DNS is active and service names will work. Anything else means you're resolving outside Docker โ anddbis meaningless out there.

