Skip to main content
You just ran kubebuilder init. When you open the generated folder it can feel like Kubebuilder dumped a lot of files at once. Think of this project as a labeled workbench: Kubebuilder has already placed the tools and drawers before you build the operator. You don’t need to memorize every file — just know which drawer to open for each job.
Treat this layout as a simple map: knowing where startup code, API types, reconcile logic, deployment manifests, and helper targets live is enough to get productive.
Start at the root. PROJECT is the label on this workbench. It records the domain, repo path, project name, and every API you add later. Kubebuilder regenerates it as needed, so you generally should not hand-edit it.
The PROJECT file is code-generated. Avoid manual edits unless you fully understand the implications—let Kubebuilder and plugins manage this file.
A typical generated PROJECT file looks like:
Next to it, go.mod is the parts list for a Go project. It pins dependencies such as controller-runtime and the Kubernetes client libraries. The Makefile is the row of buttons on the bench. Targets like make manifests, make generate, make run, and make docker-build run the same workflow the same way every time. Below is an excerpt showing common variables and setup that many targets depend on:
Dockerfile is the packaging station: one stage builds the Go binary, and a smaller image runs it. This multi-stage example is the common pattern Kubebuilder projects use (slightly cleaned for clarity):
The code in cmd/main.go is the operator’s power switch and the entry point for the controller-runtime manager. The manager owns the shared Kubernetes client, the cache, metrics and health probes, leader election, and controller registration. A minimal example showing webhook server setup looks like:
After you scaffold an API with kubebuilder create api, the generated controllers will be registered from this startup code. The config/ directory is the deployment drawer. It holds Kustomize overlays and base manifests so you can compose deployable YAML without duplicating shared pieces. For example, a config/default/kustomization.yaml often ties resources together and can include namespace, namePrefix, labels, and other resource references:
  • config/manager contains the controller Deployment/Pod spec.
  • config/rbac contains Role/ClusterRole and RoleBinding/ClusterRoleBinding yaml.
  • config/crd/ will hold generated CRD YAMLs after make manifests.
  • config/samples/ stores example custom resources you can apply to test controllers.
Kubebuilder also scaffolds helper files like hack/boilerplate.go.txt to append license headers to generated Go files. A sample RBAC rule in config/rbac looks like:
test/ is where end-to-end or integration tests live. .golangci.yml configures the linter used by make lint. A typical configuration that demonstrates plugin usage is:
These support tools are important to know where they live, but you don’t need to memorize every setting. Focus on the files you’ll edit most often. Now notice what is not here yet: there is no api/ directory and no controllers/ directory. That is expected: those folders appear after you run kubebuilder create api.
  • api/ will hold the webapp Go types (API shapes).
  • controllers/ will hold the reconciler, which is the code that reacts when a webapp changes.
Quick directory map Keep this map in your head: startup code in cmd/, API shapes in api/, reconcile logic in controllers/, deployment YAML in config/, and repeatable commands in the Makefile. Once that map is clear, the scaffold stops feeling like a wall of files and starts feeling like a workbench with labeled drawers. Use kubebuilder create api to scaffold your first API and controller. Links and references

Watch Video