Common docker run Flags

docker run creates and starts a container from an image, and its flags decide how that container connects to your host, stores data, receives configuration, and behaves after it exits. Learning the common flags matters because the same image can act very differently depending on the runtime settings you choose. A good docker run command is explicit about names, ports, volumes, environment, networking, cleanup, and resource limits.

Overview: How docker run Flags Work

An image is a read-only template made from filesystem layers and metadata. A container is an instance of that image with a thin writable layer, a process, environment variables, mounts, networking, and runtime settings. When you run docker run nginx:1.27-alpine, the Docker CLI sends your request to the Docker daemon. The daemon makes sure the image exists locally or pulls it, creates the container object, prepares its filesystem, attaches networking, applies flags, and starts the configured process.

Flags are not stored in the image. They are part of the container configuration created at runtime. For example, nginx:1.27-alpine may document that Nginx listens on port 80, but nothing is reachable from your host until you create a container with a port-publishing flag such as -p 8080:80. Likewise, an image may run fine without persistent storage, but a database container should usually be created with a volume so data survives container deletion.

Some flags affect the Docker daemon’s container setup before the process starts. --name assigns a stable name, -p configures host-to-container port forwarding, -v or --mount adds storage mounts, --network attaches the container to a Docker network, and --restart records a restart policy. Other flags affect the process environment, such as -e for variables, -w for working directory, -u for user, and command arguments after the image name.

On Linux, containers use kernel features such as namespaces and cgroups directly. On Docker Desktop for macOS and Windows, Linux containers run inside a managed Linux VM, so paths, bind mounts, and port forwarding cross that VM boundary. The CLI syntax is the same, but host filesystem paths and performance characteristics can differ.

Syntax

The general shape is:

docker run [OPTIONS] IMAGE[:TAG] [COMMAND] [ARG...]
Flag Purpose
--name NAME Assigns a human-friendly container name so you can use docker logs NAME, docker stop NAME, and docker rm NAME.
--rm Automatically removes the container when it exits. Useful for one-off tools and tests, not for containers whose stopped state you need to inspect.
-d Detached mode. Starts the container in the background and prints its container ID.
-it Allocates an interactive terminal. Common for shells and debugging.
-p HOST:CONTAINER Publishes a container port to a host port, such as -p 8080:80.
-e KEY=value Sets an environment variable inside the container. Quote values containing special shell characters.
-v SOURCE:TARGET Mounts a named volume or host path. Named volumes are managed by Docker; bind mounts map a specific host path.
--mount type=...,source=...,target=... Long mount syntax. More verbose, clearer, and better for scripts.
--network NAME Connects the container to a Docker network so it can reach other containers by name on that network.
--restart POLICY Controls whether Docker restarts the container after failure or daemon restart. Common values include no, on-failure, unless-stopped, and always.
--cpus and --memory Limit CPU and memory available to the container using cgroups.
--entrypoint Overrides the image entrypoint. Useful for debugging, but easy to misuse.

The image name separates Docker options from the command that runs inside the container. Flags before the image are Docker flags. Words after the image replace or extend the image’s default command.

Examples

Example 1: Run a Temporary Web Server

docker run --rm --name web-demo -p 8080:80 nginx:1.27-alpine

Output:

/docker-entrypoint.sh: Configuration complete; ready for start up

This creates a container named web-demo, publishes host port 8080 to container port 80, and removes the container when it stops. The image may include EXPOSE 80 metadata, but that metadata does not publish the port. The -p 8080:80 flag is what makes http://localhost:8080 reach Nginx.

Example 2: Run Detached and Read Logs

docker run -d --name web-bg -p 8081:80 nginx:1.27-alpine
docker logs web-bg
docker stop web-bg
docker rm web-bg

Output:

b6a8f2c2d7b4e45c0f3f8b9d0f6d8a1a9bb2a41bbd0dc58b5e6c4f0a2d7e9c11
/docker-entrypoint.sh: Configuration complete; ready for start up
web-bg
web-bg

-d starts the container in the background and prints its ID. Because this command does not use --rm, the stopped container remains until docker rm web-bg. That can be useful when you want to inspect exit status, logs, or filesystem changes after a process exits.

Example 3: Pass Configuration with Environment Variables

docker run --rm --name pg-demo \
  -e POSTGRES_DB=appdb \
  -e POSTGRES_USER=appuser \
  -e "POSTGRES_PASSWORD=changeme" \
  -p 5433:5432 \
  postgres:16-alpine

Output:

PostgreSQL init process complete; ready for start up

The -e flags become environment variables inside the container. This is common for local development images that read startup configuration from the environment. The password value is an obvious demo placeholder; real secrets should come from a secret store, mounted secret file, or orchestrator-managed secret, not from copied notes, image layers, or shell history.

Example 4: Persist Database Data with a Named Volume

docker volume create pgdata-demo
docker run -d --name pg-persist \
  -e POSTGRES_DB=appdb \
  -e POSTGRES_USER=appuser \
  -e "POSTGRES_PASSWORD=changeme" \
  -v pgdata-demo:/var/lib/postgresql/data \
  postgres:16-alpine
docker stop pg-persist
docker rm pg-persist

Output:

pgdata-demo
f4d35c6cb535e55b8a65f48284a5538e8f42acb8428fa7b0ec2639f28d0bb57d
pg-persist
pg-persist

A named volume is managed by Docker and lives outside the container’s writable layer. Removing pg-persist deletes the container, but it does not delete pgdata-demo. That is why volumes are the usual default for persistent application data. A bind mount, by contrast, maps a specific host path into the container and is often used for local source-code editing.

Example 5: Put Containers on a User-Defined Network

docker network create demo-net
docker run -d --name redis-cache --network demo-net redis:7.2-alpine
docker run --rm --network demo-net redis:7.2-alpine redis-cli -h redis-cache ping
docker stop redis-cache
docker rm redis-cache
docker network rm demo-net

Output:

demo-net
9e0a7c9f1c3f2e8b6a4d5c7b0e2f4a6c8d1e3f5a7b9c0d2e4f6a8b1c3d5e7f9
PONG
redis-cache
redis-cache
demo-net

Containers on the same user-defined bridge network can resolve each other by container name. The second Redis image runs redis-cli instead of the image’s default server command because the words after the image name replace the default command. This is a clean way to run a temporary client container near a service container.

How It Works Step by Step

  1. The CLI parses flags before the image name and sends a container-create request to the Docker daemon.
  2. The daemon checks whether the image exists locally. If it is missing, Docker pulls the image manifest, configuration, and missing layers from a registry.
  3. Docker creates a container object with the chosen name, environment variables, command, restart policy, resource limits, mounts, and network attachments.
  4. The storage driver mounts the image’s read-only layers and adds a thin writable container layer. Writes inside the container go there unless a path is covered by a volume or bind mount.
  5. Docker configures networking. With -p, it creates host-to-container port forwarding. Without -p, the container may still listen internally, but the host port is not published.
  6. The daemon starts the container’s process. In foreground mode, your terminal attaches to output; in detached mode, Docker prints the container ID and returns control.
  7. When the process exits, the container becomes stopped. With --rm, Docker removes the container automatically. Without it, logs, exit status, and the writable layer remain until removal.

Common Mistakes

Putting Docker Flags After the Image

docker run nginx:1.27-alpine -p 8080:80

This is wrong because -p 8080:80 appears after the image name, so Docker passes it to the command inside the container instead of treating it as a Docker port flag. Put Docker flags before the image:

docker run --rm -p 8080:80 nginx:1.27-alpine

Forgetting That EXPOSE Does Not Publish Ports

docker run --rm nginx:1.27-alpine

Nginx listens on port 80 inside the container, but the host cannot reach it unless you publish a port. Fix it with -p:

docker run --rm -p 8080:80 nginx:1.27-alpine

Losing Data by Skipping a Volume

docker run --rm \
  -e "POSTGRES_PASSWORD=changeme" \
  postgres:16-alpine

With --rm and no volume, the container and its writable layer disappear when it stops. For a database, mount a named volume at the image’s data directory:

docker run -d --name pg-safe \
  -e "POSTGRES_PASSWORD=changeme" \
  -v pgdata-demo:/var/lib/postgresql/data \
  postgres:16-alpine

Using latest for Long-Lived Containers

docker run -d --name app nginx:latest

The latest tag is a moving label, not a stability guarantee. Long-lived services should use a tested specific tag, and production systems often pin digests through a release process:

docker run -d --name app nginx:1.27-alpine

Best Practices

  • Put all Docker runtime flags before the image name.
  • Use --name for containers you will inspect, stop, restart, or connect to from other containers.
  • Use --rm for one-off commands, test runs, and temporary clients.
  • Use -d for services you want to keep running in the background, then use docker logs and docker stop to manage them.
  • Publish only the ports you need with -p HOST:CONTAINER. Do not rely on EXPOSE to make a service reachable.
  • Use named volumes for persistent data and bind mounts for local development source files.
  • Quote environment variable values that contain spaces, angle brackets, dollar signs, or other shell-sensitive characters.
  • Prefer user-defined networks for multi-container local setups so containers can reach each other by name.
  • Set memory or CPU limits for experiments that could consume the whole host, such as --memory 512m or --cpus 1.0.
  • Use specific image tags, not implicit latest, for repeatable work.

Practice Exercises

  1. Run nginx:1.27-alpine in detached mode with the name practice-web and publish it on host port 8090. Expected end state: docker ps shows the name and port mapping.
  2. Create a named volume for a PostgreSQL test container. Start the container with a placeholder password and mount the volume at the PostgreSQL data directory. Hint: the image’s data path is /var/lib/postgresql/data.
  3. Create a user-defined network, start a Redis container on it, then run a temporary Redis client container on the same network. Expected end state: the client can reach the server by container name.

Summary

  • docker run creates and starts a container from an image.
  • Runtime flags control container behavior; they do not modify the image itself.
  • --name, --rm, -d, -it, -p, -e, -v, --mount, --network, and --restart cover most daily container runs.
  • Ports are reachable from the host only when published with -p or Compose ports:.
  • Container writable layers are disposable; use volumes or bind mounts for data you need to keep.
  • Words after the image name are the command and arguments run inside the container.
  • Use explicit image tags and clear runtime settings so containers are predictable and easy to debug.