Deploy Kubernetes Resources from YAML with ConfigGroup

The kubernetes:yaml/v2:ConfigGroup resource, part of the Pulumi Kubernetes provider, creates multiple Kubernetes resources from YAML manifests, handling dependency ordering and reconciliation automatically. This guide focuses on three capabilities: file-based deployment, glob pattern matching, and inline YAML strings.

ConfigGroup requires a configured Kubernetes cluster and applies resources using your kubeconfig context. The examples are intentionally small. Combine them with your own manifest organization and dependency requirements.

Deploy manifests from local YAML files

Most Kubernetes deployments start with YAML manifests stored in version control, which ConfigGroup reads and applies.

import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

const example = new k8s.yaml.v2.ConfigGroup("example", {
    files: ["./manifest.yaml"],
});
import pulumi
from pulumi_kubernetes.yaml.v2 import ConfigGroup

example = ConfigGroup(
    "example",
    files=["./manifest.yaml"]
)
package main

import (
	yamlv2 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/yaml/v2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := yamlv2.NewConfigGroup(ctx, "example", &yamlv2.ConfigGroupArgs{
			Files: pulumi.ToStringArray([]string{"manifest.yaml"}),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using Pulumi;
using Pulumi.Kubernetes.Types.Inputs.Yaml.V2;
using Pulumi.Kubernetes.Yaml.V2;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
    var example = new ConfigGroup("example", new ConfigGroupArgs
    {
        Files = new[] { "./manifest.yaml" }
    });
});
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.kubernetes.yaml.v2.ConfigGroup;
import com.pulumi.kubernetes.yaml.v2.ConfigGroupArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {
            var example = new ConfigGroup("example", ConfigGroupArgs.builder()
                    .files("./manifest.yaml")
                    .build());
        });
    }
}
name: example
runtime: yaml
resources:
  example:
    type: kubernetes:yaml/v2:ConfigGroup
    properties:
      files:
      - ./manifest.yaml

The files property accepts paths to YAML manifests. ConfigGroup parses each file, creates the resources it defines, and waits for them to reconcile. Pulumi uses heuristics to determine application order, ensuring namespaces are created before namespaced resources.

Apply multiple manifests using glob patterns

Applications often organize manifests into directories, and glob patterns let you apply entire directories without listing each file.

import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

const example = new k8s.yaml.v2.ConfigGroup("example", {
    yaml: `
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-map
    `
});
import pulumi
from pulumi_kubernetes.yaml.v2 import ConfigGroup

example = ConfigGroup(
    "example",
    yaml="""
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-map
"""
)
package main

import (
	yamlv2 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/yaml/v2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := yamlv2.NewConfigGroup(ctx, "example", &yamlv2.ConfigGroupArgs{
			Yaml: pulumi.StringPtr(`
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-map
`),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using Pulumi;
using Pulumi.Kubernetes.Types.Inputs.Yaml.V2;
using Pulumi.Kubernetes.Yaml.V2;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
    var example = new ConfigGroup("example", new ConfigGroupArgs
    {
        Yaml = @"
            apiVersion: v1
            kind: ConfigMap
            metadata:
              name: my-map
            "
    });
});
package myproject;

import com.pulumi.Pulumi;
import com.pulumi.kubernetes.yaml.v2.ConfigGroup;
import com.pulumi.kubernetes.yaml.v2.ConfigGroupArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {
            var example = new ConfigGroup("example", ConfigGroupArgs.builder()
                    .yaml("""
                        apiVersion: v1
                        kind: ConfigMap
                        metadata:
                          name: my-map
                        """
                    )
                    .build());
        });
    }
}
name: example
runtime: yaml
resources:
  example:
    type: kubernetes:yaml/v2:ConfigGroup
    properties:
      yaml: |
        apiVersion: v1
        kind: ConfigMap
        metadata:
          name: my-map        

Glob patterns like ./manifests/*.yaml match all YAML files in a directory. This approach scales better than listing individual files, especially when manifest counts grow or change frequently.

Embed YAML directly in Pulumi code

Small configurations can be embedded directly in your Pulumi program, avoiding separate manifest files.

import * as pulumi from "@pulumi/pulumi";
import * as k8s from "@pulumi/kubernetes";

const example = new k8s.yaml.v2.ConfigGroup("example", {
    objs: [
        {
            apiVersion: "v1",
            kind: "ConfigMap",
            metadata: {
                name: "my-map"
            }
        }
    ]
});
import pulumi
from pulumi_kubernetes.yaml.v2 import ConfigGroup

example = ConfigGroup(
    "example",
    objs=[
        {
            "apiVersion": "v1",
            "kind": "ConfigMap",
            "metadata": {
                "name": "my-map",
            },
        }
    ]
)
package main

import (
	yamlv2 "github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes/yaml/v2"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := yamlv2.NewConfigGroup(ctx, "example", &yamlv2.ConfigGroupArgs{
			Objs: pulumi.Array{
				pulumi.Map{
					"apiVersion": pulumi.String("v1"),
					"kind":       pulumi.String("ConfigMap"),
					"metadata": pulumi.Map{
						"name": pulumi.String("my-map"),
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using Pulumi;
using Pulumi.Kubernetes.Types.Inputs.Yaml.V2;
using Pulumi.Kubernetes.Yaml.V2;
using System.Collections.Generic;

return await Deployment.RunAsync(() =>
{
    var example = new ConfigGroup("example", new ConfigGroupArgs
    {
        Objs = new[]
        {
            new Dictionary<string, object>
            {
                ["apiVersion"] = "v1",
                ["kind"] = "ConfigMap",
                ["metadata"] = new Dictionary<string, object>
                {
                    ["name"] = "my-map",
                },
            },
        },
    });
});
package myproject;

import java.util.Map;

import com.pulumi.Pulumi;
import com.pulumi.kubernetes.yaml.v2.ConfigGroup;
import com.pulumi.kubernetes.yaml.v2.ConfigGroupArgs;

public class App {
    public static void main(String[] args) {
        Pulumi.run(ctx -> {
            var example = new ConfigGroup("example", ConfigGroupArgs.builder()
                    .objs(Map.ofEntries(
                        Map.entry("apiVersion", "v1"),
                        Map.entry("kind", "ConfigMap"),
                        Map.entry("metadata", Map.ofEntries(
                            Map.entry("name", "my-map")
                        ))
                    ))
                    .build());
        });
    }
}
name: example
runtime: yaml
resources:
  example:
    type: kubernetes:yaml/v2:ConfigGroup
    properties:
      objs:
      - apiVersion: v1
        kind: ConfigMap
        metadata:
          name: my-map

The yaml property accepts a string containing Kubernetes YAML. This works well for simple resources like ConfigMaps or for generating manifests programmatically. For larger deployments, file-based approaches are more maintainable.

Beyond these examples

These snippets focus on specific ConfigGroup features: file-based and inline YAML deployment, and glob pattern matching for directories. They’re intentionally minimal rather than full application deployments.

The examples assume pre-existing infrastructure such as a Kubernetes cluster with configured kubeconfig, and YAML manifest files for file-based examples. They focus on how to load YAML rather than what resources to create.

To keep things focused, common ConfigGroup patterns are omitted, including:

  • Resource name prefixing (resourcePrefix)
  • Skipping reconciliation waits (skipAwait)
  • Explicit dependency ordering (config.kubernetes.io/depends-on annotation)
  • Structured object input (objs property)

These omissions are intentional: the goal is to illustrate how each YAML loading method works, not provide drop-in application modules. See the ConfigGroup resource reference for all available configuration options.

Let's deploy Kubernetes Resources from YAML with ConfigGroup

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Resource Ordering & Dependencies
How do I control the order resources are applied?
Pulumi uses heuristics to determine apply/delete order and waits for each resource to reconcile. For explicit control, use the config.kubernetes.io/depends-on annotation with comma-delimited resource references. This is essential for namespaces (which must exist before namespaced resources) and CRDs (which must be installed before custom resources).
Can I reference resources in other ConfigGroups with the depends-on annotation?
No, the config.kubernetes.io/depends-on annotation only works for resources within the same ConfigGroup. To create dependencies between ConfigGroups, use the dependsOn resource option.
What's the format for resource references in the depends-on annotation?
Use <group>/namespaces/<namespace>/<kind>/<name> for namespace-scoped resources, or <group>/<kind>/<name> for cluster-scoped resources. For core group resources, use an empty string for the group (e.g., /namespaces/test/Pod/pod-a).
What's the best way to deploy Custom Resource Definitions?
Deploy each application using its own ConfigGroup, especially when installing CRDs. This ensures proper ordering and allows other resources to depend on the CRD ConfigGroup using the dependsOn option.
YAML Input Methods
How do I supply YAML manifests to ConfigGroup?

You have four options:

  1. Files - Use files with paths like ./manifest.yaml
  2. Glob patterns - Use files with patterns like ./manifests/*.yaml
  3. Literal YAML - Use yaml with a YAML string
  4. Objects - Use objs with an array of resource objects

You can combine these methods in a single ConfigGroup.

Can I use URLs with the files property?
Yes, the files property accepts both local paths and URLs to Kubernetes manifest files.
Configuration & Behavior
How do I skip waiting for resources to reconcile?
Set skipAwait to true. By default, Pulumi waits for each resource to be fully reconciled before proceeding.
How are resource names generated in ConfigGroup?
Resource names are auto-generated with a prefix. By default, the prefix is the ConfigGroup’s name. You can customize this with the resourcePrefix property (e.g., resourcePrefix: "foo" produces foo-resourceName).