4.2.10.3 EXPOSE Publishing Contrast
A focused guide to EXPOSE Publishing Contrast, connecting core concepts with practical Docker and container operations.
The EXPOSE publishing contrast distinguishes between declaring a port with EXPOSE (documentation only) and actually publishing it with docker run -p (genuinely making it reachable), a distinction that is a frequent source of confusion for anyone newer to Docker networking.
EXPOSE Declares, Publishing Connects
EXPOSE only records, as metadata, that a container listens on a given port; it has no effect on whether that port is actually reachable from outside the container.
EXPOSE 8080
docker run myapp
curl http://localhost:8080
Despite the EXPOSE declaration, this curl command fails to connect, because no port mapping was specified at run time.
Publishing Makes the Connection Possible
The -p flag at run time is what actually creates a path from the host into the container's port, regardless of whether that port was declared with EXPOSE at all.
docker run -p 8080:8080 myapp
curl http://localhost:8080
This now succeeds, because the port mapping was explicitly created, independent of any EXPOSE declaration in the image.
EXPOSE Is Not Required for Publishing to Work
A port can be published even if it was never declared with EXPOSE in the image at all — EXPOSE is purely advisory and has no bearing on whether -p will work.
FROM node:20-alpine
CMD ["node", "server.js"]
docker run -p 9999:8080 myapp
Even with no EXPOSE instruction at all in this image, explicitly publishing port 8080 to host port 9999 still works correctly.
The One Place EXPOSE Has an Automatic Effect
The -P flag (capital P) automatically publishes every port declared with EXPOSE, mapping each to a randomly assigned host port — this is the one situation where EXPOSE's declared information is actually acted upon automatically.
docker run -P myapp
docker port myapp
Why This Contrast Matters
Understanding that EXPOSE and port publishing are two entirely separate mechanisms — one purely informational, the other functionally connecting host and container — prevents the common mistake of assuming a declared port is automatically reachable without an explicit mapping.