K9s Per-Cluster Configuration

Aim the gun away from your foot please

WillMatthews/k9s-config

K9s is a fabulously useful terminal UI for Kubernetes cluster management. It makes interacting with Kubernetes clusters slightly more tolerable meaning that I can spend more time breaking main implementing features and less time destroying your cluster navigating the Kubernetes API with kubectl. derailed/k9s

The rub

The problem with K9s’ out of the box experience is that it looks the same regardless of which cluster you’re connected to. This has resulted in multiple occurrences of senior devs at my workplace accidentally nuking pods in production because they thought they were in testing or development. :lul:

Repeated complaining about this made me think :thinker: “why doesn’t each context just look different? Why can’t prod be a scary red and dev be a chill blue?”.

Skins (not CS2 skins, but close enough)

A feature I particularly like about K9s is the ability to customise the appearance of the UI with skins. If we have a bit of a read of the documentation, we find the following:

If a skin file exists for your cluster then the skin will be loaded if not the stock skin remains in effect. So if your want different K9s look and feel on a per context basis and say your cluster is clusterX and your context is contextY then you skin attribute would read skin: blee. Where blee refers to a skin file in $XDG_CONFIG_HOME/k9s/skins/blee.yaml.

Neato! This means that we can have different skins for different clusters, which is great for keeping them visually distinct and harder to accidentally destroy. Ben Matselby has a write up on what this looks like in practice, but I wanted to take it a step further and automate the process of setting up these skins and configuring K9s to use them.

The step-by-step

To make our lives easier, we should generate skins per-context and then automatically configure K9s to use the right skin for each context. I chose the following steps.

Find a skin you like

Pick a skin from the skins directory in the K9s repo, and make sure it sets its background with an anchor, like this line from one-dark.yaml:

background: &background "#282c34"

Everything else in the skin that should be the background colour refers back to it as *background, so changing that one line recolours the whole UI. The reason why this matters will become clear in the next step. As of 10/11/2026, these skins have one:

  • dracula
  • gruvbox-dark, gruvbox-dark-hard, gruvbox-light, gruvbox-light-hard
  • gruvbox-material-dark-hard, -medium and -soft, and gruvbox-material-light-hard, -medium and -soft
  • kanagawa
  • modus-operandi and modus-vivendi, plus their -deuteranopia, -tinted and -tritanopia variants
  • monokai
  • nightfox
  • nord
  • one-dark, one-light
  • rose-pine
  • solarized-16, solarized-dark, solarized-light
  • vercel

The colours I use below are dark tints, so they suit a dark skin. I chose “one-dark” for my workplace, but I think that “dracula” looks cooler.

Create skin variations

Next we create variations of the skin by replacing the background value with different colours. I use yq to manipulate the yaml, which keeps the &background anchor in place. For example, to make a ‘red’ variation of the ‘one-dark’ skin:

yq '.background = "#3f1f28"' "$SKINS_PATH/one-dark.yaml" \
  > "$SKINS_PATH/one-dark-red.yaml"

$SKINS_PATH is the Skins: line of k9s info, which is ~/.config/k9s/skins on Linux.

Configure K9s to use the right skin for each context

Finally, we need to tell K9s which skin to use for each context. K9s keeps per-context settings in the Context Configs: directory from k9s info (~/.local/share/k9s/clusters on Linux), in a folder for the cluster and then a folder for the context: clusters/<cluster>/<context>/config.yaml. For example, if the ‘aks-scary-production’ context points at a cluster also called ‘aks-scary-production’, and we want it to use the ‘one-dark-red’ skin, we write clusters/aks-scary-production/aks-scary-production/config.yaml:

k9s:
  skin: one-dark-red

The cluster comes first, so if your context and cluster names differ, check your kubeconfig for the cluster name.

Putting it all together

I wrote a bash script to automate this process, which you can find in the WillMatthews/k9s-config repository. You describe what you want in a small YAML file:

theme: one-dark

colours:
  red: "#3f1f28"
  purple: "#2f1f3f"
  grey: "#2f2f2f"

contexts:
  - name: aks-bo-nd-dev
    colour: red
  - name: aks-bondtest-uk
    colour: purple
  - name: minikube
    colour: grey

and run ./k9s_configure.sh. It downloads the skin, makes a variation for each colour, looks up each context’s cluster in your kubeconfig, and writes the config files from the steps above. It only needs k9s, yq and curl, so it doesn’t care how you installed them, and it’s safe to run again whenever the list changes.

I include this script within bootstrap scripts for projects at my workplace, so that anyone who clones the repo and runs the bootstrap script will have their K9s configured with the right skins for each cluster. Having consistency across everyone’s machines is very helpful for avoiding accidents and making it easier to visually distinguish between clusters - especially when you’re running over to someone else’s machine to help them out, and you don’t have to worry about “do they have a different theme to me?”.

However I must wonder if in the ‘age of AI-driven code’ blog posts like this even matter any more if we can conjure stuff like this up from the void. :elmo-fire:

This post is signed by me

Cross-check this clearsigned file with my public key to verify the authenticity of this post.

Public key: key.pub
Raw Markdown: k9s-config.md
Signature: k9s-config.sig