It only documents that the app listens on 3000; nothing is published to the host
EXPOSE only documents that the app listens on port 3000. It is metadata, and it publishes nothing to the host.
To reach the container from the host, you must publish the port, which means connecting a host port to the container port. Use one of these:
• -p 3000:3000 publishes port 3000.
• -P publishes all exposed ports to random host ports.
So "It makes port 3000 reachable from the host at localhost:3000" is wrong without -p. "It forces the app inside the container to listen on port 3000" is also wrong. EXPOSE has no effect on which port the app actually listens on.
Read more