k8s.io/client-go/kubernetes package

client-go is the official Go library for talking to a Kubernetes cluster over HTTP (the same API that kubectl uses).
Package k8s.io/client-go/kubernetes gives a client for every built-in Kubernetes resource — Pods, Services, Deployments, Secrets, and so on.

*kubernetes.Clientset

struct that holds a REST client for each API group in Kubernetes. We pick the group, then the resource, then call List / Get / Create / Update / Delete.

clientset
  ├── CoreV1()      → Pods, Services, ConfigMaps, Secrets, Namespaces …
  ├── AppsV1()      → Deployments, StatefulSets, DaemonSets …
  ├── BatchV1()     → Jobs, CronJobs
  ├── NetworkingV1()→ Ingress, NetworkPolicy …
  └── …             → other built-in API groups

Each call returns a typed interface. For example clientset.CoreV1().Pods("default") gives you a PodInterface with methods like List(), Get(), Create().

Go call Same as kubectl
clientset.CoreV1().Pods("default").List(...) kubectl get pods -n default
clientset.CoreV1().Pods("default").Get(ctx, "nginx", ...) kubectl get pod nginx -n default
clientset.AppsV1().Deployments("prod").Create(...) kubectl create -f deployment.yaml -n prod

“Clientset” = set of clients — one entry point instead of constructing a separate HTTP client for every resource type yourself.

Function NewForConfig?

func NewForConfig(c *rest.Config) (*Clientset, error)

It takes a *rest.Config — connection settings for the cluster — and returns a ready-to-use *Clientset.

NewForConfig does not talk to the cluster yet. It only builds the Clientset with those settings wired in. The first real HTTP call happens when you call something like .List() or .Create().

kubeconfig file  →  rest.Config  →  NewForConfig  →  Clientset  →  .CoreV1().Pods().List()
(~/.kube/config)     (connection)      (factory)        (typed API)      (HTTP to API server)

Typical way to get rest.Config on a laptop: clientcmd.BuildConfigFromFlags("", kubeconfigPath) reads your ~/.kube/config (same file kubectl uses).

Simple example — list Pods in default

package main

import (
    "context"
    "fmt"
    "path/filepath"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
)

func main() {
    // 1. Load kubeconfig (same credentials kubectl uses)
    kubeconfig := filepath.Join(homedir.HomeDir(), ".kube", "config")
    config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
    if err != nil {
        panic(err)
    }

    // 2. NewForConfig → build the Clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err)
    }

    // 3. Use the Clientset — list Pods in namespace "default"
    pods, err := clientset.CoreV1().Pods("default").List(
        context.TODO(),
        metav1.ListOptions{},
    )
    if err != nil {
        panic(err)
    }

    fmt.Printf("Found %d pod(s) in default:\n", len(pods.Items))
    for _, pod := range pods.Items {
        fmt.Printf("  - %s  (phase: %s)\n", pod.Name, pod.Status.Phase)
    }
}

Example output

$ go run main.go
Found 2 pod(s) in default:
  - nginx-7c4b8c9d-xk2lm  (phase: Running)
  - redis-0               (phase: Running)

Create a Pod — same Clientset, different method

pod := &corev1.Pod{
    ObjectMeta: metav1.ObjectMeta{
        Name:      "demo-from-go",
        Namespace: "default",
    },
    Spec: corev1.PodSpec{
        Containers: []corev1.Container{
            {
                Name:  "nginx",
                Image: "nginx:1.25",
            },
        },
    },
}

created, err := clientset.CoreV1().Pods("default").Create(
    context.TODO(),
    pod,
    metav1.CreateOptions{},
)
// created.Name == "demo-from-go"

Add import: corev1 "k8s.io/api/core/v1" for the Pod struct.

Inside the cluster (in-cluster config)

When your Go binary runs as a Pod, there is no ~/.kube/config. Use the service account mounted into the Pod instead:

import "k8s.io/client-go/rest"

config, err := rest.InClusterConfig()
clientset, err := kubernetes.NewForConfig(config)

Install

go mod init my-k8s-tool
go get k8s.io/client-go@latest
go get k8s.io/api@latest
go get k8s.io/apimachinery@latest

Pin versions to match your cluster when possible (e.g. client-go v0.29.x for Kubernetes 1.29). Run the program with a valid kubeconfig or from inside the cluster.

client-go vs controller-runtime

k8s.io/client-go/kubernetes sigs.k8s.io/controller-runtime
Direct CRUD on API objects Watch + reconcile loop for controllers
You call List / Get when you want Framework calls your Reconcile() when things change
Good for scripts, CLIs, one-shot tools Good for operators and long-running controllers

controller-runtime uses client-go under the hood. For a controller, prefer controller-runtime. For “list all pods and print names,” use kubernetes.NewForConfig.

Related

Go Packages and Modules
controller-runtime
Kubernetes Controller