Skaffold Render is less about "rendering" manifests and more about orchestrating your entire Kubernetes deployment pipeline, with manifest generation being just one piece.

Let’s see Skaffold Render in action. Imagine you have a simple Go web application.

main.go:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello from my Go app!")
	})
	fmt.Println("Server starting on port 8080")
	http.ListenAndServe(":8080", nil)
}

skaffold.yaml:

apiVersion: skaffold/v2
kind: Config
metadata:
  name: my-go-app
build:
  artifacts:
    - image: my-go-app
      docker:
        dockerfile: Dockerfile
deploy:
  kubectl:
    manifests:
      - k8s/*.yaml
profiles:
  - name: render
    patches:
      - op: replace
        path: /spec/template/spec/containers/0/image

        value: my-go-app:{{.TAG}}

Dockerfile:

FROM golang:1.20-alpine
WORKDIR /app
COPY main.go .
RUN go build -o my-go-app
CMD ["./my-go-app"]

k8s/deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-go-app-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-go-app
  template:
    metadata:
      labels:
        app: my-go-app
    spec:
      containers:
        - name: my-go-app
          image: placeholder-image:latest # This will be replaced
          ports:
            - containerPort: 8080

Now, to generate the manifests with a specific image tag (let’s say v1.0.0), you’d run:

skaffold render -p render --tag=v1.0.0

This command will output the fully formed Kubernetes manifests to your console:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-go-app-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-go-app
  template:
    metadata:
      labels:
        app: my-go-app
    spec:
      containers:
        - name: my-go-app
          image: my-go-app:v1.0.0 # The placeholder is gone!
          ports:
            - containerPort: 8080

Skaffold Render solves the problem of managing dynamic Kubernetes manifests. Instead of manually editing image: tags, env: variables, or other configuration elements for different environments or builds, Skaffold provides a declarative way to manage these variations. It integrates with your build process (implicitly, by knowing the image name and tag you’re using) and allows you to inject those details into your Kubernetes YAML.

Internally, Skaffold parses your skaffold.yaml. When you specify a profile (like -p render), it applies the patches defined within that profile. These patches use a JSON-Patch-like syntax to modify specific fields within your Kubernetes manifests. The {{.TAG}} is a Go template variable that Skaffold populates with the value provided by the --tag flag (or derived from your build process if not explicitly set). This templating capability extends beyond just tags to include other build artifacts or environment-specific variables. The deploy.kubectl.manifests field tells Skaffold which YAML files to consider for rendering.

The most surprising true thing about Skaffold Render is that it’s not just a templating engine like Helm or Kustomize; it’s designed to be the entry point for a full CI/CD loop. While you can use skaffold render standalone to just get manifests, its real power comes when you chain it with skaffold build and skaffold deploy. Skaffold will automatically build your image, tag it, and then pass that tag to the rendering process, ensuring consistency. The profiles section can be used for more than just patching; you can define entirely different deployment strategies or manifest sets per profile, enabling complex multi-environment setups.

Once you’ve mastered rendering manifests with Skaffold, the next logical step is to integrate it into an automated CI/CD workflow, potentially using skaffold dev for local development loops or skaffold run to execute the entire build-deploy cycle.

Want structured learning?

Take the full Skaffold course →