Configure GCP Cloud Deploy Targets

The gcp:clouddeploy/target:Target resource, part of the Pulumi GCP provider, defines a Cloud Deploy target: the destination where your application deploys, whether that’s a GKE cluster, Cloud Run location, or multiple targets orchestrated together. This guide focuses on three capabilities: GKE cluster targets, Cloud Run service targets, and multi-target orchestration.

Targets reference existing infrastructure that must be created separately: GKE clusters, Cloud Run locations, or other targets. The examples are intentionally small. Combine them with your own clusters, delivery pipelines, and release configurations.

Deploy to a GKE cluster

Most Cloud Deploy pipelines start by defining a target that points to a GKE cluster where your application will run.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.clouddeploy.Target("primary", {
    location: "us-west1",
    name: "target",
    deployParameters: {
        deployParameterKey: "deployParameterValue",
    },
    description: "basic description",
    gke: {
        cluster: "projects/my-project-name/locations/us-west1/clusters/example-cluster-name",
    },
    project: "my-project-name",
    requireApproval: false,
    annotations: {
        my_first_annotation: "example-annotation-1",
        my_second_annotation: "example-annotation-2",
    },
    labels: {
        my_first_label: "example-label-1",
        my_second_label: "example-label-2",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.clouddeploy.Target("primary",
    location="us-west1",
    name="target",
    deploy_parameters={
        "deployParameterKey": "deployParameterValue",
    },
    description="basic description",
    gke={
        "cluster": "projects/my-project-name/locations/us-west1/clusters/example-cluster-name",
    },
    project="my-project-name",
    require_approval=False,
    annotations={
        "my_first_annotation": "example-annotation-1",
        "my_second_annotation": "example-annotation-2",
    },
    labels={
        "my_first_label": "example-label-1",
        "my_second_label": "example-label-2",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/clouddeploy"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := clouddeploy.NewTarget(ctx, "primary", &clouddeploy.TargetArgs{
			Location: pulumi.String("us-west1"),
			Name:     pulumi.String("target"),
			DeployParameters: pulumi.StringMap{
				"deployParameterKey": pulumi.String("deployParameterValue"),
			},
			Description: pulumi.String("basic description"),
			Gke: &clouddeploy.TargetGkeArgs{
				Cluster: pulumi.String("projects/my-project-name/locations/us-west1/clusters/example-cluster-name"),
			},
			Project:         pulumi.String("my-project-name"),
			RequireApproval: pulumi.Bool(false),
			Annotations: pulumi.StringMap{
				"my_first_annotation":  pulumi.String("example-annotation-1"),
				"my_second_annotation": pulumi.String("example-annotation-2"),
			},
			Labels: pulumi.StringMap{
				"my_first_label":  pulumi.String("example-label-1"),
				"my_second_label": pulumi.String("example-label-2"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.CloudDeploy.Target("primary", new()
    {
        Location = "us-west1",
        Name = "target",
        DeployParameters = 
        {
            { "deployParameterKey", "deployParameterValue" },
        },
        Description = "basic description",
        Gke = new Gcp.CloudDeploy.Inputs.TargetGkeArgs
        {
            Cluster = "projects/my-project-name/locations/us-west1/clusters/example-cluster-name",
        },
        Project = "my-project-name",
        RequireApproval = false,
        Annotations = 
        {
            { "my_first_annotation", "example-annotation-1" },
            { "my_second_annotation", "example-annotation-2" },
        },
        Labels = 
        {
            { "my_first_label", "example-label-1" },
            { "my_second_label", "example-label-2" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.clouddeploy.Target;
import com.pulumi.gcp.clouddeploy.TargetArgs;
import com.pulumi.gcp.clouddeploy.inputs.TargetGkeArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new Target("primary", TargetArgs.builder()
            .location("us-west1")
            .name("target")
            .deployParameters(Map.of("deployParameterKey", "deployParameterValue"))
            .description("basic description")
            .gke(TargetGkeArgs.builder()
                .cluster("projects/my-project-name/locations/us-west1/clusters/example-cluster-name")
                .build())
            .project("my-project-name")
            .requireApproval(false)
            .annotations(Map.ofEntries(
                Map.entry("my_first_annotation", "example-annotation-1"),
                Map.entry("my_second_annotation", "example-annotation-2")
            ))
            .labels(Map.ofEntries(
                Map.entry("my_first_label", "example-label-1"),
                Map.entry("my_second_label", "example-label-2")
            ))
            .build());

    }
}
resources:
  primary:
    type: gcp:clouddeploy:Target
    properties:
      location: us-west1
      name: target
      deployParameters:
        deployParameterKey: deployParameterValue
      description: basic description
      gke:
        cluster: projects/my-project-name/locations/us-west1/clusters/example-cluster-name
      project: my-project-name
      requireApproval: false
      annotations:
        my_first_annotation: example-annotation-1
        my_second_annotation: example-annotation-2
      labels:
        my_first_label: example-label-1
        my_second_label: example-label-2

The gke property specifies the cluster reference in the format projects/{project}/locations/{location}/clusters/{cluster}. The requireApproval property controls whether deployments to this target need manual approval before proceeding. The location property determines which region manages the target resource itself.

Deploy to Cloud Run services

Teams deploying containerized applications to Cloud Run define targets that specify where services will be created or updated.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.clouddeploy.Target("primary", {
    location: "us-west1",
    name: "target",
    deployParameters: {},
    description: "basic description",
    executionConfigs: [{
        usages: [
            "RENDER",
            "DEPLOY",
        ],
        executionTimeout: "3600s",
    }],
    project: "my-project-name",
    requireApproval: false,
    run: {
        location: "projects/my-project-name/locations/us-west1",
    },
    annotations: {
        my_first_annotation: "example-annotation-1",
        my_second_annotation: "example-annotation-2",
    },
    labels: {
        my_first_label: "example-label-1",
        my_second_label: "example-label-2",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.clouddeploy.Target("primary",
    location="us-west1",
    name="target",
    deploy_parameters={},
    description="basic description",
    execution_configs=[{
        "usages": [
            "RENDER",
            "DEPLOY",
        ],
        "execution_timeout": "3600s",
    }],
    project="my-project-name",
    require_approval=False,
    run={
        "location": "projects/my-project-name/locations/us-west1",
    },
    annotations={
        "my_first_annotation": "example-annotation-1",
        "my_second_annotation": "example-annotation-2",
    },
    labels={
        "my_first_label": "example-label-1",
        "my_second_label": "example-label-2",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/clouddeploy"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := clouddeploy.NewTarget(ctx, "primary", &clouddeploy.TargetArgs{
			Location:         pulumi.String("us-west1"),
			Name:             pulumi.String("target"),
			DeployParameters: pulumi.StringMap{},
			Description:      pulumi.String("basic description"),
			ExecutionConfigs: clouddeploy.TargetExecutionConfigArray{
				&clouddeploy.TargetExecutionConfigArgs{
					Usages: pulumi.StringArray{
						pulumi.String("RENDER"),
						pulumi.String("DEPLOY"),
					},
					ExecutionTimeout: pulumi.String("3600s"),
				},
			},
			Project:         pulumi.String("my-project-name"),
			RequireApproval: pulumi.Bool(false),
			Run: &clouddeploy.TargetRunArgs{
				Location: pulumi.String("projects/my-project-name/locations/us-west1"),
			},
			Annotations: pulumi.StringMap{
				"my_first_annotation":  pulumi.String("example-annotation-1"),
				"my_second_annotation": pulumi.String("example-annotation-2"),
			},
			Labels: pulumi.StringMap{
				"my_first_label":  pulumi.String("example-label-1"),
				"my_second_label": pulumi.String("example-label-2"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.CloudDeploy.Target("primary", new()
    {
        Location = "us-west1",
        Name = "target",
        DeployParameters = null,
        Description = "basic description",
        ExecutionConfigs = new[]
        {
            new Gcp.CloudDeploy.Inputs.TargetExecutionConfigArgs
            {
                Usages = new[]
                {
                    "RENDER",
                    "DEPLOY",
                },
                ExecutionTimeout = "3600s",
            },
        },
        Project = "my-project-name",
        RequireApproval = false,
        Run = new Gcp.CloudDeploy.Inputs.TargetRunArgs
        {
            Location = "projects/my-project-name/locations/us-west1",
        },
        Annotations = 
        {
            { "my_first_annotation", "example-annotation-1" },
            { "my_second_annotation", "example-annotation-2" },
        },
        Labels = 
        {
            { "my_first_label", "example-label-1" },
            { "my_second_label", "example-label-2" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.clouddeploy.Target;
import com.pulumi.gcp.clouddeploy.TargetArgs;
import com.pulumi.gcp.clouddeploy.inputs.TargetExecutionConfigArgs;
import com.pulumi.gcp.clouddeploy.inputs.TargetRunArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new Target("primary", TargetArgs.builder()
            .location("us-west1")
            .name("target")
            .deployParameters(Map.ofEntries(
            ))
            .description("basic description")
            .executionConfigs(TargetExecutionConfigArgs.builder()
                .usages(                
                    "RENDER",
                    "DEPLOY")
                .executionTimeout("3600s")
                .build())
            .project("my-project-name")
            .requireApproval(false)
            .run(TargetRunArgs.builder()
                .location("projects/my-project-name/locations/us-west1")
                .build())
            .annotations(Map.ofEntries(
                Map.entry("my_first_annotation", "example-annotation-1"),
                Map.entry("my_second_annotation", "example-annotation-2")
            ))
            .labels(Map.ofEntries(
                Map.entry("my_first_label", "example-label-1"),
                Map.entry("my_second_label", "example-label-2")
            ))
            .build());

    }
}
resources:
  primary:
    type: gcp:clouddeploy:Target
    properties:
      location: us-west1
      name: target
      deployParameters: {}
      description: basic description
      executionConfigs:
        - usages:
            - RENDER
            - DEPLOY
          executionTimeout: 3600s
      project: my-project-name
      requireApproval: false
      run:
        location: projects/my-project-name/locations/us-west1
      annotations:
        my_first_annotation: example-annotation-1
        my_second_annotation: example-annotation-2
      labels:
        my_first_label: example-label-1
        my_second_label: example-label-2

The run property points to a Cloud Run location instead of a GKE cluster. The executionConfigs property defines how Cloud Deploy executes the render and deploy phases, including timeout limits. When you specify execution configs, you must include both RENDER and DEPLOY usages.

Orchestrate deployments across multiple targets

Complex deployments often need to roll out to multiple clusters or regions simultaneously.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const primary = new gcp.clouddeploy.Target("primary", {
    location: "us-west1",
    name: "target",
    deployParameters: {},
    description: "multi-target description",
    executionConfigs: [{
        usages: [
            "RENDER",
            "DEPLOY",
        ],
        executionTimeout: "3600s",
    }],
    multiTarget: {
        targetIds: [
            "1",
            "2",
        ],
    },
    project: "my-project-name",
    requireApproval: false,
    annotations: {
        my_first_annotation: "example-annotation-1",
        my_second_annotation: "example-annotation-2",
    },
    labels: {
        my_first_label: "example-label-1",
        my_second_label: "example-label-2",
    },
});
import pulumi
import pulumi_gcp as gcp

primary = gcp.clouddeploy.Target("primary",
    location="us-west1",
    name="target",
    deploy_parameters={},
    description="multi-target description",
    execution_configs=[{
        "usages": [
            "RENDER",
            "DEPLOY",
        ],
        "execution_timeout": "3600s",
    }],
    multi_target={
        "target_ids": [
            "1",
            "2",
        ],
    },
    project="my-project-name",
    require_approval=False,
    annotations={
        "my_first_annotation": "example-annotation-1",
        "my_second_annotation": "example-annotation-2",
    },
    labels={
        "my_first_label": "example-label-1",
        "my_second_label": "example-label-2",
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/clouddeploy"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := clouddeploy.NewTarget(ctx, "primary", &clouddeploy.TargetArgs{
			Location:         pulumi.String("us-west1"),
			Name:             pulumi.String("target"),
			DeployParameters: pulumi.StringMap{},
			Description:      pulumi.String("multi-target description"),
			ExecutionConfigs: clouddeploy.TargetExecutionConfigArray{
				&clouddeploy.TargetExecutionConfigArgs{
					Usages: pulumi.StringArray{
						pulumi.String("RENDER"),
						pulumi.String("DEPLOY"),
					},
					ExecutionTimeout: pulumi.String("3600s"),
				},
			},
			MultiTarget: &clouddeploy.TargetMultiTargetArgs{
				TargetIds: pulumi.StringArray{
					pulumi.String("1"),
					pulumi.String("2"),
				},
			},
			Project:         pulumi.String("my-project-name"),
			RequireApproval: pulumi.Bool(false),
			Annotations: pulumi.StringMap{
				"my_first_annotation":  pulumi.String("example-annotation-1"),
				"my_second_annotation": pulumi.String("example-annotation-2"),
			},
			Labels: pulumi.StringMap{
				"my_first_label":  pulumi.String("example-label-1"),
				"my_second_label": pulumi.String("example-label-2"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var primary = new Gcp.CloudDeploy.Target("primary", new()
    {
        Location = "us-west1",
        Name = "target",
        DeployParameters = null,
        Description = "multi-target description",
        ExecutionConfigs = new[]
        {
            new Gcp.CloudDeploy.Inputs.TargetExecutionConfigArgs
            {
                Usages = new[]
                {
                    "RENDER",
                    "DEPLOY",
                },
                ExecutionTimeout = "3600s",
            },
        },
        MultiTarget = new Gcp.CloudDeploy.Inputs.TargetMultiTargetArgs
        {
            TargetIds = new[]
            {
                "1",
                "2",
            },
        },
        Project = "my-project-name",
        RequireApproval = false,
        Annotations = 
        {
            { "my_first_annotation", "example-annotation-1" },
            { "my_second_annotation", "example-annotation-2" },
        },
        Labels = 
        {
            { "my_first_label", "example-label-1" },
            { "my_second_label", "example-label-2" },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.clouddeploy.Target;
import com.pulumi.gcp.clouddeploy.TargetArgs;
import com.pulumi.gcp.clouddeploy.inputs.TargetExecutionConfigArgs;
import com.pulumi.gcp.clouddeploy.inputs.TargetMultiTargetArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var primary = new Target("primary", TargetArgs.builder()
            .location("us-west1")
            .name("target")
            .deployParameters(Map.ofEntries(
            ))
            .description("multi-target description")
            .executionConfigs(TargetExecutionConfigArgs.builder()
                .usages(                
                    "RENDER",
                    "DEPLOY")
                .executionTimeout("3600s")
                .build())
            .multiTarget(TargetMultiTargetArgs.builder()
                .targetIds(                
                    "1",
                    "2")
                .build())
            .project("my-project-name")
            .requireApproval(false)
            .annotations(Map.ofEntries(
                Map.entry("my_first_annotation", "example-annotation-1"),
                Map.entry("my_second_annotation", "example-annotation-2")
            ))
            .labels(Map.ofEntries(
                Map.entry("my_first_label", "example-label-1"),
                Map.entry("my_second_label", "example-label-2")
            ))
            .build());

    }
}
resources:
  primary:
    type: gcp:clouddeploy:Target
    properties:
      location: us-west1
      name: target
      deployParameters: {}
      description: multi-target description
      executionConfigs:
        - usages:
            - RENDER
            - DEPLOY
          executionTimeout: 3600s
      multiTarget:
        targetIds:
          - '1'
          - '2'
      project: my-project-name
      requireApproval: false
      annotations:
        my_first_annotation: example-annotation-1
        my_second_annotation: example-annotation-2
      labels:
        my_first_label: example-label-1
        my_second_label: example-label-2

The multiTarget property lists child target IDs that receive the deployment in parallel. Each referenced target must be defined separately as its own Target resource. Multi-targets coordinate the rollout but don’t specify infrastructure directly; the child targets define the actual GKE clusters or Cloud Run locations.

Beyond these examples

These snippets focus on specific target-level features: GKE, Cloud Run, and multi-target deployment destinations, and execution configuration and approval requirements. They’re intentionally minimal rather than full deployment pipelines.

The examples reference pre-existing infrastructure such as GKE clusters or Cloud Run locations, and child targets for multi-target configuration. They focus on configuring the target rather than provisioning the underlying compute resources.

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

  • Anthos Cluster and Custom Target configurations
  • Associated entities for Gateway API canary deployments
  • Deploy parameters for runtime configuration
  • Annotations and labels for metadata

These omissions are intentional: the goal is to illustrate how each target type is wired, not provide drop-in deployment modules. See the Cloud Deploy Target resource reference for all available configuration options.

Let's configure GCP Cloud Deploy Targets

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Target Configuration & Types
What execution environments must I configure for a target?
You must include both RENDER and DEPLOY in the executionConfigs usages array. Each usage value can only appear once, and using the same value multiple times causes an error.
What target types are available in Cloud Deploy?
Five target types are supported: GKE clusters (gke), Cloud Run (run), multiple targets (multiTarget), Anthos clusters (anthosCluster), and custom targets (customTarget).
How do I configure a GKE cluster target?
Use the gke property with a cluster reference in the format projects/PROJECT/locations/LOCATION/clusters/CLUSTER_NAME.
How do I configure a Cloud Run target?
Use the run property with a location in the format projects/PROJECT/locations/LOCATION.
How do I deploy to multiple targets at once?
Use the multiTarget property with a targetIds array containing the IDs of the targets you want to deploy to.
Naming & Constraints
What properties can't I change after creating a target?
The location, name, and project properties are immutable and cannot be modified after target creation. Changing these values requires replacing the resource.
What format must the target name follow?
Target names must match the regex a-z?, meaning they can contain lowercase letters, numbers, and hyphens, must start with a letter, and end with a letter or number.
What are associated entities and what format do their IDs require?
Associated entities let you specify deployment locations for specific features (like deploying Gateway API HTTPRoute to different clusters). Entity IDs must match the regex ^a-z?$ with a maximum length of 63 characters.
Labels & Annotations
Why don't I see all my annotations and labels in Pulumi state?
The annotations and labels fields are non-authoritative and only manage values present in your configuration. To see all annotations and labels on the resource (including those set by other clients), use effectiveAnnotations and effectiveLabels.
Execution & Timeouts
What's the format for execution timeout?
Execution timeout uses duration format with a seconds suffix, such as 3600s for one hour.

Using a different cloud?

Explore integration guides for other cloud providers: