Interactive vs Detached Mode
Running a container is easy. Knowing how it should run — whether it should hand you a shell, sit quietly in the background, or let you pop in and out without disturbing it — is where most people get tripped up early on.
We here will walks through the flags and commands that control that behavior. By the end, you’ll know exactly which one to reach for, and why mixing them up can accidentally take down a running container.
Docker Interactive Mode
Before talking about interactive mode, let’s run a container in the default way — not interactive at all:
docker container run ubuntu echo "From Non-Interactive Mode!"You get the output:
From Non-Interactive Mode!And you immediately get your shell back. That’s non-interactive mode — you never actually get a chance to interact with the container. Docker starts the container, runs the command, prints the output, and exits. There’s no conversation happening, just a one-way instruction.
Interactive Mode
To run a container in interactive mode, you use the -i (or --interactive) flag. But flag alone isn’t enough — you also need a command that’s actually capable of being interacted with. Running echo won’t help, because echo doesn’t wait for input; it just prints and exits. So this:
docker container run -i ubuntu echo "From Non-Interactive Mode!"behaves exactly the same as before. You still get your shell back immediately.
Now, Ubuntu ships with bash, and bash does give you an interactive shell. Combine that with -i:
docker container run -i ubuntu bashThis time you’re dropped into the container’s shell:
whoami
root
hostname
859a96b954d5
exitHere I ran a couple of commands inside the container — whoami and hostname — and then exited with exit.
Important
exit or Ctrl+D gets you out of container but Docker stops your container immediately.
If you want to get out of your container without stopping it use Ctrl+P and Ctrl+Q combo instead. Docker then sends your container in background.
Interactive Mode With TTY
-i lets you interact with the container, but it doesn’t give you that “real terminal” feel — no prompt, no colors, no sense of actually being inside a shell session. For that, you pair it with the -t option, which allocates a tty (pseudo-terminal).
docker container run -it ubuntu bashNow you get a proper prompt with a nice PS1 string — notice how much more like “being inside” the container this feels, compared to plain -i:
root@ab11f6923029:/# hostname
ab11f6923029
root@ab11f6923029:/# exit
exitI ran hostname and then exited out.
What exactly is a tty?
TTY stands for teletypewriter — a term that goes back to actual mechanical typewriter terminals used to interact with early computers. Today it just refers to a text-based terminal interface. For practical purposes, you can treat tty as a synonym for terminal.
Together, -it (short for -i -t) is the combination you’ll use almost every time you want to drop into a container and work inside it interactively — think of it as your “SSH into the container” flag.
Docker Detached Mode: Sending a Container to the Background
Some containers — or commands run at container startup — hold on to your terminal for as long as they run. sleep is a good example:
docker container run ubuntu sleep 300sleep 300 running inside the container occupies your terminal for a full 300 seconds (5 minutes). Your shell is stuck until the command finishes. If you want the container to keep running in the background while you immediately get your shell back, that’s detached mode, using -d:
docker container run -d ubuntu sleep 300Running in detached mode prints the container ID instead of blocking your terminal:
69ba11a9d74efcf197d449783415c7b0d6fffc4e61db79a806937b3e501be74bYou can confirm it’s running with:
docker container lsOutput:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6d0db26291cd ubuntu "sleep 300" 8 seconds ago Up 7 seconds exciting_keldyshRunning Commands on Detached Containers
While the container is already running in the background, you can run additional commands inside it using exec. The correct syntax is docker container exec <container-id> <command>:
docker container exec 6d0db26291cd hostnameThis gives you the container’s hostname:
6d0db26291cdWhy does the hostname match the container ID?
Docker uses the container ID as the container’s hostname by default. That’s why hostname inside the container returns the same (truncated) ID you see in docker container ls.
You’ll often combine exec with -it to get an interactive shell into an already-running container, without touching its main process:
docker container exec -it 6d0db26291cd bashAttaching to Detached Containers: Bringing It Back to the Foreground
You can also bring a detached container’s main process back to the foreground with attach:
docker container attach 6d0db26291cdSince we used sleep 300 as the main process, attaching just holds your terminal until sleep finishes — because that’s literally what sleep does. If it had been an nginx container instead, you’d see live web server logs streaming in your terminal instead of dead silence.
After the 300 seconds are up:
docker container ls…shows nothing. The container has exited and no longer appears in the default (running-only) list. To see it anyway, add -a:
docker container ls -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6d0db26291cd ubuntu "sleep 300" About a minute ago Exited (0) 26 seconds ago exciting_keldyshIt confirms that container 6d0db26291cd, started with sleep 300, Exited 26 seconds ago — visible in the STATUS column.
exec vs attach: They’re Not the Same Thing
It’s easy to lump these two together since both let you “get into” a running container, but they behave very differently under the hood:
attachconnects your terminal to the container’s main process (PID 1) — the exact same process that’s already running.execstarts a brand-new process inside the container’s namespaces, alongside the main process.
flowchart LR
A["Running Container<br/>(main process, PID 1)"] --> B["docker container attach"]
A --> C["docker container exec bash"]
B --> D["Connects directly to<br/>the existing main process"]
C --> E["Spawns a new process<br/>next to the main process"]
D --> F["Ctrl+C may stop<br/>the main process"]
E --> G["Exiting the shell<br/>leaves main process untouched"]
This distinction matters more than it looks. If you attach to a container and hit Ctrl+C, you can accidentally send a termination signal to the main process and stop the container entirely — not something you want to do to a production database by accident. exec, on the other hand, gives you a disposable side-shell: you can poke around, run diagnostics, and exit without ever touching the process that’s actually keeping the container alive.
As a rule of thumb: use exec when you want to look inside a running container, and reserve attach for when you genuinely want to reconnect to the main process’s own input/output stream (for example, to see live logs or respond to a prompt the main process itself is printing).
When to Choose Interactive and Detached Mode (Real World)
Choose interactive mode (-it) when:
- You’re exploring a base image for the first time and want to poke around inside it.
- You’re debugging — installing packages, checking config files, testing commands before scripting them.
- You’re running something that genuinely expects human input, like a database CLI (
psql,mysql) or a REPL (python,node). - You’re building and testing a Dockerfile step by step, and want to confirm commands work before baking them in.
Choose detached mode (-d) when:
- You’re running a long-lived service — a web server, an API, a database, a message queue — that should keep running in the background indefinitely.
- You don’t need to babysit the process; you just need it up and reachable (via exposed ports, logs, or
exec). - You’re running this in a production-like setting, where a dropped SSH session or closed terminal shouldn’t take your container down with it.
- You want to run multiple containers side by side without dedicating a terminal tab to each one.
A simple way to remember it: interactive mode is for conversations, detached mode is for coworkers. You talk to an interactive container. A detached container just does its job quietly in another room, and you check in on it with logs, exec, or attach only when you need to.
flowchart TD
Start["Do you need to talk to the container right now?"] -->|Yes, exploring/debugging| Interactive["Use -it<br/>e.g. docker container run -it ubuntu bash"]
Start -->|No, it should run on its own| Detached["Use -d<br/>e.g. docker container run -d nginx"]
Detached --> Check{"Need to check on it later?"}
Check -->|Peek inside without risk| Exec["docker container exec -it <id> bash"]
Check -->|Reconnect to main process output| Attach["docker container attach <id>"]
Quick Reference
| Flag / Command | What it does |
|---|---|
-i | Keeps STDIN open so you can send input to the container |
-t | Allocates a pseudo-terminal (tty) for a proper prompt |
-it | Combines both — the standard flag set for interactive shells |
-d | Runs the container in the background, returns shell instantly |
docker container exec <id> <cmd> | Runs a new process inside an already-running container |
docker container attach <id> | Reconnects your terminal to the container’s main process |