ko
Build and deploy Go container images without a Dockerfile
TLDR
SYNOPSIS
ko command [flags] [import-path]
DESCRIPTION
ko is a container image builder dedicated to Go. It compiles a Go main package with the local go toolchain, lays the resulting static binary on top of a small distroless base image, and produces an OCI image, all without spawning docker or executing a Dockerfile. Because the build is just go build, cross-compilation, reproducible builds, and Go module caching all work as they do outside of containers.A typical workflow stores a fragment of YAML such as image: ko://github.com/me/app/cmd/server in a Kubernetes manifest. ko resolve reads the manifest, runs ko build for every such reference, pushes the resulting images to $KO_DOCKER_REPO, and emits a new manifest where each ko:// reference has been rewritten to an immutable digest. ko apply does the same and pipes the output to kubectl apply, giving GitOps-style deployment in a single command.Images include an SBOM by default (SPDX) and are reproducible across machines because the Go binary, base image digest, and entrypoint are the only inputs. Multi-platform images are built in parallel and assembled into an OCI image index.
PARAMETERS
-B, --base-import-paths
Tag images with only the final path component (e.g. app).-P, --preserve-import-paths
Tag images with the full import path.--bare
Use $KODOCKERREPO as the image name verbatim, with no suffix.--platform list
Comma-separated platforms (e.g. linux/amd64,linux/arm64,linux/arm/v7). Use all for every platform the base image supports.-t, --tags list
Comma-separated tags applied to the published image (default: latest).-L, --local
Load the built image into the local Docker daemon instead of pushing.--image-refs file
Write the published image references to file, one per line.--sbom format
SBOM format to embed: spdx (default), cyclonedx, go.version-m, or none.--push bool
When false, build without pushing. Useful with --tarball.--tarball file
Write the image to a tarball loadable by docker load.--kubeconfig file
Path to a kubeconfig used by apply, create, run, delete.--selector label=value
Apply only to resources matching the label selector.
CONFIGURATION
ko reads a per-project .ko.yaml at the repository root. Common keys:defaultBaseImage: registry/image:tag
Distroless image used as the base layer (default: cgr.dev/chainguard/static).baseImageOverrides: map
Per-import-path base images.builds: list
Per-import-path build settings (env, flags, ldflags, main, dir).defaultPlatforms: list
Default value for --platform.ko also honors these environment variables:KO_DOCKER_REPO
Target registry/repo. Set to ko.local to write to the local Docker daemon, or kind.local to load into a Kind cluster.KO_DEFAULTBASEIMAGE
Overrides defaultBaseImage from .ko.yaml.KOCACHE
Directory used to cache built layers; speeds up incremental builds.KO_CONFIG_PATH
Path to .ko.yaml when it is not at the repo root.
COMMANDS
ko build [import-path ...]
Build OCI images for one or more Go main packages and push them to $KO_DOCKER_REPO. Aliases: publish.ko resolve -f file
Read Kubernetes YAML, build every ko:// image reference, push it, and print the manifest with each reference rewritten to its image digest.ko apply -f file
Like resolve, then pipe the rewritten manifest into kubectl apply.ko create -f file
Like resolve, then pipe into kubectl create.ko delete -f file
Delete resources defined in the manifest from the cluster.ko run import-path
Build the binary, push the image, and run it as a Pod in the cluster.ko login registry
Authenticate to a container registry; credentials are stored in the standard Docker config file.ko deps import-path
Print the Go module dependency tree that would be baked into the image.ko version
Print client version.
CAVEATS
ko only ships Go binaries; cgo, system packages, and arbitrary RUN steps are not supported. Projects that need glibc, system tools, or a custom base layer must pick an alternate distroless or cgr.dev/chainguard/\* base via defaultBaseImage, or use a different builder.The --local flag requires a running Docker daemon; without it, ko talks directly to the registry and never touches Docker.
HISTORY
ko was created at Google in 2018 by Jason Hall, Matt Moore, and others on the Knative team to publish their Go services without writing Dockerfiles. It was donated to the ko-build GitHub organization in 2021 and accepted into the CNCF Sandbox in 2022.
