CMD in Dockerfile: Setting the default command that runs when no command is provided

CMD in Dockerfile defines the default command that runs when a container starts. It helps ensure predictable behavior, especially in production. Compare CMD with ENTRYPOINT and note how docker run can override CMD for flexibility in real-world projects. It also helps teams ship reliable apps faster.

What CMD really does in a Dockerfile (and why it matters)

If you’ve poked around a Dockerfile, you’ve probably bumped into CMD at least once. It’s one of those lines that sounds simple on the surface, but it quietly governs how your container behaves when you press “run” without adding extra instructions. Think of CMD as the default setting you’d get if you start a container with no extra arguments. It’s the soft landing, the sensible starting point, the fallback option that keeps things predictable.

So, what is the purpose of the CMD directive?

Here’s the thing: CMD defines the default command that runs when no command is specified. In plain terms, if you build an image and then run a container from it without giving a command, Docker will execute whatever you put in CMD by default. That’s incredibly handy because it gives you a sane, working baseline. You don’t have to specify a command every time—unless you want to, of course.

A simple analogy helps. Imagine you’re hosting a small party and you set out a default playlist. If guests don’t request something different, the music keeps going. CMD is that playlist for your container. You don’t have to micromanage every moment, but you can hand someone the mic and override the track if you want to hear something else.

CMD, ENV, and ENTRYPOINT: how they fit together

To truly grasp CMD, you should see it alongside a couple of other Dockerfile directives.

  • ENV sets environment variables. These are like settings you want available to your app at runtime. CMD doesn’t set variables; it tells the container what command to run.

  • ENTRYPOINT defines the main executable for the container. If you want your container to run a specific program no matter what, you use ENTRYPOINT. CMD then supplies default arguments to that program.

  • The filesystem and initial state of the container come from the base image plus any RUN, COPY, or ADD commands you’ve declared. CMD doesn’t touch the filesystem directly; it tells Docker what to run when the container starts.

So, CMD is the command you want to run by default, while ENTRYPOINT is the thing that actually runs (and CMD can provide the default arguments to that thing). If you imagine a movie projector, ENTRYPOINT is the projector itself and CMD is the default reel you load into it. You can swap in a different reel easily, but the projector (the entrypoint) stays the same.

Exec form vs shell form: two ways to write CMD

There are two ways to express CMD, and they behave a little differently in practice.

  • Exec form: CMD ["executable", "param1", "param2"]

This is the preferred form for most Dockerfiles. It runs the command directly, without invoking a shell. It’s cleaner and avoids shell quirks. It also makes signals and PID 1 handling more predictable inside the container.

  • Shell form: CMD command param1 param2

This looks like a shell command because Docker runs it through /bin/sh -c. It’s convenient for chaining commands or using shell features, but it can introduce shell-specific quirks and makes signal handling a bit more indirect.

Here’s the important bit: if you pair CMD with ENTRYPOINT, CMD supplies default arguments to the ENTRYPOINT command. If there’s no ENTRYPOINT, CMD becomes the command that runs by default. That interplay is where the real control happens. It’s like having a main actor (ENTRYPOINT) and a default line they usually deliver (CMD), but you can hand the actor fresh lines when you want to.

Real-world examples you can actually use

Let’s ground this with a couple of tiny, practical examples.

  • A minimal image that prints a message by default:

FROM alpine:3.18

CMD ["echo", "Hello from CMD"]

Build and run. If you don’t pass anything to docker run, you’ll see Hello from CMD. If you decide to override, you can: docker run yourimage echo "Hi there!"

  • A Web app with a default script:

FROM node:18

WORKDIR /app

COPY . .

RUN npm install

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

Here, the container will start the Node server by default. If you want to run a quick one-off task instead, you can override with docker run yourimage npm test, for example.

  • CMD with ENTRYPOINT for sensible defaults:

FROM python:3.11

COPY app.py /

ENTRYPOINT ["python", "/app.py"]

CMD ["--help"]

In this setup, the container will always run python /app.py by default, but if you pass arguments, those arguments feed into the Python script as default arguments rather than replacing the executable.

Why you might choose to override CMD at runtime

There’s freedom baked into CMD. If you spin up a container and say, “Give me something a little different today,” you can override the default command with docker run args. It’s a practical feature that makes containers versatile without rewriting the image each time.

For example, with the simple CMD that prints a message, docker run yourimage echo "Fresh take" overrides the default and prints something new. Or, with an app that starts a server, you could use docker run yourimage npm run dev to launch a development variant. The key is that CMD provides a sensible, ready-to-go start, but it’s not a prison sentence—you can bend it when you need to.

Common misunderstandings (and how CMD actually behaves)

A few myths tend to float around, especially for folks who are new to containers. Let me debunk a couple quickly:

  • CMD only sets environment variables, right? Not true. CMD sets the default command to run, not environment variables. ENV handles environment variables.

  • CMD and ENTRYPOINT are the same thing? Not at all. ENTRYPOINT defines the main command; CMD supplies defaults or, if there’s no ENTRYPOINT, the command to run. They’re siblings that play different roles.

  • CMD creates the filesystem? No. The filesystem is created by the base image and modifications from RUN, COPY, or ADD. CMD is about what you run when the container starts.

A few practical tips to keep CMD clear in your Dockerfiles

  • Start with a clear default. If your container often runs the same thing, CMD is a neat way to communicate that intent right from the image level.

  • Use exec form for clarity and reliability. It avoids shell quirks and makes signal handling smoother.

  • Pair CMD with ENTRYPOINT when you have a fixed entry process but want flexible arguments. This gives you a predictable default plus the option to override.

  • Reserve CMD for the short, default action. If your startup logic gets long or complex, consider moving some of that logic into scripts that the CMD line can invoke.

A quick mental model to keep CMD straight

  • CMD = default command to run if no command is given

  • ENTRYPOINT = the main command that will always run (you can pass extra arguments to it via CMD)

  • ENV = variables your app can read at runtime

  • The image’s filesystem = everything defined by the base image and your RUN/COPY/ADD commands

If you’re ever unsure, try a tiny experiment. Build a couple of images with the same base but different CMD instructions. Run them with and without arguments. You’ll see how the default behavior shifts and how easy it is to override when you want something different. It’s a small, hands-on way to internalize the concept without pulling you into a labyrinth of edge cases.

A few digressions you might appreciate (and why they matter)

  • Why strings and spaces matter in CMD. The exec form is strict and predictable. The shell form can be handy when you want shell features, but you’ll trade some predictability for convenience. If you’re aiming for reliability in production-like environments, favor the exec form.

  • The upgrade path. If you’re tinkering with base images, you’ll notice how CMD interacts with the image’s lifecycle. It’s not just a line in a file—it’s part of how the container responds when it wakes up. That small behavioral nuance can influence debugging and deployment strategies.

  • Real-world tooling love. Tools like Docker Compose rely on CMD (and ENTRYPOINT) to define how services start in a multi-container setup. When you see a docker-compose.yml that launches a web service and passes arguments, you’re witnessing CMD in action across an orchestration layer.

Bringing it all together

CMD is a simple line with a surprisingly big impact. It gives you a sensible default behavior for every container you build, while still letting you override that behavior on a whim. It’s not the star of the show—that honor belongs to the entry point or the image’s core startup routine—but it’s a reliable supporting actor that keeps things predictable and practical.

If you’ve been wrestling with how to structure a Dockerfile for everyday use, think of CMD as the keeper of sensible defaults. It’s the quiet promise that your container will behave as expected when no one supplies a command at run-time. And when you do want a different path, you have the flexibility to steer the ship with a simple override.

In the end, it’s all about balance: a default that’s useful, not rigid; a command that’s easy to replace, not a trap you can’t escape. That balance is what makes Docker containers such a practical, friendly tool for modern software delivery. And CMD, tucked neatly in the Dockerfile, is the quiet lever that helps you maintain that balance every time you build and run.

Subscribe

Get the latest from Examzify

You can unsubscribe at any time. Read our privacy policy