kubectx
.mdVerified against kubectx/kubens v0.11.0, flags verified via `kubectx --help` / `kubens --help` run · official docs
What it is and where it fits 🎯#
kubectx and kubens are one project released together — two tiny, single-purpose binaries that solve the
single most repetitive friction point of working with kubectl day to day: which cluster and namespace am
I about to run this command against? kubectl config use-context <long-name> and
kubectl config set-context --current --namespace=<name> both work fine, but nobody types them from memory
at 2am during an incident. kubectx switches the active context (which cluster/user/kubeconfig entry
kubectl targets); kubens switches the active namespace within whichever context is already selected.
Neither tool talks to the cluster to do its job — they edit the kubeconfig file on disk, which is also why
kubectx keeps working fine even when a cluster is completely unreachable, while kubens's listing and
validation behavior genuinely does need a live API connection (see the pitfalls section — this is a real,
confirmed-live distinction, not a documentation nuance). Where this differs from k9s: k9s is a full
interactive TUI for browsing and managing resources; kubectx/kubens are non-interactive, script-friendly,
one-shot switches meant to be typed dozens of times a day, or wired into a shell prompt.
How the two tools relate to your kubeconfig#
Both tools are thin, local edits to the same file kubectl already reads — there's no daemon, no cache, no
separate state store. That's why switching is instant and why a shell alias/prompt integration can safely
call either tool as often as it wants.
Installation#
brew install kubectx # macOS/Linux Homebrew — installs both kubectx and kubens
sudo apt-get install kubectx # Debian/Ubuntu, if present in your repos (ships both binaries)
# or download the binaries directly (verified release: v0.11.0):
curl -sL -o kubectx.tar.gz \
https://github.com/ahmetb/kubectx/releases/download/v0.11.0/kubectx_v0.11.0_linux_x86_64.tar.gz
curl -sL -o kubens.tar.gz \
https://github.com/ahmetb/kubectx/releases/download/v0.11.0/kubens_v0.11.0_linux_x86_64.tar.gz
tar -xzf kubectx.tar.gz kubectx && tar -xzf kubens.tar.gz kubens
chmod +x kubectx kubens && sudo mv kubectx kubens /usr/local/bin/
kubectx --version
kubens --versionTip
Install fzf alongside them. Neither kubectx nor kubens bundles a fuzzy finder, but both detect
fzf on $PATH at runtime and switch into an interactive fuzzy-select menu automatically when you run
them with no argument — the plain listing shown throughout this page is what you get without fzf
installed. Set KUBECTX_IGNORE_FZF=1 to keep the plain listing behavior even with fzf present.
Command reference — kubectx (context switching)#
Real kubectx --help output (v0.11.0):
Manage and switch between kubectl contexts.
USAGE:
kubectx : list the contexts
kubectx <NAME> : switch to context <NAME>
kubectx - : switch to the previous context
kubectx -s, --shell <NAME> : start a shell scoped to context <NAME>
kubectx -s, --shell : interactively select a context to start a shell
kubectx -r, --readonly <NAME> : start a read-only shell for context <NAME>
kubectx -r, --readonly : interactively select a context for read-only shell
kubectx -c, --current : show the current context name
kubectx -u, --unset : unset the current context
kubectx <NEW_NAME>=<NAME> : rename context <NAME> to <NEW_NAME>
kubectx <NEW_NAME>=. : rename current-context to <NEW_NAME>
kubectx -d <NAME> [<NAME...>] : delete context <NAME> ('.' for current-context)
(this command won't delete the user/cluster entry
referenced by the context entry)
kubectx -h, --help : show this message
kubectx -V, --version : show version
kubectx # list every context in the kubeconfig
kubectx staging-cluster # switch the active context
kubectx - # switch back to whichever context was active before the last switch
kubectx -c # print just the current context name — the shell-prompt-safe formReal captured output against a local three-context kubeconfig (prod-cluster, staging-cluster,
dev-cluster):
$ kubectx
dev-cluster
prod-cluster
staging-cluster
$ kubectx -c
prod-cluster
$ kubectx staging-cluster
✔ Switched to context "staging-cluster".
$ kubectx -
✔ Switched to context "prod-cluster".
kubectx - is the same "toggle to previous" idea as cd - — genuinely the single most-used invocation once
it's muscle memory, since bouncing between two clusters (say, staging to check a fix, then back to prod)
is far more common than a full three-way rotation.
Command reference — kubens (namespace switching)#
Real kubens --help output (v0.11.0):
Switch between Kubernetes namespaces.
USAGE:
kubens : list the namespaces in the current context
kubens <NAME> : change the active namespace of current context
kubens <NAME> --force/-f : force change the active namespace of current context (even if it doesn't exist)
kubens - : switch to the previous namespace in this context
kubens -c, --current : show the current namespace
kubens -h,--help : show this message
kubens -u,--unset : unset the namespace choice (set to 'default')
kubens -V,--version : show version
kubens # list namespaces in the CURRENT context — this calls the live API
kubens checkout # switch the active namespace within the current context
kubens - # switch back to the previous namespace
kubens -c # print the current namespace — no API call, reads the kubeconfig only
kubens checkout --force # set the namespace field even if the API can't confirm it exists yetReal captured output, same kubeconfig, prod-cluster context active but pointed at an unreachable server:
$ kubens -c
checkout
$ kubens
error: could not list namespaces (is the cluster accessible?): failed to list namespaces from k8s API: ...
$ kubens checkout --force
✔ Active namespace is "checkout"
Important
kubens -c and kubens <name> --force never touch the network — plain kubens (listing) and a
non-forced kubens <name> (validating the namespace exists) both do. This is a genuine, confirmed-live
asymmetry between the two tools: kubectx never needs cluster connectivity for anything, because a
context switch is pure kubeconfig editing. kubens needs connectivity for its discovery/validation
paths but not for reading/writing the active namespace value itself. If you're scripting namespace
switches against a cluster that might be cold-starting or behind a VPN that isn't up yet, --force is
the flag that keeps the switch itself from blocking on that.
Renaming and deleting contexts#
kubectx dev=dev-cluster-us-east-1-a1b2c3d4 # rename a long auto-generated EKS context to something typeable
kubectx prod=. # rename the CURRENT context (the "." shorthand)
kubectx -d old-cluster # delete one context
kubectx -d ctx-a ctx-b ctx-c # delete several at onceReal captured rename + delete, same demo kubeconfig:
$ kubectx dev=dev-cluster
✔ Context dev-cluster renamed to dev.
$ kubectx -d dev
✔ Deleted context dev.
Tip
Rename cloud-provider auto-generated contexts immediately after aws eks update-kubeconfig /
gcloud container clusters get-credentials / az aks get-credentials. EKS in particular generates
names like arn:aws:eks:us-east-1:123456789012:cluster/prod-checkout — technically unique, completely
unusable for fast typing or for telling two similarly-named clusters apart at a glance in a busy terminal.
kubectx prod=. right after the credentials command becomes a one-line habit worth scripting into
onboarding docs.
Scoped shells — the safety feature most teams don't know about#
kubectx -s staging-cluster # open a new subshell with ONLY staging-cluster active as context
kubectx -r prod-cluster # open a read-only subshell scoped to prod-cluster-s/--shell spawns a child shell with its own isolated KUBECONFIG pointed at a temp copy scoped to just
that one context — switching context inside that subshell (or exiting it) never touches your real, permanent
kubeconfig or the context you had active before. -r/--readonly goes further: it also rewrites the
context's server-side RBAC-relevant defaults to prevent destructive kubectl verbs from that subshell.
Caution
A permanent context switch (kubectx prod-cluster with no -s/-r) changes what every open terminal
tab and every other tool reading the same kubeconfig sees, immediately. A teammate running a script in a
different tab that assumes it's still pointed at staging will silently start running against prod
instead. For any genuinely risky one-off ("let me just check something in prod real quick"), kubectx -s
or kubectx -r scopes the blast radius to that one subshell — the permanent switch is for the cluster you
intend to keep working in for a while, not for a quick look.
Real-world scenario: an on-call engineer triaging three environments during an incident#
An SRE gets paged for elevated error rates in checkout. The runbook says "confirm it's not also happening
in staging before you start rolling back prod" — a sequence that needs fast, low-error switching between
three clusters and namespaces under time pressure, which is exactly the failure mode these two tools exist
to remove:
kubectx prod-cluster && kubens checkout # confirm the alert is real
kubectx staging-cluster && kubens checkout # rule out a shared regression before touching prod
kubectx - # back to prod-cluster in one keystroke, no retyping the name
kubectx -r prod-cluster # open a READ-ONLY scoped shell to poke around further, safelyChaining kubectx <ctx> && kubens <ns> on one line is the standard idiom for "I need to be fully positioned
in one place before I run anything" — a single line an on-call engineer can paste from a runbook without two
separate steps that could be interrupted halfway.
Real-world scenario: a CI/CD pipeline deploying to three environments from one kubeconfig#
# .github/workflows/deploy.yml
- name: Configure kubeconfig
run: aws eks update-kubeconfig --name ${{ inputs.cluster }} --region us-east-1
- name: Point at the right context and namespace
run: |
kubectx $(kubectx | grep ${{ inputs.cluster }})
kubens ${{ inputs.namespace }} --force
- name: Deploy
run: kubectl apply -f k8s/Warning
Always pass --force to kubens in a fresh CI runner. A brand-new runner's kubeconfig was just
generated by update-kubeconfig seconds earlier — the API server might not yet be fully warmed up on a
newly-scaled node pool, or the pipeline's service-account token might have a brief propagation delay. A
non-forced kubens blocks on a live namespace-existence check that can flake in exactly that window;
--force writes the value unconditionally and lets kubectl apply be the thing that actually surfaces a
real connectivity failure, with a real error message, instead of kubens failing first with a more
confusing one.
Common pitfalls#
- Assuming
kubensfailures mean the namespace doesn't exist. A barekubens <name>failure is far more often a connectivity problem (VPN down, expired token, cold API server) than a genuinely missing namespace — checkkubens -c(never hits the network) andkubectl cluster-infobefore concluding the namespace itself is the problem. - Forgetting a permanent
kubectxswitch is shell-session-wide, not command-wide — see the CAUTION above. Reach for-s/-rfor anything exploratory. - Scripting against
kubectx <name>output parsing instead ofkubectx -c— the plain listing form can change shape iffzfintegration is active in an interactive shell;-cis the stable, script-safe form for reading the current context. - Renaming a context and forgetting the old auto-generated name is what CI secrets/scripts elsewhere might still reference — a rename is local to your kubeconfig only, but if a deploy script hardcodes the original long ARN-style name, renaming your local copy doesn't change what that script expects.
Exit codes#
0 success · non-zero on a failed switch (unreachable API for kubens's non-forced path, unknown context/
namespace name, or a malformed kubeconfig).
When to reach for something else#
For actually browsing what's running once you've switched — pods, logs, events, resource usage — reach for
k9s instead of chaining more kubectl get commands by hand; its own cheat sheet in this same category covers
launching it already scoped to a context/namespace via --context/--namespace, picking up right where
kubectx/kubens left off. For tailing logs across several pods matching a pattern once you're in the right
namespace, see the stern cheat sheet.