docker/compose · error

the classic builder doesn't support multi-arch build, set DO

Error message

the classic builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use BuildKit

What it means

When BuildKit is not in use (DOCKER_BUILDKIT=0, no buildx plugin, or COMPOSE_BAKE=false), compose falls back to the legacy builder API in doBuildImage. That API can only build a single platform for the host OS/architecture, so a service declaring more than one entry in build.platforms is rejected with a pointer to re-enable BuildKit. This is a capability gate on the classic path.

Source

Thrown at pkg/compose/build_classic.go:134

			service := project.Services[names[i]]
			imageRef := api.GetImageNameOrDefault(service, project.Name)
			imageIDs[imageRef] = imageDigest
		}
	}
	return imageIDs, err
}

//nolint:gocyclo
func (s *composeService) doBuildImage(ctx context.Context, project *types.Project, service types.ServiceConfig, options api.BuildOptions) (string, error) {
	var (
		buildCtx      io.ReadCloser
		dockerfileCtx io.ReadCloser
		contextDir    string
		relDockerfile string
	)

	if len(service.Build.Platforms) > 1 {
		return "", fmt.Errorf("the classic builder doesn't support multi-arch build, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if service.Build.Privileged {
		return "", fmt.Errorf("the classic builder doesn't support privileged mode, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if len(service.Build.AdditionalContexts) > 0 {
		return "", fmt.Errorf("the classic builder doesn't support additional contexts, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if len(service.Build.SSH) > 0 {
		return "", fmt.Errorf("the classic builder doesn't support SSH keys, set DOCKER_BUILDKIT=1 to use BuildKit")
	}
	if len(service.Build.Secrets) > 0 {
		return "", fmt.Errorf("the classic builder doesn't support secrets, set DOCKER_BUILDKIT=1 to use BuildKit")
	}

	if service.Build.Labels == nil {
		service.Build.Labels = make(map[string]string)
	}
	service.Build.Labels[api.ImageBuilderLabel] = "classic"

View on GitHub (pinned to ddc4b044b6)

Solutions

  1. Re-enable BuildKit: unset DOCKER_BUILDKIT and ensure the buildx plugin (>= 0.17.0) is installed
  2. Unset COMPOSE_BAKE=false so compose uses the bake/BuildKit path
  3. Reduce build.platforms to the single host platform if the classic builder is mandatory
  4. Install buildx: docker's get.docker.com script or a manual plugin download

Example fix

# before
$ DOCKER_BUILDKIT=0 docker compose build   # platforms: [linux/amd64, linux/arm64]
# after — option A
$ unset DOCKER_BUILDKIT; unset COMPOSE_BAKE; docker compose build
# after — option B (classic builder mandatory)
services:
  web:
    build:
      platforms: [linux/amd64]   # host platform only
Defensive patterns

Strategy: validation

Validate before calling

// Before routing a build to the classic builder:
for name, svc := range project.Services {
	if svc.Build == nil {
		continue
	}
	if len(svc.Build.Platforms) > 1 && classicBuilder() {
		return fmt.Errorf("service %s needs BuildKit for multi-platform; unset DOCKER_BUILDKIT/COMPOSE_BAKE", name)
	}
}

Prevention

When it happens

Trigger: docker compose build with COMPOSE_BAKE=false or DOCKER_BUILDKIT=0 while a service lists two or more platforms under build.platforms; buildx missing so compose silently downgraded to the classic builder.

Common situations: Users forcing the legacy builder for corporate/registry reasons but keeping multi-arch compose files; environments without the buildx plugin (minimal VMs, old Docker installs); setting DOCKER_BUILDKIT=0 to work around an unrelated issue and forgetting the platforms list.

Related errors


AI-assisted analysis of docker/compose@ddc4b044b6 (2026-08-15). Data as JSON: /api/errors/266e56a63936bdfd. Report an issue: GitHub.