What Docker Commands Do You Reach For Most as a Developer?

Docker commands — Chunky Munster

Most developers keep reaching for the same Docker commands: build an image, run a container, inspect what’s alive, read the logs, jump into a shell, and clean up the wreckage. The skill is not memorising every flag; it’s knowing the small set that covers 90% of day-to-day container work. If you want to move faster without typo roulette, try our free Docker command generator.

The commands that show up in real workflows

When people say they “use Docker,” they usually mean a loop of a few commands repeated in different orders. Build the image with docker build, start it with docker run, check status with docker ps, and inspect failures with docker logs. That’s the core loop, whether you’re building a local API, a worker, or a throwaway test environment.

The useful part is consistency. If your app always listens on the same port, always uses the same image tag, and always exposes the same environment variables, the commands stay short and boring. Boring is good here.

A common starter set looks like this:

docker build -t my-api:dev .
docker run -d --name my-api-dev -p 3000:3000 my-api:dev
docker ps
docker logs my-api-dev

That gets you from source code to a running container and gives you the first line of debugging when something goes sideways.

Build, run, inspect, repeat

docker build turns a Dockerfile into an image. The image is the packaged artifact; the container is the running instance. If you rebuild often, use tags that mean something, like my-api:dev or my-api:1.4.2, instead of vague names like latest that make debugging annoying later.

docker run starts a container from an image, and that’s where most flags matter. You’ll commonly use -d for detached mode, --name to give the container a stable label, -p to map ports, and -e to pass environment variables. Example:

docker run -d \
  --name postgres-dev \
  -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 \
  postgres:16

docker ps shows running containers. Add -a if you need stopped ones too. That small distinction matters when a container exits instantly and you assume it never started.

If you want a broader refresher on command syntax habits in general, our guide on the Git commands developers actually use every day covers the same idea from another angle: fewer commands, used well, beat a giant cheat sheet nobody remembers.

Debugging the container, not your laptop

When a bug only appears inside the container, the fastest move is usually docker exec -it. It drops you into the running container so you can inspect files, environment variables, installed packages, and runtime state in the same sandbox your app is using. That avoids the classic trap of debugging your host machine while the real problem lives in the image.

A typical debug session might look like this:

docker exec -it my-api-dev sh
# or, if bash exists:
docker exec -it my-api-dev bash

From there, you can check whether config files exist, whether the app can reach its dependencies, and whether the filesystem looks the way you expect. In Alpine-based images, sh is often available; bash may not be. That’s not a bug, just container minimalism doing its thing.

For crash loops, combine docker logs with docker inspect. Logs tell you what happened; inspect tells you how the container was configured. If the app dies before binding a port, logs are usually first. If the app starts but can’t reach a database, inspect often reveals a missing env var or wrong network setting.

Day-to-day cleanup without turning your machine into a landfill

Containers and images pile up fast, especially if you rebuild often. The cleanup commands are the ones people forget until disk space starts barking. docker stop halts a running container, docker rm removes the container, and docker rmi removes an image if nothing depends on it.

There’s a practical order to this. Stop the container first, remove the container second, and only then remove the image if you no longer need it. If you skip the stop step, Docker will complain because you’re trying to delete something that’s still active.

Example:

docker stop my-api-dev
docker rm my-api-dev
docker rmi my-api:dev

For bigger cleanup jobs, you may reach for pruning commands, but use them with care. They’re efficient, and they’re also blunt instruments. Great when you know exactly what you want gone, less great when you’ve got a half-finished experiment tucked away somewhere.

Ports, volumes, and environment variables are where the real pain lives

The most-used Docker commands are simple, but the flags around them decide whether your setup is smooth or cursed. Port mappings with -p host:container are the first place people get tripped up. If your app listens on port 3000 inside the container, you still need to map it to a host port if you want to hit it from the browser.

Volumes are the next common moving part. Mounting source code into a container with -v lets you edit locally and have the container see the changes immediately. That’s handy for dev loops, but it also means the filesystem inside the container is no longer a sealed little universe.

Environment variables are the other usual suspect. Pass them with -e or via an env file if the list gets long. If you’re debugging configuration issues, print them inside the container and compare them to what you thought you passed in. Containers are very literal and extremely unromantic about your assumptions.

Make the commands shorter, not the debugging harder

There’s a point where everyone starts aliasing command fragments or wrapping them in scripts. That’s usually a good sign, as long as the script is still readable six months later. If you repeatedly type the same image name, port mapping, and env vars, the command generator can save you from rebuilding the same wall of flags by hand.

The goal isn’t to avoid learning Docker. The goal is to stop wasting attention on syntax you already understand. A clean command beats a clever one, and a generated command beats a typo in the middle of a 40-minute debugging session.

When you’re setting up local services, the pattern is often stable enough to automate mentally: build, run, inspect, exec, stop, remove. Once that cycle is familiar, Docker stops feeling like a command jungle and starts feeling like a small, sharp toolkit.

A Worked Example

Here’s a realistic dev loop for a Node API that talks to PostgreSQL. You want the API in one container, the database in another, and a shell into the API when the health check fails. The commands below show the before and after of doing it the hard way versus a cleaner repeatable setup.

# before: ad hoc and easy to forget

docker build -t api .
docker run -d -p 3000:3000 api

docker logs hopeful_stallman

docker exec -it hopeful_stallman sh

# after: named, debuggable, reusable

docker build -t api:dev .

docker run -d \
  --name api-dev \
  -p 3000:3000 \
  -e NODE_ENV=development \
  -e DATABASE_URL=postgres://postgres:secret@db:5432/app \
  api:dev

docker ps
docker logs api-dev
docker exec -it api-dev sh

docker stop api-dev
docker rm api-dev

The second version is better because every object has a name and every step is easy to reverse. If the container crashes, you know what to inspect. If you need to restart it, you don’t have to guess which anonymous container is the right one.

This is the pattern worth copying: keep names stable, map ports explicitly, pass env vars intentionally, and always leave yourself a clean exit. That makes Docker feel less like a black box and more like a controlled environment.

Frequently Asked Questions

What Docker command do I use most often?

For most developers, the top three are docker build, docker run, and docker logs. Those cover image creation, container startup, and first-pass debugging. After that, docker ps and docker exec -it tend to show up constantly.

What is the difference between a Docker image and a container?

An image is the packaged template; a container is a running instance of that image. Think of the image as the blueprint and the container as the actual building. You can run many containers from one image, each with its own state.

Why does my Docker container exit immediately?

Usually the main process inside the container finishes or crashes. Check docker logs <name> first, then use docker ps -a to confirm whether it stopped. If the container needs a long-running foreground process, make sure your image starts one.

How do I get a shell inside a running container?

Use docker exec -it <container> sh or bash if it exists in the image. This is the fastest way to inspect files, environment variables, and runtime state. If neither shell exists, the image is probably stripped down and you may need a different debugging approach.

The Bottom Line

The Docker commands most developers reach for are the ones that keep the feedback loop short: build, run, inspect, debug, and clean up. Once you know those by muscle memory, the rest is mostly flags and container hygiene. The win is not memorising the whole CLI; it’s reducing friction when you need to ship, debug, or reset a broken local environment.

If you’re tired of retyping long command lines or second-guessing flag order, use the Docker command generator and let the boring parts handle themselves. Then spend your attention on the thing that actually matters: why the container is failing in the first place.

// try the tool
try our free Docker command generator →
// related reading
← all posts