What's the difference between ENTRYPOINT and CMD?

6 minintermediatedockerfileentrypointcmd

Quick Answer

ENTRYPOINT defines the fixed, primary command a container always runs, while CMD provides default arguments to that command (or, used alone with no ENTRYPOINT, defines the whole default command) that can be easily overridden at docker run time. When both are set, CMD's value is passed as arguments to ENTRYPOINT — this combination is the standard pattern for building an image that behaves like a fixed executable with sensible, overridable default arguments.

Detailed Answer

CMD alone — a default command, easily overridden

CMD ["node", "server.js"]
docker run myapp                  # runs: node server.js
docker run myapp node debug.js     # OVERRIDES the entire CMD -- runs: node debug.js instead

Any arguments given after the image name on docker run completely replace the CMD. This makes CMD alone appropriate when the image is meant to be flexible about what it runs — a general-purpose base image, or a development image where you might want to run a shell or a different script for debugging.

ENTRYPOINT alone — a fixed command that always runs

ENTRYPOINT ["node", "server.js"]
docker run myapp                    # runs: node server.js
docker run myapp --port=9000         # runs: node server.js --port=9000 (appended as ARGS, not a replacement)

Arguments given at docker run are appended to the ENTRYPOINT, not used to replace it. This makes ENTRYPOINT appropriate when the image should always run one specific thing no matter what. It essentially makes the container behave like a fixed, dedicated executable.

Combining both — the standard, recommended pattern

ENTRYPOINT ["node"]
CMD ["server.js"]
docker run myapp                # runs: node server.js       (CMD's default argument used)
docker run myapp debug.js        # runs: node debug.js        (CMD's default OVERRIDDEN, but still passed to ENTRYPOINT)

This gives you the best of both: ENTRYPOINT fixes what program runs (node, always), while CMD provides a sensible default argument to it. That default argument is still easy to override for a one-off different invocation, without needing to override the entire command.

Exec form vs. shell form — a critical, easy-to-miss distinction

# Exec form (recommended): runs the command DIRECTLY, no shell involved
CMD ["node", "server.js"]

# Shell form: runs the command wrapped in "/bin/sh -c ..."
CMD node server.js

The exec form (JSON array syntax) runs the specified program directly as PID 1 inside the container. Signals like SIGTERM (sent by docker stop) go straight to it, allowing graceful shutdown handling. The shell form instead runs /bin/sh -c "node server.js". The shell itself becomes PID 1, and it's the shell's responsibility to forward signals to the actual application process underneath it — a responsibility it doesn't always fulfill correctly. This is a common, subtle cause of containers that don't shut down gracefully: they ignore SIGTERM and only stop after docker stop's timeout forces a SIGKILL.

ScenarioRecommended setup
Fixed, purpose-built application containerENTRYPOINT + CMD (overridable default args)
General-purpose or dev image, command often replaced entirelyCMD alone
Either form, alwaysExec (JSON array) syntax, for correct signal handling