Skip to content
Open
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
221 changes: 127 additions & 94 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ ___
* [`type=ref`](#typeref)
* [`type=raw`](#typeraw)
* [`type=sha`](#typesha)
* [`annotations` and `labels` inputs](#annotations-and-labels-inputs)
* [Default labels and annotations](#default-labels-and-annotations)
* [Customize labels and annotations](#customize-labels-and-annotations)

Choose a reason for hiding this comment

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

The only customization is opt-out of defaults (which could be covered in the defaults section), at which point you're back to overwriting the defaults (also valid for explaining opt-out) or adding your own (which implicitly overwrites defaults).

Additionally, there's no need to repeat labels and annotations for the subsections linked. Previously these were under a "Notes" section, so the added context was necessary.

* [Annotation outputs](#annotation-outputs)
* [Annotation levels](#annotation-levels)
* [Notes](#notes)
* [Image name and tag sanitization](#image-name-and-tag-sanitization)
* [Latest tag](#latest-tag)
Expand All @@ -49,8 +54,6 @@ ___
* [`{{commit_date '<format>' tz='<timezone>'}}`](#commit_date-format-tztimezone)
* [Major version zero](#major-version-zero)
* [JSON output object](#json-output-object)
* [Overwrite labels and annotations](#overwrite-labels-and-annotations)
* [Annotations](#annotations)
* [Contributing](#contributing)

## Usage
Expand Down Expand Up @@ -745,6 +748,128 @@ tags: |
type=sha,enable=true,priority=100,prefix=sha-,suffix=,format=short
```

## `annotations` and `labels` inputs

### Default labels and annotations

The action will set the following default labels and annotations based on repository metadata:

- `org.opencontainers.image.title`
- `org.opencontainers.image.description`
- `org.opencontainers.image.url`
- `org.opencontainers.image.source`
- `org.opencontainers.image.version`
- `org.opencontainers.image.created`
- `org.opencontainers.image.revision`
- `org.opencontainers.image.licenses`
Comment on lines +753 to +764
Copy link

@polarathene polarathene Jan 24, 2026

Choose a reason for hiding this comment

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

It might be helpful to better communicate better how those values are acquired?

  • While it's useful to know what defaults are being provided by the action, it's also helpful to know what to expect those values are without having to experiment.
  • I have opened an issue requesting better documenting the defaults as sometimes it's preferable to configure explicitly for visibility.

EDIT: I moved the bulk of this comment to the associated issue for documenting defaults.


### Customize labels and annotations

If some [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
generated are not suitable as labels/annotations, you can overwrite them like
this:

```yaml
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: name/app
labels: |
maintainer=CrazyMax
org.opencontainers.image.title=MyCustomTitle
org.opencontainers.image.description=Another description
org.opencontainers.image.vendor=MyCompany
```

Alternatively, you may wish to omit certain labels and annotations from the action output. For example, you may have `LABEL` directives in a Dockerfile that you would prefer to use instead of the labels set by this action. You can omit labels and annotations with `enable=false`.

```yaml
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: name/app
labels: |
name=org.opencontainers.image.url,enable=false
Copy link

@polarathene polarathene Jan 24, 2026

Choose a reason for hiding this comment

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

I am not sure about this syntax, would it make more sense to just opt-out via setting an empty value instead? Slight more terse, and doesn't introduce an alternative syntax.


I had suggested opt-out by setting an empty value in a recent issue I opened.

  • Some of the default values can already produce an empty value, but are still applied (which also overrides the LABEL if present in a Dockerfile) but I don't think there's a good reason to expect/want that to occur?
  • I'm not sure how often someone would want to set an empty annotation or label, I suppose for LABEL it might be to "unset" one that was inherited? If so they could still do that within their Dockerfile, so I don't think it's relevant for docker/metadata-action to support keeping empty annotations/labels to apply.

However my request would be a breaking change to anyone who did rely on setting empty values to override image labels.


An alternative could be a separate input to provide a list of default labels/annotations to exclude? They're all using the same namespace and defaults aren't configurable, so it's probably okay to take that approach instead too 🤷‍♂️ (then it avoids the risk of breaking anyone that might expect empty values to be supported + less verbose if disabling multiple labels)

```

### Annotation outputs

Since Buildx 0.12, it is possible to set annotations to your image through the
`--annotation` flag.

With the [`build-push-action`](https://github.com/docker/build-push-action/),
you can set the `annotations` input with the value of the `annotations` output
of the `metadata-action`:

```yaml
-
name: Docker meta
uses: docker/metadata-action@v5
with:
images: name/app
-
name: Build and push
uses: docker/build-push-action@v6
with:
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
```

The same can be done with the [`bake-action`](https://github.com/docker/bake-action/):

```yaml
-
name: Docker meta
uses: docker/metadata-action@v5
with:
images: name/app
-
name: Build
uses: docker/bake-action@v6
with:
files: |
./docker-bake.hcl
cwd://${{ steps.meta.outputs.bake-file-tags }}
cwd://${{ steps.meta.outputs.bake-file-annotations }}
targets: build
```

### Annotation levels

Note that annotations can be attached at many different levels within a manifest.
By default, the generated annotations will be attached to image manifests,
but different registries may expect annotations at different places;
a common practice is to read annotations at _image indexes_ if present,
which are often used by multi-arch builds to index platform-specific images.
If you want to specify level(s) for your annotations, you can use the
[`DOCKER_METADATA_ANNOTATIONS_LEVELS` environment variable](#environment-variables)
with a comma separated list of all levels the annotations should be attached to (defaults to `manifest`).
The following configuration demonstrates the ability to attach annotations to both image manifests and image indexes,
though your registry may only need annotations at the index level. (That is, `index` alone may be enough.)
Please consult the documentation of your registry.

```yaml
-
name: Docker meta
uses: docker/metadata-action@v5
with:
images: name/app
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
-
name: Build and push
uses: docker/build-push-action@v6
with:
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
```

More information about annotations in the [BuildKit documentation](https://github.com/moby/buildkit/blob/master/docs/annotations.md).

## Notes

### Image name and tag sanitization
Expand Down Expand Up @@ -955,98 +1080,6 @@ that you can reuse them further in your workflow using the [`fromJSON` function]
REVISION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
```

### Overwrite labels and annotations

If some [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
generated are not suitable as labels/annotations, you can overwrite them like
this:

```yaml
-
name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: name/app
labels: |
maintainer=CrazyMax
org.opencontainers.image.title=MyCustomTitle
org.opencontainers.image.description=Another description
org.opencontainers.image.vendor=MyCompany
```

### Annotations

Since Buildx 0.12, it is possible to set annotations to your image through the
`--annotation` flag.

With the [`build-push-action`](https://github.com/docker/build-push-action/),
you can set the `annotations` input with the value of the `annotations` output
of the `metadata-action`:

```yaml
-
name: Docker meta
uses: docker/metadata-action@v5
with:
images: name/app
-
name: Build and push
uses: docker/build-push-action@v6
with:
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
```

The same can be done with the [`bake-action`](https://github.com/docker/bake-action/):

```yaml
-
name: Docker meta
uses: docker/metadata-action@v5
with:
images: name/app
-
name: Build
uses: docker/bake-action@v6
with:
files: |
./docker-bake.hcl
cwd://${{ steps.meta.outputs.bake-file-tags }}
cwd://${{ steps.meta.outputs.bake-file-annotations }}
targets: build
```

Note that annotations can be attached at many different levels within a manifest.
By default, the generated annotations will be attached to image manifests,
but different registries may expect annotations at different places;
a common practice is to read annotations at _image indexes_ if present,
which are often used by multi-arch builds to index platform-specific images.
If you want to specify level(s) for your annotations, you can use the
[`DOCKER_METADATA_ANNOTATIONS_LEVELS` environment variable](#environment-variables)
with a comma separated list of all levels the annotations should be attached to (defaults to `manifest`).
The following configuration demonstrates the ability to attach annotations to both image manifests and image indexes,
though your registry may only need annotations at the index level. (That is, `index` alone may be enough.)
Please consult the documentation of your registry.

```yaml
-
name: Docker meta
uses: docker/metadata-action@v5
with:
images: name/app
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index
-
name: Build and push
uses: docker/build-push-action@v6
with:
tags: ${{ steps.meta.outputs.tags }}
annotations: ${{ steps.meta.outputs.annotations }}
```

More information about annotations in the [BuildKit documentation](https://github.com/moby/buildkit/blob/master/docs/annotations.md).

## Contributing

Want to contribute? Awesome! You can find information about contributing to
Expand Down
83 changes: 83 additions & 0 deletions __tests__/annotation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {describe, expect, test} from '@jest/globals';

import {Transform, Annotation} from '../src/annotation';

describe('annotation transform', () => {
test.each([
[
[`org.opencontainers.image.version=1.1.1`],
[
{
name: `org.opencontainers.image.version`,
value: `1.1.1`,
enable: true
}
] as Annotation[],
false
],
[
[`name=my.annotation,value="my value",enable=true`],
[
{
name: `my.annotation`,
value: `"my value"`,
enable: true
}
] as Annotation[],
false
],
[
[`name=my.annotation,value=myvalue,enable=false`],
[
{
name: `my.annotation`,
value: `myvalue`,
enable: false
}
] as Annotation[],
false
],
[
[`my.annotation=my value`],
[
{
name: `my.annotation`,
value: `my value`,
enable: true
}
] as Annotation[],
false
],
[
[`name=,value=val`], // empty name
undefined,
true
],
[
[`name=org.opencontainers.image.url,enable=false`], // empty value
[
{
name: `org.opencontainers.image.url`,
value: null,
enable: false
}
] as Annotation[],
false
],
[
[`name=my.annotation,value=myvalue,enable=bar`], // invalid enable
undefined,
true
]
])('given %p', async (l: string[], expected: Annotation[] | undefined, invalid: boolean) => {
try {
const annotations = Transform(l);
expect(annotations).toEqual(expected);
} catch (err) {
if (!invalid) {
console.error(err);
}
expect(invalid).toBeTruthy();
}
});
});
Loading