diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 387dff8..b476f55 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1539,3 +1539,23 @@ jobs:
             echo "::error::Should have failed"
             exit 1
           fi
+
+  distribute:
+    uses: ./.github/workflows/reusable-distribute-mp.yml
+    with:
+      push: false
+      meta-image: user/app
+      build-context: "{{defaultContext}}:test"
+      build-file: multi.Dockerfile
+      build-platforms: linux/amd64,linux/arm64
+
+  distribute-cache:
+    uses: ./.github/workflows/reusable-distribute-mp.yml
+    with:
+      push: false
+      cache: true
+      cache-scope: multi
+      meta-image: user/app
+      build-context: "{{defaultContext}}:test"
+      build-file: multi.Dockerfile
+      build-platforms: linux/amd64,linux/arm64
diff --git a/.github/workflows/reusable-distribute-mp.yml b/.github/workflows/reusable-distribute-mp.yml
new file mode 100644
index 0000000..826f083
--- /dev/null
+++ b/.github/workflows/reusable-distribute-mp.yml
@@ -0,0 +1,636 @@
+# Reusable workflow to distribute multi-platform builds efficiently
+# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
+name: reusable-distribute-mp
+
+on:
+  workflow_call:
+    inputs:
+      # inputs specific to this reusable worklow
+      runner:
+        type: string
+        description: "Runner instance"
+        required: false
+        default: 'auto'
+      push:
+        type: boolean
+        description: "Push image to registry"
+        required: false
+        default: false
+      cache:
+        type: boolean
+        description: "Enable cache to GitHub Actions cache backend"
+        required: false
+        default: false
+      cache-scope:
+        type: string
+        description: "Which scope cache object belongs to if cache enabled (default is target name)"
+        required: false
+      cache-mode:
+        type: string
+        description: "Cache layers to export if cache enabled (min or max)"
+        required: false
+        default: 'min'
+      set-meta-annotations:
+        type: boolean
+        description: "Set metadata-action annotations"
+        required: false
+        default: false
+      set-meta-labels:
+        type: boolean
+        description: "Set metadata-action labels"
+        required: false
+        default: false
+      setup-qemu:
+        type: boolean
+        description: "Install QEMU static binaries"
+        required: false
+        default: true
+      # same as docker/metadata-action inputs (minus sep-tags, sep-labels, sep-annotations, bake-target)
+      meta-image:
+        type: string
+        description: "Image to use as base name for tags"
+        required: true
+      meta-tags:
+        type: string
+        description: "List of tags as key-value pair attributes"
+        required: false
+      meta-flavor:
+        type: string
+        description: "Flavors to apply"
+        required: false
+      meta-labels:
+        type: string
+        description: "List of custom labels"
+        required: false
+      meta-annotations:
+        type: string
+        description: "List of custom annotations"
+        required: false
+      # same as docker/setup-buildx-action inputs (minus driver, install, use, endpoint, append, cleanup)
+      buildx-version:
+        type: string
+        description: "Buildx version. (eg. v0.3.0)"
+        required: false
+      buildx-cache-binary:
+        type: boolean
+        description: "Cache buildx binary to GitHub Actions cache backend"
+        default: true
+        required: false
+      buildx-driver-opts:
+        type: string
+        description: "List of additional docker-container options. (eg. image=moby/buildkit:master)"
+        required: false
+      buildkitd-flags:
+        type: string
+        description: "BuildKit daemon flags"
+        required: false
+      buildkitd-config:
+        type: string
+        description: "BuildKit daemon config file"
+        required: false
+      buildkitd-config-inline:
+        type: string
+        description: "Inline BuildKit daemon config"
+        required: false
+      # same as docker/login-action inputs (minus logout)
+      login-registry:
+        type: string
+        description: "Server address of Docker registry. If not set then will default to Docker Hub"
+        required: false
+      login-username:
+        type: string
+        description: "Username used to log against the Docker registry"
+        required: false
+      login-ecr:
+        type: string
+        description: "Specifies whether the given registry is ECR (auto, true or false)"
+        default: 'auto'
+        required: false
+      # same as docker/setup-qemu-action inputs (minus platforms, cache-image)
+      qemu-image:
+        type: string
+        description: "QEMU static binaries Docker image (e.g. tonistiigi/binfmt:latest)"
+        required: false
+      # same as docker/build-push-action inputs (minus builder, cache-from, cache-to, call, load, no-cache, no-cache-filters, outputs, platforms, push, tags)
+      build-add-hosts:
+        type: string
+        description: "List of a customs host-to-IP mapping (e.g., docker:10.180.0.1)"
+        required: false
+      build-allow:
+        type: string
+        description: "List of extra privileged entitlement (e.g., network.host,security.insecure)"
+        required: false
+      build-annotations:
+        type: string
+        description: "List of annotation to set to the image"
+        required: false
+      build-attests:
+        type: string
+        description: "List of attestation parameters (e.g., type=sbom,generator=image)"
+        required: false
+      build-args:
+        type: string
+        description: "List of build-time variables"
+        required: false
+      build-cgroup-parent:
+        type: string
+        description: "Optional parent cgroup for the container used in the build"
+        required: false
+      build-context:
+        type: string
+        description: "Build's context is the set of files located in the specified PATH or URL"
+        required: false
+      build-contexts:
+        type: string
+        description: "List of additional build contexts (e.g., name=path)"
+        required: false
+      build-file:
+        type: string
+        description: "Path to the Dockerfile"
+        required: false
+      build-labels:
+        type: string
+        description: "List of metadata for an image"
+        required: false
+      build-network:
+        type: string
+        description: "Set the networking mode for the RUN instructions during build"
+        required: false
+      build-platforms:
+        type: string
+        description: "List of target platforms for build"
+        required: true
+      build-provenance:
+        type: string
+        description: "Generate provenance attestation for the build (shorthand for --attest=type=provenance)"
+        required: false
+      build-pull:
+        type: boolean
+        description: "Always attempt to pull all referenced images"
+        required: false
+        default: false
+      build-sbom:
+        type: string
+        description: "Generate SBOM attestation for the build (shorthand for --attest=type=sbom)"
+        required: false
+      build-secrets:
+        type: string
+        description: "List of secrets to expose to the build (e.g., key=string, GIT_AUTH_TOKEN=mytoken)"
+        required: false
+      build-secret-envs:
+        type: string
+        description: "List of secret env vars to expose to the build (e.g., key=envname, MY_SECRET=MY_ENV_VAR)"
+        required: false
+      build-secret-files:
+        type: string
+        description: "List of secret files to expose to the build (e.g., key=filename, MY_SECRET=./secret.txt)"
+        required: false
+      build-shm-size:
+        type: string
+        description: "Size of /dev/shm (e.g., 2g)"
+        required: false
+      build-ssh:
+        type: string
+        description: "List of SSH agent socket or keys to expose to the build"
+        required: false
+      build-target:
+        type: string
+        description: "Sets the target stage to build"
+        required: false
+      build-ulimit:
+        type: string
+        description: "Ulimit options (e.g., nofile=1024:1024)"
+        required: false
+    secrets:
+      login-username:
+        description: 'Username used to log against the Docker registry'
+        required: false
+      login-password:
+        description: "Password or personal access token used to log against the Docker registry"
+        required: false
+      github-token:
+        description: "GitHub Token used to authenticate against a repository for Git context"
+        required: false
+
+env:
+  ACTIONS_TOOLKIT_VERSION: "0.56.0"
+
+jobs:
+  prepare:
+    runs-on: ubuntu-latest
+    outputs:
+      includes: ${{ steps.set.outputs.includes }}
+    steps:
+      -
+        name: Install npm dependencies
+        uses: actions/github-script@v7
+        with:
+          script: |
+            await exec.exec('npm', ['install',
+              '@docker/actions-toolkit@${{ env.ACTIONS_TOOLKIT_VERSION }}'
+            ]);
+      -
+        name: Set includes
+        id: set
+        uses: actions/github-script@v7
+        env:
+          INPUT_RUNNER: ${{ inputs.runner }}
+          INPUT_META-IMAGE: ${{ inputs.meta-image }}
+          INPUT_BUILD-PLATFORMS: ${{ inputs.build-platforms }}
+          GITHUB_TOKEN: ${{ secrets.github-token || github.token }}
+        with:
+          script: |
+            const { Util } = require('@docker/actions-toolkit/lib/util');
+
+            if (Util.getInputList('meta-image').length > 1) {
+              throw new Error('Only one meta-image is allowed');
+            }
+
+            const inpRunner = core.getInput('runner');
+            const inpBuildPlatforms = Util.getInputList('build-platforms');
+            if (inpBuildPlatforms.length > 100) {
+              throw new Error('Too many platforms');
+            } else if (inpBuildPlatforms.length <= 1) {
+              throw new Error('At least 2 platforms are required');
+            }
+
+            await core.group(`Set includes`, async () => {
+              let includes = [];
+              inpBuildPlatforms.forEach((platform, index) => {
+                let runner = inpRunner;
+                if (runner === 'auto') {
+                  runner = platform.startsWith('linux/arm') ? 'ubuntu-24.04-arm' : 'ubuntu-latest';
+                }
+                includes.push({
+                  index: index,
+                  platform: platform,
+                  runner: runner
+                });
+              });
+              core.info(JSON.stringify(includes, null, 2));
+              core.setOutput('includes', JSON.stringify(includes));
+            });
+
+  warmup:
+    runs-on: ${{ inputs.runner == 'auto' && 'ubuntu-latest' || inputs.runner }}
+    steps:
+      -
+        name: Set up QEMU
+        uses: docker/setup-qemu-action@v3
+        if: ${{ inputs.setup-qemu }}
+        with:
+          image: ${{ inputs.qemu-image }}
+      -
+        name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+        with:
+          version: ${{ inputs.buildx-version }}
+          driver-opts: ${{ inputs.buildx-driver-opts }}
+          buildkitd-flags: ${{ inputs.buildkitd-flags }}
+          buildkitd-config: ${{ inputs.buildkitd-config }}
+          buildkitd-config-inline: ${{ inputs.buildkitd-config-inline }}
+          cache-binary: ${{ inputs.buildx-cache-binary }}
+      -
+        name: Warm up cache
+        uses: docker/build-push-action@v6
+        if: ${{ inputs.cache }}
+        with:
+          add-hosts: ${{ inputs.build-add-hosts }}
+          allow: ${{ inputs.build-allow }}
+          build-args: ${{ inputs.build-build-args }}
+          build-contexts: ${{ inputs.build-contexts }}
+          cache-from: type=gha,scope=${{ inputs.cache-scope || inputs.target || 'buildkit' }}-warmup
+          cache-to: type=gha,scope=${{ inputs.cache-scope || inputs.target || 'buildkit' }}-warmup,mode=${{ inputs.cache-mode }}
+          cgroup-parent: ${{ inputs.build-cgroup-parent }}
+          context: ${{ inputs.build-context }}
+          file: ${{ inputs.build-file }}
+          labels: ${{ steps.build-inputs.outputs.labels }}
+          network: ${{ inputs.build-network }}
+          outputs: type=cacheonly
+          pull: ${{ inputs.build-pull }}
+          secrets: ${{ inputs.build-secrets }}
+          secret-envs: ${{ inputs.build-secret-envs }}
+          secret-files: ${{ inputs.build-secret-files }}
+          shm-size: ${{ inputs.build-shm-size }}
+          ssh: ${{ inputs.build-ssh }}
+          target: ${{ inputs.build-target }}
+          ulimit: ${{ inputs.build-ulimit }}
+          github-token: ${{ secrets.github-token || github.token }}
+
+  build:
+    runs-on: ${{ matrix.runner }}
+    needs:
+      - prepare
+      - warmup
+    outputs:
+      # needs predefined outputs as we can't use dynamic ones atm: https://github.com/actions/runner/pull/2477
+      # 100 is the maximum number of platforms supported by the matrix strategy
+      digest_0: ${{ steps.digest.outputs.digest_0 }}
+      digest_1: ${{ steps.digest.outputs.digest_1 }}
+      digest_2: ${{ steps.digest.outputs.digest_2 }}
+      digest_3: ${{ steps.digest.outputs.digest_3 }}
+      digest_4: ${{ steps.digest.outputs.digest_4 }}
+      digest_5: ${{ steps.digest.outputs.digest_5 }}
+      digest_6: ${{ steps.digest.outputs.digest_6 }}
+      digest_7: ${{ steps.digest.outputs.digest_7 }}
+      digest_8: ${{ steps.digest.outputs.digest_8 }}
+      digest_9: ${{ steps.digest.outputs.digest_9 }}
+      digest_10: ${{ steps.digest.outputs.digest_10 }}
+      digest_11: ${{ steps.digest.outputs.digest_11 }}
+      digest_12: ${{ steps.digest.outputs.digest_12 }}
+      digest_13: ${{ steps.digest.outputs.digest_13 }}
+      digest_14: ${{ steps.digest.outputs.digest_14 }}
+      digest_15: ${{ steps.digest.outputs.digest_15 }}
+      digest_16: ${{ steps.digest.outputs.digest_16 }}
+      digest_17: ${{ steps.digest.outputs.digest_17 }}
+      digest_18: ${{ steps.digest.outputs.digest_18 }}
+      digest_19: ${{ steps.digest.outputs.digest_19 }}
+      digest_20: ${{ steps.digest.outputs.digest_20 }}
+      digest_21: ${{ steps.digest.outputs.digest_21 }}
+      digest_22: ${{ steps.digest.outputs.digest_22 }}
+      digest_23: ${{ steps.digest.outputs.digest_23 }}
+      digest_24: ${{ steps.digest.outputs.digest_24 }}
+      digest_25: ${{ steps.digest.outputs.digest_25 }}
+      digest_26: ${{ steps.digest.outputs.digest_26 }}
+      digest_27: ${{ steps.digest.outputs.digest_27 }}
+      digest_28: ${{ steps.digest.outputs.digest_28 }}
+      digest_29: ${{ steps.digest.outputs.digest_29 }}
+      digest_30: ${{ steps.digest.outputs.digest_30 }}
+      digest_31: ${{ steps.digest.outputs.digest_31 }}
+      digest_32: ${{ steps.digest.outputs.digest_32 }}
+      digest_33: ${{ steps.digest.outputs.digest_33 }}
+      digest_34: ${{ steps.digest.outputs.digest_34 }}
+      digest_35: ${{ steps.digest.outputs.digest_35 }}
+      digest_36: ${{ steps.digest.outputs.digest_36 }}
+      digest_37: ${{ steps.digest.outputs.digest_37 }}
+      digest_38: ${{ steps.digest.outputs.digest_38 }}
+      digest_39: ${{ steps.digest.outputs.digest_39 }}
+      digest_40: ${{ steps.digest.outputs.digest_40 }}
+      digest_41: ${{ steps.digest.outputs.digest_41 }}
+      digest_42: ${{ steps.digest.outputs.digest_42 }}
+      digest_43: ${{ steps.digest.outputs.digest_43 }}
+      digest_44: ${{ steps.digest.outputs.digest_44 }}
+      digest_45: ${{ steps.digest.outputs.digest_45 }}
+      digest_46: ${{ steps.digest.outputs.digest_46 }}
+      digest_47: ${{ steps.digest.outputs.digest_47 }}
+      digest_48: ${{ steps.digest.outputs.digest_48 }}
+      digest_49: ${{ steps.digest.outputs.digest_49 }}
+      digest_50: ${{ steps.digest.outputs.digest_50 }}
+      digest_51: ${{ steps.digest.outputs.digest_51 }}
+      digest_52: ${{ steps.digest.outputs.digest_52 }}
+      digest_53: ${{ steps.digest.outputs.digest_53 }}
+      digest_54: ${{ steps.digest.outputs.digest_54 }}
+      digest_55: ${{ steps.digest.outputs.digest_55 }}
+      digest_56: ${{ steps.digest.outputs.digest_56 }}
+      digest_57: ${{ steps.digest.outputs.digest_57 }}
+      digest_58: ${{ steps.digest.outputs.digest_58 }}
+      digest_59: ${{ steps.digest.outputs.digest_59 }}
+      digest_60: ${{ steps.digest.outputs.digest_60 }}
+      digest_61: ${{ steps.digest.outputs.digest_61 }}
+      digest_62: ${{ steps.digest.outputs.digest_62 }}
+      digest_63: ${{ steps.digest.outputs.digest_63 }}
+      digest_64: ${{ steps.digest.outputs.digest_64 }}
+      digest_65: ${{ steps.digest.outputs.digest_65 }}
+      digest_66: ${{ steps.digest.outputs.digest_66 }}
+      digest_67: ${{ steps.digest.outputs.digest_67 }}
+      digest_68: ${{ steps.digest.outputs.digest_68 }}
+      digest_69: ${{ steps.digest.outputs.digest_69 }}
+      digest_70: ${{ steps.digest.outputs.digest_70 }}
+      digest_71: ${{ steps.digest.outputs.digest_71 }}
+      digest_72: ${{ steps.digest.outputs.digest_72 }}
+      digest_73: ${{ steps.digest.outputs.digest_73 }}
+      digest_74: ${{ steps.digest.outputs.digest_74 }}
+      digest_75: ${{ steps.digest.outputs.digest_75 }}
+      digest_76: ${{ steps.digest.outputs.digest_76 }}
+      digest_77: ${{ steps.digest.outputs.digest_77 }}
+      digest_78: ${{ steps.digest.outputs.digest_78 }}
+      digest_79: ${{ steps.digest.outputs.digest_79 }}
+      digest_80: ${{ steps.digest.outputs.digest_80 }}
+      digest_81: ${{ steps.digest.outputs.digest_81 }}
+      digest_82: ${{ steps.digest.outputs.digest_82 }}
+      digest_83: ${{ steps.digest.outputs.digest_83 }}
+      digest_84: ${{ steps.digest.outputs.digest_84 }}
+      digest_85: ${{ steps.digest.outputs.digest_85 }}
+      digest_86: ${{ steps.digest.outputs.digest_86 }}
+      digest_87: ${{ steps.digest.outputs.digest_87 }}
+      digest_88: ${{ steps.digest.outputs.digest_88 }}
+      digest_89: ${{ steps.digest.outputs.digest_89 }}
+      digest_90: ${{ steps.digest.outputs.digest_90 }}
+      digest_91: ${{ steps.digest.outputs.digest_91 }}
+      digest_92: ${{ steps.digest.outputs.digest_92 }}
+      digest_93: ${{ steps.digest.outputs.digest_93 }}
+      digest_94: ${{ steps.digest.outputs.digest_94 }}
+      digest_95: ${{ steps.digest.outputs.digest_95 }}
+      digest_96: ${{ steps.digest.outputs.digest_96 }}
+      digest_97: ${{ steps.digest.outputs.digest_97 }}
+      digest_98: ${{ steps.digest.outputs.digest_98 }}
+      digest_99: ${{ steps.digest.outputs.digest_99 }}
+    strategy:
+      fail-fast: false
+      matrix:
+        include: ${{ fromJson(needs.prepare.outputs.includes) }}
+    steps:
+      -
+        name: Docker meta
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: ${{ inputs.meta-image }}
+          tags: ${{ inputs.meta-tags }}
+          flavor: ${{ inputs.meta-flavor }}
+          labels: ${{ inputs.meta-labels }}
+          annotations: ${{ inputs.meta-annotations }}
+      -
+        name: Login to registry
+        uses: docker/login-action@v3
+        if: ${{ inputs.push }}
+        with:
+          registry: ${{ inputs.login-registry }}
+          username: ${{ inputs.login-username || secrets.login-username }}
+          password: ${{ secrets.login-password }}
+      -
+        name: Set up QEMU
+        uses: docker/setup-qemu-action@v3
+        if: ${{ inputs.setup-qemu }}
+        with:
+          image: ${{ inputs.qemu-image }}
+      -
+        name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+        with:
+          version: ${{ inputs.buildx-version }}
+          driver-opts: ${{ inputs.buildx-driver-opts }}
+          buildkitd-flags: ${{ inputs.buildkitd-flags }}
+          buildkitd-config: ${{ inputs.buildkitd-config }}
+          buildkitd-config-inline: ${{ inputs.buildkitd-config-inline }}
+          cache-binary: ${{ inputs.buildx-cache-binary }}
+      -
+        name: Set build inputs
+        id: build-inputs
+        uses: actions/github-script@v7
+        env:
+          PLATFORM: ${{ matrix.platform }}
+          INPUT_CACHE: ${{ inputs.cache }}
+          INPUT_CACHE-SCOPE: ${{ inputs.cache-scope }}
+          INPUT_CACHE-MODE: ${{ inputs.cache-mode }}
+          INPUT_SET-META-ANNOTATIONS: ${{ inputs.set-meta-annotations }}
+          INPUT_SET-META-LABELS: ${{ inputs.set-meta-labels }}
+          INPUT_BUILD-ANNOTATIONS: ${{ inputs.build-annotations }}
+          INPUT_BUILD-LABELS: ${{ inputs.build-labels }}
+          INPUT_BUILD-TARGET: ${{ inputs.build-target }}
+        with:
+          script: |
+            const platformPair = process.env.PLATFORM.replace(/\//g, '-');
+            const inpCache = core.getBooleanInput('cache');
+            const inpCacheScope = core.getInput('cache-scope');
+            const inpCacheMode = core.getInput('cache-mode');
+            const inpSetMetaAnnotations = core.getBooleanInput('set-meta-annotations');
+            const inpSetMetaLabels = core.getBooleanInput('set-meta-labels');
+            let inpBuildAnnotations = core.getInput('build-annotations');
+            let inpBuildLabels = core.getInput('build-labels');
+            const inpBuildTarget = core.getInput('build-target');
+
+            if (inpCache) {
+              core.setOutput('cache-from', `type=gha,scope=${inpCacheScope || inpTarget || 'buildkit'}-warmup\ntype=gha,scope=${inpCacheScope || inpTarget}-${platformPair}`);
+              core.setOutput('cache-to', `type=gha,scope=${inpCacheScope || inpTarget || 'buildkit'}-${platformPair},mode=${inpCacheMode}`);
+            }
+            if (inpSetMetaAnnotations) {
+              inpBuildAnnotations += `\n${{ steps.meta.outputs.annotations }}`;
+            }
+            core.setOutput('annotations', inpBuildAnnotations);
+            if (inpSetMetaLabels) {
+              inpBuildLabels += `\n${{ steps.meta.outputs.labels }}`;
+            }
+            core.setOutput('labels', inpBuildLabels);
+      -
+        name: Build
+        id: build
+        uses: docker/build-push-action@v6
+        with:
+          add-hosts: ${{ inputs.build-add-hosts }}
+          allow: ${{ inputs.build-allow }}
+          annotations: ${{ steps.build-inputs.outputs.annotations }}
+          attests: ${{ inputs.build-attests }}
+          build-args: ${{ inputs.build-build-args }}
+          build-contexts: ${{ inputs.build-contexts }}
+          cache-from: ${{ steps.build-inputs.outputs.cache-from }}
+          cache-to: ${{ steps.build-inputs.outputs.cache-to }}
+          cgroup-parent: ${{ inputs.build-cgroup-parent }}
+          context: ${{ inputs.build-context }}
+          file: ${{ inputs.build-file }}
+          labels: ${{ steps.build-inputs.outputs.labels }}
+          network: ${{ inputs.build-network }}
+          outputs: |
+            type=image,"name=${{ inputs.meta-image }}",push-by-digest=true,name-canonical=true,push=${{ inputs.push }}
+          platforms: ${{ matrix.platform }}
+          provenance: ${{ inputs.build-provenance }}
+          pull: ${{ inputs.build-pull }}
+          sbom: ${{ inputs.build-sbom }}
+          secrets: ${{ inputs.build-secrets }}
+          secret-envs: ${{ inputs.build-secret-envs }}
+          secret-files: ${{ inputs.build-secret-files }}
+          shm-size: ${{ inputs.build-shm-size }}
+          ssh: ${{ inputs.build-ssh }}
+          target: ${{ inputs.build-target }}
+          ulimit: ${{ inputs.build-ulimit }}
+          github-token: ${{ secrets.github-token || github.token }}
+      -
+        name: Set digest output
+        id: digest
+        uses: actions/github-script@v7
+        with:
+          script: |
+            const metadata = JSON.parse(`${{ steps.build.outputs.metadata }}`);
+            const digest = metadata['containerimage.digest'];
+            const outputKey = `digest_${{ matrix.index }}`;
+            core.info(`Setting digest output: ${outputKey}=${digest}`);
+            core.setOutput(outputKey, digest);
+
+  merge:
+    runs-on: ubuntu-latest
+    needs:
+      - build
+    steps:
+      -
+        name: Docker meta
+        id: meta
+        uses: docker/metadata-action@v5
+        with:
+          images: ${{ inputs.meta-image }}
+          tags: ${{ inputs.meta-tags }}
+          flavor: ${{ inputs.meta-flavor }}
+      -
+        name: Login to registry
+        uses: docker/login-action@v3
+        if: ${{ inputs.push }}
+        with:
+          registry: ${{ inputs.login-registry }}
+          username: ${{ inputs.login-username || secrets.login-username }}
+          password: ${{ secrets.login-password }}
+      -
+        name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+        with:
+          version: ${{ inputs.buildx-version }}
+          driver-opts: ${{ inputs.buildx-driver-opts }}
+          buildkitd-flags: ${{ inputs.buildkitd-flags }}
+          buildkitd-config: ${{ inputs.buildkitd-config }}
+          buildkitd-config-inline: ${{ inputs.buildkitd-config-inline }}
+          cache-binary: ${{ inputs.buildx-cache-binary }}
+      -
+        name: Create manifest list
+        uses: actions/github-script@v7
+        env:
+          INPUT_PUSH: ${{ inputs.push }}
+          INPUT_META-IMAGE: ${{ inputs.meta-image }}
+        with:
+          script: |
+            const inpPush = core.getBooleanInput('push');
+            const inpMetaImage = core.getInput('meta-image');
+
+            let digests = [];
+            await core.group(`Digests`, async () => {
+              digests = Object.values(JSON.parse(`${{ toJSON(needs.build.outputs) }}`));
+              core.info(JSON.stringify(digests, null, 2));
+            });
+
+            let tags = [];
+            await core.group(`Tags`, async () => {
+              tags = `${{ steps.meta.outputs.tags }}`.split('\n').filter(Boolean);
+              core.info(JSON.stringify(tags, null, 2));
+            });
+
+            let createArgs = ['buildx', 'imagetools', 'create'];
+            for (const tag of tags) {
+              createArgs.push(`-t`, tag);
+            }
+            for (const digest of digests) {
+              createArgs.push(`${inpMetaImage}@${digest}`);
+            }
+
+            if (inpPush) {
+              if (tags.length === 0) {
+                throw new Error('No tags to create manifest list');
+              }
+              await exec.getExecOutput('docker', createArgs, {
+                ignoreReturnCode: true
+              }).then(res => {
+                if (res.stderr.length > 0 && res.exitCode != 0) {
+                  throw new Error(res.stderr);
+                }
+              });
+              await core.group(`Inspect image`, async () => {
+                await exec.getExecOutput('docker', ['buildx', 'imagetools', 'inspect', `${inpMetaImage}:${tags[0]}`], {
+                  ignoreReturnCode: true
+                }).then(res => {
+                  if (res.stderr.length > 0 && res.exitCode != 0) {
+                    throw new Error(res.stderr);
+                  }
+                });
+              });
+            } else {
+              await core.group(`Generated imagetools create command`, async () => {
+                core.info(`docker ${createArgs.join(' ')}`);
+              });
+              core.info(`Push is disabled, skipping manifest list creation`);
+            }
diff --git a/README.md b/README.md
index 509d87e..5bb8569 100644
--- a/README.md
+++ b/README.md
@@ -156,6 +156,7 @@ jobs:
 ## Examples
 
 * [Multi-platform image](https://docs.docker.com/build/ci/github-actions/multi-platform/)
+* [Distribute multi-platform build across runners](https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-multi-platform-build-across-runners)
 * [Secrets](https://docs.docker.com/build/ci/github-actions/secrets/)
 * [Push to multi-registries](https://docs.docker.com/build/ci/github-actions/push-multi-registries/)
 * [Manage tags and labels](https://docs.docker.com/build/ci/github-actions/manage-tags-labels/)
@@ -170,6 +171,7 @@ jobs:
 * [SBOM and provenance attestations](https://docs.docker.com/build/ci/github-actions/attestations/)
 * [Annotations](https://docs.docker.com/build/ci/github-actions/annotations/)
 * [Reproducible builds](https://docs.docker.com/build/ci/github-actions/reproducible-builds/)
+* [Build checks](https://docs.docker.com/build/ci/github-actions/checks/#run-checks-with-dockerbuild-push-action)
 
 ## Summaries