
How to Find Unused PVCs in Kubernetes
PVCs can remain after their workloads are gone. Kubernetes v1.37 adds an Unused status to PVCs, so you can list claims that no active pods reference.
The Short Answer
Run this command to list unused PVCs across all namespaces. It needs kubectl and jq:
kubectl get pvc -A -o json | jq -r '
.items[]
| select(.status.conditions[]? | select(.type == "Unused" and .status == "True"))
| "\(.metadata.namespace)/\(.metadata.name)"
'
Example output:
payments/archive-data
Each result is shown as namespace/name. The -A flag includes all namespaces. To check one namespace, replace -A with -n <namespace>.
What Kubernetes v1.37 Adds
Kubernetes v1.37 adds the Unused condition through the PersistentVolumeClaimUnusedSinceTime feature. It is Beta and enabled by default. Kubernetes updates the condition as pods start and stop using a claim.
You can inspect the condition on an individual claim with:
kubectl get pvc archive-data -n payments -o yaml
In the output, find type: Unused. The status will be True or False.
Find Claims That Have Been Idle for a While
Each condition has a lastTransitionTime, which records when it last changed. This command lists claims that have been unused for more than 30 days:
kubectl get pvc -A -o json | jq -r '
.items[]
| . as $pvc
| (($pvc.status.conditions // []) | map(select(.type == "Unused" and .status == "True")) | .[0]) as $unused
| select($unused != null)
| select((now - ($unused.lastTransitionTime | fromdateiso8601)) > (30 * 86400))
| "\($pvc.metadata.namespace)/\($pvc.metadata.name) unused since \($unused.lastTransitionTime)"
'
The 30 * 86400 part sets the age limit in seconds. Change 30 to choose a different number of days.
Read the Unused Condition
Unused=True means no non-terminal pods reference the claim. Unused=False means a running or pending pod does. Completed and failed pods do not count. If several pods use a claim, it stays marked in use until they are all gone.
If the condition is missing, check your Kubernetes version and feature settings. A missing condition does not tell you whether a claim is in use.
Important Edge Cases
The condition tracks pod references, not reads or writes to storage. A claim marked unused may still contain data you need or be used again later.
Check the Results Before Cleanup
Treat this list as a starting point. Before deleting a claim, check:
- Whether an application or team still owns it.
- Whether a scaled-down workload, scheduled job, or StatefulSet may use it again.
- Whether you need to keep its data or have a backup.
- What happens to the storage if you delete the PVC. Check the PersistentVolume’s reclaim policy.
If you are unsure, ask the owner before deleting it.
Optional: Limit the Search
To check one namespace, add -n and print only the claim name:
kubectl get pvc -n payments -o json | jq -r '
.items[]
| select(.status.conditions[]? | select(.type == "Unused" and .status == "True"))
| .metadata.name
'
You need permission to list PVCs in the namespace. The -A version also requires cluster-wide list permission.
Summary
Filter for Unused=True to find claims that no non-terminal pods reference. Use lastTransitionTime to see how long they have been unused. Check with the owner and protect any data you still need before deleting a claim.