Dockerfile CMD reference

Last reviewed on 2026-09-25

How CMD sets a container's default command, how docker run, Compose and Kubernetes override it, and how it supplies default arguments to ENTRYPOINT.

Syntax

# Exec form (preferred): JSON array, no shell
CMD ["executable", "arg1", "arg2"]

# Default arguments for an exec-form ENTRYPOINT
CMD ["arg1", "arg2"]

# Shell form: run via /bin/sh -c
CMD command arg1 arg2

CMD is a default, not a fixed command: anything passed after the image name in docker run replaces it. It is stored in the image configuration and runs when a container starts — docker build never executes it. Only the last CMD in a Dockerfile takes effect.

Exec form vs shell form

The two forms follow the same rules as for ENTRYPOINT:

  • Exec form CMD ["node", "server.js"] is a JSON array. Use double quotes; with single quotes the line is not valid JSON and Docker falls back to the shell form. No shell runs, so $VAR is not expanded, and the program is PID 1 and receives SIGTERM from docker stop.
  • Shell form CMD node server.js runs as /bin/sh -c "node server.js". Variables are expanded, but the shell is PID 1 and may not forward signals, so the container can take the full stop timeout to shut down.

To expand variables in exec form, invoke the shell explicitly and exec the program:

CMD ["sh", "-c", "exec gunicorn --bind 0.0.0.0:\"$PORT\" app:app"]

Both forms can be overridden at run time in exactly the same way.

Overriding CMD at run time

Arguments after the image name replace the entire CMD. They are not appended to it or merged with it:

FROM python:3.12-slim
WORKDIR /app
COPY . .
CMD ["python", "app.py"]
docker run --rm myapp
# runs: python app.py

docker run --rm myapp python manage.py migrate
# runs: python manage.py migrate

docker run --rm -it myapp bash
# runs: bash (interactive shell instead of the app)

Other places that override CMD:

ToolOverrides CMDOverrides ENTRYPOINT
docker runArguments after the image name--entrypoint (also discards CMD)
Docker Composecommand:entrypoint: (also discards the image's CMD)
Kubernetesargs:command: (image CMD is ignored unless you set args:)

CMD is also inherited: if your Dockerfile has none, the base image's CMD is used. That is why FROM python:3.12-slim with no CMD starts a Python REPL.

CMD with ENTRYPOINT

When an image also has an ENTRYPOINT, CMD stops being the command and becomes the default arguments to it. Run-time arguments then replace only those defaults, not the executable:

ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]

docker run myimage runs nginx -g "daemon off;"; docker run myimage -t runs nginx -t.

The resulting command for each combination of forms:

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry (shell) ENTRYPOINT ["exec_entry", "p1_entry"] (exec)
No CMD Error: no command specified /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD ["exec_cmd", "p1_cmd"] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
  • A shell-form ENTRYPOINT ignores CMD completely.
  • A shell-form CMD under an exec-form ENTRYPOINT passes /bin/sh -c … as literal arguments. Use the exec form for both.
  • Setting ENTRYPOINT in your Dockerfile resets the CMD inherited from the base image. Write CMD after it if you want defaults.

Signal handling, --entrypoint, and entrypoint scripts that end in exec "$@" are covered in the ENTRYPOINT reference.

CMD vs RUN vs HEALTHCHECK CMD

  • RUN executes during docker build and commits the result as an image layer (installing packages, compiling code).
  • CMD executes nothing at build time. It only sets metadata for the container's default process.
  • HEALTHCHECK CMD uses CMD as a keyword to introduce a probe command, for example HEALTHCHECK CMD curl -f http://localhost/ || exit 1. The probe runs periodically inside the running container alongside the main process; it does not replace the image's CMD.

Examples

Web application

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER node
CMD ["node", "server.js"]

Calls node directly rather than npm start, so Node is PID 1 and receives SIGTERM.

Default arguments for ENTRYPOINT

FROM alpine:3.20
ENTRYPOINT ["ping", "-c", "3"]
CMD ["localhost"]

docker run pinger pings localhost; docker run pinger 1.1.1.1 replaces only the target.

Shell as the default

FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends curl jq \
 && rm -rf /var/lib/apt/lists/*
CMD ["bash"]

A toolbox image: docker run -it toolbox opens bash, docker run toolbox jq --version runs a single tool.

Notes

  • Only the last CMD takes effect. To start several processes, make the single command a script or a process manager.
  • CMD does not add a filesystem layer; it only changes image metadata.
  • Build-time ENV and ARG substitution does not apply to CMD; variables are only expanded at run time, and only by a shell.
  • Inspect the effective value with docker image inspect --format '{{json .Config.Cmd}}' myimage.

FAQ

Does docker build run the CMD instruction?

No. CMD only records the default command in the image configuration; it runs when a container starts. Commands that must run during docker build belong in RUN instructions.

How do I override CMD when running a container?

Add a command after the image name: docker run myimage python manage.py migrate. Whatever you pass replaces the whole CMD; it is not merged with it. In Compose use command:, in Kubernetes use args: (or command: if the image has no ENTRYPOINT you want to keep).

Can a Dockerfile have more than one CMD?

You can write several, but only the last CMD takes effect. To run more than one process at start-up, use a script or a process manager as the single command.

Is CMD in HEALTHCHECK the same as the CMD instruction?

No. In HEALTHCHECK CMD curl -f http://localhost/ || exit 1, CMD is a keyword that introduces the health probe command. It runs periodically inside the running container and does not change or replace the container's main CMD.

Should I use CMD or ENTRYPOINT?

Use CMD alone when users should be able to replace the whole command easily, for example docker run myimage bash. Use ENTRYPOINT for the fixed executable and CMD for its default arguments when the image wraps one program.