Self-hosted service
yonahd/kor avatar
yonahd/kor

Kor for Kubernetes: Finding Unused Cluster Resources

A Golang Tool to discover unused Kubernetes Resources

1,896 stars154 forksGoMIT

At a glance

What is it?
Kor is a Go command-line tool for discovering unused Kubernetes resources across namespaces and cluster-scoped objects. It supports filtering, optional deletion, Prometheus metrics, Helm deployment, and a documented exception mechanism.
Who is it for?
Adopt Kor for read-only inventory of potentially unused Kubernetes objects, then verify workload intent and references before deleting anything. Do not use its unused classification as automatic proof of removal when external controllers, retention rules, or operational dependencies may exist.
Can I use it commercially?
Yes. MIT 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 1 day 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 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Kor Checks in a Cluster

Kor addresses a specific Kubernetes maintenance problem: finding objects that appear to have no active user or workload relationship. It is intended for cluster operators, platform engineers, and developers reviewing namespaces that have accumulated obsolete configuration or workload objects. The README describes detection for ConfigMaps, Secrets, Services, ServiceAccounts, Deployments, StatefulSets, Roles, ClusterRoles, ClusterRoleBindings, HPAs, PVCs, Ingresses, PDBs, CRDs, PVs, Pods, Jobs, ReplicaSets, DaemonSets, StorageClasses, NetworkPolicies, RoleBindings, VolumeAttachments, PriorityClasses, and resources pending deletion through the `finalizer` command.

The distinction between namespaced and cluster-scoped resources matters. Commands such as `configmap`, `secret`, `service`, and `deployment` can target a specified namespace or all namespaces. Commands such as `clusterrolebinding`, `pv`, `storageclass`, `crd`, `volumeattachment`, and `priorityclass` operate at cluster scope. The README also states that `clusterrole` examines namespace context through RoleBindings, which is a useful reminder that resource classification does not always match a simple namespaced versus cluster-wide split.

Kor reports candidates rather than providing a general-purpose Kubernetes dependency graph. That makes it useful for inventory and cleanup preparation, but it also means the output should be reviewed against application behavior. The documentation does not claim that every candidate is safe to delete.

How the Go CLI Queries Kubernetes

Based on the repository layout and Go module, Kor is organized as a Cobra-based command-line application with entry-point code in `main.go`, command definitions under `cmd/`, and implementation packages under `pkg/`. It depends on `k8s.io/client-go`, Kubernetes API types, API machinery packages, Cobra, and Viper. Those dependencies indicate that the tool talks to the Kubernetes API through Go clients and parses command-line and configuration input rather than scraping the Kubernetes dashboard.

The command flow is direct. A subcommand selects a resource family, optional namespace and label filters constrain the search, and the result is printed as a list of unused candidates. The `exporter` command is the documented route for Prometheus metrics. In-cluster use can run Kor as a CronJob, with an option for Slack updates, or as a deployment exposing Prometheus metrics. The Helm chart is located at `./charts/kor`, so the installation mechanism is versioned with the repository rather than being only a shell script.

The README exposes several controls that affect what gets considered. `--older-than` and `--newer-than` set an age boundary, and the two flags cannot be used together. Namespace include and exclude lists are comma-separated. Label exclusion accepts selectors such as `key1=value1,key2=value2`, while label inclusion currently supports one label. If inclusion is set, the README says the corresponding exclusion option is ignored. `--group-by` changes output grouping and defaults to `namespace`. These controls are useful for reducing a broad result set, but they also create combinations that operators need to check before acting.

Installing Kor and Running a First Audit

The README offers several installation paths. For a quick local audit on macOS, Homebrew installs the command and puts it on the user's command path. Developers can install the latest module version with Go, or build a local checkout with `go build main.go`. Kubernetes plugin users can install the Krew command. The Helm path adds Kor's chart repository and can create either a CronJob or a deployment.

For a first use, the smallest documented workflow is to install the binary and run `kor` without `--delete`. That produces an inventory rather than modifying the cluster.

Namespace, Age, and Output Filters

A broad audit can be narrowed with `--include-namespaces`, which accepts comma-separated namespace names. The README warns that when `--include-namespaces` is set, non-namespaced resources are ignored. This behavior is important for operators who expect a complete cluster-wide review from the same invocation. A namespace-scoped pass and a cluster-scoped pass are different operations in Kor's command model.

Age filters are expressed as Go-style durations in the documented examples. `--older-than` defines the minimum age for a resource to be considered unused, while `--newer-than` defines the maximum age. The flags cannot be combined. This can help distinguish recently created objects from older leftovers, but it also means a resource outside the selected age window will not appear. The exact interpretation of age should be checked against the command being run before using the output as a cleanup list.

Label selectors provide another boundary. `--exclude-labels` can omit objects carrying specified labels, while `--include-labels` currently supports one label. The README says inclusion takes precedence when both inclusion and exclusion are supplied. That is convenient for protecting marked objects, but it does not document support for multiple include labels. Operators should record the selector used with an audit so that later deletion decisions can be reproduced.

Output grouping can be changed with `--group-by`, whose documented default is `namespace`. The `all` command combines checks for supported resource types, while individual commands provide a narrower query. Individual commands are preferable when reviewing one object class, especially before using `--delete`.

Helm, Metrics, and Deletion Boundaries

The Helm chart supports two distinct deployment shapes. Enabling `cronJob.enabled=true` is documented for scheduled in-cluster runs and includes an option for Slack updates. Installing without that option is documented as a deployment that exposes Prometheus metrics. The commands are explicit about the namespace and chart path:

bash
helm repo add kor https://yonahd.github.io/kor

This command adds the repository named `kor`. The following chart installation enables the CronJob mode and creates the `kor` namespace if needed.

bash
helm upgrade -i kor \
    --namespace kor \
    --create-namespace \
    --set cronJob.enabled=true \
    ./charts/kor

For a deployment rather than the CronJob mode, the README shows the same install flow without the `cronJob.enabled=true` setting. The chart directory includes deployment configuration, but the README does not document metrics port, scrape interval, Slack credentials, or retention settings. Those values should be read from the chart before deploying it.

Deletion is an opt-in operation exposed through `--delete`. The `--no-interactive` flag suppresses the confirmation prompt, and the README labels that option as potentially dangerous. Kor therefore supports automation, but the safe operational sequence is a listing first, review the exact resource names and namespaces, then a separate deletion run. The documentation does not describe rollback, dry-run output, audit logging, or recovery behavior after deletion.

Repository, Release, and License Context

The repository is written primarily in Go and declares `github.com/yonahd/kor` as its module. Its `go.mod` requires Go `1.26.8` and Kubernetes client packages at `v0.37.1`. The `Dockerfile` uses `golang:1.26.8` for the build stage, copies the resulting binary into a `scratch` image, installs CA certificates, and sets the container entrypoint to `/usr/bin/kor` with `--help` as the default command.

This build setup makes the container small because the final image contains the binary and certificate bundle rather than a full base operating system. It also means the container needs a working kubeconfig mount when used against a cluster. The README's Docker examples run the image interactively, including an example that mounts `/path/to/.kube/config` at `/root/.kube/config`.

The repository lists releases `v0.6.9` and `kor-0.2.16` on 2026-09-04, plus `v0.6.8` on 2026-04-22. The last push was on 2026-10-01. The project is not archived. The repository includes a Makefile with build, lint, test, and exception-file maintenance targets. The exception files under `pkg/kor/exceptions` are used by project maintenance checks for sorting and duplicate detection, although the truncated README does not explain the runtime matching semantics.

The declared license is MIT. That identifies the repository's licensing label, but users still need to review the `LICENSE` file and any dependency notices for their own compliance and distribution requirements.

Editorial conclusion

Adopt Kor for read-only inventory of potentially unused Kubernetes objects, then verify workload intent and references before deleting anything. Do not use its unused classification as automatic proof of removal when external controllers, retention rules, or operational dependencies may exist. The first checks are Kubernetes client permissions, the selected namespace scope, label and age filters, and the exact resource kind before any `--delete` operation.

Frequently asked questions

How do I install Kor?

The README documents Homebrew installation with `brew install kor`, Go installation with `go install github.com/yonahd/kor@latest`, local source builds with `go build main.go`, Krew installation, and Docker usage. Choose the path that matches the target environment.

How do I find unused resources in a specific namespace?

Use a resource subcommand such as `configmap` or `deployment` and pass the documented `--include-namespaces` flag with comma-separated namespace names. The README says this flag ignores non-namespaced resources.

Does Kor delete unused Kubernetes resources automatically?

No. The README lists `--delete` as a flag for deleting unused resources and `--no-interactive` as a way to suppress confirmation. The documentation does not describe rollback or recovery, so listing and reviewing results first is the safer workflow.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. yonahd/kor on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/yonahd-kor.svg)](https://hysenlabs.com/projects/yonahd-kor)

Was this useful?