Configure GCP Service Load Balancing Policies

The gcp:networkservices/serviceLbPolicies:ServiceLbPolicies resource, part of the Pulumi GCP provider, defines global load balancing policies that control traffic distribution and failover behavior for backend services. This guide focuses on three capabilities: traffic distribution algorithms, automatic capacity draining, and regional isolation controls.

Policies are attached to backend services via the serviceLbPolicy property. The examples are intentionally small. Combine them with your own backend services and health checks.

Create a minimal global load balancing policy

Most deployments start with a basic policy that establishes the foundation for traffic distribution.

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

const _default = new gcp.networkservices.ServiceLbPolicies("default", {
    name: "my-lb-policy",
    location: "global",
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networkservices.ServiceLbPolicies("default",
    name="my-lb-policy",
    location="global")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := networkservices.NewServiceLbPolicies(ctx, "default", &networkservices.ServiceLbPoliciesArgs{
			Name:     pulumi.String("my-lb-policy"),
			Location: pulumi.String("global"),
		})
		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 @default = new Gcp.NetworkServices.ServiceLbPolicies("default", new()
    {
        Name = "my-lb-policy",
        Location = "global",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.ServiceLbPolicies;
import com.pulumi.gcp.networkservices.ServiceLbPoliciesArgs;
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 default_ = new ServiceLbPolicies("default", ServiceLbPoliciesArgs.builder()
            .name("my-lb-policy")
            .location("global")
            .build());

    }
}
resources:
  default:
    type: gcp:networkservices:ServiceLbPolicies
    properties:
      name: my-lb-policy
      location: global

The name property identifies the policy, and location must be set to “global” for service-level load balancing policies. Without additional configuration, the policy uses default behavior (WATERFALL_BY_REGION algorithm).

Configure traffic distribution and failover behavior

Production workloads often need custom traffic distribution and automatic capacity draining when backends become unhealthy.

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

const _default = new gcp.networkservices.ServiceLbPolicies("default", {
    name: "my-lb-policy",
    location: "global",
    description: "my description",
    loadBalancingAlgorithm: "SPRAY_TO_REGION",
    autoCapacityDrain: {
        enable: true,
    },
    failoverConfig: {
        failoverHealthThreshold: 70,
    },
    labels: {
        foo: "bar",
    },
});
const defaultBackendService = new gcp.compute.BackendService("default", {
    name: "my-lb-backend",
    description: "my description",
    loadBalancingScheme: "INTERNAL_SELF_MANAGED",
    protocol: "HTTP",
    serviceLbPolicy: pulumi.interpolate`//networkservices.googleapis.com/${_default.id}`,
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networkservices.ServiceLbPolicies("default",
    name="my-lb-policy",
    location="global",
    description="my description",
    load_balancing_algorithm="SPRAY_TO_REGION",
    auto_capacity_drain={
        "enable": True,
    },
    failover_config={
        "failover_health_threshold": 70,
    },
    labels={
        "foo": "bar",
    })
default_backend_service = gcp.compute.BackendService("default",
    name="my-lb-backend",
    description="my description",
    load_balancing_scheme="INTERNAL_SELF_MANAGED",
    protocol="HTTP",
    service_lb_policy=default.id.apply(lambda id: f"//networkservices.googleapis.com/{id}"))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := networkservices.NewServiceLbPolicies(ctx, "default", &networkservices.ServiceLbPoliciesArgs{
			Name:                   pulumi.String("my-lb-policy"),
			Location:               pulumi.String("global"),
			Description:            pulumi.String("my description"),
			LoadBalancingAlgorithm: pulumi.String("SPRAY_TO_REGION"),
			AutoCapacityDrain: &networkservices.ServiceLbPoliciesAutoCapacityDrainArgs{
				Enable: pulumi.Bool(true),
			},
			FailoverConfig: &networkservices.ServiceLbPoliciesFailoverConfigArgs{
				FailoverHealthThreshold: pulumi.Int(70),
			},
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:                pulumi.String("my-lb-backend"),
			Description:         pulumi.String("my description"),
			LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
			Protocol:            pulumi.String("HTTP"),
			ServiceLbPolicy: _default.ID().ApplyT(func(id string) (string, error) {
				return fmt.Sprintf("//networkservices.googleapis.com/%v", id), nil
			}).(pulumi.StringOutput),
		})
		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 @default = new Gcp.NetworkServices.ServiceLbPolicies("default", new()
    {
        Name = "my-lb-policy",
        Location = "global",
        Description = "my description",
        LoadBalancingAlgorithm = "SPRAY_TO_REGION",
        AutoCapacityDrain = new Gcp.NetworkServices.Inputs.ServiceLbPoliciesAutoCapacityDrainArgs
        {
            Enable = true,
        },
        FailoverConfig = new Gcp.NetworkServices.Inputs.ServiceLbPoliciesFailoverConfigArgs
        {
            FailoverHealthThreshold = 70,
        },
        Labels = 
        {
            { "foo", "bar" },
        },
    });

    var defaultBackendService = new Gcp.Compute.BackendService("default", new()
    {
        Name = "my-lb-backend",
        Description = "my description",
        LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
        Protocol = "HTTP",
        ServiceLbPolicy = @default.Id.Apply(id => $"//networkservices.googleapis.com/{id}"),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.ServiceLbPolicies;
import com.pulumi.gcp.networkservices.ServiceLbPoliciesArgs;
import com.pulumi.gcp.networkservices.inputs.ServiceLbPoliciesAutoCapacityDrainArgs;
import com.pulumi.gcp.networkservices.inputs.ServiceLbPoliciesFailoverConfigArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
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 default_ = new ServiceLbPolicies("default", ServiceLbPoliciesArgs.builder()
            .name("my-lb-policy")
            .location("global")
            .description("my description")
            .loadBalancingAlgorithm("SPRAY_TO_REGION")
            .autoCapacityDrain(ServiceLbPoliciesAutoCapacityDrainArgs.builder()
                .enable(true)
                .build())
            .failoverConfig(ServiceLbPoliciesFailoverConfigArgs.builder()
                .failoverHealthThreshold(70)
                .build())
            .labels(Map.of("foo", "bar"))
            .build());

        var defaultBackendService = new BackendService("defaultBackendService", BackendServiceArgs.builder()
            .name("my-lb-backend")
            .description("my description")
            .loadBalancingScheme("INTERNAL_SELF_MANAGED")
            .protocol("HTTP")
            .serviceLbPolicy(default_.id().applyValue(_id -> String.format("//networkservices.googleapis.com/%s", _id)))
            .build());

    }
}
resources:
  default:
    type: gcp:networkservices:ServiceLbPolicies
    properties:
      name: my-lb-policy
      location: global
      description: my description
      loadBalancingAlgorithm: SPRAY_TO_REGION
      autoCapacityDrain:
        enable: true
      failoverConfig:
        failoverHealthThreshold: 70
      labels:
        foo: bar
  defaultBackendService:
    type: gcp:compute:BackendService
    name: default
    properties:
      name: my-lb-backend
      description: my description
      loadBalancingScheme: INTERNAL_SELF_MANAGED
      protocol: HTTP
      serviceLbPolicy: //networkservices.googleapis.com/${default.id}

The loadBalancingAlgorithm property controls how traffic spreads across regions. SPRAY_TO_REGION distributes requests more evenly than the default WATERFALL_BY_REGION, which prefers closer regions first. The autoCapacityDrain block enables automatic removal of unhealthy backends from the load balancing pool. The failoverConfig sets a health threshold (70%) that triggers failover to healthy backends. The policy is attached to a backend service by referencing its ID in the serviceLbPolicy property using the full resource path format.

Add isolation controls for regional traffic containment

Applications with data residency requirements or latency-sensitive workloads benefit from isolation configuration.

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

const _default = new gcp.networkservices.ServiceLbPolicies("default", {
    name: "my-lb-policy",
    location: "global",
    description: "my description",
    loadBalancingAlgorithm: "SPRAY_TO_REGION",
    autoCapacityDrain: {
        enable: true,
    },
    failoverConfig: {
        failoverHealthThreshold: 70,
    },
    isolationConfig: {
        isolationGranularity: "REGION",
        isolationMode: "NEAREST",
    },
    labels: {
        foo: "bar",
    },
});
const defaultBackendService = new gcp.compute.BackendService("default", {
    name: "my-lb-backend",
    description: "my description",
    loadBalancingScheme: "INTERNAL_SELF_MANAGED",
    protocol: "HTTP",
    serviceLbPolicy: pulumi.interpolate`//networkservices.googleapis.com/${_default.id}`,
});
import pulumi
import pulumi_gcp as gcp

default = gcp.networkservices.ServiceLbPolicies("default",
    name="my-lb-policy",
    location="global",
    description="my description",
    load_balancing_algorithm="SPRAY_TO_REGION",
    auto_capacity_drain={
        "enable": True,
    },
    failover_config={
        "failover_health_threshold": 70,
    },
    isolation_config={
        "isolation_granularity": "REGION",
        "isolation_mode": "NEAREST",
    },
    labels={
        "foo": "bar",
    })
default_backend_service = gcp.compute.BackendService("default",
    name="my-lb-backend",
    description="my description",
    load_balancing_scheme="INTERNAL_SELF_MANAGED",
    protocol="HTTP",
    service_lb_policy=default.id.apply(lambda id: f"//networkservices.googleapis.com/{id}"))
package main

import (
	"fmt"

	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/networkservices"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := networkservices.NewServiceLbPolicies(ctx, "default", &networkservices.ServiceLbPoliciesArgs{
			Name:                   pulumi.String("my-lb-policy"),
			Location:               pulumi.String("global"),
			Description:            pulumi.String("my description"),
			LoadBalancingAlgorithm: pulumi.String("SPRAY_TO_REGION"),
			AutoCapacityDrain: &networkservices.ServiceLbPoliciesAutoCapacityDrainArgs{
				Enable: pulumi.Bool(true),
			},
			FailoverConfig: &networkservices.ServiceLbPoliciesFailoverConfigArgs{
				FailoverHealthThreshold: pulumi.Int(70),
			},
			IsolationConfig: &networkservices.ServiceLbPoliciesIsolationConfigArgs{
				IsolationGranularity: pulumi.String("REGION"),
				IsolationMode:        pulumi.String("NEAREST"),
			},
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
		})
		if err != nil {
			return err
		}
		_, err = compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:                pulumi.String("my-lb-backend"),
			Description:         pulumi.String("my description"),
			LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
			Protocol:            pulumi.String("HTTP"),
			ServiceLbPolicy: _default.ID().ApplyT(func(id string) (string, error) {
				return fmt.Sprintf("//networkservices.googleapis.com/%v", id), nil
			}).(pulumi.StringOutput),
		})
		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 @default = new Gcp.NetworkServices.ServiceLbPolicies("default", new()
    {
        Name = "my-lb-policy",
        Location = "global",
        Description = "my description",
        LoadBalancingAlgorithm = "SPRAY_TO_REGION",
        AutoCapacityDrain = new Gcp.NetworkServices.Inputs.ServiceLbPoliciesAutoCapacityDrainArgs
        {
            Enable = true,
        },
        FailoverConfig = new Gcp.NetworkServices.Inputs.ServiceLbPoliciesFailoverConfigArgs
        {
            FailoverHealthThreshold = 70,
        },
        IsolationConfig = new Gcp.NetworkServices.Inputs.ServiceLbPoliciesIsolationConfigArgs
        {
            IsolationGranularity = "REGION",
            IsolationMode = "NEAREST",
        },
        Labels = 
        {
            { "foo", "bar" },
        },
    });

    var defaultBackendService = new Gcp.Compute.BackendService("default", new()
    {
        Name = "my-lb-backend",
        Description = "my description",
        LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
        Protocol = "HTTP",
        ServiceLbPolicy = @default.Id.Apply(id => $"//networkservices.googleapis.com/{id}"),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.ServiceLbPolicies;
import com.pulumi.gcp.networkservices.ServiceLbPoliciesArgs;
import com.pulumi.gcp.networkservices.inputs.ServiceLbPoliciesAutoCapacityDrainArgs;
import com.pulumi.gcp.networkservices.inputs.ServiceLbPoliciesFailoverConfigArgs;
import com.pulumi.gcp.networkservices.inputs.ServiceLbPoliciesIsolationConfigArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
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 default_ = new ServiceLbPolicies("default", ServiceLbPoliciesArgs.builder()
            .name("my-lb-policy")
            .location("global")
            .description("my description")
            .loadBalancingAlgorithm("SPRAY_TO_REGION")
            .autoCapacityDrain(ServiceLbPoliciesAutoCapacityDrainArgs.builder()
                .enable(true)
                .build())
            .failoverConfig(ServiceLbPoliciesFailoverConfigArgs.builder()
                .failoverHealthThreshold(70)
                .build())
            .isolationConfig(ServiceLbPoliciesIsolationConfigArgs.builder()
                .isolationGranularity("REGION")
                .isolationMode("NEAREST")
                .build())
            .labels(Map.of("foo", "bar"))
            .build());

        var defaultBackendService = new BackendService("defaultBackendService", BackendServiceArgs.builder()
            .name("my-lb-backend")
            .description("my description")
            .loadBalancingScheme("INTERNAL_SELF_MANAGED")
            .protocol("HTTP")
            .serviceLbPolicy(default_.id().applyValue(_id -> String.format("//networkservices.googleapis.com/%s", _id)))
            .build());

    }
}
resources:
  default:
    type: gcp:networkservices:ServiceLbPolicies
    properties:
      name: my-lb-policy
      location: global
      description: my description
      loadBalancingAlgorithm: SPRAY_TO_REGION
      autoCapacityDrain:
        enable: true
      failoverConfig:
        failoverHealthThreshold: 70
      isolationConfig:
        isolationGranularity: REGION
        isolationMode: NEAREST
      labels:
        foo: bar
  defaultBackendService:
    type: gcp:compute:BackendService
    name: default
    properties:
      name: my-lb-backend
      description: my description
      loadBalancingScheme: INTERNAL_SELF_MANAGED
      protocol: HTTP
      serviceLbPolicy: //networkservices.googleapis.com/${default.id}

The isolationConfig block adds geographic traffic boundaries. The isolationGranularity property sets the boundary level (REGION keeps traffic within regional boundaries), while isolationMode determines routing behavior (NEAREST routes to the closest available backend within the isolation boundary). This configuration extends the previous example’s traffic distribution and failover settings with an additional isolation layer.

Beyond these examples

These snippets focus on specific policy-level features: traffic distribution algorithms, capacity draining and failover, and regional isolation controls. They’re intentionally minimal rather than full load balancing configurations.

The examples may reference pre-existing infrastructure such as GCP projects with Network Services API enabled and backend services to attach policies to. They focus on configuring the policy rather than provisioning the complete load balancing stack.

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

  • Policy attachment to multiple backend services
  • Custom health check thresholds beyond failover
  • Integration with Cloud Armor security policies
  • Monitoring and observability configuration

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

Let's configure GCP Service Load Balancing Policies

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Setup
How do I attach a ServiceLbPolicy to a BackendService?
Set the BackendService’s serviceLbPolicy property to the policy’s ID using the format //networkservices.googleapis.com/${policyId}, as shown in the advanced example.
What location should I use for a ServiceLbPolicy?
The location property is required. Examples in the schema use global for global load balancing policies.
What load balancing algorithms are available?
Four algorithms are supported: SPRAY_TO_REGION, SPRAY_TO_WORLD, WATERFALL_BY_REGION (default), and WATERFALL_BY_ZONE.
Labels & Metadata
Why aren't all my labels showing up in the labels field?
The labels field is non-authoritative and only manages labels in your configuration. Use effectiveLabels to access all labels present on the resource in GCP, including those configured through other clients and services.
Advanced Features
What's the difference between failoverConfig and Network Load Balancer FailoverPolicy?
The failoverConfig property provides health-based failover behavior for ServiceLbPolicy and is NOT related to Network Load Balancer FailoverPolicy. They are separate features.
What does autoCapacityDrain do?
The autoCapacityDrain option specifies whether an unhealthy MIG (Managed Instance Group) or NEG (Network Endpoint Group) should be considered for global load balancing and traffic routing.
What is isolationConfig used for?
The isolationConfig property provides isolation support for the associated Backend Service. It’s shown in the beta example with isolationGranularity and isolationMode settings.
Resource Management
Can I change the project after creating a ServiceLbPolicy?
No, the project property is immutable. Changing it after creation forces resource replacement.

Using a different cloud?

Explore networking guides for other cloud providers: