Skaffold’s tag policies are surprisingly flexible, allowing you to tie image tags directly to your Git commit, a SHA256 hash of the build context, or a timestamp, often eliminating the need for manual versioning entirely.

Let’s see Skaffold in action with Git tags. Imagine you have a simple Go app:

package main

import "fmt"

func main() {
	fmt.Println("Hello from Skaffold!")
}

And a Dockerfile:

FROM alpine:latest
COPY main .
CMD ["./main"]

Now, let’s configure skaffold.yaml to use Git tags. We’ll set up a git tagger and a basic builder:

apiVersion: skaffold/v2
kind: Config
build:
  artifacts:
    - image: my-git-tagged-app
      docker: {}
  tagPolicy:
    git:
      variant: tags # or commit, or dirty

When you run skaffold dev, Skaffold will look at your Git history. If your current commit has a Git tag like v1.0.0, it will tag your image my-git-tagged-app:v1.0.0. If you haven’t tagged it, and you use variant: commit, it’ll use the short Git commit hash. If you use variant: dirty, it appends -dirty to the tag if there are uncommitted changes.

Here’s what you might see in your Docker build output or image registry:

my-git-tagged-app:v1.0.0 my-git-tagged-app:a1b2c3d4 my-git-tagged-app:a1b2c3d4-dirty

The sha256 tag policy offers a more deterministic approach. Instead of relying on Git’s history, it calculates a SHA256 hash of your entire build context (all files in your docker.context directory). This ensures that even if your Git commit hash remains the same, a change in a file will result in a different image tag, guaranteeing a unique image for every unique build context.

Consider this skaffold.yaml using sha256:

apiVersion: skaffold/v2
kind: Config
build:
  artifacts:
    - image: my-sha256-tagged-app
      docker:
        context: . # Default context is the directory containing skaffold.yaml
  tagPolicy:
    sha256: {}

Running skaffold dev with this configuration will produce an image tag that is the SHA256 hash of your project’s root directory. For example:

my-sha256-tagged-app:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

This is incredibly useful for ensuring immutability; if your code or build artifacts change, the tag changes, and you get a new, distinct image.

The datetime tag policy is the simplest, assigning a timestamp to your image. This is great for continuous deployments where you want to easily identify the build time.

Here’s skaffold.yaml with datetime:

apiVersion: skaffold/v2
kind: Config
build:
  artifacts:
    - image: my-datetime-tagged-app
      docker: {}
  tagPolicy:
    datetime: {}

A typical tag would look like this:

my-datetime-tagged-app:20231027103045

This policy is less about deterministic builds and more about easily tracking deployments by their creation time.

You can even combine these policies. For instance, you could use git as the primary policy and fall back to sha256 if no Git tag is found, or append a timestamp to a Git tag. The appendBaseImageTag option within tagPolicy allows you to append the tag of the base image you are using to your custom tag, which can be useful for tracking dependencies.

A common pattern is to use the Git commit hash for reproducibility and then append a timestamp to ensure uniqueness across multiple builds of the same commit, especially in CI/CD pipelines where you might trigger multiple builds for the same commit.

apiVersion: skaffold/v2
kind: Config
build:
  artifacts:
    - image: my-combined-tagged-app
      docker: {}
  tagPolicy:
    git:
      variant: commit
     
    # This will append a timestamp to the commit hash tag
    # Example: my-combined-tagged-app:a1b2c3d4-20231027103045
    appendBaseImageTag: true # This is not a combined policy, but an option for git tag policy

Wait, that appendBaseImageTag isn’t a separate policy, it’s an option for the git policy. Let’s correct that. The true power comes from composing policies or using specific variants. For instance, to combine a Git commit with a timestamp:

apiVersion: skaffold/v2
kind: Config
build:
  artifacts:
    - image: my-git-ts-tagged-app
      docker: {}
  tagPolicy:
    git:
      variant: commit
       
    # If you want to append a timestamp, you'd typically do this in your CI/CD script
    # or by using a custom tagger if Skaffold's built-ins aren't sufficient.
    # However, Skaffold *does* have a datetime policy that can be used independently.
    # Let's illustrate a different, but common, scenario: using a Git tag and ensuring it's unique.
    # For truly combining, you'd often use a CI variable.
    # Example of using a specific Git tag and appending a build ID from CI:
    # image: my-app
    # docker: {}
    # tagPolicy:
    #   git:
    #     variant: tags # Use Git tags like v1.0.0
    # deploy:
    #   kubectl:
    #     manifests:
    #       - k8s/deployment.yaml
    # In your CI script: export IMAGE_TAG=$(skaffold build --quiet --tag ${GIT_TAG}-${BUILD_ID})

Let’s re-focus on the built-in tagPolicy options for clarity. The git policy with variant: tags will use the most recent Git tag. If you want to explicitly use a specific tag from your history, Skaffold itself doesn’t directly expose a "use this specific tag" option within the tagPolicy block. Instead, you’d typically leverage environment variables or orchestrate the tagging outside of Skaffold’s direct tagPolicy configuration, perhaps by setting the TAG environment variable before running skaffold build.

The sha256 policy is particularly robust because it hashes the entire build context. This means that even if your main.go file hasn’t changed, but a dependency in your go.mod file has been updated, the sha256 hash will change, resulting in a new image tag. This provides a strong guarantee that the image produced is uniquely tied to the exact state of your project’s files at build time, regardless of Git history or manual versioning.

What many users overlook is that the sha256 policy’s "build context" includes everything within the specified docker.context (or the current directory if not specified). This means that even seemingly unrelated files, like README.md or .gitignore, if present in that context directory, will influence the SHA256 hash. This can sometimes lead to unexpected tag changes if these files are modified.

The next logical step after mastering image tagging is understanding how Skaffold manages deployments, specifically how it handles image updates in your Kubernetes manifests.

Want structured learning?

Take the full Skaffold course →