Docker CMD vs ENTRYPOINT
Every container needs a command to run when it starts. A Dockerfile offers two instructions for this job: CMD and ENTRYPOINT. Both look similar, and many beginners mix them up. Each one plays a different role, and knowing the difference helps you build images that behave exactly the way users expect.
The Restaurant Analogy
Picture a restaurant that only serves pizza. The restaurant type never changes, because every guest walks into a pizza place. The toppings change from guest to guest, and a default topping appears when the guest does not choose one.
ENTRYPOINT = the fixed job (always make pizza) CMD = the default choice (use cheese unless told otherwise)
ENTRYPOINT defines what the container is. CMD supplies default arguments that a user can replace without much effort.
What CMD Does
CMD sets the default command or default arguments for a container. A user can override CMD by typing a new command after the image name in docker run.
FROM python:3.12-slim COPY app.py /app/app.py CMD ["python", "/app/app.py"]
Running docker run my-app starts the Python script. Running docker run my-app echo hello replaces the whole CMD, and the container prints hello and exits.
What ENTRYPOINT Does
ENTRYPOINT turns the container into an executable program. Anything a user types after the image name becomes an argument to that program instead of replacing it.
FROM alpine ENTRYPOINT ["ping"] CMD ["localhost"]
Running docker run pinger pings localhost. Running docker run pinger example.com pings example.com. The ping program stays fixed while the argument changes.
How They Work Together
Docker joins ENTRYPOINT and CMD into a single command line. ENTRYPOINT supplies the program, and CMD supplies the default arguments.
Dockerfile Final command at start ------------------------- ---------------------- ENTRYPOINT ["ping"] ping localhost CMD ["localhost"] docker run pinger 8.8.8.8 ping 8.8.8.8
Exec Form and Shell Form
Both instructions accept two writing styles.
Exec form : CMD ["node", "server.js"] Shell form : CMD node server.js
Exec form runs the program directly as process number 1 inside the container. Shell form wraps the command in /bin/sh -c, which places a shell between Docker and your program. A shell does not pass stop signals to your program, so docker stop waits ten seconds and then kills the container forcefully. Exec form lets the program receive the signal and shut down cleanly. Choose exec form for all production images.
Overriding ENTRYPOINT
Sometimes you need a shell inside an image that defines an ENTRYPOINT. The --entrypoint flag replaces it for one run.
docker run -it --entrypoint sh pinger
This command opens a shell inside the pinger image and skips the ping program. Debugging sessions use this trick often.
Quick Decision Guide
+----------------------------+-------------------------------+ | Goal | Instruction | +----------------------------+-------------------------------+ | Run a general-purpose app | CMD | | Build a command-line tool | ENTRYPOINT (plus CMD default) | | Let users swap the command | CMD | | Lock the program in place | ENTRYPOINT | +----------------------------+-------------------------------+
Common Mistakes
- Writing several CMD lines. Docker keeps only the last CMD and ignores the rest.
- Using shell form and wondering why containers take ten seconds to stop.
- Expecting
docker run image commandto replace an ENTRYPOINT. It only replaces CMD. - Forgetting the square brackets and quotes in exec form, which turns it into shell form.
Practice Exercise
Build an image from the pinger example above. Run it with no arguments, run it with a new hostname, and run it with --entrypoint sh. Watch how each run changes the final command. This small experiment makes the relationship between the two instructions clear.
Real-World Scenario
A team builds a small image that converts images into thumbnails. The program lives at /usr/local/bin/thumbnailer. The Dockerfile sets ENTRYPOINT to that program and CMD to a default size of 200 pixels. A teammate runs the image with a different size by adding one argument, and the program receives the new value directly. Nobody types the program path again, and nobody can accidentally replace the program with an unrelated command.
Compare this with a web application image that uses CMD alone. Developers frequently need a shell inside that image to inspect files. They type docker run -it my-web sh, and the shell replaces the server command. This flexibility suits applications that people explore and debug often.
