Skaffold Reference: K8s Local Dev Loop, File Sync, Profiles, Debug & Helm Deploy
Skaffold handles the build-tag-push-deploy loop for Kubernetes development so you don’t have to run those commands manually. skaffold dev watches source files and automatically rebuilds + redeploys on every save — your pods update while you code.
1. Install & Init
Install Skaffold and generate a skaffold.yaml
# Install:
brew install skaffold # macOS
# Or: curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
# chmod +x skaffold && mv skaffold /usr/local/bin/
# Initialize Skaffold for an existing project:
skaffold init # detects Dockerfile + K8s manifests, generates skaffold.yaml
skaffold init --generate-manifests # also generates K8s manifests if missing
# Basic skaffold.yaml:
apiVersion: skaffold/v4beta11
kind: Config
metadata:
name: my-app
build:
artifacts:
- image: my-app # image name (no tag — Skaffold manages tags)
docker:
dockerfile: Dockerfile
deploy:
kubectl:
manifests:
- k8s/*.yaml # K8s manifests to apply
2. skaffold dev — Continuous Development Loop
Watch, rebuild, and redeploy on every file change
# Start the dev loop:
skaffold dev # build → push → deploy, then watch for changes
skaffold dev --port-forward # also auto-port-forward all Services to localhost
skaffold dev --no-prune # don't delete images on exit
skaffold dev --cleanup=false # don't delete K8s resources on CTRL+C
# What happens on each file save:
# 1. Skaffold detects changed files
# 2. Rebuilds only affected images (cached layers)
# 3. Re-tags with a content hash
# 4. Pushes to local registry or remote
# 5. Updates K8s Deployment (rolling update)
# 6. Streams logs from updated pods
# Sync: copy files directly into running container without full rebuild
# Much faster for interpreted languages (Python, Node.js):
build:
artifacts:
- image: my-python-app
docker:
dockerfile: Dockerfile
sync:
infer:
- "**/*.py" # auto-detect Python files to sync
- "**/*.html"
- "**/*.css"
# On .py file change: Skaffold copies file into container instead of rebuilding
# The running process picks up the change (works with hot-reload frameworks)
# Manual sync rules (explicit):
sync:
manual:
- src: "src/**/*.js"
dest: /app/src # copies to /app/src in container
3. Builders — Docker, Buildpacks, Ko, Jib
Build images with different backends
# Docker (default — uses local Docker daemon):
build:
artifacts:
- image: my-app
docker:
dockerfile: Dockerfile
buildArgs:
NODE_ENV: development
cacheFrom:
- my-app:latest # use as cache source
# Ko (Go only — builds Go binaries directly into distroless images, no Dockerfile):
build:
artifacts:
- image: my-go-service
ko:
fromImage: gcr.io/distroless/static-debian11
# Cloud Native Buildpacks (no Dockerfile needed):
build:
artifacts:
- image: my-node-app
buildpacks:
builder: paketobuildpacks/builder-jammy-full
# Jib (Java — Maven/Gradle, no Docker daemon needed):
build:
artifacts:
- image: my-java-app
jib:
project: my-module # Maven module or Gradle project
fromImage: eclipse-temurin:21-jre-alpine
# Build in cluster (Kaniko — build inside K8s, useful when no local Docker):
build:
cluster:
pullSecretName: regcred # K8s secret with registry credentials
artifacts:
- image: my-app
kaniko: {}
4. skaffold run, debug & render
One-off builds, remote debugging, and manifest rendering
# One-off build + deploy (CI/CD — no watch loop):
skaffold run # build → push → deploy once
skaffold run --tag=git-sha # use git SHA as tag
skaffold run --profile=production # use production profile
# Profiles — different configs for local vs CI vs production:
profiles:
- name: production
build:
artifacts:
- image: my-app
docker:
dockerfile: Dockerfile.prod # different Dockerfile in prod
deploy:
helm:
releases:
- name: my-app
chartPath: helm/my-app
setValues:
replicaCount: 3
# Remote debugging (attach debugger to running pod):
skaffold debug # auto-configures remote debugging ports
# For Python: injects debugpy, exposes port 5678
# For Node.js: injects --inspect, exposes port 9229
# For Java: injects JDWP agent, exposes port 5005
# IDE (VS Code/IntelliJ) attaches to port-forwarded debug port
# Render manifests (dry-run — see what K8s YAML Skaffold would apply):
skaffold render # outputs rendered YAML to stdout
skaffold render --output=rendered.yaml
# Build only (no deploy):
skaffold build # build + push images, print tags
skaffold build -q -o tags.json # quiet, output tags as JSON (for CI chaining)
5. Helm & Kustomize Deploy
Deploy with Helm charts or Kustomize overlays
# Helm deployment:
deploy:
helm:
releases:
- name: my-app
chartPath: helm/my-app # local chart
# OR: repo: https://charts.example.com, remoteChart: my-chart
setValues:
image.repository: my-app
image.tag: "" # Skaffold fills in the tag
valuesFiles:
- helm/values-dev.yaml
upgradeOnChange: true # upgrade if already installed
# Kustomize deployment:
deploy:
kustomize:
paths:
- k8s/overlays/development # uses kustomize overlays
# Image replacement in Kustomize:
# Skaffold automatically updates kustomize images to use the built tag
# No manual image: line needed in kustomize overlays
# Verify (post-deployment health check):
verify:
- name: integration-tests
container:
name: tests
image: my-integration-tests:latest
command: [pytest, integration/, -v]
Track Skaffold, Kubernetes, and developer tooling releases.
ReleaseRun monitors Kubernetes, Docker, and 13+ DevOps technologies.
Related: Kubernetes YAML Reference | Kustomize Reference | ArgoCD Reference
🔍 Free tool: K8s YAML Security Linter — check the K8s manifests Skaffold deploys for 12 security misconfigurations before dev or CI runs.
Founded
2023 in London, UK
Contact
hello@releaserun.com