When I first started learning Docker, I came across this command:
docker network create bank-network
And honestly, my first question was:
“Why are we creating a network? Doesn’t Docker already have a bridge network?"
Docker already gives us a default network called bridge, so creating another one can feel unnecessary.
But once you understand how containers communicate with each other, the reason becomes pretty simple.
Let’s break it down from the beginning.

First: What Is a Docker Container?
A container is basically a small, isolated environment where your application runs.
For example, imagine we’re building a simple application.
We might have:
┌──────────────┐
│ App │
└──────────────┘
Our application might need a database.
So we create another container:
┌──────────────┐ ┌──────────────┐
│ App │ ────> │ PostgreSQL │
└──────────────┘ └──────────────┘
Now we have a question:
How does the App container find the PostgreSQL container?
That’s where Docker networking comes in.
Containers Need a Way to Talk
Think about your normal computer.
If one application wants to communicate with another application, there needs to be some way for them to communicate.
The same thing happens with Docker containers.
For example:
App
│
│ "Hey PostgreSQL, give me the data."
│
▼
PostgreSQL
Docker provides networks so containers can communicate with each other.
Docker Already Gives Us a bridge Network
If you run:
docker network ls
you’ll see something similar to:
NETWORK ID NAME DRIVER
xxxxxx bridge bridge
xxxxxx host host
xxxxxx none null
The bridge network is created automatically by Docker.
So you might think:
“Great. I’ll just put all my containers on**bridge."
You can.
But when you’re building an application with multiple containers, there is a better option: a user-defined bridge network.
Create Your Own Network
We can create a custom network:
docker network create bank-network
Now Docker has a network called:
bank-network
We can put our containers on it.
For example:
docker run -d \
--name postgres \
--network bank-network \
postgres
And our application:
docker run -d \
--name app \
--network bank-network \
my-app
Now we have:
bank-network
┌──────────────────┐
│ │
│ App │
│ │ │
│ │ │
│ ▼ │
│ PostgreSQL │
│ │
└──────────────────┘
Both containers are on the same network, so they can communicate with each other.
But here’s where things get interesting.
Don’t Depend on Container IP Addresses
Suppose our PostgreSQL container gets an IP address like:
172.18.0.2
Our application could technically connect to:
172.18.0.2
But we don’t want to do that.
Why?
Because container IP addresses can change.
Imagine This Happens
Today:
postgres → 172.18.0.2
Tomorrow, you delete the PostgreSQL container and create it again.
Docker might give it:
postgres → 172.18.0.5
Your application was using:
172.18.0.2
So now the application can’t find the database.
That’s a problem.
Use the Container Name Instead
Instead of using the IP address, we can use the container name.
Our PostgreSQL container is called:
postgres
So our application can connect to:
postgres:5432
For example:
postgres://root:secret@postgres:5432/mydb
Look at this part:
@postgres:5432
We’re saying:
“Connect to the container called postgres on port**5432."
Docker takes care of finding the current IP address.
So it doesn’t matter if PostgreSQL is:
172.18.0.2
or:
172.18.0.5
or:
172.18.0.10
Our application still uses:
postgres
That’s much easier to manage.
Think of It Like Your Contacts App
Here’s an easy way to think about it.
Imagine your friend’s phone number is:
9876543210
You could memorize the number.
But what happens if they change their phone number?
You’d have to update everything.
Instead, you save them as:
Rahul
Your phone keeps track of the number.
Docker networking works in a similar way.
Instead of your application remembering:
172.18.0.5
it remembers:
postgres
Docker figures out the IP address.
So Why Create a Custom Network?
Now we can answer the original question.
We create a custom network because it gives our containers a clean way to find and communicate with each other.
For example:
bank-network
│
├── app
├── postgres
└── redis
The app can talk to:
postgres
and:
redis
without worrying about their IP addresses.
What About the Default bridge?
This is important.
The default bridge network isn't "bad."
You can absolutely use it.
It’s useful for simple experiments and temporary containers.
The important difference is that user-defined bridge networks provide automatic DNS-based name resolution between containers, along with better control over the network.
That makes them much more convenient when you’re building an application with multiple containers.
Another Benefit: Keeping Things Separate
Imagine you have two applications.
Application 1
bank-network
app
postgres
redis
Application 2
shop-network
app
postgres
redis
They’re on separate networks.
This helps keep the applications isolated from each other.
You can think of it as giving each application its own private network:
Bank Application
├── App
├── Database
└── Redis
Shop Application
├── App
├── Database
└── Redis
As your infrastructure grows, this kind of separation becomes increasingly useful.
One More Thing: localhost Can Be Confusing
This is one of the most common Docker mistakes beginners make.
Suppose your application is running inside a container.
You might think:
localhost:5432
means:
“Connect to my PostgreSQL container.”
But that’s not what it means.
Inside a container:
localhost
means:
“This container.”
So if your application is running inside:
app
then:
localhost
refers to the app container itself.
It does not refer to:
postgres
Instead, your application should use the PostgreSQL container’s name:
postgres:5432
So:
localhost
and:
postgres
are two very different things in Docker.
What About -p 5432:5432?
You may have also seen:
docker run -p 5432:5432 postgres
This is a different concept.
It allows your computer to access the PostgreSQL container.
Think of it like:
Your Computer
│
│ localhost:5432
▼
PostgreSQL Container
For example, a database client running on your computer could connect using:
localhost:5432
But another container on the same Docker network can communicate using:
postgres:5432
So:
From your computer:
localhost:5432
while:
From another Docker container:
postgres:5432
This distinction is important when you’re starting with Docker.
You Don’t Need to Expose Every Port
Here’s another useful Docker concept.
Container-to-container communication doesn’t require publishing every port to your host.
Suppose you have:
API → PostgreSQL
PostgreSQL might only need to be accessible by the API.
You don’t necessarily need to publish PostgreSQL’s port to your host.
The Docker network can provide the internal communication path.
For example:
Docker
┌─────────────────────┐
│ │
│ API ──────── DB │
│ │
└─────────────────────┘
│
│
Published ports
│
▼
Host
Only services that need to be accessed from outside Docker generally need published ports.
What Happens When a Container Is Recreated?
This is where the custom network becomes particularly useful.
Imagine:
postgres
↓
172.18.0.2
You remove the container.
Docker creates a new one:
postgres
↓
172.18.0.7
Your application doesn’t need to change.
It still connects to:
postgres:5432
Docker resolves the name to the current container address.
That’s the abstraction we want.
The Real Mindset Shift
The biggest lesson here isn’t really about Docker commands.
It’s about how applications find the services they depend on.
Don’t make your application think:
“My database lives at 172.18.0.7.”
Make it think:
“My database is called postgres."
The infrastructure can change without forcing you to change your application configuration.
That’s a useful concept far beyond Docker.
When Should You Create a Custom Network?
A simple rule:
One-off containers
The default network may be perfectly fine.
Multiple containers forming an application
Consider creating a user-defined network.
For example:
docker network create app-network
Then:
app-network
│
├── frontend
├── backend
├── postgres
├── redis
└── worker
Your services can communicate using meaningful names rather than container IP addresses.
A Practical Example
Create the network:
docker network create app-network
Run the database:
docker run -d \
--name postgres \
--network app-network \
postgres
Run your application:
docker run -d \
--name app \
--network app-network \
my-app
Now the application can communicate with PostgreSQL using:
postgres:5432
No need to find the database container’s IP address.
The Main Idea
Docker networking might look complicated when you first encounter it.
But the core idea is simple:
Containers need a way to communicate with each other.
A user-defined network gives those containers a dedicated network and makes it easy for them to discover each other by name.
So instead of thinking:
"What's PostgreSQL's IP address?"
think:
"What's PostgreSQL's name?"
And let Docker handle the rest.
Final Takeaway

You don’t create a custom Docker network because the default bridge network doesn't work.
You create one because it provides a cleaner setup for applications made up of multiple containers.
Remember these three things:
1. Containers need networks to communicate.
2. Don’t depend on container IP addresses.
3. Use container names on a user-defined network.
So instead of:
App → 172.18.0.5
think:
App → postgres
Let Docker figure out the IP.
Once you understand this, Docker networking becomes much easier to understand.