Docker Compose Lifecycle
Once you have a Compose file, the next question is simple: what happens to the application over time? Compose gives you commands to create, start, stop, restart, and remove the resources described by that file.
Understanding this lifecycle is important because up, stop, and down do different things. They are not interchangeable.
The Compose Lifecycle
Let’s use a small application with two services so the lifecycle is easier to see.
Create a directory:
mkdir compose-lifecycle
cd compose-lifecycleCreate compose.yaml:
services:
first:
image: alpine
command: ["sleep", "infinity"]
second:
image: alpine
command: ["sleep", "infinity"]Both services use the alpine image, but the containers stay running because their main process is sleep.
The application now looks like this:
Compose project
│
├── first service
│ └── container
│
└── second service
└── containerdocker compose up
Start the application:
docker compose upCompose reads compose.yaml, creates the required containers, and starts them.
You’ll see Compose attach to the containers’ output.
Because the containers are running continuously, the command remains attached to them.
You can stop the attached output with:
Ctrl+CThis is an important distinction:
Stopping the command’s attached output is not the same thing as removing the application.
The containers can still exist after you leave the attached view.
You can start the application in the background with:
docker compose up -dThe -d option means Compose starts the application in detached mode.
Conceptually:
docker compose up
│
▼
Read compose.yaml
│
▼
Create required resources
│
▼
Start services
│
▼
Application is runningWith -d, your terminal is returned to you while the application continues running.
docker compose stop
Now stop the running services:
docker compose stopThis stops the containers, but it does not remove them.
Think of stop as:
“Pause the running application, but keep its containers.”
The state becomes:
Compose project
│
├── first service
│ └── stopped container
│
└── second service
└── stopped containerThe containers still exist.
This is useful when you temporarily don’t need the application running but expect to start it again.
docker compose start
Because the containers still exist, you can start them again:
docker compose startCompose starts the existing stopped containers.
The lifecycle now looks like:
up
│
▼
running
│
▼
stop
│
▼
stopped
│
▼
start
│
▼
runningNotice what happened here.
stop did not destroy the containers.
start did not create new containers.
It simply started the existing ones again.
That’s the key difference between stop and down.
docker compose down
Now take the application down:
docker compose downUnlike stop, down removes the containers created for the Compose application.
Conceptually:
running application
│
▼
docker compose down
│
▼
Compose resources removedAfter down, the containers no longer exist.
So you cannot use:
docker compose startto bring those same containers back.
Instead, use:
docker compose up -dCompose will create what is needed from the configuration again.
Tip
docker compose down does not remove volumes if any are configured. This is meaningful because you want the volume as part of persistent storage, and Compose respects that. But if you want to remove volumes too, you obviously can:
docker compose down --volumesstop vs down
This is one of the most important distinctions in Compose.
| Command | Containers | Typical purpose |
|---|---|---|
docker compose up | Creates if needed, then starts | Bring the application up |
docker compose stop | Keeps them, but stops them | Temporarily stop |
docker compose start | Starts existing containers | Resume a stopped application |
docker compose down | Removes Compose-managed containers | Tear the application down |
A simple mental model is:
docker compose up
│
▼
┌─────────┐
│ RUNNING │
└────┬────┘
│
docker compose stop
│
▼
┌─────────┐
│ STOPPED │
└────┬────┘
│
docker compose start
│
└──────────────► RUNNING
RUNNING / STOPPED
│
docker compose down
│
▼
CONTAINERS
REMOVEDThe important idea is:
stopchanges the running state.downremoves the application resources.
What Happens When You Run up Again?
Suppose you have already run:
docker compose up -dand the application is running.
If you run:
docker compose up -dagain, Compose does not simply create a second copy of every container.
It examines the current configuration and the resources associated with the project.
This is another benefit of declarative configuration:
You describe the desired application, and Compose works to bring the Docker resources into that state.
For a simple unchanged configuration, running up again does not mean “make another application.”
What Happens If You Change the Compose File?
Now make a small change.
Change the second service:
services:
first:
image: alpine
command: ["sleep", "infinity"]
second:
image: alpine
command: ["sleep", "infinity"]
environment:
APP\_MODE: demoThen run:
docker compose up -dCompose notices that the service configuration has changed and updates the affected container as necessary.
This is an important reason to keep configuration in the Compose file.
You change the desired configuration, then ask Compose to bring the application to that state.
You don’t need to manually remember every Docker command required to recreate the changed resource.
up is more than “start”
A common beginner mistake is to think:
docker compose upmeans exactly:
start existing containersThat’s not quite right.
up means roughly:
“Make the application described by this Compose file running.”
That can involve creating containers that don’t exist, starting existing containers, and recreating resources when their configuration needs to change.
By contrast:
docker compose starthas a much narrower meaning:
“Start existing stopped containers.”
This distinction becomes very useful as your Compose projects become more complex.
A Practical Lifecycle
Imagine you are developing an application.
In the morning, you bring it up:
docker compose up -dYou work with it for a while.
When you’re taking a break, you might stop it:
docker compose stopLater, you resume:
docker compose startAt the end of the day, you might decide to completely remove the Compose application’s containers:
docker compose downThe next day:
docker compose up -dCompose recreates what is necessary from compose.yaml.
This gives you a useful workflow:
stateDiagram-v2
direction LR
[*] --> Absent
Absent --> Running: up -d
state Running {
[*] --> RunningState
RunningState --> RunningState: restart
}
Running --> Stopped: stop
Stopped --> Running: start
Stopped --> Running: up -d
Running --> Paused: pause
Paused --> Running: unpause
Running --> Removed: down
Stopped --> Removed: down
Removed --> [*]
- Absent → No container exists.
up -d/up→ Create + start → Running.- Running →
stop→ Stopped. - Stopped →
start/up -d/up→ Running. - Running →
pause→ Paused →unpause→ Running. - Running →
restart→ Running. - Running / Stopped →
down→ Removed. - Removed → Container no longer exists.
Warning
One useful distinction using up after Stopped is that now Compose will start new container. If you use start than the same container is started. This is a useful distinction because you may lose data associated with the old container.
restart is different from stop + start
Compose also provides:
docker compose restartThis restarts the services.
Conceptually:
RUNNING
│
▼
restart
│
▼
RUNNINGThe containers are not being intentionally removed as part of this operation.
You can think of it as useful when a service needs to be restarted but you don’t want to tear down the Compose application.
For example:
docker compose restart firstrestarts only the first service.
Or:
docker compose restartrestarts the services in the Compose application.
The important point is that restart is about restarting existing services, while down is about tearing down the application’s resources.
up, start, stop, restart, and down
It helps to compare all five together:
| Command | Main idea |
|---|---|
docker compose up | Create/update as needed and start |
docker compose start | Start existing stopped containers |
docker compose stop | Stop running containers without removing them |
docker compose restart | Restart existing services |
docker compose down | Stop and remove the Compose application’s containers and associated default resources |
The most important pair to remember is:
stop → keep containers
down → remove containersAnd the most important distinction for starting is:
start → existing containers
up → make the configured application runningWhat About Networks and Volumes?
This is where the lifecycle becomes especially interesting.
A Compose application can contain more than containers.
It can also define:
services
networks
volumesSome of those resources have different lifecycle behavior.
For example, if you define a named volume for a database, you generally do not want a normal application shutdown to destroy the database’s data.
That is why understanding the difference between:
docker compose stopand:
docker compose downbecomes important.
The exact behavior of networks and volumes will become much clearer when you define them explicitly in the upcoming lessons.
For now, remember that containers are not the only resources involved in a Compose application.
A Useful Mental Model
Think of the Compose lifecycle as three levels:
CONFIGURATION
compose.yaml
│
│ describes
▼
APPLICATION
│
┌─────────┴─────────┐
│ │
running stopped
│ │
└─────────┬─────────┘
│
down
│
▼
RESOURCES
removedThe Compose file is the source of the desired configuration.
up brings the application into that desired running state.
stop temporarily changes the running state.
start resumes existing stopped containers.
restart restarts services.
down tears down the application resources managed by Compose.
Once you have this model in your head, the commands stop feeling like a collection of unrelated commands.
Hands-on Cleanup
If your example is still running, bring it down:
docker compose downThen return to the parent directory:
cd ..If you no longer need the example directory, remove it on Linux/macOS with:
rm -rf compose-lifecycleWarning
rm -rf permanently removes the specified directory and its contents. Make sure you are in the correct parent directory and have the correct directory name before running it.
What You Should Remember?
The Compose lifecycle is mainly about understanding what happens to the resources behind your application:
docker compose up
↓
create/update + start
↓
running
│
├── stop → stopped
│ │
│ start
│ │
│ └──→ running
│
├── restart → running
│
└── down → resources removedIf you remember only two distinctions from this lesson, remember these:
stop keeps the containers; down removes them.
start starts existing containers; up makes the Compose application match its configuration and run.
In the next lesson, you’ll connect this lifecycle to one of the most important parts of a multi-container application: networking.