# Run lifecycle hooks

Run bounded migrations and post-deployment automation as part of an apply.

Canonical: https://docs.deliberate.space/build/lifecycle-hooks/

Lifecycle hooks let a Component run one bounded command before or after a
deployment. Use them for work that belongs to a specific application revision,
such as applying database migrations or warming a cache.

They are deliberately not a general workflow engine. A Component has two
ordered hook points:

```text
release → deploy → ready → postDeploy
```

## Run work before deployment

Use `release` when the new Component revision must not deploy unless a command
succeeds:

```yaml
resource: component
name: api
image: registry.deliberate.cloud/acme/api:1.8.0
env:
  DATABASE_URL: "${{ postgres.url }}"
needs:
  databases:
    - postgres
release:
  command: ["./api", "migrate"]
  timeout: 10m
```

deliberate. runs the command before updating the Component. A non-zero exit or
timeout fails the apply and leaves the currently deployed revision serving
traffic. Run `deliberate apply` again after correcting the problem; the failed
hook is retried and its logs appear in the apply output.

This is the appropriate hook for database migrations that must complete before
new application code starts.

## Run work after the Component is ready

Use `postDeploy` for automation that needs the new revision to be available
first:

```yaml
resource: component
name: api
image: registry.deliberate.cloud/acme/api:1.8.0
postDeploy:
  command: ["./api", "warm-cache"]
  timeout: 5m
```

The platform deploys the Component, waits for it to become ready, and then runs
the command. A failed `postDeploy` fails the apply, but the new Component is
already deployed and may already be serving traffic. deliberate. does not roll
it back or hide it from public routes.

Use readiness configuration or a private route when an application must not
receive public traffic before some setup step. `postDeploy` is after
availability; it is not a traffic gate.

## Understand where hooks run

Each hook runs as a separate, one-shot container:

- It uses the Component's image, environment variables, secret references,
  mounted configuration files, and resource configuration.
- It runs in the same Environment and with the same workload isolation and
  network identity as the Component.
- It does not run inside a serving replica and cannot reach that replica over
  `localhost`.
- It does not share the serving replica's processes or ephemeral filesystem.
- Durable volumes declared in `needs.volumes` are not mounted into lifecycle
  hooks.

If a hook needs to contact the running application, address its internal
service rather than `localhost`. Keep the necessary address in the Component's
declared environment configuration.

The command is an argument array, not a shell expression. Invoke a shell
explicitly when shell syntax is required:

```yaml
postDeploy:
  command: ["sh", "-c", "./api warm-cache && ./api verify-cache"]
```

Hooks are not available on Components with `schedule`, because scheduled
Components already run to completion.

## Make hooks safe to retry

A hook command must be idempotent: running it again should converge on the same
result. A command may complete its external action immediately before the
platform loses its completion result, so a retry can repeat the whole command.

Successful hook execution is remembered separately for each Environment,
Component, phase, and hook identity. An unrelated apply does not run it again.
A hook runs when it is introduced, when its meaningful declarative inputs
change, or when its previous attempt did not succeed.

Meaningful inputs include the Component image, hook command, declared
environment, dependency and secret bindings, and mounted file content or
references. Changing only CPU, memory, timeout, or a stored secret value does
not repeat a successful hook. If a hook intentionally needs to run for such an
external change, change an explicit environment value or the hook command as
part of the same revision.

## Bound execution

`timeout` accepts a deliberate. duration such as `30s`, `5m`, or `10m`.

- Default: `10m`
- Minimum: `1s`
- Maximum: `30m`

Timeouts and non-zero exits are reported with the hook's logs in the streamed
apply output.

## Volume backup hooks are different

Volume `consistency.before` and `consistency.after` commands surround a volume
snapshot. They run inside the Component that mounts the volume so the
application can flush, lock, and resume its data. They do not participate in
the Component deployment sequence described here.

See [Make snapshots application-consistent](/data/volumes/#make-snapshots-application-consistent)
for that backup-specific contract.
