It's not clear to me what are the differences between CMD and CMD-SHELL in Docker Compose healthcheck.

What are the benefits of using CMD-SHELL compared to CMD? What are the use cases for CMD and CMD-SHELL?

3 Answers 3


Docker can either run the command using CMD which is the equivalent of the OS exec syscall directly in the kernel, or it can run using CMD-SHELL which runs a shell to call your command (typically /bin/sh.)

A shell provides functionality you are accustomed to from the command line, including:

  • I/O redirection and pipes (>, >>, <, etc)
  • Command chaining (&& and ||)
  • Variable expansion ($var)

However, a shell may also intercept signals, particularly when running as pid 1, which can prevent a graceful shutdown of a container (not much of an issue for a healthcheck).

In addition, to run a the shell syntax, your container's image must include a shell, which means that won't work for images based on scratch that do not include a /bin/sh.


As per Docker Documentation

RUN has 2 forms:

  • RUN <command> (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
  • RUN ["executable", "param1", "param2"] (exec form)

The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.

Layering RUN instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image’s history, much like source control.

The exec form makes it possible to avoid shell string munging, and to RUN commands using a base image that does not contain the specified shell executable.

And the second form, exec was created for cases when there is not any shell in containers.

There is appropriate issue for healthchecks: Use CMD instead of CMD-SHELL for --healthcheck-cmd by vdemeester · Pull Request #28679 · moby/moby

Motivation for the issue is clear: Use CMD instead of CMD-SHELL for --healthcheck-cmd by vdemeester · Pull Request #28679 · moby/moby

UPD: both the issue and the PR are closed without fix.

Using CMD-SHELL will not work on any image that do not ship with a
shell (/bin/sh) and/or that do not define a default shell using
SHELL in Dockerfile.


Based on docs for healthcheck both of them are equal with a tiny difference:

  test: ["CMD", "curl", "-f", "http://localhost"]
  test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]

As you see there is no difference between them. the former form - CMD - just allow you to pass params separately.

  • 2
    Why is exit 1 not necessary in CMD version? Or is it not fully equivalent? Commented Jun 29, 2022 at 9:24
  • @PetrPřikryl thanks for comment, it is just an example. I had no intention. But TBH you mentioned a good point. I cannot test it right now. But I will do it and update the answer. Commented Jun 29, 2022 at 14:58
  • 2
    @PetrPřikryl looking at the documentation of docker-compose and interpreting what is written if you use CMD then wrapping || exit 1 is performed automatically, while cmd-shell requires you to wrap a command, Dockerfile expects healthcheck to return 0 or 1 (2 is reserved) and curl can return myriad of error codes Commented Jun 19, 2023 at 15:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.