Meet kubepatch — a simple tool for deploying Kubernetes manifests using a patch-based approach.

Unlike tools that embed logic into YAML or require custom template languages, kubepatch keeps your base manifests clean and idiomatic.

🛠 Example

Given a base set of manifests for deploy a basic microservice
see examples

---
apiVersion: v1
kind: Service
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  type: NodePort
  selector:
    app: myapp
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: "localhost:5000/restapiapp:latest"

patches/prod.yamlmight look like:

name: myapp-prod

labels:
  app: myapp-prod

patches:
  # deployment
  - target:
      kind: Deployment
      name: myapp
    patches:
      - op: replace
        path: /spec/replicas
        value: 1

      - op: replace
        path: /spec/template/spec/containers/0/image
        value: "localhost:5000/restapiapp:1.21"

      - op: add
        path: /spec/template/spec/containers/0/env
        value:
          - name: RESTAPIAPP_VERSION
            value: prod
          - name: LOG_LEVEL
            value: info

      - op: add
        path: /spec/template/spec/containers/0/resources
        value:
          limits:
            cpu: "500m"
            memory: "512Mi"
          requests:
            cpu: "64m"
            memory: "128Mi"

  # service
  - target:
      kind: Service
      name: myapp
    patches:
      - op: add
        path: /spec/ports/0/nodePort
        value: 30266

patches/dev.yamlmight look like:

name: myapp-dev

labels:
  app: myapp-dev

patches:
  # deployment
  - target:
      kind: Deployment
      name: myapp
    patches:
      - op: add
        path: /spec/template/spec/containers/0/env
        value:
          - name: RESTAPIAPP_VERSION
            value: dev
          - name: LOG_LEVEL
            value: debug

  # service
  - target:
      kind: Service
      name: myapp
    patches:
      - op: add
        path: /spec/ports/0/nodePort
        value: 30265

Apply the appropriate patch set based on the target environment.

kubepatch patch -f base/ -p patches/dev.yaml | kubectl apply -f -

Rendered manifest may look like this (note that all labels are set, as well as all patches are applied)

---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: myapp-dev
  name: myapp-dev
spec:
  ports:
    - nodePort: 30265
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    app: myapp-dev
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: myapp-dev
  name: myapp-dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: myapp-dev
  template:
    metadata:
      labels:
        app: myapp-dev
    spec:
      containers:
        - env:
            - name: RESTAPIAPP_VERSION
              value: dev
            - name: LOG_LEVEL
              value: debug
          image: localhost:5000/restapiapp:1.22
          name: myapp

Installation

Manual Installation

  1. Download the latest binary for your platform from the Releases page.
  2. Place the binary in your system's PATH (e.g., /usr/local/bin).

Installation script

(
set -euo pipefail

OS="$(uname | tr '[:upper:]' '[:lower:]')"
ARCH="$(uname -m | sed -e 's/x86_64/amd64/' -e 's/\(arm\)\(64\)\?.*/\1\2/' -e 's/aarch64$/arm64/')"
TAG="$(curl -s https://api.github.com/repos/kubepatch/kubepatch/releases/latest | jq -r .tag_name)"

curl -L "https://github.com/kubepatch/kubepatch/releases/download/${TAG}/kubepatch_${TAG}_${OS}_${ARCH}.tar.gz" |
tar -xzf - -C /usr/local/bin && \
chmod +x /usr/local/bin/kubepatch
)

Package-Based installation (suitable in CI/CD)

Debian

sudo apt update -y && sudo apt install -y curl
curl -LO https://github.com/kubepatch/kubepatch/releases/latest/download/kubepatch_linux_amd64.deb
sudo dpkg -i kubepatch_linux_amd64.deb

Alpine Linux

apk update && apk add --no-cache bash curl
curl -LO https://github.com/kubepatch/kubepatch/releases/latest/download/kubepatch_linux_amd64.apk
apk add kubepatch_linux_amd64.apk --allow-untrusted

✨ Key Features

JSON Patch Only

Patches are applied using JSON Patch:

- op: replace
  path: /spec/replicas
  value: 1

Every patch is minimal, explicit, and easy to understand. No string manipulation or text templating involved.

Plain Kubernetes YAML Manifests

Your base manifests are 100% pure Kubernetes objects - no logic, no annotations, no overrides, no preprocessing. This
ensures:

Cross-Environment Deploys

Deploy to devstaging, or prodjust by selecting the right set of patches. All logic lives in patch files, not
your base manifests.

Common Labels Support

Inject common labels (like envteamapp), including deep paths like pod templates and selectors.

Env Var Substitution (in Patch Values Only)

You can inject secrets and configuration values directly into patch files:

- op: add
  path: /spec/template/spec/containers/0/env
  value:
    - name: PGPASSWORD
      value: ${IAM_SERVICE_PGPASS}

Strict env-var substitution (prefix-based) is only allowed inside patches - never in base manifests.

Feedback

Have a feature request or issue? Feel free to open an issue or submit a PR!