Skip to content
4 changes: 4 additions & 0 deletions blog/2020-10-29-supervisor-update.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ authorTwitter: ludeeus
title: "Upcoming changes to add-ons"
---

:::note
The builder action described in this post (`home-assistant/builder@master`) is a legacy workflow. It has since been replaced by dedicated composite actions. See the [builder migration post](/blog/2026/04/02/builder-migration) for the current recommended approach.
:::

## GitHub Action

You can now use our [builder][marketplace] as a [GitHub action][github_action]! :tada:
Expand Down
75 changes: 75 additions & 0 deletions blog/2026-04-02-builder-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
author: Jan Čermák
authorURL: https://github.com/sairon
authorImageURL: https://avatars.githubusercontent.com/u/211416?s=96&v=4
title: "Migrating app builds to Docker BuildKit"
---

The legacy `home-assistant/builder` container and the old `home-assistant/builder` GitHub Action have been retired. We recommend migrating all GitHub workflows and Dockerfiles for apps (formerly add-ons) as described in this post.

## What changed and why

The old builder ran every architecture build inside a single privileged Docker-in-Docker container using QEMU emulation. This was slow, required elevated privileges, and those who were already familiar with Docker needed to learn how to use the custom Home Assistant's builder container. The old builder also had unnecessary maintenance overhead. Today, what the builder does can be fully replaced with Docker BuildKit, which is natively supported on GitHub Actions runners and has built-in multi-arch support with QEMU emulation if needed.

For your CI, the replacement is a set of focused [composite GitHub Actions](https://github.com/home-assistant/builder) that delegate building to the runner's native Docker with Docker BuildKit. Outside the CI, the migration means that your `Dockerfile` is now the single source of truth for building your app image, and you can use `docker build` directly to build and test your app locally without needing to use the builder container.

## Migration process

The migration has two parts: updating your Dockerfiles and updating your GitHub Actions workflows.

### Update Dockerfiles

The new build workflow doesn't use `build.yaml` anymore. Move the content into your `Dockerfile` as follows:

- **`build_from`** - replace the `build_from` key in `build.yaml` with a `FROM` statement in your `Dockerfile`:

```dockerfile
FROM ghcr.io/home-assistant/base:latest
```

As the base images are now published as multi-platform manifests, there is usually no need to define per-arch base images anymore. The `build-image` action still supplies `BUILD_ARCH` as a build argument though, so you can use that in your `Dockerfile` if you need to use it in the template for the base image name.

- **`labels`** - move any custom Docker labels directly into your `Dockerfile` with a `LABEL` statement:

```dockerfile
LABEL \
org.opencontainers.image.title="Your awesome app" \
org.opencontainers.image.description="Description of your app." \
org.opencontainers.image.source="https://github.com/your/repo" \
org.opencontainers.image.licenses="Apache License 2.0"
```

If you are creating a custom workflow, note that the legacy builder used to add the `io.hass.type`, `io.hass.name`, `io.hass.description`, and `io.hass.url` labels automatically. The new actions do not infer these values, so add them explicitly via the `labels` input of the `build-image` (or similar) action.

- **`args`** - move custom build arguments into your `Dockerfile` as `ARG` definitions with default values:

```dockerfile
ARG MY_BUILD_ARG="default-value"
```

Default values in `ARG` replace what was previously supplied via `build.yaml`'s `args` dictionary. They can still be overridden at build time with `--build-arg` if needed.

With the content of `build.yaml` migrated, you can delete the file from your repository.

### Update GitHub Actions workflows

Remove any workflow steps using `home-assistant/builder@master` and replace them with the new composite actions. See the [example workflow](https://github.com/home-assistant/apps-example/blob/main/.github/workflows/builder.yaml) in our example app repository for a complete working example. Alternatively, use the [individual actions](https://github.com/home-assistant/builder?tab=readme-ov-file#example-workflow) in a more custom workflow as needed.

### Image naming

The preferred way to reference a published app image is now the **generic (multi-arch) name** without an architecture prefix:

```yaml
# config.yaml
image: "ghcr.io/my-org/my-app"
```

The `{arch}` placeholder (e.g. `ghcr.io/my-org/{arch}-my-app`) is still supported as a compatibility fallback, but it's encouraged to use the generic name and let the manifest handle the platform resolution.

### Local builds

After updating your `Dockerfile`, you can use `docker build` to build the app image directly - you can refer to [Local app testing](/docs/apps/testing) for more details.

## Apps built locally by Supervisor

For backward compatibility, Supervisor still reads `build.yaml` file if it's present and populates the image build arguments with values read from this file. This will produce warnings and eventually be removed in the future, so it's recommended to migrate to the new Dockerfile-based approach as described above.
2 changes: 1 addition & 1 deletion docs/apps.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Useful links:
- [Home Assistant Supervisor](https://github.com/home-assistant/supervisor)
- [Home Assistant Core Apps](https://github.com/home-assistant/addons)
- [Home Assistant Docker base images](https://github.com/home-assistant/docker-base)
- [Home Assistant Builder](https://github.com/home-assistant/builder)
- [Home Assistant Builder actions](https://github.com/home-assistant/builder)
- [Home Assistant community apps](https://github.com/hassio-addons)
- [Home Assistant Operating System](https://github.com/home-assistant/operating-system)
- [Home Assistant Docker images](https://github.com/home-assistant/docker)
47 changes: 12 additions & 35 deletions docs/apps/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ addon_name/
translations/
en.yaml
apparmor.txt
build.yaml
CHANGELOG.md
config.yaml
DOCS.md
Expand All @@ -21,7 +20,7 @@ addon_name/
```

:::note
Translation files, `config` and `build` all support `.json`, `.yml` and `.yaml` as the file type.
Translation files and `config` support `.json`, `.yml` and `.yaml` as the file type.

To keep it simple all examples use `.yaml`
:::
Expand Down Expand Up @@ -58,7 +57,7 @@ then there will be a variable `TARGET` containing `beer` in the environment of y
All apps (formerly known as add-ons) are based on the latest Alpine Linux image. Home Assistant will automatically substitute the right base image based on the machine architecture. Add `tzdata` if you need to run in a different timezone. `tzdata` Is is already added to our base images.

```dockerfile
ARG BUILD_FROM
ARG BUILD_FROM=ghcr.io/home-assistant/base:latest
FROM $BUILD_FROM

# Install requirements for app
Expand All @@ -73,17 +72,15 @@ RUN chmod a+x /run.sh
CMD [ "/run.sh" ]
```

If you don't use local build on the device or our build script, make sure that the Dockerfile also has a set of labels that include:
If you are not using Home Assistant GitHub builder actions (see [Publishing your app](/docs/apps/publishing)), make sure that the Dockerfile also has a set of labels that include:

```dockerfile
LABEL \
io.hass.version="VERSION" \
io.hass.type="addon" \
io.hass.arch="armhf|aarch64|i386|amd64"
io.hass.type="app" \
io.hass.arch="aarch64|amd64"
```

It is possible to use your own base image with `build.yaml` or if you do not need support for automatic multi-arch building you can also use a simple docker `FROM`. You can also suffix the Dockerfile with the specific architecture to use a specific Dockerfile for a particular architecture, i.e. `Dockerfile.amd64`.

### Build args

We support the following build arguments by default:
Expand Down Expand Up @@ -116,11 +113,11 @@ map:
- type: homeassistant_config
read_only: False
path: /custom/config/path
image: repo/{arch}-my-custom-addon
image: ghcr.io/my-org/my-app
```

:::note
Avoid using `config.yaml` as filename in your app for anything other than the app configuration. The Supervisor does a recursively search for `config.yaml` in the app repository.
Avoid using `config.yaml` as filename in your app for anything other than the app configuration. The Supervisor does recursively search for `config.yaml` in the app repository.
:::

### Required configuration options
Expand All @@ -131,7 +128,7 @@ Avoid using `config.yaml` as filename in your app for anything other than the ap
| `version` | string | Version of the app. If you are using a docker image with the `image` option, this needs to match the tag of the image that will be used.
| `slug` | string | Slug of the app. This needs to be unique in the scope of the [repository](/docs/apps/repository) that the app is published in and URI friendly. |
| `description` | string | Description of the app.
| `arch` | list | A list of supported architectures: `armhf`, `armv7`, `aarch64`, `amd64`, `i386`.
| `arch` | list | A list of supported architectures: `aarch64`, `amd64`.
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.

⚠️ Potential issue | 🟡 Minor

Fix markdown table pipe style (MD055)

Lines 131 and 172 are missing trailing |, which is causing markdownlint MD055 warnings.

Suggested fix
-| `arch` | list | A list of supported architectures: `aarch64`, `amd64`.
+| `arch` | list | A list of supported architectures: `aarch64`, `amd64`. |

-| `image` | string | | For use with container registries. Set this to the generic (multi-arch) image name, e.g. `ghcr.io/my-org/my-app`. The `{arch}` placeholder is still supported as a compatibility fallback for per-architecture image names (e.g. `ghcr.io/my-org/{arch}-my-app`). If you use this option, set the active Docker tag using the `version` option.
+| `image` | string | | For use with container registries. Set this to the generic (multi-arch) image name, e.g. `ghcr.io/my-org/my-app`. The `{arch}` placeholder is still supported as a compatibility fallback for per-architecture image names (e.g. `ghcr.io/my-org/{arch}-my-app`). If you use this option, set the active Docker tag using the `version` option. |

Also applies to: 172-172

🧰 Tools
🪛 markdownlint-cli2 (0.22.0)

[warning] 131-131: Table pipe style
Expected: leading_and_trailing; Actual: leading_only; Missing trailing pipe

(MD055, table-pipe-style)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/apps/configuration.md` at line 131, The markdown table row for the
`arch` entry is missing a trailing pipe causing MD055 warnings; fix by adding
the missing trailing `|` at the end of the `| `arch` | list | A list of
supported architectures: `aarch64`, `amd64`. |` row and likewise add a trailing
`|` to the other affected row around line 172 so all table rows consistently
start and end with `|`.


### Optional configuration options

Expand Down Expand Up @@ -172,8 +169,7 @@ Avoid using `config.yaml` as filename in your app for anything other than the ap
| `legacy` | bool | `false` | If the Docker image has no `hass.io` labels, you can enable the legacy mode to use the config data.
| `options` | dict | | Default options value of the app.
| `schema` | dict | | Schema for options value of the app. It can be `false` to disable schema validation and options.
| `image` | string | | For use with Docker Hub and other container registries. This should be set to the name of the image only (E.g, `ghcr.io/home-assistant/{arch}-addon-example`). If you use this option, set the active docker tag using the `version` option.
| `codenotary` | string | | For use with Codenotary CAS. This is the E-Mail address used to verify your image with Codenotary (E.g, `[email protected]`). This should match the E-Mail address used as the signer in the [app's extended build options](#app-extended-build)
| `image` | string | | For use with container registries. Set this to the generic (multi-arch) image name, e.g. `ghcr.io/my-org/my-app`. The `{arch}` placeholder is still supported as a compatibility fallback for per-architecture image names (e.g. `ghcr.io/my-org/{arch}-my-app`). If you use this option, set the active Docker tag using the `version` option.
| `timeout` | integer | 10 | Default 10 (seconds). The timeout to wait until the Docker daemon is done or will be killed.
| `tmpfs` | bool | `false` | If this is set to `true`, the containers `/tmp` uses tmpfs, a memory file system.
| `discovery` | list | | A list of services that this app provides for Home Assistant.
Expand Down Expand Up @@ -269,30 +265,11 @@ We support:
- `list(val1|val2|...)`
- `device` / `device(filter)`: Device filter can be in the following format: `subsystem=TYPE` i.e. `subsystem=tty` for serial devices.

## App extended build

Additional build options for an app are stored in `build.yaml`. This file will be read from our build systems.
This is only needed if you are not using the default images or need additional things.

```yaml
build_from:
armhf: mycustom/base-image:latest
args:
my_build_arg: xy
```

| Key | Required | Description |
| --- | -------- | ----------- |
| build_from | no | A dictionary with the hardware architecture as the key and the base Docker image as the value.
| args | no | Allow additional Docker build arguments as a dictionary.
| labels | no | Allow additional Docker labels as a dictionary.
| codenotary | no | Enable container signature with codenotary CAS.
| codenotary.signer | no | Owner signer E-Mail address for this image.
| codenotary.base_image | no | Verify the base container image. If you use our official images, use `[email protected]`
:::note

We provide a set of [base images][docker-base] which should cover a lot of needs. If you don't want to use the Alpine based version or need a specific image tag, feel free to pin this requirement for your build with the `build_from` option.
Previously, additional build options such as `build_from`, `args`, and `labels` were configured in a separate `build.yaml` file that was read by the legacy builder. This file is no longer used. Base images should be set directly with a `FROM` statement in your `Dockerfile`, labels with a `LABEL` statement, and custom build arguments with `ARG` definitions. See the [builder migration blog post](/blog/2026/04/02/builder-migration) for detailed migration instructions.

[docker-base]: https://github.com/home-assistant/docker-base
:::

## App translations

Expand Down
5 changes: 1 addition & 4 deletions docs/apps/presentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,8 @@ version: "1.0.0"
slug: "nginx-ingress-example"
description: "Ingress testing"
arch:
- aarch64
- amd64
- armhf
- armv7
- i386
ingress: true
```

Expand All @@ -219,7 +217,6 @@ Each app starts with a base rating of 5, on a scale of 1 to 6. Depending on deci
|---|---|---|
| Use `ingress: true` in [`config.yaml`](/docs/apps/configuration#optional-configuration-options) | +2 | overrides `auth_api` rating |
| Use `auth_api: true` in [`config.yaml`](/docs/apps/configuration#optional-configuration-options) | +1 | overridden by `ingress` |
| App is signed with [CodeNotary](https://cas.codenotary.com/)| +1||
| Use custom [`apparmor.txt`](/docs/apps/presentation#apparmor)| +1| Rating applied after installation |
| Set `apparmor: false` in [`config.yaml`](/docs/apps/configuration#optional-configuration-options) | -1 | |
| Use `privileged: NET_ADMIN`, `SYS_ADMIN`, `SYS_RAWIO`, `SYS_PTRACE`, `SYS_MODULE`, or `DAC_READ_SEARCH`, or `kernel_modules:` used in [`config.yaml`](/docs/apps/configuration#optional-configuration-options)| -1 | Rating applied only once if multiple are used. |
Expand Down
Loading