Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions content/manuals/compose/how-tos/lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
title: Using lifecycle hooks with Compose
linkTitle: Use lifecycle hooks
weight: 20
description: Learn how to use Docker Compose lifecycle hooks like post_start and pre_stop to customize container behavior.
keywords: docker compose lifecycle hooks, post_start, pre_stop, docker compose entrypoint, docker container stop hooks, compose hook commands
description: Learn how to use Docker Compose lifecycle hooks like pre_start, post_start, and pre_stop to customize container behavior.
keywords: docker compose lifecycle hooks, post_start, pre_stop, pre_start, docker compose entrypoint, docker container stop hooks, compose hook commands
---

{{< summary-bar feature_name="Compose lifecycle hooks" >}}
Expand All @@ -22,6 +22,35 @@ Lifecycle hooks are particularly useful because they can have special privileges
for security. This means that certain tasks requiring higher permissions can be done without
compromising the overall security of the container.

### Pre-start hooks

Pre-start hooks let you run init containers that must complete successfully before your service starts - database migrations, volume permission fixes, or configuration seeding. Unlike [`post_start`](#post-start-hooks) and [`pre_stop`](#pre-stop-hooks), each `pre_start` step runs in its own ephemeral container before the service container starts. Hooks run once for the service as a whole, not per replica, and won't re-run when you add more replicas of the service.
Comment thread
aevesdocker marked this conversation as resolved.

A `pre_start` step is skipped on subsequent `docker compose up` runs if it previously succeeded and its definition hasn't changed, but reruns if the definition changes, the previous run failed, or the service is recreated.

In the following example, two steps run in order before the application starts: database migrations using the service's own image, then a `busybox` container to fix volume ownership.

```yaml
services:
app:
image: myapp:latest
depends_on:
db:
condition: service_healthy
pre_start:
- command: ["./manage.py", "migrate"]
- image: busybox
command: sh -c 'chown -R 1000:1000 /data'
volumes:
- data:/data

db:
image: postgres:16

volumes:
data:
```

### Post-start hooks

Post-start hooks are commands that run after the container has started, but there's no
Expand Down Expand Up @@ -72,5 +101,6 @@ volumes:

## Reference information

- [`pre_start`](/reference/compose-file/services.md#pre_start)
- [`post_start`](/reference/compose-file/services.md#post_start)
- [`pre_stop`](/reference/compose-file/services.md#pre_stop)
41 changes: 41 additions & 0 deletions content/reference/compose-file/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -1752,6 +1752,47 @@ services:

For more information, see [Use lifecycle hooks](/manuals/compose/how-tos/lifecycle.md).

### pre_start

_Todo: Add Compose version_

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[HIGH] Unresolved TODO placeholder left in published reference documentation

The new pre_start section contains _Todo: Add Compose version_ as its second line. This internal reminder will be rendered as italic text on the published docs site and is visible to all users. The minimum Compose version that supports pre_start should be determined and documented before merging.


`pre_start` defines a sequence of init containers to run before the service container is started. Each step runs to completion, in declared order, and the service container only starts once every step has exited `0`. A non-zero exit fails the bring-up of the service and its dependents.

Unlike `post_start` and `pre_stop`, which run a command inside the running service container, each `pre_start` step runs in its own ephemeral container, created after the service container is created but before it is started. Possible values are:

- `command`: The command to run. Optional when the chosen image's entrypoint already runs the intended command.
- `image`: The image used for the ephemeral container. If omitted, the parent service's image is used.
- `user`: The user to run the command. If not set, defaults to the user declared in `image` (or to the main service command's user when `image` is omitted).
- `privileged`: Lets the `pre_start` command run with privileged access.
- `working_dir`: The working directory in which to run the command. If not set, it is run in the same working directory as the main service command.
- `environment`: Sets the environment variables to run the `pre_start` command. The command inherits the `environment` set for the service's main command, and this section lets you append or override values.
- `per_replica: false`: Whether the hook runs once for the service as a whole before any replica starts.

A `pre_start` container joins the same networks as the service, so it can reach services declared in `depends_on`, and shares the service's declared volume mounts so files it produces in a shared volume are visible to the service. With `per_replica: false` and a scaled service, only mounts that are shared across replicas (named volumes, bind mounts) are usable. Per-instance mounts (`tmpfs`, anonymous volumes) cannot be addressed by a single run.

A `pre_start` step that has already succeeded for its current definition is not re-run on a subsequent `up`, nor when the service container restarts under its `restart` policy. A step runs again when its definition changes, when the previous run did not succeed, or when the service is recreated.

```yaml
services:
app:
image: myapp:latest
depends_on:
db:
condition: service_healthy
pre_start:
- command: ["./manage.py", "migrate"]
- image: busybox
command: sh -c 'chown -R 1000:1000 /data'
volumes:
- data:/data

db:
image: postgres:16

volumes:
data:
```

### `pre_stop`

{{< summary-bar feature_name="Compose pre stop" >}}
Expand Down