← Back to blog

Kubernetes Namespace Management: A Practical Guide

October 20, 2026
Kubernetes Namespace Management: A Practical Guide

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.

Kubezilla Desktop
Manage Kubernetes Clusters in One Interface
Kubezilla Desktop connects multiple clusters in a native app, with live logs, metrics, and access to Helm and ArgoCD operations.
Explore Kubezilla Desktop

TL;DR

  • List namespaces with kubectl get namespaces, and change your default with kubectl config set-context --current --namespace=<name> so you stop typing -n on 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

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:

NamespacePurpose
defaultWhere objects land when you specify nothing
kube-systemObjects created by the Kubernetes system itself
kube-publicReadable by all clients, reserved for cluster-wide public information
kube-node-leaseNode 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:

  1. An explicit --namespace (or -n) flag always wins over the context default, so you can still peek at another namespace without changing anything.
  2. 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 -n explicitly 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.

ResourceQuota: the namespace ceiling — overview diagram

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

ResourceQuotaLimitRange
ScopeWhole namespaceEach 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 failureDeploy rejected with 403Pod 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:

  1. Treat the production context as hazardous. Make it look different in your prompt or window.
  2. Never rely on the default namespace for deletes or scaling.
  3. Put quotas on every shared namespace from the start. Adding them later is a migration project.
  4. 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:

  1. Does each team or environment have its own namespace, and is nothing real running in default?
  2. Does each shared namespace have one ResourceQuota and one named LimitRange?
  3. Is there a default-deny NetworkPolicy, with explicit allows for the traffic you expect?
  4. Are RoleBindings scoped to the namespace and to the right group?
  5. Can the namespace, with its policies, be recreated from Git?
  6. 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