kuttl: declarative Kubernetes tests that read as a folder of YAML steps
KUbernetes Test TooL (kuttl)
At a glance
- What is it?
- kuttl is a Go tool for testing Kubernetes operators declaratively, where each test is a directory of YAML steps asserting on the objects that result, rather than a script written in Go. It runs through a kubectl plugin, works with any Kubernetes objects, and can execute the whole suite inside a container against a cluster.
- Who is it for?
- kuttl fits a team maintaining Kubernetes operators who wants tests that a reviewer can read without knowing Go, and who already has a cluster or a kind cluster to run them against. It does not fit a team that needs unit level tests of controller logic, or one that has no cluster available in CI.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 25, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A test tool that is designed for operators
KUTTL stands for KUbernetes Test TooL and provides a declarative approach to testing Kubernetes operators. The README makes a distinction that matters for scope: it is designed for testing operators, however it can declaratively test any Kubernetes objects.
That second clause is the useful one in practice. Most operator teams eventually need to verify more than the operator itself, since an operator's behaviour often shows up in the custom resources, the secrets, the services and the configuration it writes. A tool that only understands operators forces you to test the surrounding objects with a different framework.
The approach is declarative in the sense that a test describes expected states rather than steps to execute. The repository contains a kuttl-test.yaml file at the top level, which is the configuration file for a test suite, and the docs directory carries the getting started guide that the README points to for all usage detail. The README itself is short, and deliberately so: it describes what the tool is and points at the documentation rather than trying to summarise it.
The implementation is Go, the licence is Apache-2.0, and the last push to the repository was on 2026-10-19. The release history is steady, with v0.27.0 on 2026-09-23, v0.26.0 on 2026-05-11 and v0.25.0 on 2026-02-18.
It runs as a kubectl plugin, not a standalone binary
The build setup is worth understanding because it explains how the tool is invoked. The Makefile defines the CLI as kubectl-kuttl, and the version information is stamped into the binary through linker flags pointing at internal/version.gitVersion, gitCommit and buildDate, with the build date derived from the commit timestamp so that a rebuild of the same commit produces the same date.
The dependency list in go.mod shows what a Kubernetes testing tool has to carry. It pulls in the Kubernetes API, apiextensions-apiserver, apimachinery, client-go and code-generator at 0.37.1, and controller-runtime at 0.25.2. It uses controller-tools at 0.23.0 and sigs.k8s.io/kind at 0.33.0, which is the kind cluster tool, and cobra with pflag for the command line. The CEL library from Google appears at v0.31.0, along with sprig for templating, yaml.v2 and yaml.v3, and Masterminds semver. There is also a dependency on the moby API and client, which is how the tool talks to a container runtime.
The go directive is go 1.26.0, so the tool tracks recent Go releases. The lint configuration is golangci-lint at version 2.11.4, and the Makefile carries a comment reminding contributors to update the linter list in the configuration when they bump that version, which is the kind of housekeeping note that only appears in a project where people actually bump things.
Because the binary is a kubectl plugin, the invocation is kubectl kuttl rather than a separate command on the path, and the Docker image encodes that in its entrypoint.
Running the suite from a container
The Dockerfile is the most informative file in the repository, because its leading comment block explains the whole runtime model. The image is meant to run kuttl tests from Docker, and it expects a mount point to be provided where /opt/project is the root of the test suite. The root of that mount point needs a kuttl-test.yaml file and a kubeconfig file that a process running in Docker can reach.
The comment names the kind case specifically. It says that if you use kind, then `kind get kubeconfig --internal > kubeconfig` provides the proper configuration, and it notes that 0.8.0 of kind breaks this ability and that the problem is being worked on in the kind community. That is a concrete, dated caveat that will bite anyone running this against kind.
The invocation is then simple. Assuming a test folder at the mount root named e2e, the comment gives:
docker run -v $PWD:/opt/project kuttl e2eAnd there is a second form for running the tests from within the cluster, by specifying an empty KUBECONFIG so that kuttl uses the in-cluster config:
docker run -e KUBECONFIG= -v $PWD:/opt/project kuttl e2eThe image itself is built in two stages. The builder is golang:1.24 and runs go get and make cli. The release image is based on the Red Hat UBI 8 minimal image, with vim, tar and gzip installed and an alias mapping vi to vim, plus kubectl 1.31.0 downloaded into /usr/local/bin. The final image copies the built binary to /usr/bin/kubectl-kuttl, sets the working directory to /opt/project, sets KUBECONFIG to kubeconfig by default, and declares the entrypoint as kubectl kuttl test so that flags and a test folder can be passed as the command arguments.
The repository structure tells you what the tool covers
The top-level entries are the clearest description of scope. There is a cmd directory for the command entry points, a pkg directory for the library surface, an internal directory, a config directory, a crds directory for custom resource definitions, and a test directory. The keps directory holds Kubernetes enhancement proposals, which tells you the project engages with the upstream process rather than only shipping a tool.
There are also the supporting files a project of this size accumulates: a Makefile, a Dockerfile, a DOCKER.md, a .goreleaser.yml for release binaries, a .golangci.yml for linting, a hack directory for scripts, a tools.go file, a SECURITY_CONTACTS file, an OWNERS file, a RELEASE.md and a CONTRIBUTING.md. The .travis-era CI configuration is gone, replaced by GitHub Actions workflows, and the README badges show separate lint, unit test and integration test pipelines.
The three CI pipelines are the detail that matters most for evaluation, because they tell you what the project considers its quality gates. Linting runs on its own, unit tests run on their own, and integration tests run on their own. Integration testing a Kubernetes tool means a real cluster in CI, which means the project either uses kind or a hosted cluster, and the kind caveat in the Dockerfile suggests kind.
There is also a docs directory with the getting started guide that the README delegates to, and the release cadence of roughly every two to three months suggests a project that maintains compatibility with Kubernetes releases rather than chasing them.
Where kuttl is the wrong choice
The first limitation is that kuttl needs a cluster. Every test runs against a live Kubernetes API, so a team without cluster access in its development environment or in CI cannot use it at all. This is a much larger operational commitment than a unit test library, and it is worth being honest that a passing kuttl suite proves something different from what a fast unit test suite proves.
The second is the kind of test it can write. Because the assertions are on observed cluster state, kuttl verifies convergence: that the operator eventually produces the expected object, resource or status. It does not verify the internal logic that got there. A bug in a branching condition that happens to converge on the expected state in one case will not be caught. That is why the project sits alongside controller-runtime and envtest rather than replacing them, and a team that skips those layers is testing less than it thinks.
The third is the ceiling on readability. A YAML step directory is easier to review than Go, but it is not unlimited. Once a test needs to make a decision based on what it observed, the declarative format runs out, and the suite either stays simple or grows the kind of workaround that makes tests brittle. The tool is best at the direct case: apply this object, assert that this resource eventually has these fields.
The alternative is worth naming honestly. Writing the tests in Go against a fake client gives full control and fast feedback, at the cost of a suite that only your team can comfortably read and maintain. For an operator whose behaviour is mostly reconciliation, kuttl's declarative form is a genuine improvement in reviewability. For an operator with complicated logic, the Go tests are where the coverage should live regardless.
Editorial conclusion
kuttl fits a team maintaining Kubernetes operators who wants tests that a reviewer can read without knowing Go, and who already has a cluster or a kind cluster to run them against. It does not fit a team that needs unit level tests of controller logic, or one that has no cluster available in CI. Before adopting it, read the getting started guide rather than the short README, since the README delegates all usage detail to the documentation, check how your operator reconciles so the assert steps poll on a condition rather than a fixed delay, and confirm the kubectl plugin installation path works in your environment, because the binary is distributed as kubectl-kuttl and invoked through kubectl.
Frequently asked questions
What is kuttl used for?
kuttl is a Go tool that provides a declarative approach to testing Kubernetes operators. It is designed for operators, and the README notes it can declaratively test any Kubernetes objects, which lets a team verify custom resources, services and other outputs in the same style.
How is kuttl invoked and how is it distributed?
The CLI is named kubectl-kuttl and it works as a kubectl plugin, so the Docker image declares the entrypoint as kubectl kuttl test and the release image installs kubectl 1.31.0 alongside the built binary.
How do I run the kuttl test suite in a container?
Mount the test suite root at /opt/project, which needs a kuttl-test.yaml file and a reachable kubeconfig, then run `docker run -v $PWD:/opt/project kuttl e2e`. To run from inside the cluster, pass an empty KUBECONFIG so kuttl uses the in-cluster config.
Does kuttl work with kind clusters?
The Dockerfile notes that with kind you should use `kind get kubeconfig --internal > kubeconfig` to produce a configuration a Docker process can reach, and that kind 0.8.0 breaks this ability, with the issue being worked on in the kind community.
Which Kubernetes and Go versions does kuttl target?
The go.mod declares go 1.26.0 and pins the Kubernetes API, apiextensions-apiserver, apimachinery, client-go and code-generator at 0.37.1, with controller-runtime at 0.25.2 and controller-tools at 0.23.0. The Docker builder stage uses golang:1.24 and the release image ships kubectl 1.31.0.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/kudobuilder-kuttl)Was this useful?