Skaffold’s custom builder lets you run any command to build your container image, not just Dockerfiles.

Let’s see it in action. Imagine you have a Go application and you want to build a container image using docker buildx. Here’s how you’d configure Skaffold:

apiVersion: skaffold.dev/v2beta24
kind: Config
build:
  artifacts:
    - image: my-go-app
      docker:
        # We're not using Dockerfile directly here
        # dockerfile: Dockerfile
      custom:
        buildCommand: |
          docker buildx build \
            --platform linux/amd64,linux/arm64 \

            -t {{.IMAGE_NAME}}:{{.VERSION}} \

            .
        envTemplate:
          MAP:
            IMAGE_NAME: my-go-app
            VERSION: latest

When Skaffold runs skaffold build, it will execute the docker buildx build command. The {{.IMAGE_NAME}} and {{.VERSION}} are placeholders that Skaffold fills in with the image name and tag it’s generating. The envTemplate section provides environment variables that are available to your buildCommand.

This is incredibly powerful because it decouples your image building process from a specific tool like Docker. You could use buildah, kaniko, or even a custom shell script that fetches source code from a Git repository, compiles it, and then packages it into an image.

The core problem this solves is flexibility. Not all projects use a standard Dockerfile. You might have complex build steps involving multiple languages, proprietary build tools, or specific environment requirements that a simple Dockerfile can’t capture efficiently. Skaffold’s custom builder acts as an adapter, allowing you to plug in your existing, potentially complex, build logic.

Internally, Skaffold treats the output of your buildCommand as the source for building the image. It doesn’t care how you generated the image layers, only that the command successfully produced an image tagged with the name and version it expects. Skaffold will then push this image to your configured registry.

The envTemplate is where you can inject runtime information into your custom build command. Beyond simple string substitution, Skaffold offers more advanced templating capabilities if you need to pass more complex data. You can access environment variables, Skaffold configuration, and even build context information.

Here’s another example using buildah:

apiVersion: skaffold.dev/v2beta24
kind: Config
build:
  artifacts:
    - image: my-node-app
      custom:
        buildCommand: |
          buildah bud \

            --tag {{.IMAGE_NAME}}:{{.VERSION}} \

            --platform linux/amd64 \
            .
        envTemplate:
          MAP:
            IMAGE_NAME: my-node-app
            VERSION: v1.0.0

This configuration tells Skaffold to use buildah bud to build the image. The . at the end of the buildah bud command indicates that the build context is the current directory, where your Containerfile (or Dockerfile) would typically reside.

One aspect that often trips people up is how Skaffold manages the build context for custom builders. When you specify custom.buildCommand, Skaffold still gathers the build context (e.g., your application source code, Containerfile) and makes it available, usually as a tarball or a directory. The buildCommand itself will typically run within a temporary directory containing this context. This means your build script can directly reference files within that context, just as a docker build command would.

The next step after mastering custom builders is often integrating them with multi-stage builds or more advanced CI/CD workflows.

Want structured learning?

Take the full Skaffold course →