If you're learning backend development, you've probably seen things like:
localhost:3000
localhost:5000
:80
:443
At first, the port number can seem like just another configuration value.
But why does a server need a port when it already has an IP address?
If one server is running a Node.js API, PostgreSQL, Redis, and NGINX at the same time, how does the operating system know which application should receive an incoming request?
That's the problem ports solve.
What Is a Port?
A network port is a logical endpoint used to identify a network service or application on a device.
A simple mental model is:
IP Address → Which machine?
Port → Which service?
For example:
192.168.1.10:3000
Here:
-
192.168.1.10is the IP address. -
3000is the port.
The IP address gets the traffic to the correct machine.
The port helps the operating system determine which application should receive that traffic.
Why Isn't an IP Address Enough?
This is the key question.
Imagine a server with this IP address:
203.0.113.10
That server could be running:
NGINX
Node.js API
PostgreSQL
Redis
SSH
All of these services are running on the same machine, so they share the machine's network interfaces and IP addresses.
If a packet arrives for:
203.0.113.10
the operating system knows:
This traffic belongs to this machine.
But it still needs to determine:
Which application should receive it?
That's where the port comes in.
The services can listen on different ports:
203.0.113.10:22 → SSH
203.0.113.10:80 → HTTP
203.0.113.10:443 → HTTPS
203.0.113.10:3000 → Node.js
203.0.113.10:5432 → PostgreSQL
203.0.113.10:6379 → Redis
Now the operating system has a way to distinguish between the services.
Think of It Like a Building
A useful analogy is an apartment building.
Suppose the building has this address:
221B Example Street
That's similar to an IP address.
Inside the building:
Apartment 101
Apartment 102
Apartment 103
are different destinations.
The building address tells you which building to visit.
The apartment number tells you where inside the building to go.
Networking works similarly:
IP Address → Building
Port → Service/endpoint
So:
203.0.113.10:443
can be thought of as:
203.0.113.10 → Which machine?
443 → Which network service?
This is an analogy, not a literal description of how networking works, but it's a useful mental model.
IP Address vs Port
Let's separate the two concepts.
IP address
An IP address identifies a network destination.
Example:
203.0.113.10
Port
A port identifies a logical network endpoint associated with a service.
Example:
443
Together:
203.0.113.10:443
You can think of this as:
Machine + Service
This is why developers frequently write endpoints as:
IP:PORT
What Does It Mean When an Application "Listens" on a Port?
You'll often hear:
"My Node.js server is listening on port 3000."
This means the application has created a network socket and is waiting for incoming connections on that port.
For example:
app.listen(3000);
Conceptually:
Node.js Application
│
↓
Listen on :3000
│
↓
Operating System
The operating system can now associate incoming traffic for that listening endpoint with the appropriate process.
A Simple Node.js Example
Consider this Express application:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("Hello from the server!");
});
app.listen(3000, () => {
console.log("Server running on port 3000");
});
When you run it, the application starts listening on:
localhost:3000
You can then open:
http://localhost:3000
The simplified flow is:
Browser
│
│ HTTP request
↓
localhost:3000
│
↓
Operating System
│
↓
Node.js Process
│
↓
GET /
│
↓
HTTP Response
The port 3000 is what allows the operating system to identify the network endpoint associated with your Node.js application.
What Is localhost?
localhost refers to the local machine.
So:
localhost:3000
means:
Connect to port 3000 on this computer.
This is extremely common during development.
You might run:
npm run dev
and your application may start at:
http://localhost:3000
The browser and application are communicating through the local machine's networking stack.
One Server Can Have Many Ports
A server doesn't have just one port.
A single machine can have many applications listening on different ports.
For example:
SERVER
203.0.113.10
│
┌────────────┼────────────┐
↓ ↓ ↓
:80 :443 :3000
HTTP HTTPS Node.js
│
:5432
PostgreSQL
The IP address identifies the machine.
The ports distinguish the network services.
Common Ports
Some port numbers are commonly associated with specific services.
| Port | Common use |
|---|---|
22 |
SSH |
53 |
DNS |
80 |
HTTP |
443 |
HTTPS |
3000 |
Common development port |
5432 |
PostgreSQL |
6379 |
Redis |
These are conventions, not permanent rules.
For example, Node.js does not require port 3000.
You could write:
app.listen(5000);
and your application would listen on:
:5000
Ports Are Logical, Not Physical
A network port is not a physical connector.
It's different from:
- USB port
- Ethernet port
- HDMI port
A network port is a logical number used by networking protocols and the operating system.
For TCP and UDP, port numbers range from:
0 - 65535
TCP and UDP Ports
Ports are used with transport protocols such as TCP and UDP.
For example:
TCP + 443
is commonly used for HTTPS.
And:
UDP + 53
is commonly used for DNS.
This is important because a port number alone isn't the complete identity of a network endpoint.
Conceptually:
Protocol + IP + Port
forms part of the information used to identify network communication.
Source Port vs Destination Port
When a client connects to a server, there is usually both a source port and a destination port.
For example:
Client
192.168.1.20:52000
│
│
↓
Server
203.0.113.10:443
Here:
Source IP: 192.168.1.20
Source Port: 52000
Destination IP: 203.0.113.10
Destination Port: 443
The server is listening on port 443.
The client's operating system typically selects an ephemeral source port for the connection.
How Can Thousands of Users Connect to Port 443?
A common beginner question is:
If a server has only one port 443, how can thousands of users connect to it?
Because the destination port isn't the only thing that identifies a connection.
For TCP, the connection is associated with information such as:
Source IP
Source Port
Destination IP
Destination Port
Protocol
For example:
Client A
10.0.0.5:51001
↓
Server
10.0.0.10:443
and:
Client B
10.0.0.6:51002
↓
Server
10.0.0.10:443
Both clients can connect to the same server port.
Their connection information is different, so the operating system can keep track of them independently.
What Happens If Two Applications Use the Same Port?
Suppose you already have:
Application A → :3000
Then you start another application configured for:
Application B → :3000
You will generally get an error because the address/port combination is already in use.
In Node.js, you may see:
EADDRINUSE
which means:
Address already in use
The solution is usually to stop the existing process or use another port:
Application A → :3000
Application B → :4000
Open, Closed, and Blocked Ports
These terms are often confused.
Open Port
A service is listening and accepting connections.
Port 443
↓
HTTPS service
↓
Listening
Closed Port
Nothing is listening on the port.
Port 3000
↓
No service
Blocked Port
A firewall or network security rule prevents traffic from reaching the service.
For example:
Internet
│
↓
Firewall
│
├── 443 ✓ Allowed
└── 3000 ✗ Blocked
A service can be listening on a port but still be unreachable from outside the machine if a firewall blocks the traffic.
Ports and Firewalls
Ports become especially important when deploying applications to a server.
Suppose your server has:
22 → SSH
80 → HTTP
443 → HTTPS
3000 → Node.js
5432 → PostgreSQL
You probably don't want every port publicly accessible.
A typical setup might allow:
80 → Public
443 → Public
while restricting:
22 → Restricted
3000 → Internal
5432 → Internal
A firewall controls which traffic can reach which ports.
This reduces the server's attack surface.
Why Keep Databases Behind the Firewall?
Suppose PostgreSQL is running on:
:5432
You usually don't want random internet clients connecting directly to it.
A better architecture is often:
INTERNET
│
↓
:443
│
↓
NGINX
│
↓
Node.js :3000
│
↓
PostgreSQL :5432
Here:
-
443is publicly accessible. - Node.js can communicate with PostgreSQL internally.
- PostgreSQL doesn't need to be exposed directly to the internet.
This is a common production architecture.
What Happens When You Visit a Website?
Consider:
https://example.com
There are several steps involved.
First, the domain needs to resolve to an IP address through DNS.
Conceptually:
example.com
↓
DNS
↓
203.0.113.10
The browser then connects to the server using HTTPS.
HTTPS normally uses:
443
So the simplified flow is:
https://example.com
↓
203.0.113.10:443
↓
Server
↓
HTTPS service
The request is then processed by the server's networking and application layers.
Why Don't We Write :443?
You may have noticed that we normally write:
https://example.com
instead of:
https://example.com:443
That's because 443 is the standard port for HTTPS.
The browser knows the default port associated with the protocol.
Similarly:
http://example.com
normally uses port:
80
But when you're developing locally, you often see:
localhost:3000
because 3000 isn't the default HTTP port.
A Real Production Example
Let's look at a common Node.js deployment.
You might have:
INTERNET
│
│ HTTPS :443
↓
┌─────────────┐
│ NGINX │
└─────────────┘
│
│ proxy
↓
localhost:3000
│
↓
┌─────────────┐
│ Node.js │
│ API │
└─────────────┘
│
↓
PostgreSQL
The user visits:
https://example.com
The request reaches the server through port 443.
NGINX receives it and can forward it internally to:
localhost:3000
where the Node.js application is running.
The user doesn't need to know that Node.js is using port 3000.
Why Is Port 3000 So Common?
You may see this constantly in JavaScript development:
localhost:3000
That's simply a common convention.
There is nothing inherently special about 3000.
Your application could use:
3001
4000
5000
8000
8080
or another available port.
For example:
app.listen(8080);
means the application listens on:
:8080
Port Ranges
Port numbers range from:
0 → 65535
They are commonly divided into three broad categories:
0–1023
Well-known ports
1024–49151
Registered ports
49152–65535
Dynamic/private ports
This classification is useful as a general mental model, although the exact rules and allocations are more nuanced.
Well-Known Ports
Ports 0–1023 are commonly referred to as well-known ports.
Examples include:
22 → SSH
53 → DNS
80 → HTTP
443 → HTTPS
These ports are associated with widely used protocols and services.
Registered Ports
The range:
1024–49151
contains registered ports associated with various applications and services.
Again, registration does not mean an application is forced to use that port.
Applications can often be configured to use another available port.
Dynamic or Ephemeral Ports
When a client makes an outgoing connection, the operating system typically chooses a temporary source port.
For example:
Client
192.168.1.20:53124
│
↓
Server
203.0.113.10:443
Here:
53124
could be an ephemeral source port.
The exact ephemeral port range depends on the operating system and its configuration.
A Complete Request Flow
Let's combine everything.
Suppose a browser wants to access:
https://api.example.com/users
A simplified flow looks like:
Browser
│
│ DNS lookup
↓
api.example.com
│
↓
Server IP
│
│ TCP connection
↓
Server:443
│
↓
HTTPS server / NGINX
│
│ reverse proxy
↓
Node.js:3000
│
↓
/users route
│
↓
Database
│
↓
Response
│
↓
Browser
Notice how the port appears at different stages.
The public service may be available on:
443
while the internal Node.js application may be listening on:
3000
The port doesn't represent the entire application architecture. It identifies a network endpoint at a particular layer of the system.
Ports Are About Routing Traffic to Processes
At the application level, it is tempting to think:
"Port 3000 belongs to Node.js."
That's not quite correct.
Port 3000 doesn't inherently belong to Node.js.
Instead, a process binds to a network endpoint.
For example:
Node.js → 0.0.0.0:3000
The operating system maintains the relationship between the network endpoint and the process.
Another application could use port 3000 after the Node.js process stops and releases it.
So ports are not permanently assigned to applications.
A Few Important Things to Remember
1. A port is not an IP address
IP → Machine/network destination
Port → Network service/endpoint
2. A server can use many ports
:22
:80
:443
:3000
:5432
can all exist on the same machine.
3. Port numbers are configurable
Node.js doesn't require 3000.
4. Open doesn't always mean publicly reachable
A firewall can block traffic even when a service is listening.
5. Ports are logical
They're not physical connectors.
6. TCP and UDP have separate port spaces
A TCP port and a UDP port with the same number aren't the same endpoint.
The Mental Model You Should Remember
If you're learning backend development, don't memorize hundreds of port numbers.
Understand this:
REQUEST
│
↓
IP ADDRESS
│
↓
SERVER
│
↓
PORT
│
↓
SERVICE
│
↓
APPLICATION
Or even simpler:
IP Address → Which machine?
Port → Which service?
For example:
203.0.113.10:443
means:
203.0.113.10 → destination machine
443 → destination port
And:
localhost:3000
means:
localhost → this machine
3000 → service listening on port 3000
Conclusion
Ports are one of those networking concepts that look complicated at first but become straightforward once you understand the problem they're solving.
A server can run many network services at the same time. The IP address helps identify the machine, while the port identifies the network endpoint associated with a particular service.
A typical server might look like:
SERVER
203.0.113.10
│
┌────────────┼────────────┐
↓ ↓ ↓
:22 :443 :3000
SSH HTTPS Node.js
│
:5432
PostgreSQL
So when you see:
IP:PORT
don't think of the port as just a random number.
Think:
"I know which machine I want. Now I need to specify which network service I want to communicate with."
That's the fundamental purpose of network ports.
Top comments (1)
The NGINX:443 Node.js:3000 PostgreSQL:5432 example makes the deployment implications concrete, especially alongside your distinction between listening and publicly reachable. One detail I'd add is that the bind address matters too: a service listening on 127.0.0.1:3000 has different exposure from one on 0.0.0.0:3000, even though the port is identical. For a small team, documenting the intended bind address and access rules for each service makes deployment reviews easier and helps catch accidental exposure before it becomes an incident.