4.2.6.3 CMD Exec Form
A focused guide to CMD Exec Form, connecting core concepts with practical Docker and container operations.
The CMD exec form writes the default command as a JSON array of strings, causing it to be executed directly as the container's main process without an intermediary shell, which is generally the preferred way to write CMD for application startup commands.
Syntax of the Exec Form
The exec form lists the command and each of its arguments as separate elements of a JSON array.
CMD ["python", "app.py", "--port", "8080"]
This is executed directly, with python becoming the container's actual main process (PID 1 within its namespace), rather than being run by an intermediate shell.
Why Direct Execution Matters for Signal Handling
Because the specified command becomes the container's actual main process, it directly receives signals like SIGTERM when the container is asked to stop, allowing the application to handle shutdown gracefully if it is written to do so.
docker stop myapp
This sends SIGTERM directly to the application process when using exec form, giving it the opportunity to clean up before exiting.
No Shell Features Available
Because there is no shell involved, shell-specific features like environment variable expansion ($VAR), command chaining (&&), or output redirection (>) are not available within the exec form's arguments — each element is passed literally to the executed program.
CMD ["echo", "$HOME"]
This prints the literal string $HOME rather than the value of the HOME environment variable, since there is no shell present to perform that substitution.
When Shell Features Are Genuinely Needed
If shell features are actually required, the shell form remains available, or the exec form can explicitly invoke a shell itself as the first element, making the shell's involvement explicit rather than implicit.
CMD ["sh", "-c", "echo $HOME"]
Why the Exec Form Is Generally Preferred
For typical application startup commands, the exec form's direct process execution and correct signal handling make it the recommended default, with the shell form reserved specifically for cases that genuinely need shell features like variable expansion or command chaining within the startup command itself.