Configure GCP Bigtable App Profiles

The gcp:bigquery/appProfile:AppProfile resource, part of the Pulumi GCP provider, defines how Cloud Bigtable routes traffic from an application to clusters within a Bigtable instance. This guide focuses on three capabilities: multi-cluster routing strategies, single-cluster routing for consistency, and traffic priority isolation.

App profiles belong to Bigtable instances and reference cluster IDs that must already exist. The examples are intentionally small. Combine them with your own Bigtable instances and cluster configurations.

Route requests to any available cluster

Applications that prioritize availability over strict consistency can route to the nearest cluster and fail over automatically when issues occur.

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

const instance = new gcp.bigtable.Instance("instance", {
    name: "bt-instance",
    clusters: [
        {
            clusterId: "cluster-1",
            zone: "us-central1-a",
            numNodes: 3,
            storageType: "HDD",
        },
        {
            clusterId: "cluster-2",
            zone: "us-central1-b",
            numNodes: 3,
            storageType: "HDD",
        },
        {
            clusterId: "cluster-3",
            zone: "us-central1-c",
            numNodes: 3,
            storageType: "HDD",
        },
    ],
    deletionProtection: true,
});
const ap = new gcp.bigtable.AppProfile("ap", {
    instance: instance.name,
    appProfileId: "bt-profile",
    multiClusterRoutingUseAny: true,
    ignoreWarnings: true,
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.bigtable.Instance("instance",
    name="bt-instance",
    clusters=[
        {
            "cluster_id": "cluster-1",
            "zone": "us-central1-a",
            "num_nodes": 3,
            "storage_type": "HDD",
        },
        {
            "cluster_id": "cluster-2",
            "zone": "us-central1-b",
            "num_nodes": 3,
            "storage_type": "HDD",
        },
        {
            "cluster_id": "cluster-3",
            "zone": "us-central1-c",
            "num_nodes": 3,
            "storage_type": "HDD",
        },
    ],
    deletion_protection=True)
ap = gcp.bigtable.AppProfile("ap",
    instance=instance.name,
    app_profile_id="bt-profile",
    multi_cluster_routing_use_any=True,
    ignore_warnings=True)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		instance, err := bigtable.NewInstance(ctx, "instance", &bigtable.InstanceArgs{
			Name: pulumi.String("bt-instance"),
			Clusters: bigtable.InstanceClusterArray{
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-1"),
					Zone:        pulumi.String("us-central1-a"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-2"),
					Zone:        pulumi.String("us-central1-b"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-3"),
					Zone:        pulumi.String("us-central1-c"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
			},
			DeletionProtection: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = bigtable.NewAppProfile(ctx, "ap", &bigtable.AppProfileArgs{
			Instance:                  instance.Name,
			AppProfileId:              pulumi.String("bt-profile"),
			MultiClusterRoutingUseAny: pulumi.Bool(true),
			IgnoreWarnings:            pulumi.Bool(true),
		})
		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 instance = new Gcp.BigTable.Instance("instance", new()
    {
        Name = "bt-instance",
        Clusters = new[]
        {
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-1",
                Zone = "us-central1-a",
                NumNodes = 3,
                StorageType = "HDD",
            },
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-2",
                Zone = "us-central1-b",
                NumNodes = 3,
                StorageType = "HDD",
            },
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-3",
                Zone = "us-central1-c",
                NumNodes = 3,
                StorageType = "HDD",
            },
        },
        DeletionProtection = true,
    });

    var ap = new Gcp.BigTable.AppProfile("ap", new()
    {
        Instance = instance.Name,
        AppProfileId = "bt-profile",
        MultiClusterRoutingUseAny = true,
        IgnoreWarnings = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigtable.Instance;
import com.pulumi.gcp.bigtable.InstanceArgs;
import com.pulumi.gcp.bigtable.inputs.InstanceClusterArgs;
import com.pulumi.gcp.bigtable.AppProfile;
import com.pulumi.gcp.bigtable.AppProfileArgs;
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 instance = new Instance("instance", InstanceArgs.builder()
            .name("bt-instance")
            .clusters(            
                InstanceClusterArgs.builder()
                    .clusterId("cluster-1")
                    .zone("us-central1-a")
                    .numNodes(3)
                    .storageType("HDD")
                    .build(),
                InstanceClusterArgs.builder()
                    .clusterId("cluster-2")
                    .zone("us-central1-b")
                    .numNodes(3)
                    .storageType("HDD")
                    .build(),
                InstanceClusterArgs.builder()
                    .clusterId("cluster-3")
                    .zone("us-central1-c")
                    .numNodes(3)
                    .storageType("HDD")
                    .build())
            .deletionProtection(true)
            .build());

        var ap = new AppProfile("ap", AppProfileArgs.builder()
            .instance(instance.name())
            .appProfileId("bt-profile")
            .multiClusterRoutingUseAny(true)
            .ignoreWarnings(true)
            .build());

    }
}
resources:
  instance:
    type: gcp:bigtable:Instance
    properties:
      name: bt-instance
      clusters:
        - clusterId: cluster-1
          zone: us-central1-a
          numNodes: 3
          storageType: HDD
        - clusterId: cluster-2
          zone: us-central1-b
          numNodes: 3
          storageType: HDD
        - clusterId: cluster-3
          zone: us-central1-c
          numNodes: 3
          storageType: HDD
      deletionProtection: true
  ap:
    type: gcp:bigtable:AppProfile
    properties:
      instance: ${instance.name}
      appProfileId: bt-profile
      multiClusterRoutingUseAny: true
      ignoreWarnings: true

When multiClusterRoutingUseAny is true, Bigtable routes read and write requests to the nearest available cluster. If a cluster experiences transient errors or delays, requests fail over to the next nearest cluster. This sacrifices read-your-writes consistency for improved availability. The instance property references the Bigtable instance name, and appProfileId sets the profile’s unique identifier.

Pin requests to a single cluster

Workloads requiring strong consistency or transactional writes route all traffic to a specific cluster.

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

const instance = new gcp.bigtable.Instance("instance", {
    name: "bt-instance",
    clusters: [{
        clusterId: "cluster-1",
        zone: "us-central1-b",
        numNodes: 3,
        storageType: "HDD",
    }],
    deletionProtection: true,
});
const ap = new gcp.bigtable.AppProfile("ap", {
    instance: instance.name,
    appProfileId: "bt-profile",
    singleClusterRouting: {
        clusterId: "cluster-1",
        allowTransactionalWrites: true,
    },
    ignoreWarnings: true,
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.bigtable.Instance("instance",
    name="bt-instance",
    clusters=[{
        "cluster_id": "cluster-1",
        "zone": "us-central1-b",
        "num_nodes": 3,
        "storage_type": "HDD",
    }],
    deletion_protection=True)
ap = gcp.bigtable.AppProfile("ap",
    instance=instance.name,
    app_profile_id="bt-profile",
    single_cluster_routing={
        "cluster_id": "cluster-1",
        "allow_transactional_writes": True,
    },
    ignore_warnings=True)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		instance, err := bigtable.NewInstance(ctx, "instance", &bigtable.InstanceArgs{
			Name: pulumi.String("bt-instance"),
			Clusters: bigtable.InstanceClusterArray{
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-1"),
					Zone:        pulumi.String("us-central1-b"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
			},
			DeletionProtection: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = bigtable.NewAppProfile(ctx, "ap", &bigtable.AppProfileArgs{
			Instance:     instance.Name,
			AppProfileId: pulumi.String("bt-profile"),
			SingleClusterRouting: &bigtable.AppProfileSingleClusterRoutingArgs{
				ClusterId:                pulumi.String("cluster-1"),
				AllowTransactionalWrites: pulumi.Bool(true),
			},
			IgnoreWarnings: pulumi.Bool(true),
		})
		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 instance = new Gcp.BigTable.Instance("instance", new()
    {
        Name = "bt-instance",
        Clusters = new[]
        {
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-1",
                Zone = "us-central1-b",
                NumNodes = 3,
                StorageType = "HDD",
            },
        },
        DeletionProtection = true,
    });

    var ap = new Gcp.BigTable.AppProfile("ap", new()
    {
        Instance = instance.Name,
        AppProfileId = "bt-profile",
        SingleClusterRouting = new Gcp.BigTable.Inputs.AppProfileSingleClusterRoutingArgs
        {
            ClusterId = "cluster-1",
            AllowTransactionalWrites = true,
        },
        IgnoreWarnings = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigtable.Instance;
import com.pulumi.gcp.bigtable.InstanceArgs;
import com.pulumi.gcp.bigtable.inputs.InstanceClusterArgs;
import com.pulumi.gcp.bigtable.AppProfile;
import com.pulumi.gcp.bigtable.AppProfileArgs;
import com.pulumi.gcp.bigtable.inputs.AppProfileSingleClusterRoutingArgs;
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 instance = new Instance("instance", InstanceArgs.builder()
            .name("bt-instance")
            .clusters(InstanceClusterArgs.builder()
                .clusterId("cluster-1")
                .zone("us-central1-b")
                .numNodes(3)
                .storageType("HDD")
                .build())
            .deletionProtection(true)
            .build());

        var ap = new AppProfile("ap", AppProfileArgs.builder()
            .instance(instance.name())
            .appProfileId("bt-profile")
            .singleClusterRouting(AppProfileSingleClusterRoutingArgs.builder()
                .clusterId("cluster-1")
                .allowTransactionalWrites(true)
                .build())
            .ignoreWarnings(true)
            .build());

    }
}
resources:
  instance:
    type: gcp:bigtable:Instance
    properties:
      name: bt-instance
      clusters:
        - clusterId: cluster-1
          zone: us-central1-b
          numNodes: 3
          storageType: HDD
      deletionProtection: true
  ap:
    type: gcp:bigtable:AppProfile
    properties:
      instance: ${instance.name}
      appProfileId: bt-profile
      singleClusterRouting:
        clusterId: cluster-1
        allowTransactionalWrites: true
      ignoreWarnings: true

The singleClusterRouting property pins all requests to the specified clusterId. Setting allowTransactionalWrites to true enables transactional operations, which require single-cluster routing to maintain consistency. This configuration ensures read-your-writes consistency at the cost of availability if the cluster becomes unavailable.

Route to a subset of clusters

Some applications need multi-cluster availability but want to limit routing to specific clusters in particular regions.

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

const instance = new gcp.bigtable.Instance("instance", {
    name: "bt-instance",
    clusters: [
        {
            clusterId: "cluster-1",
            zone: "us-central1-a",
            numNodes: 3,
            storageType: "HDD",
        },
        {
            clusterId: "cluster-2",
            zone: "us-central1-b",
            numNodes: 3,
            storageType: "HDD",
        },
        {
            clusterId: "cluster-3",
            zone: "us-central1-c",
            numNodes: 3,
            storageType: "HDD",
        },
    ],
    deletionProtection: true,
});
const ap = new gcp.bigtable.AppProfile("ap", {
    instance: instance.name,
    appProfileId: "bt-profile",
    multiClusterRoutingUseAny: true,
    multiClusterRoutingClusterIds: [
        "cluster-1",
        "cluster-2",
    ],
    ignoreWarnings: true,
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.bigtable.Instance("instance",
    name="bt-instance",
    clusters=[
        {
            "cluster_id": "cluster-1",
            "zone": "us-central1-a",
            "num_nodes": 3,
            "storage_type": "HDD",
        },
        {
            "cluster_id": "cluster-2",
            "zone": "us-central1-b",
            "num_nodes": 3,
            "storage_type": "HDD",
        },
        {
            "cluster_id": "cluster-3",
            "zone": "us-central1-c",
            "num_nodes": 3,
            "storage_type": "HDD",
        },
    ],
    deletion_protection=True)
ap = gcp.bigtable.AppProfile("ap",
    instance=instance.name,
    app_profile_id="bt-profile",
    multi_cluster_routing_use_any=True,
    multi_cluster_routing_cluster_ids=[
        "cluster-1",
        "cluster-2",
    ],
    ignore_warnings=True)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		instance, err := bigtable.NewInstance(ctx, "instance", &bigtable.InstanceArgs{
			Name: pulumi.String("bt-instance"),
			Clusters: bigtable.InstanceClusterArray{
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-1"),
					Zone:        pulumi.String("us-central1-a"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-2"),
					Zone:        pulumi.String("us-central1-b"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-3"),
					Zone:        pulumi.String("us-central1-c"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
			},
			DeletionProtection: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = bigtable.NewAppProfile(ctx, "ap", &bigtable.AppProfileArgs{
			Instance:                  instance.Name,
			AppProfileId:              pulumi.String("bt-profile"),
			MultiClusterRoutingUseAny: pulumi.Bool(true),
			MultiClusterRoutingClusterIds: pulumi.StringArray{
				pulumi.String("cluster-1"),
				pulumi.String("cluster-2"),
			},
			IgnoreWarnings: pulumi.Bool(true),
		})
		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 instance = new Gcp.BigTable.Instance("instance", new()
    {
        Name = "bt-instance",
        Clusters = new[]
        {
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-1",
                Zone = "us-central1-a",
                NumNodes = 3,
                StorageType = "HDD",
            },
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-2",
                Zone = "us-central1-b",
                NumNodes = 3,
                StorageType = "HDD",
            },
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-3",
                Zone = "us-central1-c",
                NumNodes = 3,
                StorageType = "HDD",
            },
        },
        DeletionProtection = true,
    });

    var ap = new Gcp.BigTable.AppProfile("ap", new()
    {
        Instance = instance.Name,
        AppProfileId = "bt-profile",
        MultiClusterRoutingUseAny = true,
        MultiClusterRoutingClusterIds = new[]
        {
            "cluster-1",
            "cluster-2",
        },
        IgnoreWarnings = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigtable.Instance;
import com.pulumi.gcp.bigtable.InstanceArgs;
import com.pulumi.gcp.bigtable.inputs.InstanceClusterArgs;
import com.pulumi.gcp.bigtable.AppProfile;
import com.pulumi.gcp.bigtable.AppProfileArgs;
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 instance = new Instance("instance", InstanceArgs.builder()
            .name("bt-instance")
            .clusters(            
                InstanceClusterArgs.builder()
                    .clusterId("cluster-1")
                    .zone("us-central1-a")
                    .numNodes(3)
                    .storageType("HDD")
                    .build(),
                InstanceClusterArgs.builder()
                    .clusterId("cluster-2")
                    .zone("us-central1-b")
                    .numNodes(3)
                    .storageType("HDD")
                    .build(),
                InstanceClusterArgs.builder()
                    .clusterId("cluster-3")
                    .zone("us-central1-c")
                    .numNodes(3)
                    .storageType("HDD")
                    .build())
            .deletionProtection(true)
            .build());

        var ap = new AppProfile("ap", AppProfileArgs.builder()
            .instance(instance.name())
            .appProfileId("bt-profile")
            .multiClusterRoutingUseAny(true)
            .multiClusterRoutingClusterIds(            
                "cluster-1",
                "cluster-2")
            .ignoreWarnings(true)
            .build());

    }
}
resources:
  instance:
    type: gcp:bigtable:Instance
    properties:
      name: bt-instance
      clusters:
        - clusterId: cluster-1
          zone: us-central1-a
          numNodes: 3
          storageType: HDD
        - clusterId: cluster-2
          zone: us-central1-b
          numNodes: 3
          storageType: HDD
        - clusterId: cluster-3
          zone: us-central1-c
          numNodes: 3
          storageType: HDD
      deletionProtection: true
  ap:
    type: gcp:bigtable:AppProfile
    properties:
      instance: ${instance.name}
      appProfileId: bt-profile
      multiClusterRoutingUseAny: true
      multiClusterRoutingClusterIds:
        - cluster-1
        - cluster-2
      ignoreWarnings: true

Combining multiClusterRoutingUseAny with multiClusterRoutingClusterIds restricts routing to the specified clusters. Bigtable routes to the nearest cluster in the list and fails over within that subset. This balances availability with control over which clusters handle traffic.

Set traffic priority for resource isolation

Applications with different performance requirements can use priority settings to prevent lower-priority workloads from affecting critical operations.

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

const instance = new gcp.bigtable.Instance("instance", {
    name: "bt-instance",
    clusters: [{
        clusterId: "cluster-1",
        zone: "us-central1-b",
        numNodes: 3,
        storageType: "HDD",
    }],
    deletionProtection: true,
});
const ap = new gcp.bigtable.AppProfile("ap", {
    instance: instance.name,
    appProfileId: "bt-profile",
    singleClusterRouting: {
        clusterId: "cluster-1",
        allowTransactionalWrites: true,
    },
    standardIsolation: {
        priority: "PRIORITY_LOW",
    },
    ignoreWarnings: true,
});
import pulumi
import pulumi_gcp as gcp

instance = gcp.bigtable.Instance("instance",
    name="bt-instance",
    clusters=[{
        "cluster_id": "cluster-1",
        "zone": "us-central1-b",
        "num_nodes": 3,
        "storage_type": "HDD",
    }],
    deletion_protection=True)
ap = gcp.bigtable.AppProfile("ap",
    instance=instance.name,
    app_profile_id="bt-profile",
    single_cluster_routing={
        "cluster_id": "cluster-1",
        "allow_transactional_writes": True,
    },
    standard_isolation={
        "priority": "PRIORITY_LOW",
    },
    ignore_warnings=True)
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		instance, err := bigtable.NewInstance(ctx, "instance", &bigtable.InstanceArgs{
			Name: pulumi.String("bt-instance"),
			Clusters: bigtable.InstanceClusterArray{
				&bigtable.InstanceClusterArgs{
					ClusterId:   pulumi.String("cluster-1"),
					Zone:        pulumi.String("us-central1-b"),
					NumNodes:    pulumi.Int(3),
					StorageType: pulumi.String("HDD"),
				},
			},
			DeletionProtection: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = bigtable.NewAppProfile(ctx, "ap", &bigtable.AppProfileArgs{
			Instance:     instance.Name,
			AppProfileId: pulumi.String("bt-profile"),
			SingleClusterRouting: &bigtable.AppProfileSingleClusterRoutingArgs{
				ClusterId:                pulumi.String("cluster-1"),
				AllowTransactionalWrites: pulumi.Bool(true),
			},
			StandardIsolation: &bigtable.AppProfileStandardIsolationArgs{
				Priority: pulumi.String("PRIORITY_LOW"),
			},
			IgnoreWarnings: pulumi.Bool(true),
		})
		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 instance = new Gcp.BigTable.Instance("instance", new()
    {
        Name = "bt-instance",
        Clusters = new[]
        {
            new Gcp.BigTable.Inputs.InstanceClusterArgs
            {
                ClusterId = "cluster-1",
                Zone = "us-central1-b",
                NumNodes = 3,
                StorageType = "HDD",
            },
        },
        DeletionProtection = true,
    });

    var ap = new Gcp.BigTable.AppProfile("ap", new()
    {
        Instance = instance.Name,
        AppProfileId = "bt-profile",
        SingleClusterRouting = new Gcp.BigTable.Inputs.AppProfileSingleClusterRoutingArgs
        {
            ClusterId = "cluster-1",
            AllowTransactionalWrites = true,
        },
        StandardIsolation = new Gcp.BigTable.Inputs.AppProfileStandardIsolationArgs
        {
            Priority = "PRIORITY_LOW",
        },
        IgnoreWarnings = true,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.bigtable.Instance;
import com.pulumi.gcp.bigtable.InstanceArgs;
import com.pulumi.gcp.bigtable.inputs.InstanceClusterArgs;
import com.pulumi.gcp.bigtable.AppProfile;
import com.pulumi.gcp.bigtable.AppProfileArgs;
import com.pulumi.gcp.bigtable.inputs.AppProfileSingleClusterRoutingArgs;
import com.pulumi.gcp.bigtable.inputs.AppProfileStandardIsolationArgs;
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 instance = new Instance("instance", InstanceArgs.builder()
            .name("bt-instance")
            .clusters(InstanceClusterArgs.builder()
                .clusterId("cluster-1")
                .zone("us-central1-b")
                .numNodes(3)
                .storageType("HDD")
                .build())
            .deletionProtection(true)
            .build());

        var ap = new AppProfile("ap", AppProfileArgs.builder()
            .instance(instance.name())
            .appProfileId("bt-profile")
            .singleClusterRouting(AppProfileSingleClusterRoutingArgs.builder()
                .clusterId("cluster-1")
                .allowTransactionalWrites(true)
                .build())
            .standardIsolation(AppProfileStandardIsolationArgs.builder()
                .priority("PRIORITY_LOW")
                .build())
            .ignoreWarnings(true)
            .build());

    }
}
resources:
  instance:
    type: gcp:bigtable:Instance
    properties:
      name: bt-instance
      clusters:
        - clusterId: cluster-1
          zone: us-central1-b
          numNodes: 3
          storageType: HDD
      deletionProtection: true
  ap:
    type: gcp:bigtable:AppProfile
    properties:
      instance: ${instance.name}
      appProfileId: bt-profile
      singleClusterRouting:
        clusterId: cluster-1
        allowTransactionalWrites: true
      standardIsolation:
        priority: PRIORITY_LOW
      ignoreWarnings: true

The standardIsolation property with priority set to PRIORITY_LOW marks this app profile’s traffic as lower priority. Bigtable uses this to isolate batch or analytical workloads from production traffic, preventing resource contention. This works with both single-cluster and multi-cluster routing policies.

Beyond these examples

These snippets focus on specific app profile features: multi-cluster and single-cluster routing, cluster subset selection, and traffic priority isolation. They’re intentionally minimal rather than full Bigtable deployments.

The examples reference pre-existing infrastructure such as Bigtable instances with one or more clusters. They focus on configuring routing policies rather than provisioning the underlying instance infrastructure.

To keep things focused, common app profile patterns are omitted, including:

  • Data Boost isolation for read-only workloads (dataBoostIsolationReadOnly)
  • Row affinity sticky routing (rowAffinity)
  • App profile descriptions and metadata

These omissions are intentional: the goal is to illustrate how each routing policy is wired, not provide drop-in Bigtable modules. See the Bigtable AppProfile resource reference for all available configuration options.

Let's configure GCP Bigtable App Profiles

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Routing Configuration
What's the difference between single-cluster and multi-cluster routing?
Use singleClusterRouting to route all traffic to one cluster with guaranteed consistency. Use multiClusterRoutingUseAny to route to the nearest available cluster with automatic failover, which improves availability but sacrifices read-your-writes consistency.
Can I use both single-cluster and multi-cluster routing in the same app profile?
No, you must choose one routing policy. The examples show either singleClusterRouting or multiClusterRoutingUseAny, never both.
What does multiClusterRoutingClusterIds do?
It restricts routing to a specific subset of clusters. The order is ignored; clusters are tried in order of distance. If left empty, all clusters in the instance are eligible for routing.
How do I restrict multi-cluster routing to specific clusters?
Set multiClusterRoutingUseAny to true and specify cluster IDs in multiClusterRoutingClusterIds. For example, you can route to only cluster-1 and cluster-2 even if cluster-3 exists.
Consistency & Performance
What is rowAffinity and when should I use it?
Row affinity routes requests for the same row key to the same cluster, improving read-your-writes consistency. It must be used with multi-cluster routing and improves consistency for most requests without sacrificing availability, though consistency is not guaranteed.
What consistency tradeoffs does multiClusterRoutingUseAny make?
It sacrifices read-your-writes consistency to improve availability. Requests route to the nearest cluster and fail over on errors, but you may read stale data. Use rowAffinity to improve consistency or singleClusterRouting for guaranteed consistency.
Resource Configuration
What are the naming requirements for appProfileId?
The appProfileId must match the format [_a-zA-Z0-9][-_.a-zA-Z0-9]*, meaning it can start with underscore, letter, or number, followed by hyphens, underscores, letters, or numbers.
What properties are immutable after creation?
The appProfileId, project, and instance properties cannot be changed after the app profile is created.
What does ignoreWarnings do?
Setting ignoreWarnings to true bypasses safety checks when deleting or updating the app profile. All examples in the schema use this flag.

Using a different cloud?

Explore database guides for other cloud providers: