In short
Your API container can't find the database, or your laptop can't reach the API. Almost every Docker networking problem comes down to two ideas: shared networks and published ports.
How containers communicate with each other and the outside world — Docker's default bridge networks let containers reach each other by service name within the same Compose setup.

Think of it like this
The apartment intercom
Inside your building, you press 'B-204' on the intercom and reach your neighbour directly, no outside phone number needed. Visitors from the street can only reach flats the gate lets them through to. Containers on a network call each other by name; -p is the gate.
Watch it happen
Who can reach whom
where is db?
1/5Both containers are on the user-defined network shopnet. The api asks Docker's built-in DNS for db.
The big ideas
What you need to know
User-defined networks
Containers on the same user-defined network find each other by container name. The default bridge doesn't do name lookup.
-p publishes a port
-p 8080:3000 means laptop port 8080 forwards to container port 3000. Left is host, right is container.
localhost is per container
Inside a container, localhost means that container. To reach another, use its name.
Publish only what you must
Keep databases unpublished in production. Only the API or proxy should face the outside.
See it in code
Walk through the code
1docker network create shopnet2 3docker run -d --name db --network shopnet -e POSTGRES_PASSWORD=secret postgres:174docker run -d --name api --network shopnet -p 3000:3000 \5 -e DATABASE_URL=postgres://postgres:secret@db:5432/postgres my-api6 7# Inside the network, containers find each other by name8docker run --rm --network shopnet alpine ping -c 1 db1/3Create a user-defined bridge network. It comes with DNS for container names.
Compose creates a network like shopnet for every project automatically. That's why service names just work there.
Save yourself the pain
Common mistakes
Oops
Publishing the database with -p 5432:5432 on a public server.
Do this instead
That exposes it to the internet. Keep it on a private network and let only the api reach it.
Oops
Mixing up the order in -p 3000:8080.
Do this instead
It's host:container. Check which port your app listens on inside the container.
Your mission
Debug a broken connection
Quick check
You run docker run -p 8080:3000 my-api. Where does your browser go?
Go deeper
- 1Confirm two containers in the same Compose file can reach each other by service name.
- 2Learn how port mapping (`-p 3000:3000`) exposes a container's port to your host machine.
- 3Explore Docker's network types: bridge, host, none.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.