Skaffold’s configuration inheritance lets you define base settings and layer environment-specific overrides, but it’s more about composing configurations than simple hierarchical inheritance.

Let’s see it in action. Imagine you have a skaffold.yaml that defines your application’s build and deploy steps. This is your base configuration.

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: my-app
      docker:
        dockerfile: Dockerfile
deploy:
  kubectl:
    manifests:
      - k8s/base/*.yaml

Now, you want to deploy this same my-app image to a staging environment, but with different Kubernetes manifests and a different tag. You can create a new Skaffold configuration file, say skaffold-staging.yaml, that references the base configuration and overrides specific parts.

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: my-app
      docker:
        tagPolicy:
          git:
            tag: v1.0.0-staging
deploy:
  kubectl:
    manifests:
      - k8s/staging/*.yaml

When you run skaffold dev -f skaffold-staging.yaml, Skaffold doesn’t just merge these two files. It uses the skaffold-staging.yaml as the primary configuration and composes it with the skaffold.yaml. The build.artifacts[0].docker.tagPolicy in skaffold-staging.yaml replaces the default tag policy for the my-app image defined in the base configuration. Similarly, the deploy.kubectl.manifests in skaffold-staging.yaml completely replaces the manifests from the base.

This composition model is powerful. You can have a skaffold.yaml for your core application build, then separate files for skaffold-dev.yaml, skaffold-staging.yaml, and skaffold-prod.yaml, each extending or overriding the base as needed. The --filename or -f flag is your primary tool here, allowing you to chain configurations. Skaffold processes these files in the order they are specified on the command line, applying overrides from right to left.

The mental model to build here is one of layering and composition, not simple inheritance where a child automatically gets everything from its parent and then adds its own. When you specify multiple configuration files, Skaffold merges them. If a field exists in multiple configurations, the value from the last configuration file specified on the command line takes precedence. This means your environment-specific files should generally be listed after your base configuration file.

Consider this common pattern: you have a skaffold.yaml with your base build and deploy, a skaffold-dev.yaml that enables hot reloading and sets up a local registry, and a skaffold-staging.yaml that targets a remote cluster and uses specific ingress configurations.

skaffold.yaml:

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: my-service
      docker:
        dockerfile: Dockerfile
deploy:
  kubectl:
    manifests:
      - k8s/base/*.yaml

skaffold-dev.yaml:

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: my-service
      docker:
        tagPolicy:

          envTemplate: "{{.GIT_COMMIT_SHORT}}"

pipeline:
  # Enable dev mode
  dev:
    autoDeploy:
      enabled: true
    hotReload:
      paths:
        - path: .
          glob: "**/*.go"
    sync:
      manual: {}
    enableJibInit: false
    artifactOverrides:
      my-service:
        image: my-service-local
deploy:
  kubectl:
    manifests:
      - k8s/dev/*.yaml

skaffold-staging.yaml:

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: my-service
      docker:
        tagPolicy:
          git:
            prefix: "staging-"
deploy:
  kubectl:
    manifests:
      - k8s/staging/*.yaml

Running skaffold dev -f skaffold.yaml -f skaffold-dev.yaml will merge skaffold.yaml and skaffold-dev.yaml. The dev specific settings will be active, and the my-service image will be tagged with {{.GIT_COMMIT_SHORT}} and deployed using k8s/base/*.yaml and k8s/dev/*.yaml. The my-service-local override will be used for the image name.

Running skaffold dev -f skaffold.yaml -f skaffold-staging.yaml will merge skaffold.yaml and skaffold-staging.yaml. The my-service image will be tagged with a staging- prefix, and the deployment will use k8s/base/*.yaml and k8s/staging/*.yaml.

The most surprising thing about Skaffold’s configuration layering is that it’s not a deep merge of all fields. For lists, like manifests, the new list replaces the old one entirely, rather than appending to it. This means if you want to include manifests from a base file and an environment-specific file, you must explicitly list all desired manifests in the environment-specific file.

If you want to build your application with a specific Skaffold configuration file, and then deploy it to a Kubernetes cluster using a different Skaffold configuration file, you’ll be looking at how to chain profiles.

Want structured learning?

Take the full Skaffold course →