> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nuon.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Container Actions

> Execute actions inside a user-managed container image.

By default, actions run on the install [runner](/concepts/runners). Setting `image` executes the
action inside a container image you provide.

## Configure it

Add `image` to the action and configure a step with `inline_contents`:

```toml actions/db_migrate.toml theme={null}
# action
name    = "db_migrate"
timeout = "10m"
image   = "ghcr.io/acme/migrate-tools:v1.4.0"

[[triggers]]
type = "manual"

[[steps]]
name            = "migrate"
inline_contents = """
#!/usr/bin/env sh
set -eu
migrate -database "$DATABASE_URL" -path /migrations up
"""

[steps.env_vars]
DATABASE_URL = "{{.nuon.install.sandbox.outputs.database_url}}"
```

Sync it the same way as any other action:

```sh theme={null}
nuon apps sync
```

Everything else about the action is unchanged: triggers, `timeout` (30 minutes maximum), `role`,
`enable_kube_config`, `env_vars`, and templating all behave exactly as they do when the action runs
on the runner. See [Configure actions](/guides/actions).

## Choosing an image

You can use publically hosted images or component images from your Nuon app config.

### A public reference

```toml actions/db_migrate.toml theme={null}
image = "ghcr.io/acme/migrate-tools:v1.4.0"
```

### A private image

Publish the image as a [container image component](/guides/container-image-components) and point
`image` at its `image.ref` output:

```toml actions/db_migrate.toml theme={null}
image = "{{.nuon.components.migrate_tools.outputs.image.ref}}"
```

<Warning>
  Use the component's `image.ref` output, not `image.repository` and
  `image.tag`. A bare `repository:tag` is rejected with `not digest-pinned`.
</Warning>

## Building the image

Nuon does not modify the image. It must include every tool and dependency the action needs
