Skaffold doesn’t actually build artifacts in the order you might think, it builds them based on dependencies defined in your skaffold.yaml.

Let’s see it in action. Imagine you have two Docker images: a frontend and a backend. The frontend depends on the backend being available for its integration tests.

Here’s a simplified skaffold.yaml:

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: my-backend
      docker:
        dockerfile: backend/Dockerfile
    - image: my-frontend
      docker:
        dockerfile: frontend/Dockerfile
deploy:
  kubectl:
    manifests:
      - k8s/*
profiles:
  - name: with-tests
    build:
      artifacts:
        - image: my-frontend
          # This tells Skaffold that my-frontend depends on my-backend
          dependencies:
            images:
              - my-backend

When you run skaffold dev -p with-tests, Skaffold doesn’t just build my-backend then my-frontend. It first analyzes the dependencies section. Because my-frontend has dependencies.images: [my-backend], Skaffold knows it must build my-backend before it can build my-frontend.

Let’s trace this:

  1. Skaffold starts. It reads your skaffold.yaml.
  2. It identifies build artifacts: my-backend and my-frontend.
  3. It checks for dependencies. It sees my-frontend lists my-backend as a dependency.
  4. Dependency resolution: Skaffold determines the build order. It sees my-backend has no upstream dependencies, and my-frontend depends on my-backend. The resolved order is my-backend then my-frontend.
  5. Build my-backend. Skaffold executes the build steps for my-backend.
  6. Build my-frontend. Only after my-backend has successfully built, Skaffold proceeds to build my-frontend.

This dependency mechanism is crucial for complex applications where one service’s build or test phase relies on another. For example, you might have a shared library that multiple microservices depend on. You can define that dependency in skaffold.yaml to ensure the library is built and pushed before any service that uses it.

The dependencies field can also point to other Skaffold artifacts defined within the same skaffold.yaml, dependencies.paths for file-based dependencies, or even external Skaffold configurations. This allows for very intricate build graphs.

The most surprising true thing about Skaffold’s artifact dependencies is that they are evaluated before any build actually begins. Skaffold constructs a directed acyclic graph (DAG) of your build artifacts based on these declarations. If there’s a cycle in your dependencies (e.g., A depends on B, and B depends on A), Skaffold will error out before attempting any builds, preventing an infinite loop. This pre-analysis ensures that the build order is always valid and deterministic.

Consider this scenario: you have a base-image that both your backend and frontend images use. You can declare this:

apiVersion: skaffold/v2beta29
kind: Config
build:
  artifacts:
    - image: base-image
      docker:
        dockerfile: base/Dockerfile
    - image: my-backend
      docker:
        dockerfile: backend/Dockerfile
      dependencies:
        images:
          - base-image
    - image: my-frontend
      docker:
        dockerfile: frontend/Dockerfile
      dependencies:
        images:
          - base-image
deploy:
  kubectl:
    manifests:
      - k8s/*

When you run skaffold dev, Skaffold will first build base-image. Then, it will build my-backend and my-frontend concurrently (or in parallel if you have multiple builders configured) because they both depend on base-image and have no dependencies on each other. This parallelization is a key optimization Skaffold performs once the dependency graph is resolved.

The next concept you’ll likely encounter is managing complex build graphs with external Skaffold configurations or artifact tagging strategies.

Want structured learning?

Take the full Skaffold course →