Configure GCP Cloud Deploy Targets

The gcp:clouddeploy/target:Target resource, part of the Pulumi GCP provider, defines a Cloud Deploy target that specifies where your application deploys: GKE clusters, Cloud Run services, or multiple targets in parallel. This guide focuses on three capabilities: GKE cluster deployment, Cloud Run service deployment, and multi-target orchestration.

Targets reference existing infrastructure that must be created separately. The examples are intentionally small. Combine them with your own GKE clusters, Cloud Run services, and delivery pipelines.

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 deployParameters property passes environment-specific values to your deployment manifests. The location and name properties identify where Cloud Deploy manages this target resource.

Deploy to Cloud Run services

Teams deploying serverless containers use Cloud Run targets instead of GKE clusters.

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 specifies the Cloud Run location where services will be deployed. The executionConfigs property defines how Cloud Deploy executes the deployment: usages specifies which phases (RENDER, DEPLOY) use this configuration, and executionTimeout sets the maximum duration for each execution.

Coordinate 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 orchestrates parallel deployments by listing targetIds that reference other Cloud Deploy targets. Each child target must be created separately before being referenced. This enables multi-region or multi-cluster rollouts from a single delivery pipeline.

Beyond these examples

These snippets focus on specific target-level features: GKE, Cloud Run, and multi-target deployment, execution configuration and timeouts, and annotations and labels for metadata. 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 infrastructure.

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

  • Approval requirements (requireApproval)
  • Anthos Cluster and Custom Target configurations
  • Associated entities for Gateway API routing
  • Deploy parameters for environment-specific values

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

Configuration & Constraints
Why am I getting an error about duplicate ExecutionEnvironmentUsage values?
Each usage value (like RENDER or DEPLOY) can only appear once across all executionConfigs. When you specify configurations, you must include both RENDER and DEPLOY usages.
What properties can't I change after creating a target?
The location, name, and project properties are immutable. Changing any of these will force resource replacement.
What's the naming format for Cloud Deploy targets?
Target names must match the format a-z? (lowercase letters, numbers, and hyphens, with specific start/end requirements).
What's the format for associated entity IDs?
Entity IDs must consist of lowercase letters, numbers, and hyphens, start with a letter, end with a letter or number, and have a max length of 63 characters (matching regex ^a-z?$).
Target Types & Deployment
What target types can I deploy to with Cloud Deploy?
You can deploy to five target types: gke (GKE clusters), run (Cloud Run), multiTarget (multiple targets), anthosCluster (Anthos), and customTarget (custom deployment targets).
How do I deploy to a GKE cluster?
Configure the gke property with a cluster reference in the format projects/{project}/locations/{location}/clusters/{cluster-name}.
How do I deploy to Cloud Run?
Configure the run property with a location in the format projects/{project}/locations/{location}.
How do I create a multi-target deployment?
Use the multiTarget property with a targetIds array containing the IDs of targets you want to deploy to simultaneously.
Annotations & Labels
Why aren't my annotations or labels showing up in the resource?
The annotations and labels fields are non-authoritative and only manage values in your configuration. Use effectiveAnnotations and effectiveLabels output properties to see all annotations and labels present on the resource, including those set by other clients.
Does the target require approval before deployment?
By default, no. Set requireApproval to true if you want to require approval before deployments to this target.

Using a different cloud?

Explore integration guides for other cloud providers: