Q: What is the difference between -p (publish) and EXPOSE in Docker?

Answer:

This is a commonly misunderstood distinction.

EXPOSE (Dockerfile instruction)

EXPOSE is purely documentation. It tells other developers and tools (like Docker Compose) which ports the application inside the container listens on. It does NOT actually publish or open any ports.

FROM node:20-alpine
WORKDIR /app
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

Even with EXPOSE 3000, you cannot access the container on port 3000 from the host unless you explicitly publish it with -p.

-p / --publish (Runtime flag)

This is what actually creates a port mapping between the host machine and the container. It sets up iptables rules to forward traffic.

# Map host port 8080 to container port 3000
docker run -p 8080:3000 myapp

# Map to all interfaces on a random host port
docker run -p 3000 myapp   # Docker picks a random host port

# Bind to a specific host interface
docker run -p 127.0.0.1:8080:3000 myapp  # Only accessible from localhost

-P (Publish All)

The uppercase -P flag automatically publishes all ports that were declared with EXPOSE, mapping each to a random high port on the host.

docker run -P myapp
# If EXPOSE 3000 was in the Dockerfile, 
# Docker maps a random host port → container 3000

docker port myapp
# 3000/tcp -> 0.0.0.0:32768

Summary

FeatureEXPOSE-p / --publish
WhereDockerfiledocker run command
PurposeDocumentation onlyActually opens/maps the port
EffectNone on networkingCreates host↔container port forwarding
Required?NoYes, for external access