Kubernetes
    CLI
    Productivity
    DevOps

    K9s Kubernetes CLI: Advanced Productivity Techniques for Platform Engineers

    Target-Ops Team• DevOps Engineers
    April 22, 2026
    12 min read

    K9s Kubernetes CLI: Advanced Productivity Techniques for Platform Engineers

    K9s has quietly become the default terminal interface for serious Kubernetes work. Once you're managing more than a handful of clusters, raw kubectl becomes a productivity tax — every debug loop turns into a 6-command dance of get, describe, logs, exec, and edit.

    At Target-Ops we use K9s every day across EKS, GKE, and self-managed clusters. Over time we've built a library of custom views, plugins, and keyboard workflows that cut a typical investigation from 15 minutes to under 2. This guide distills the techniques that actually move the needle — the ones we rely on in production, not the tutorial basics.

    If you already know what K9s is and you're comfortable moving around in it, this article will make you faster. If you're a platform lead rolling out standardized tooling to your team, the custom views, plugins, and aliases here are directly copy-pasteable into your onboarding repo.

    Why K9s Beats Raw kubectl for Operations Work

    Raw kubectl is a great API client. It's a mediocre investigation tool. The difference matters when you're on call at 2 AM.

    The Cost of Context Switches

    Every time you run kubectl get pods, then kubectl describe pod, then kubectl logs, you're re-parsing output, re-typing names, and re-building mental state. K9s keeps the state on screen — selection, namespace, filters — and turns investigation into a navigation problem instead of a typing problem.

    What this looks like in practice:

    • Pod crash investigation: 15+ kubectl commands → 6 keystrokes in K9s
    • Multi-pod log tailing with filtering: shell scripts and tee → built-in feature
    • Cross-namespace comparison: scripted loops → :pods -A with live filtering
    • Editing a ConfigMap and verifying the pod reloaded: 4 terminals → a single K9s session

    In our experience, standardizing on K9s for on-call work consistently cuts alert-to-insight time by 30–50%. The path from "something's wrong" to "I know what's wrong" is just dramatically shorter than it is with raw kubectl.

    Installation and First-Run Configuration

    # macOS
    brew install k9s
    
    # Linux
    curl -sS https://webinstall.dev/k9s | bash
    
    # Windows
    scoop install k9s
    

    On first launch, K9s creates $HOME/.k9s/ with its config directory. The files that matter most:

    • config.yaml — global behavior, refresh rates, skins
    • views.yaml — custom columns per resource type
    • plugins.yaml — your custom commands bound to shortcuts
    • aliases.yaml — short names for frequently-used commands
    • hotkeys.yaml — custom keybindings

    We'll use each of these below.

    Custom Resource Views: See What Actually Matters

    The default pod view is fine for demos. In real operations, you need node placement, QoS class, and resource metrics at a glance.

    # $HOME/.k9s/views.yaml
    k9s:
      views:
        v1/pods:
          columns:
            - NAME
            - READY
            - STATUS
            - RESTARTS
            - CPU
            - MEM
            - "%CPU/R"
            - "%CPU/L"
            - "%MEM/R"
            - "%MEM/L"
            - IP
            - NODE
            - QOS
            - AGE
        apps/v1/deployments:
          columns:
            - NAME
            - READY
            - UP-TO-DATE
            - AVAILABLE
            - IMAGE
            - AGE
        v1/services:
          columns:
            - NAME
            - TYPE
            - CLUSTER-IP
            - EXTERNAL-IP
            - PORT(S)
            - SELECTOR
            - AGE
    

    Why this matters: The %CPU/R and %MEM/R columns show usage relative to requests — the single best signal for spotting pods that are about to get OOMKilled or that are wasting resources. Having these visible by default means your team catches problems passively instead of reactively.

    Plugins: Turn Hard-Won Tribal Knowledge Into Keyboard Shortcuts

    Plugins are K9s' most underused feature. Any shell command, any context menu, any investigation pattern can become a single keystroke. Here are the ones our team uses daily.

    Plugin: Show Recent Events for Selected Resource

    # $HOME/.k9s/plugins.yaml
    plugins:
      events:
        shortCut: Ctrl-E
        description: Recent events
        scopes:
          - all
        command: sh
        background: false
        args:
          - -c
          - "kubectl events --for $KIND/$NAME -n $NAMESPACE | less"
    

    Select any resource, hit Ctrl-E, immediately see its events. This one plugin has saved our team hundreds of hours of kubectl describe | grep -A 20 Events over the years.

    Plugin: Open a Debug Shell on a Node

      node-shell:
        shortCut: Shift-S
        description: Debug shell on node
        scopes:
          - nodes
        command: kubectl
        background: false
        args:
          - debug
          - node/$NAME
          - -it
          - --image=busybox
    

    Node troubleshooting without SSH keys, without bastion hops. Uses ephemeral containers — works even on locked-down managed Kubernetes.

    Plugin: Dump All Pod Logs to a File

      log-dump:
        shortCut: Ctrl-D
        description: Dump pod logs
        scopes:
          - pods
        command: sh
        background: false
        args:
          - -c
          - "kubectl logs $NAME -n $NAMESPACE --all-containers=true --since=1h > /tmp/$NAME-$(date +%s).log && echo Wrote /tmp/$NAME-*.log"
    

    For incident postmortems when you need to walk away with logs.

    Plugin: Find Stuck Deployments

      stuck-deployments:
        shortCut: Ctrl-X
        description: Stuck deployments
        scopes:
          - all
        command: sh
        background: false
        args:
          - -c
          - |
            kubectl get deployments -A -o json | jq -r '
              .items[] |
              select(.spec.replicas != .status.availableReplicas) |
              "\(.metadata.namespace)\t\(.metadata.name)\t\(.spec.replicas)/\(.status.availableReplicas // 0)"
            ' | column -t -s 
      
    
    \t' -N "NAMESPACE,DEPLOYMENT,DESIRED/AVAILABLE" | less
    

    One keystroke audit of every deployment whose current state doesn't match its desired state. Run this across a cluster and you'll instantly see what's broken.

    Aliases: Fewer Keystrokes for Common Navigation

    # $HOME/.k9s/aliases.yaml
    aliases:
      pp: v1/pods
      dp: apps/v1/deployments
      ss: apps/v1/statefulsets
      svc: v1/services
      cm: v1/configmaps
      sec: v1/secrets
      ing: networking.k8s.io/v1/ingresses
      hpa: autoscaling/v2/horizontalpodautoscalers
      pvc: v1/persistentvolumeclaims
      pv: v1/persistentvolumes
    

    Type :pp for pods, :dp for deployments, :svc for services. Small change, used thousands of times per week per engineer.

    Multi-Cluster Context Switching

    The single most productive habit you can build is K9s context switching. With multiple clusters under your care, :ctx and :ns become more important than any individual resource shortcut.

    Our pattern:

    • Split your shell profile to pre-seed KUBECONFIG with every cluster you operate
    • Use :ctx inside K9s to jump between them without restarting
    • Use the .kube/config current-context with descriptive names like prod-us-east-eks so you see at a glance what you're about to break
    # In your shell profile
    export KUBECONFIG=$(find ~/.kube/configs -type f | tr '\n' ':')
    

    Log Streaming at Scale

    One of K9s' most underrated features is multi-pod log streaming with live filtering.

    Workflow:

    1. Navigate to pods (:pods)
    2. Use Space to mark multiple pods
    3. Press l to stream all selected pods' logs in a single view
    4. Press / to filter: error|warning|5\d\d
    5. Press a to toggle "all containers" — critical for sidecar-heavy deployments

    Real scenario: When an API service degrades, select every pod in the deployment, tail 500|503|timeout live, and watch the pattern emerge across replicas in seconds. The same workflow in kubectl needs stern or a script.

    Resource Diffing and Editing

    K9s has built-in diff and edit workflows that outperform manual kubectl edit:

    • d — diff the live resource against its last-applied-configuration annotation
    • e — edit in $EDITOR with automatic validation on save
    • y — YAML view with syntax highlighting
    • Ctrl-Z — toggle between compact and full YAML

    The diff view is genuinely useful for catching drift — especially when auditing what GitOps controllers have mutated since last sync.

    Monitoring and Triage Views

    • :pulses or Ctrl-U — real-time cluster-wide CPU/memory/storage usage with sparklines
    • :events or Ctrl-E — live event stream, filterable with /
    • :top pods — like kubectl top pods but live-updating
    • :xray <kind> — tree view showing relationships (pod → service → ingress)

    xray in particular is the closest thing to a service map you get in pure K8s tooling — perfect for "who is calling this pod" questions.

    Best Practices for K9s in Teams

    • Commit your K9s config to a team repo. Views, plugins, aliases, hotkeys — check them into a dotfiles/k9s/ directory so every engineer has the same keybindings and context menus.
    • Version your plugins. Plugins invoke shell commands that can be destructive. Pin them, review PRs that change them, and audit what scopes: all plugins can do.
    • Use read-only contexts in prod. Create a separate kubeconfig for production with limited RBAC, and start K9s against it by default. This prevents e (edit) from being a footgun.
    • Set a sane refresh rate. K9s defaults to 2-second refresh. On large clusters this hammers the API server. Bump to 5–10 seconds in config.yaml.
    • Disable the skin contest. Pick a high-contrast skin and standardize. Reading red-on-red diffs during an incident costs real seconds.
    • Teach / filtering explicitly. Most new K9s users never discover that / supports regex. Lead with it during onboarding.

    Common K9s Pitfalls We've Seen

    1. Leaving K9s open against prod with write access. A stray d (delete) from muscle memory can remove a production resource. Fix: use a read-only kubeconfig and require a deliberate context switch to get write permissions.
    2. Custom views that hide critical columns. Someone removes RESTARTS to make the view cleaner; suddenly crash loops go unnoticed. Fix: treat views as code, code-review them.
    3. Plugin commands with unescaped $NAMESPACE. If a namespace contains a shell-special character (rare but possible), plugin commands can behave unexpectedly. Fix: always quote in shell plugins.
    4. Running K9s in screen/tmux without sizing. Truncated column layouts hide important info. Fix: :config → adjust noIcons and column widths.
    5. Ignoring :pulses on large clusters. The live resource aggregation is O(N) on pods. On 10K-pod clusters it can add measurable load. Fix: use sparingly or replace with Prometheus dashboards.

    Worked Example: A Typical Incident Triage in K9s

    Here's what a K9s-native investigation looks like for a common incident pattern — API latency suddenly doubles, customers start timing out — compared to doing the same thing in raw kubectl.

    With K9s:

    1. :pulses — cluster CPU flat, so not a resource exhaustion issue
    2. :events + /Warning — a flood of FailedMount events in one namespace stands out
    3. :pods -n <ns> — the custom view shows restarts climbing on a single StatefulSet
    4. Select all the pods, l, filter timeout — confirmed mount timeouts on an EBS volume
    5. :pvc — PVC in Pending, event says the EBS CSI controller pod itself is stuck
    6. Ctrl-E plugin for events on the controller → root cause: a KMS key rotation revoked CSI IAM access

    This kind of investigation is routinely a few minutes of navigation in K9s. The same thing in kubectl means flipping between four terminals, copy-pasting pod names, and running describe over and over. For a pattern like this we'd expect the kubectl path to take 30–40 minutes instead.

    Conclusion

    K9s is not a toy — it's a force multiplier for any team doing serious Kubernetes operations. The gains compound: every custom view, every plugin, every alias shaves seconds off operations you perform hundreds of times per week. Over a year that's real engineering hours redirected from typing into thinking.

    Treat K9s configuration as infrastructure-as-code: versioned, reviewed, and deployed to every engineer's laptop through your dotfiles or onboarding pipeline. A consistent, curated setup outperforms ad-hoc raw kubectl by a wide margin.

    Next Steps

    Ready to get faster with K9s? Do these in order:

    1. Adopt the custom views and plugins above. Drop them into ~/.k9s/ today.
    2. Standardize across your team. Commit the config to a shared repo and make it part of onboarding.
    3. Build one team-specific plugin per week. Every painful kubectl workflow is a plugin opportunity.
    4. Separate your production kubeconfig. Read-only by default; escalate explicitly.

    Want help standardizing Kubernetes tooling across your engineering team? Book a free 30-minute call with Target-Ops — we'll walk through your current setup and share the configs, RBAC patterns, and operational playbooks we use day to day.

    Related Resources


    Last updated: April 2026 | Published by the Target-Ops DevOps Engineering Team

    Need Help with Your DevOps?

    Book a free 30-minute consultation with our DevOps experts. No sales pitch, just honest advice about your infrastructure challenges.

    Schedule Free Consultation

    Related Articles