Skip to content

CMD vs ENTRYPOINT

Docker gives you two instructions for defining what happens when a container starts:

  • CMD — the default command (or default arguments). Easily overridden at docker run.
  • ENTRYPOINT — the fixed executable. Harder to override; makes the container behave like a specific program.

They are often confused. Understanding the difference lets you build containers that are easy to use correctly.

Both CMD and ENTRYPOINT accept two syntax forms.

CMD ["node", "server.js"]
ENTRYPOINT ["node"]

Arguments are a JSON array. Docker executes the program directly — no shell involved. PID 1 inside the container is your process. This means it receives OS signals (SIGTERM, SIGINT) properly, which is critical for graceful shutdown.

CMD node server.js
ENTRYPOINT node

Docker wraps the command in /bin/sh -c "...". The shell becomes PID 1, not your process. Your app runs as a child of the shell, and OS signals are not forwarded reliably. Avoid this form for production services.

CMD sets the default command a container runs. If the user passes a command on docker run, it replaces CMD entirely.

# syntax=docker/dockerfile:1
FROM alpine:3.24
CMD ["echo", "Hello from CMD!"]
Terminal window
# Uses CMD
docker run --rm myimage
# Output: Hello from CMD!
# Overrides CMD completely
docker run --rm myimage echo "Custom message"
# Output: Custom message

ENTRYPOINT sets the executable that always runs. Arguments passed on docker run are appended to the entry point — not substituted.

# syntax=docker/dockerfile:1
FROM alpine:3.24
ENTRYPOINT ["ping"]
CMD ["-c", "3", "8.8.8.8"]
Terminal window
# Uses ENTRYPOINT + CMD defaults
docker run --rm pinger
# Runs: ping -c 3 8.8.8.8
# Appends to ENTRYPOINT, replaces CMD
docker run --rm pinger -c 1 1.1.1.1
# Runs: ping -c 1 1.1.1.1

The most flexible and idiomatic pattern:

  • ENTRYPOINT = the executable (fixed)
  • CMD = default arguments (replaceable by the user)
# syntax=docker/dockerfile:1
FROM node:24-alpine
WORKDIR /app
COPY server.js .
ENTRYPOINT ["node"]
CMD ["server.js"]
Terminal window
# Default: node server.js
docker run --rm myapp
# Override: node --version
docker run --rm myapp --version

You can still override ENTRYPOINT when needed using the --entrypoint flag:

Terminal window
docker run --rm --entrypoint sh myapp

This drops you into a shell inside the container — useful for debugging.

No overridedocker run img argsdocker run --entrypoint X img
Only CMDruns CMDreplaces CMD with argsn/a — uses new entrypoint
Only ENTRYPOINTruns ENTRYPOINTappends args to ENTRYPOINTreplaces ENTRYPOINT
ENTRYPOINT + CMDruns ENTRYPOINT + CMD defaultsreplaces CMD with argsreplaces ENTRYPOINT
# syntax=docker/dockerfile:1
FROM alpine:3.24
# ENTRYPOINT sets the fixed executable
# CMD sets the default arguments
ENTRYPOINT ["echo"]
CMD ["Hello from ENTRYPOINT + CMD!"]
# --- build ---
# docker build -t greet .
# Run with defaults (uses CMD):
# docker run --rm greet
# Override CMD with your own message:
# docker run --rm greet "My custom message"
# Override ENTRYPOINT entirely:
# docker run --rm --entrypoint sh greet
OptionBenefitCost
CMDEasy to override at docker run, good for dev/debugA user can accidentally change the whole default behavior without meaning to
ENTRYPOINTFixed, forces the container to always do one job, safer in productionHarder to override — needs --entrypoint, which makes debugging more awkward
  • Using shell form instead of exec form, so the process is not PID 1, does not receive OS signals, and cannot shut down gracefully.
  • Putting both the executable and its arguments into ENTRYPOINT, leaving CMD with nothing left to override.
  • Assuming arguments passed to docker run always append to CMD, when they actually replace CMD entirely.

💡 Real-world example

The official postgres image uses ENTRYPOINT ["docker-entrypoint.sh"] as its fixed executable and CMD ["postgres"] as the default arguments, so users can override just the postgres arguments without touching the entrypoint script (github.com/docker-library/postgres).

Why is exec form (["node", "server.js"]) preferred over shell form (node server.js)?
If a Dockerfile has both ENTRYPOINT ["ping"] and CMD ["-c", "3", "8.8.8.8"], what runs when you execute docker run img -c 1 1.1.1.1?
Which docker run flag allows you to replace ENTRYPOINT at runtime?
What is the idiomatic use of CMD when ENTRYPOINT is also set?