Managing Kubernetes namespaces comes down to four jobs: seeing what exists, working in the right one without mistakes, putting limits on what each team can consume, and making sure one team cannot touch another's workloads. This guide covers all four, with the exact kubectl commands, the policy objects that matter, and the pitfalls that catch people on shared clusters.
TL;DR
- List namespaces with
kubectl get namespaces, and change your default withkubectl config set-context --current --namespace=<name>so you stop typing-non every command. - A namespace is a naming and policy scope, not a security wall. Pair it with RBAC and NetworkPolicies if teams must be isolated.
- Use one ResourceQuota and one clearly named LimitRange per namespace to cap consumption and set sane container defaults.
- Most namespace incidents come from running a command against the wrong namespace or the wrong cluster. Make the active context visible before you act.
- Keep namespace definitions in Git and apply them with a GitOps tool so manual changes do not drift.
Table of Contents
- What a namespace actually gives you
- Listing namespaces with kubectl
- Changing the default namespace
- Switching between namespaces and clusters quickly
- Put limits on a namespace: ResourceQuota and LimitRange
- Isolation: a namespace is not a security boundary
- Creating and deleting namespaces safely
- Stop drift: manage namespaces from Git
- Our perspective: namespace mistakes are visibility mistakes
- Working across namespaces and clusters with Kubezilla Desktop
- A short namespace checklist
- FAQ
- Sources
What a namespace actually gives you
According to the Kubernetes documentation, namespaces isolate groups of resources within a single cluster. Resource names must be unique inside a namespace but not across namespaces, so two teams can each run a Deployment called api without colliding.
The same page is candid about when you need them: they are meant for environments with many users, and a cluster with a handful of users often does not need them at all. If three engineers share a dev cluster, extra namespaces can add friction without adding value.
A fresh cluster starts with four namespaces, as shown in the official task guide:
| Namespace | Purpose |
|---|---|
default | Where objects land when you specify nothing |
kube-system | Objects created by the Kubernetes system itself |
kube-public | Readable by all clients, reserved for cluster-wide public information |
kube-node-lease | Node heartbeat lease objects |
A common mistake is leaving real workloads in default. It works, but it gives you no boundary to hang quotas or access rules on, and it makes cleanup guesswork.
Listing namespaces with kubectl
The basic command is:
kubectl get namespaces
The output shows name, status and age. A few variations earn their keep daily:
# Short form
kubectl get ns
# Show labels, which policy tooling often keys on
kubectl get ns --show-labels
# See every pod in every namespace
kubectl get pods --all-namespaces
# Same thing, shorter
kubectl get pods -A
# Describe one namespace, including quotas and limit ranges applied to it
kubectl describe namespace payments
kubectl describe namespace is the underrated one. It prints any ResourceQuota and LimitRange attached to that namespace, which answers "why can't I schedule this?" faster than reading events.
When you list across namespaces, add -o wide or a custom column for the namespace so you can tell which api pod belongs to which team. With -A, the namespace column is included by default for most resource types.
Changing the default namespace
Every kubectl command runs against a namespace. If you do not say which, it uses the one set in your current context, and that is default unless you changed it.
The kubectl reference documents the persistent approach:
kubectl config set-context --current --namespace=payments
This rewrites the namespace stored in your current context in kubeconfig. From then on, kubectl get pods means pods in payments. To confirm what you are pointing at:
kubectl config view --minify | grep namespace:
Two behaviors to remember:
- An explicit
--namespace(or-n) flag always wins over the context default, so you can still peek at another namespace without changing anything. - The change belongs to the context, not the cluster. If you have separate contexts for staging and production, each keeps its own default namespace.
For one-off work, a shell alias such as alias kp='kubectl -n payments' is a lightweight option that leaves your kubeconfig untouched.
Why persistent defaults bite
Setting a default is convenient and slightly dangerous. You set payments on Monday, forget, and on Thursday run kubectl delete deployment api expecting a different namespace. The command succeeds, because a deployment named api exists there too.
Habits that prevent this:
- Put the current context and namespace in your shell prompt.
- Use
-nexplicitly for anything destructive, even if the default is correct. - Run
kubectl get <resource> -n <ns>first and read the output before you delete.
Switching between namespaces and clusters quickly
The set-context command is verbose, which is why engineers wrap it in aliases, shell functions or small helper utilities. That works for a single cluster. It gets harder with several clusters, because you are now juggling context names, kubeconfig files and namespaces together.
The failure pattern is predictable: the namespace is right, the cluster is wrong. A namespace called production can exist in three clusters. A visible, unified view of cluster and namespace together is more valuable than a faster way to type the switch. We return to this in our perspective section below.
Put limits on a namespace: ResourceQuota and LimitRange
A namespace without limits is just a label with ambitions. Two objects turn it into something you can actually manage.
ResourceQuota: the namespace ceiling
Per the Kubernetes resource quota docs, quotas address the concern that one team could use more than its fair share of a cluster with a fixed number of nodes. A ResourceQuota caps aggregate consumption in a namespace: total CPU and memory requests, and counts of objects such as pods or services.
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-quota
namespace: payments
spec:
hard:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "50"
When a request would push the namespace over a quota, the API server rejects it with a 403 Forbidden response, according to the same documentation. Teams usually see this as a failed deploy, so tell them quotas exist before they hit one.
A pitfall for migrations: quota checks apply when a resource is created. Existing pods are not evicted when you add a quota, so a namespace can already be over its new limit and you will need a cleanup plan.
One more catch. If a quota tracks CPU or memory, every new pod must declare requests and limits for them, or be rejected. That is where LimitRange comes in.

LimitRange: defaults and per-container bounds
The LimitRange documentation explains that containers run with unbounded compute resources by default. A LimitRange sets minimums, maximums and default requests and limits for individual containers or pods in a namespace.
apiVersion: v1
kind: LimitRange
metadata:
name: container-defaults
namespace: payments
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 250m
memory: 256Mi
With this in place, a pod that forgets to declare resources inherits the defaults instead of being rejected by the quota. Keep one LimitRange per namespace with a clear name. When several exist in the same namespace, the defaults that get applied are not predictable, which is a miserable thing to debug.
Quota versus limit range
| ResourceQuota | LimitRange | |
|---|---|---|
| Scope | Whole namespace | Each pod or container |
| Answers | "How much can this team use in total?" | "How big can one workload be, and what if it says nothing?" |
| Typical failure | Deploy rejected with 403 | Pod gets defaults you did not expect |
Use both. Quota without defaults frustrates developers; defaults without quota protect nothing at the namespace level.
Isolation: a namespace is not a security boundary
This is the point most guides bury. Namespaces are logical boundaries. On their own they organize resources; they do not secure them. Pods in one namespace can, by default, talk to pods in another.
For real multi-tenant separation you need to add:
- RBAC, so a team's Roles and RoleBindings only grant access to its own namespace, and so teams cannot edit or delete the policies meant to constrain them.
- NetworkPolicies, so traffic between namespaces is denied unless you allow it.
- Quotas and limit ranges, so a noisy neighbor cannot starve the rest.
Managed platforms follow the same logic. Microsoft's overview of managed namespaces in AKS describes using namespaces for logical isolation of teams and workloads within one cluster, with policy layered on top.
A practical default for a new tenant namespace: a default-deny NetworkPolicy, a RoleBinding scoped to that team's group, one ResourceQuota and one LimitRange. Create all four together, every time.
Creating and deleting namespaces safely
Create one imperatively for a quick test:
kubectl create namespace scratch
For anything lasting, write the manifest and commit it. Specifying metadata.namespace in your YAML also prevents the classic accident of applying a manifest into whatever namespace your context happens to point at.
Deletion deserves respect. Deleting a namespace deletes everything inside it: deployments, services, config maps, secrets, and persistent volume claims. Before you run kubectl delete namespace, list what is in there:
kubectl get all,pvc,configmap,secret -n scratch
If a namespace hangs in Terminating, it is usually because a resource inside still has a finalizer that is waiting on something. Google's troubleshooting page on namespaces stuck in Terminating explains that namespaces use finalizers to block deletion while resources remain. Find the remaining resources and the controller responsible before you force anything, because stripping finalizers by hand can leave orphaned external resources behind.
Stop drift: manage namespaces from Git
Hand-created namespaces are fine on day one. By month six nobody knows which quota is current or who changed a LimitRange. The remedy is declarative: store namespaces, quotas, limit ranges, RBAC and NetworkPolicies in Git and let a GitOps controller apply them.
Red Hat's developer article on managing namespaces in multitenant clusters with Argo CD, Kustomize and Helm walks through provisioning namespaces together with quotas and limit ranges automatically. It dates from 2022, so check current Argo CD syntax, but the pattern holds: one template, many namespaces, no hand edits.
If you run Argo CD across several clusters, our post on Argo CD across clusters covers the credential side.
Our perspective: namespace mistakes are visibility mistakes
We build a desktop tool for people who work in many clusters every day, so we see the same pattern in how engineers describe their incidents. Almost nobody says "I didn't understand namespaces." They say "I thought I was in staging."
The commands are not the hard part. get, describe, set-context are simple. The hard part is that the state that matters, which cluster, which namespace, which credentials, lives in a kubeconfig file and a prompt, and is easy to stop noticing. Add three or four clusters, a couple of SSH tunnels or bastion hops, and each action becomes a small gamble.
That is why we think about namespace management as a problem of keeping context in front of you rather than a problem of typing less. A single interface that holds multiple clusters, shows resources, logs and metrics side by side, and keeps kubeconfigs stored locally means fewer terminals to confuse. It also means you do not paste cluster credentials into a browser-based service to get that view. Our position is local-first: no cloud sync, no telemetry.
A few rules we would give any team, with or without our tool:
- Treat the production context as hazardous. Make it look different in your prompt or window.
- Never rely on the default namespace for deletes or scaling.
- Put quotas on every shared namespace from the start. Adding them later is a migration project.
- Keep namespace policy in Git. If it cannot be rebuilt from the repo, it is not managed.
— Margus
Working across namespaces and clusters with Kubezilla Desktop
If you spend your day hopping between namespaces and clusters, Kubezilla Desktop is a native app for Linux, macOS and Windows that gives you one interface for cluster and resource operations. You can connect to multiple clusters, reach remote ones through SSH tunnels, stream live logs, watch metrics, open pod terminals, edit YAML, scale workloads, and run Helm and Argo CD operations. Kubeconfigs stay stored locally on your machine, and the app is built in Rust to stay light on memory.
It costs 5 EUR per month. See the pricing page for details, or read more about the Kubernetes desktop app approach.
A short namespace checklist
Use this when you onboard a team or audit a cluster:
- Does each team or environment have its own namespace, and is nothing real running in
default? - Does each shared namespace have one ResourceQuota and one named LimitRange?
- Is there a default-deny NetworkPolicy, with explicit allows for the traffic you expect?
- Are RoleBindings scoped to the namespace and to the right group?
- Can the namespace, with its policies, be recreated from Git?
- Does everyone know how to see their active cluster and namespace before running a destructive command?
If you manage workloads across several clouds, the same checklist applies per cluster. Our posts on multi-cloud Kubernetes management and multi-cluster management go deeper on that side. When you act on a namespace, our guides to scaling a deployment and restarting a deployment show how to avoid bulk mistakes.
FAQ
How do I list all namespaces in a cluster?
Run kubectl get namespaces, or kubectl get ns for short. Add --show-labels to see labels, and use kubectl get pods -A to list pods across every namespace at once. You need permission to list namespaces, which some restricted RBAC roles do not grant.
How do I change the default namespace in kubectl?
Run kubectl config set-context --current --namespace=<name>. This stores the namespace in your current context, so later commands use it without -n. Confirm it with kubectl config view --minify. An explicit --namespace flag still overrides the default.
Do I need namespaces on a small cluster?
Not always. The Kubernetes documentation recommends them for clusters with many users and says small clusters often do not need them. Add them when you need separate quotas, access rules or clean separation of environments or teams.
Are namespaces enough to isolate tenants?
No. A namespace is a logical scope, not a security boundary. To keep tenants apart you also need RBAC scoped to each namespace and NetworkPolicies that restrict traffic between namespaces. Quotas then stop one tenant from consuming the shared capacity.
Why was my deployment rejected with 403 Forbidden after I added a quota?
The API server rejects requests that would exceed a namespace ResourceQuota, and the resource quota documentation describes this as a 403 response. Check kubectl describe namespace <name> for current usage against limits. If the quota covers CPU or memory, make sure your pods declare requests and limits, or add a LimitRange with defaults.
Sources
- Namespaces | Kubernetes
- Share a Cluster with Namespaces | Kubernetes
- Command line tool (kubectl) | Kubernetes
- Resource Quotas | Kubernetes
- Limit Ranges | Kubernetes
- Overview of Managed Namespaces in AKS | Microsoft Learn
- Troubleshoot namespace stuck in the Terminating state | Google Cloud
- Manage namespaces in multitenant clusters with Argo CD, Kustomize, and Helm | Red Hat Developer
