Configure GCP Regional Network Endpoint Groups

The gcp:compute/regionNetworkEndpointGroup:RegionNetworkEndpointGroup resource, part of the Pulumi GCP provider, defines regional network endpoint groups that route load balancer traffic to serverless services, Private Service Connect endpoints, or external backends. This guide focuses on three capabilities: serverless backend integration, Private Service Connect configuration, and external endpoint routing.

Regional NEGs reference existing Cloud Run services, Cloud Functions, App Engine versions, VPC networks, and Service Attachments. The examples are intentionally small. Combine them with your own load balancer configuration and backend services.

Route traffic to Cloud Run services

Load balancers distribute traffic to serverless Cloud Run services without managing individual endpoints. Regional NEGs provide a stable target that automatically tracks service revisions.

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

const cloudrunNegService = new gcp.cloudrun.Service("cloudrun_neg", {
    name: "cloudrun-neg",
    location: "us-central1",
    template: {
        spec: {
            containers: [{
                image: "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
    },
    traffics: [{
        percent: 100,
        latestRevision: true,
    }],
});
// Cloud Run Example
const cloudrunNeg = new gcp.compute.RegionNetworkEndpointGroup("cloudrun_neg", {
    name: "cloudrun-neg",
    networkEndpointType: "SERVERLESS",
    region: "us-central1",
    cloudRun: {
        service: cloudrunNegService.name,
    },
});
import pulumi
import pulumi_gcp as gcp

cloudrun_neg_service = gcp.cloudrun.Service("cloudrun_neg",
    name="cloudrun-neg",
    location="us-central1",
    template={
        "spec": {
            "containers": [{
                "image": "us-docker.pkg.dev/cloudrun/container/hello",
            }],
        },
    },
    traffics=[{
        "percent": 100,
        "latest_revision": True,
    }])
# Cloud Run Example
cloudrun_neg = gcp.compute.RegionNetworkEndpointGroup("cloudrun_neg",
    name="cloudrun-neg",
    network_endpoint_type="SERVERLESS",
    region="us-central1",
    cloud_run={
        "service": cloudrun_neg_service.name,
    })
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		cloudrunNegService, err := cloudrun.NewService(ctx, "cloudrun_neg", &cloudrun.ServiceArgs{
			Name:     pulumi.String("cloudrun-neg"),
			Location: pulumi.String("us-central1"),
			Template: &cloudrun.ServiceTemplateArgs{
				Spec: &cloudrun.ServiceTemplateSpecArgs{
					Containers: cloudrun.ServiceTemplateSpecContainerArray{
						&cloudrun.ServiceTemplateSpecContainerArgs{
							Image: pulumi.String("us-docker.pkg.dev/cloudrun/container/hello"),
						},
					},
				},
			},
			Traffics: cloudrun.ServiceTrafficArray{
				&cloudrun.ServiceTrafficArgs{
					Percent:        pulumi.Int(100),
					LatestRevision: pulumi.Bool(true),
				},
			},
		})
		if err != nil {
			return err
		}
		// Cloud Run Example
		_, err = compute.NewRegionNetworkEndpointGroup(ctx, "cloudrun_neg", &compute.RegionNetworkEndpointGroupArgs{
			Name:                pulumi.String("cloudrun-neg"),
			NetworkEndpointType: pulumi.String("SERVERLESS"),
			Region:              pulumi.String("us-central1"),
			CloudRun: &compute.RegionNetworkEndpointGroupCloudRunArgs{
				Service: cloudrunNegService.Name,
			},
		})
		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 cloudrunNegService = new Gcp.CloudRun.Service("cloudrun_neg", new()
    {
        Name = "cloudrun-neg",
        Location = "us-central1",
        Template = new Gcp.CloudRun.Inputs.ServiceTemplateArgs
        {
            Spec = new Gcp.CloudRun.Inputs.ServiceTemplateSpecArgs
            {
                Containers = new[]
                {
                    new Gcp.CloudRun.Inputs.ServiceTemplateSpecContainerArgs
                    {
                        Image = "us-docker.pkg.dev/cloudrun/container/hello",
                    },
                },
            },
        },
        Traffics = new[]
        {
            new Gcp.CloudRun.Inputs.ServiceTrafficArgs
            {
                Percent = 100,
                LatestRevision = true,
            },
        },
    });

    // Cloud Run Example
    var cloudrunNeg = new Gcp.Compute.RegionNetworkEndpointGroup("cloudrun_neg", new()
    {
        Name = "cloudrun-neg",
        NetworkEndpointType = "SERVERLESS",
        Region = "us-central1",
        CloudRun = new Gcp.Compute.Inputs.RegionNetworkEndpointGroupCloudRunArgs
        {
            Service = cloudrunNegService.Name,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.cloudrun.Service;
import com.pulumi.gcp.cloudrun.ServiceArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTemplateSpecArgs;
import com.pulumi.gcp.cloudrun.inputs.ServiceTrafficArgs;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroup;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroupArgs;
import com.pulumi.gcp.compute.inputs.RegionNetworkEndpointGroupCloudRunArgs;
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 cloudrunNegService = new Service("cloudrunNegService", ServiceArgs.builder()
            .name("cloudrun-neg")
            .location("us-central1")
            .template(ServiceTemplateArgs.builder()
                .spec(ServiceTemplateSpecArgs.builder()
                    .containers(ServiceTemplateSpecContainerArgs.builder()
                        .image("us-docker.pkg.dev/cloudrun/container/hello")
                        .build())
                    .build())
                .build())
            .traffics(ServiceTrafficArgs.builder()
                .percent(100)
                .latestRevision(true)
                .build())
            .build());

        // Cloud Run Example
        var cloudrunNeg = new RegionNetworkEndpointGroup("cloudrunNeg", RegionNetworkEndpointGroupArgs.builder()
            .name("cloudrun-neg")
            .networkEndpointType("SERVERLESS")
            .region("us-central1")
            .cloudRun(RegionNetworkEndpointGroupCloudRunArgs.builder()
                .service(cloudrunNegService.name())
                .build())
            .build());

    }
}
resources:
  # Cloud Run Example
  cloudrunNeg:
    type: gcp:compute:RegionNetworkEndpointGroup
    name: cloudrun_neg
    properties:
      name: cloudrun-neg
      networkEndpointType: SERVERLESS
      region: us-central1
      cloudRun:
        service: ${cloudrunNegService.name}
  cloudrunNegService:
    type: gcp:cloudrun:Service
    name: cloudrun_neg
    properties:
      name: cloudrun-neg
      location: us-central1
      template:
        spec:
          containers:
            - image: us-docker.pkg.dev/cloudrun/container/hello
      traffics:
        - percent: 100
          latestRevision: true

The networkEndpointType property set to SERVERLESS indicates this NEG routes to serverless backends. The cloudRun block specifies which Cloud Run service receives traffic. The NEG automatically discovers and tracks the service’s endpoints as revisions deploy.

Route traffic to Cloud Functions

HTTP-triggered Cloud Functions serve as backend targets for load balancers, enabling custom domains, SSL termination, and traffic management.

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

const bucket = new gcp.storage.Bucket("bucket", {
    name: "cloudfunctions-function-example-bucket",
    location: "US",
});
const archive = new gcp.storage.BucketObject("archive", {
    name: "index.zip",
    bucket: bucket.name,
    source: new pulumi.asset.FileAsset("path/to/index.zip"),
});
const functionNegFunction = new gcp.cloudfunctions.Function("function_neg", {
    name: "function-neg",
    description: "My function",
    runtime: "nodejs20",
    availableMemoryMb: 128,
    sourceArchiveBucket: bucket.name,
    sourceArchiveObject: archive.name,
    triggerHttp: true,
    timeout: 60,
    entryPoint: "helloGET",
});
// Cloud Functions Example
const functionNeg = new gcp.compute.RegionNetworkEndpointGroup("function_neg", {
    name: "function-neg",
    networkEndpointType: "SERVERLESS",
    region: "us-central1",
    cloudFunction: {
        "function": functionNegFunction.name,
    },
});
import pulumi
import pulumi_gcp as gcp

bucket = gcp.storage.Bucket("bucket",
    name="cloudfunctions-function-example-bucket",
    location="US")
archive = gcp.storage.BucketObject("archive",
    name="index.zip",
    bucket=bucket.name,
    source=pulumi.FileAsset("path/to/index.zip"))
function_neg_function = gcp.cloudfunctions.Function("function_neg",
    name="function-neg",
    description="My function",
    runtime="nodejs20",
    available_memory_mb=128,
    source_archive_bucket=bucket.name,
    source_archive_object=archive.name,
    trigger_http=True,
    timeout=60,
    entry_point="helloGET")
# Cloud Functions Example
function_neg = gcp.compute.RegionNetworkEndpointGroup("function_neg",
    name="function-neg",
    network_endpoint_type="SERVERLESS",
    region="us-central1",
    cloud_function={
        "function": function_neg_function.name,
    })
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/cloudfunctions"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		bucket, err := storage.NewBucket(ctx, "bucket", &storage.BucketArgs{
			Name:     pulumi.String("cloudfunctions-function-example-bucket"),
			Location: pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		archive, err := storage.NewBucketObject(ctx, "archive", &storage.BucketObjectArgs{
			Name:   pulumi.String("index.zip"),
			Bucket: bucket.Name,
			Source: pulumi.NewFileAsset("path/to/index.zip"),
		})
		if err != nil {
			return err
		}
		functionNegFunction, err := cloudfunctions.NewFunction(ctx, "function_neg", &cloudfunctions.FunctionArgs{
			Name:                pulumi.String("function-neg"),
			Description:         pulumi.String("My function"),
			Runtime:             pulumi.String("nodejs20"),
			AvailableMemoryMb:   pulumi.Int(128),
			SourceArchiveBucket: bucket.Name,
			SourceArchiveObject: archive.Name,
			TriggerHttp:         pulumi.Bool(true),
			Timeout:             pulumi.Int(60),
			EntryPoint:          pulumi.String("helloGET"),
		})
		if err != nil {
			return err
		}
		// Cloud Functions Example
		_, err = compute.NewRegionNetworkEndpointGroup(ctx, "function_neg", &compute.RegionNetworkEndpointGroupArgs{
			Name:                pulumi.String("function-neg"),
			NetworkEndpointType: pulumi.String("SERVERLESS"),
			Region:              pulumi.String("us-central1"),
			CloudFunction: &compute.RegionNetworkEndpointGroupCloudFunctionArgs{
				Function: functionNegFunction.Name,
			},
		})
		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 bucket = new Gcp.Storage.Bucket("bucket", new()
    {
        Name = "cloudfunctions-function-example-bucket",
        Location = "US",
    });

    var archive = new Gcp.Storage.BucketObject("archive", new()
    {
        Name = "index.zip",
        Bucket = bucket.Name,
        Source = new FileAsset("path/to/index.zip"),
    });

    var functionNegFunction = new Gcp.CloudFunctions.Function("function_neg", new()
    {
        Name = "function-neg",
        Description = "My function",
        Runtime = "nodejs20",
        AvailableMemoryMb = 128,
        SourceArchiveBucket = bucket.Name,
        SourceArchiveObject = archive.Name,
        TriggerHttp = true,
        Timeout = 60,
        EntryPoint = "helloGET",
    });

    // Cloud Functions Example
    var functionNeg = new Gcp.Compute.RegionNetworkEndpointGroup("function_neg", new()
    {
        Name = "function-neg",
        NetworkEndpointType = "SERVERLESS",
        Region = "us-central1",
        CloudFunction = new Gcp.Compute.Inputs.RegionNetworkEndpointGroupCloudFunctionArgs
        {
            Function = functionNegFunction.Name,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.storage.BucketObject;
import com.pulumi.gcp.storage.BucketObjectArgs;
import com.pulumi.gcp.cloudfunctions.Function;
import com.pulumi.gcp.cloudfunctions.FunctionArgs;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroup;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroupArgs;
import com.pulumi.gcp.compute.inputs.RegionNetworkEndpointGroupCloudFunctionArgs;
import com.pulumi.asset.FileAsset;
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 bucket = new Bucket("bucket", BucketArgs.builder()
            .name("cloudfunctions-function-example-bucket")
            .location("US")
            .build());

        var archive = new BucketObject("archive", BucketObjectArgs.builder()
            .name("index.zip")
            .bucket(bucket.name())
            .source(new FileAsset("path/to/index.zip"))
            .build());

        var functionNegFunction = new Function("functionNegFunction", FunctionArgs.builder()
            .name("function-neg")
            .description("My function")
            .runtime("nodejs20")
            .availableMemoryMb(128)
            .sourceArchiveBucket(bucket.name())
            .sourceArchiveObject(archive.name())
            .triggerHttp(true)
            .timeout(60)
            .entryPoint("helloGET")
            .build());

        // Cloud Functions Example
        var functionNeg = new RegionNetworkEndpointGroup("functionNeg", RegionNetworkEndpointGroupArgs.builder()
            .name("function-neg")
            .networkEndpointType("SERVERLESS")
            .region("us-central1")
            .cloudFunction(RegionNetworkEndpointGroupCloudFunctionArgs.builder()
                .function(functionNegFunction.name())
                .build())
            .build());

    }
}
resources:
  # Cloud Functions Example
  functionNeg:
    type: gcp:compute:RegionNetworkEndpointGroup
    name: function_neg
    properties:
      name: function-neg
      networkEndpointType: SERVERLESS
      region: us-central1
      cloudFunction:
        function: ${functionNegFunction.name}
  functionNegFunction:
    type: gcp:cloudfunctions:Function
    name: function_neg
    properties:
      name: function-neg
      description: My function
      runtime: nodejs20
      availableMemoryMb: 128
      sourceArchiveBucket: ${bucket.name}
      sourceArchiveObject: ${archive.name}
      triggerHttp: true
      timeout: 60
      entryPoint: helloGET
  bucket:
    type: gcp:storage:Bucket
    properties:
      name: cloudfunctions-function-example-bucket
      location: US
  archive:
    type: gcp:storage:BucketObject
    properties:
      name: index.zip
      bucket: ${bucket.name}
      source:
        fn::FileAsset: path/to/index.zip

The cloudFunction block identifies the function by name. Like Cloud Run NEGs, this configuration uses networkEndpointType SERVERLESS and automatically tracks the function’s endpoint. Only one serverless backend type (cloudRun, cloudFunction, or appEngine) can be specified per NEG.

Route traffic to App Engine services

App Engine applications receive traffic through load balancers by specifying both the service name and version ID.

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

const appengineNegBucket = new gcp.storage.Bucket("appengine_neg", {
    name: "appengine-neg",
    location: "US",
    uniformBucketLevelAccess: true,
});
const appengineNegBucketObject = new gcp.storage.BucketObject("appengine_neg", {
    name: "hello-world.zip",
    bucket: appengineNegBucket.name,
    source: new pulumi.asset.FileAsset("./test-fixtures/hello-world.zip"),
});
const appengineNegFlexibleAppVersion = new gcp.appengine.FlexibleAppVersion("appengine_neg", {
    versionId: "v1",
    service: "appengine-neg",
    runtime: "nodejs",
    flexibleRuntimeSettings: {
        operatingSystem: "ubuntu22",
        runtimeVersion: "20",
    },
    entrypoint: {
        shell: "node ./app.js",
    },
    deployment: {
        zip: {
            sourceUrl: pulumi.interpolate`https://storage.googleapis.com/${appengineNegBucket.name}/${appengineNegBucketObject.name}`,
        },
    },
    livenessCheck: {
        path: "/",
    },
    readinessCheck: {
        path: "/",
    },
    envVariables: {
        port: "8080",
    },
    handlers: [{
        urlRegex: ".*\\/my-path\\/*",
        securityLevel: "SECURE_ALWAYS",
        login: "LOGIN_REQUIRED",
        authFailAction: "AUTH_FAIL_ACTION_REDIRECT",
        staticFiles: {
            path: "my-other-path",
            uploadPathRegex: ".*\\/my-path\\/*",
        },
    }],
    automaticScaling: {
        coolDownPeriod: "120s",
        cpuUtilization: {
            targetUtilization: 0.5,
        },
    },
    deleteServiceOnDestroy: true,
});
// App Engine Example
const appengineNeg = new gcp.compute.RegionNetworkEndpointGroup("appengine_neg", {
    name: "appengine-neg",
    networkEndpointType: "SERVERLESS",
    region: "us-central1",
    appEngine: {
        service: appengineNegFlexibleAppVersion.service,
        version: appengineNegFlexibleAppVersion.versionId,
    },
});
import pulumi
import pulumi_gcp as gcp

appengine_neg_bucket = gcp.storage.Bucket("appengine_neg",
    name="appengine-neg",
    location="US",
    uniform_bucket_level_access=True)
appengine_neg_bucket_object = gcp.storage.BucketObject("appengine_neg",
    name="hello-world.zip",
    bucket=appengine_neg_bucket.name,
    source=pulumi.FileAsset("./test-fixtures/hello-world.zip"))
appengine_neg_flexible_app_version = gcp.appengine.FlexibleAppVersion("appengine_neg",
    version_id="v1",
    service="appengine-neg",
    runtime="nodejs",
    flexible_runtime_settings={
        "operating_system": "ubuntu22",
        "runtime_version": "20",
    },
    entrypoint={
        "shell": "node ./app.js",
    },
    deployment={
        "zip": {
            "source_url": pulumi.Output.all(
                appengineNegBucketName=appengine_neg_bucket.name,
                appengineNegBucketObjectName=appengine_neg_bucket_object.name
).apply(lambda resolved_outputs: f"https://storage.googleapis.com/{resolved_outputs['appengineNegBucketName']}/{resolved_outputs['appengineNegBucketObjectName']}")
,
        },
    },
    liveness_check={
        "path": "/",
    },
    readiness_check={
        "path": "/",
    },
    env_variables={
        "port": "8080",
    },
    handlers=[{
        "url_regex": ".*\\/my-path\\/*",
        "security_level": "SECURE_ALWAYS",
        "login": "LOGIN_REQUIRED",
        "auth_fail_action": "AUTH_FAIL_ACTION_REDIRECT",
        "static_files": {
            "path": "my-other-path",
            "upload_path_regex": ".*\\/my-path\\/*",
        },
    }],
    automatic_scaling={
        "cool_down_period": "120s",
        "cpu_utilization": {
            "target_utilization": 0.5,
        },
    },
    delete_service_on_destroy=True)
# App Engine Example
appengine_neg = gcp.compute.RegionNetworkEndpointGroup("appengine_neg",
    name="appengine-neg",
    network_endpoint_type="SERVERLESS",
    region="us-central1",
    app_engine={
        "service": appengine_neg_flexible_app_version.service,
        "version": appengine_neg_flexible_app_version.version_id,
    })
package main

import (
	"fmt"

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		appengineNegBucket, err := storage.NewBucket(ctx, "appengine_neg", &storage.BucketArgs{
			Name:                     pulumi.String("appengine-neg"),
			Location:                 pulumi.String("US"),
			UniformBucketLevelAccess: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		appengineNegBucketObject, err := storage.NewBucketObject(ctx, "appengine_neg", &storage.BucketObjectArgs{
			Name:   pulumi.String("hello-world.zip"),
			Bucket: appengineNegBucket.Name,
			Source: pulumi.NewFileAsset("./test-fixtures/hello-world.zip"),
		})
		if err != nil {
			return err
		}
		appengineNegFlexibleAppVersion, err := appengine.NewFlexibleAppVersion(ctx, "appengine_neg", &appengine.FlexibleAppVersionArgs{
			VersionId: pulumi.String("v1"),
			Service:   pulumi.String("appengine-neg"),
			Runtime:   pulumi.String("nodejs"),
			FlexibleRuntimeSettings: &appengine.FlexibleAppVersionFlexibleRuntimeSettingsArgs{
				OperatingSystem: pulumi.String("ubuntu22"),
				RuntimeVersion:  pulumi.String("20"),
			},
			Entrypoint: &appengine.FlexibleAppVersionEntrypointArgs{
				Shell: pulumi.String("node ./app.js"),
			},
			Deployment: &appengine.FlexibleAppVersionDeploymentArgs{
				Zip: &appengine.FlexibleAppVersionDeploymentZipArgs{
					SourceUrl: pulumi.All(appengineNegBucket.Name, appengineNegBucketObject.Name).ApplyT(func(_args []interface{}) (string, error) {
						appengineNegBucketName := _args[0].(string)
						appengineNegBucketObjectName := _args[1].(string)
						return fmt.Sprintf("https://storage.googleapis.com/%v/%v", appengineNegBucketName, appengineNegBucketObjectName), nil
					}).(pulumi.StringOutput),
				},
			},
			LivenessCheck: &appengine.FlexibleAppVersionLivenessCheckArgs{
				Path: pulumi.String("/"),
			},
			ReadinessCheck: &appengine.FlexibleAppVersionReadinessCheckArgs{
				Path: pulumi.String("/"),
			},
			EnvVariables: pulumi.StringMap{
				"port": pulumi.String("8080"),
			},
			Handlers: appengine.FlexibleAppVersionHandlerArray{
				&appengine.FlexibleAppVersionHandlerArgs{
					UrlRegex:       pulumi.String(".*\\/my-path\\/*"),
					SecurityLevel:  pulumi.String("SECURE_ALWAYS"),
					Login:          pulumi.String("LOGIN_REQUIRED"),
					AuthFailAction: pulumi.String("AUTH_FAIL_ACTION_REDIRECT"),
					StaticFiles: &appengine.FlexibleAppVersionHandlerStaticFilesArgs{
						Path:            pulumi.String("my-other-path"),
						UploadPathRegex: pulumi.String(".*\\/my-path\\/*"),
					},
				},
			},
			AutomaticScaling: &appengine.FlexibleAppVersionAutomaticScalingArgs{
				CoolDownPeriod: pulumi.String("120s"),
				CpuUtilization: &appengine.FlexibleAppVersionAutomaticScalingCpuUtilizationArgs{
					TargetUtilization: pulumi.Float64(0.5),
				},
			},
			DeleteServiceOnDestroy: pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		// App Engine Example
		_, err = compute.NewRegionNetworkEndpointGroup(ctx, "appengine_neg", &compute.RegionNetworkEndpointGroupArgs{
			Name:                pulumi.String("appengine-neg"),
			NetworkEndpointType: pulumi.String("SERVERLESS"),
			Region:              pulumi.String("us-central1"),
			AppEngine: &compute.RegionNetworkEndpointGroupAppEngineArgs{
				Service: appengineNegFlexibleAppVersion.Service,
				Version: appengineNegFlexibleAppVersion.VersionId,
			},
		})
		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 appengineNegBucket = new Gcp.Storage.Bucket("appengine_neg", new()
    {
        Name = "appengine-neg",
        Location = "US",
        UniformBucketLevelAccess = true,
    });

    var appengineNegBucketObject = new Gcp.Storage.BucketObject("appengine_neg", new()
    {
        Name = "hello-world.zip",
        Bucket = appengineNegBucket.Name,
        Source = new FileAsset("./test-fixtures/hello-world.zip"),
    });

    var appengineNegFlexibleAppVersion = new Gcp.AppEngine.FlexibleAppVersion("appengine_neg", new()
    {
        VersionId = "v1",
        Service = "appengine-neg",
        Runtime = "nodejs",
        FlexibleRuntimeSettings = new Gcp.AppEngine.Inputs.FlexibleAppVersionFlexibleRuntimeSettingsArgs
        {
            OperatingSystem = "ubuntu22",
            RuntimeVersion = "20",
        },
        Entrypoint = new Gcp.AppEngine.Inputs.FlexibleAppVersionEntrypointArgs
        {
            Shell = "node ./app.js",
        },
        Deployment = new Gcp.AppEngine.Inputs.FlexibleAppVersionDeploymentArgs
        {
            Zip = new Gcp.AppEngine.Inputs.FlexibleAppVersionDeploymentZipArgs
            {
                SourceUrl = Output.Tuple(appengineNegBucket.Name, appengineNegBucketObject.Name).Apply(values =>
                {
                    var appengineNegBucketName = values.Item1;
                    var appengineNegBucketObjectName = values.Item2;
                    return $"https://storage.googleapis.com/{appengineNegBucketName}/{appengineNegBucketObjectName}";
                }),
            },
        },
        LivenessCheck = new Gcp.AppEngine.Inputs.FlexibleAppVersionLivenessCheckArgs
        {
            Path = "/",
        },
        ReadinessCheck = new Gcp.AppEngine.Inputs.FlexibleAppVersionReadinessCheckArgs
        {
            Path = "/",
        },
        EnvVariables = 
        {
            { "port", "8080" },
        },
        Handlers = new[]
        {
            new Gcp.AppEngine.Inputs.FlexibleAppVersionHandlerArgs
            {
                UrlRegex = ".*\\/my-path\\/*",
                SecurityLevel = "SECURE_ALWAYS",
                Login = "LOGIN_REQUIRED",
                AuthFailAction = "AUTH_FAIL_ACTION_REDIRECT",
                StaticFiles = new Gcp.AppEngine.Inputs.FlexibleAppVersionHandlerStaticFilesArgs
                {
                    Path = "my-other-path",
                    UploadPathRegex = ".*\\/my-path\\/*",
                },
            },
        },
        AutomaticScaling = new Gcp.AppEngine.Inputs.FlexibleAppVersionAutomaticScalingArgs
        {
            CoolDownPeriod = "120s",
            CpuUtilization = new Gcp.AppEngine.Inputs.FlexibleAppVersionAutomaticScalingCpuUtilizationArgs
            {
                TargetUtilization = 0.5,
            },
        },
        DeleteServiceOnDestroy = true,
    });

    // App Engine Example
    var appengineNeg = new Gcp.Compute.RegionNetworkEndpointGroup("appengine_neg", new()
    {
        Name = "appengine-neg",
        NetworkEndpointType = "SERVERLESS",
        Region = "us-central1",
        AppEngine = new Gcp.Compute.Inputs.RegionNetworkEndpointGroupAppEngineArgs
        {
            Service = appengineNegFlexibleAppVersion.Service,
            Version = appengineNegFlexibleAppVersion.VersionId,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.storage.BucketObject;
import com.pulumi.gcp.storage.BucketObjectArgs;
import com.pulumi.gcp.appengine.FlexibleAppVersion;
import com.pulumi.gcp.appengine.FlexibleAppVersionArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionFlexibleRuntimeSettingsArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionEntrypointArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionDeploymentArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionDeploymentZipArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionLivenessCheckArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionReadinessCheckArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionHandlerArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionHandlerStaticFilesArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionAutomaticScalingArgs;
import com.pulumi.gcp.appengine.inputs.FlexibleAppVersionAutomaticScalingCpuUtilizationArgs;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroup;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroupArgs;
import com.pulumi.gcp.compute.inputs.RegionNetworkEndpointGroupAppEngineArgs;
import com.pulumi.asset.FileAsset;
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 appengineNegBucket = new Bucket("appengineNegBucket", BucketArgs.builder()
            .name("appengine-neg")
            .location("US")
            .uniformBucketLevelAccess(true)
            .build());

        var appengineNegBucketObject = new BucketObject("appengineNegBucketObject", BucketObjectArgs.builder()
            .name("hello-world.zip")
            .bucket(appengineNegBucket.name())
            .source(new FileAsset("./test-fixtures/hello-world.zip"))
            .build());

        var appengineNegFlexibleAppVersion = new FlexibleAppVersion("appengineNegFlexibleAppVersion", FlexibleAppVersionArgs.builder()
            .versionId("v1")
            .service("appengine-neg")
            .runtime("nodejs")
            .flexibleRuntimeSettings(FlexibleAppVersionFlexibleRuntimeSettingsArgs.builder()
                .operatingSystem("ubuntu22")
                .runtimeVersion("20")
                .build())
            .entrypoint(FlexibleAppVersionEntrypointArgs.builder()
                .shell("node ./app.js")
                .build())
            .deployment(FlexibleAppVersionDeploymentArgs.builder()
                .zip(FlexibleAppVersionDeploymentZipArgs.builder()
                    .sourceUrl(Output.tuple(appengineNegBucket.name(), appengineNegBucketObject.name()).applyValue(values -> {
                        var appengineNegBucketName = values.t1;
                        var appengineNegBucketObjectName = values.t2;
                        return String.format("https://storage.googleapis.com/%s/%s", appengineNegBucketName,appengineNegBucketObjectName);
                    }))
                    .build())
                .build())
            .livenessCheck(FlexibleAppVersionLivenessCheckArgs.builder()
                .path("/")
                .build())
            .readinessCheck(FlexibleAppVersionReadinessCheckArgs.builder()
                .path("/")
                .build())
            .envVariables(Map.of("port", "8080"))
            .handlers(FlexibleAppVersionHandlerArgs.builder()
                .urlRegex(".*\\/my-path\\/*")
                .securityLevel("SECURE_ALWAYS")
                .login("LOGIN_REQUIRED")
                .authFailAction("AUTH_FAIL_ACTION_REDIRECT")
                .staticFiles(FlexibleAppVersionHandlerStaticFilesArgs.builder()
                    .path("my-other-path")
                    .uploadPathRegex(".*\\/my-path\\/*")
                    .build())
                .build())
            .automaticScaling(FlexibleAppVersionAutomaticScalingArgs.builder()
                .coolDownPeriod("120s")
                .cpuUtilization(FlexibleAppVersionAutomaticScalingCpuUtilizationArgs.builder()
                    .targetUtilization(0.5)
                    .build())
                .build())
            .deleteServiceOnDestroy(true)
            .build());

        // App Engine Example
        var appengineNeg = new RegionNetworkEndpointGroup("appengineNeg", RegionNetworkEndpointGroupArgs.builder()
            .name("appengine-neg")
            .networkEndpointType("SERVERLESS")
            .region("us-central1")
            .appEngine(RegionNetworkEndpointGroupAppEngineArgs.builder()
                .service(appengineNegFlexibleAppVersion.service())
                .version(appengineNegFlexibleAppVersion.versionId())
                .build())
            .build());

    }
}
resources:
  # App Engine Example
  appengineNeg:
    type: gcp:compute:RegionNetworkEndpointGroup
    name: appengine_neg
    properties:
      name: appengine-neg
      networkEndpointType: SERVERLESS
      region: us-central1
      appEngine:
        service: ${appengineNegFlexibleAppVersion.service}
        version: ${appengineNegFlexibleAppVersion.versionId}
  appengineNegFlexibleAppVersion:
    type: gcp:appengine:FlexibleAppVersion
    name: appengine_neg
    properties:
      versionId: v1
      service: appengine-neg
      runtime: nodejs
      flexibleRuntimeSettings:
        operatingSystem: ubuntu22
        runtimeVersion: '20'
      entrypoint:
        shell: node ./app.js
      deployment:
        zip:
          sourceUrl: https://storage.googleapis.com/${appengineNegBucket.name}/${appengineNegBucketObject.name}
      livenessCheck:
        path: /
      readinessCheck:
        path: /
      envVariables:
        port: '8080'
      handlers:
        - urlRegex: .*\/my-path\/*
          securityLevel: SECURE_ALWAYS
          login: LOGIN_REQUIRED
          authFailAction: AUTH_FAIL_ACTION_REDIRECT
          staticFiles:
            path: my-other-path
            uploadPathRegex: .*\/my-path\/*
      automaticScaling:
        coolDownPeriod: 120s
        cpuUtilization:
          targetUtilization: 0.5
      deleteServiceOnDestroy: true
  appengineNegBucket:
    type: gcp:storage:Bucket
    name: appengine_neg
    properties:
      name: appengine-neg
      location: US
      uniformBucketLevelAccess: true
  appengineNegBucketObject:
    type: gcp:storage:BucketObject
    name: appengine_neg
    properties:
      name: hello-world.zip
      bucket: ${appengineNegBucket.name}
      source:
        fn::FileAsset: ./test-fixtures/hello-world.zip

The appEngine block requires both service and version properties to target a specific App Engine deployment. This allows you to route traffic to particular versions while maintaining other versions for testing or gradual rollouts.

Connect to Google APIs via Private Service Connect

Private Service Connect enables private connectivity to Google APIs without traversing the public internet, improving security and reducing latency.

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

const pscNeg = new gcp.compute.RegionNetworkEndpointGroup("psc_neg", {
    name: "psc-neg",
    region: "asia-northeast3",
    networkEndpointType: "PRIVATE_SERVICE_CONNECT",
    pscTargetService: "asia-northeast3-cloudkms.googleapis.com",
});
import pulumi
import pulumi_gcp as gcp

psc_neg = gcp.compute.RegionNetworkEndpointGroup("psc_neg",
    name="psc-neg",
    region="asia-northeast3",
    network_endpoint_type="PRIVATE_SERVICE_CONNECT",
    psc_target_service="asia-northeast3-cloudkms.googleapis.com")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := compute.NewRegionNetworkEndpointGroup(ctx, "psc_neg", &compute.RegionNetworkEndpointGroupArgs{
			Name:                pulumi.String("psc-neg"),
			Region:              pulumi.String("asia-northeast3"),
			NetworkEndpointType: pulumi.String("PRIVATE_SERVICE_CONNECT"),
			PscTargetService:    pulumi.String("asia-northeast3-cloudkms.googleapis.com"),
		})
		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 pscNeg = new Gcp.Compute.RegionNetworkEndpointGroup("psc_neg", new()
    {
        Name = "psc-neg",
        Region = "asia-northeast3",
        NetworkEndpointType = "PRIVATE_SERVICE_CONNECT",
        PscTargetService = "asia-northeast3-cloudkms.googleapis.com",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroup;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroupArgs;
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 pscNeg = new RegionNetworkEndpointGroup("pscNeg", RegionNetworkEndpointGroupArgs.builder()
            .name("psc-neg")
            .region("asia-northeast3")
            .networkEndpointType("PRIVATE_SERVICE_CONNECT")
            .pscTargetService("asia-northeast3-cloudkms.googleapis.com")
            .build());

    }
}
resources:
  pscNeg:
    type: gcp:compute:RegionNetworkEndpointGroup
    name: psc_neg
    properties:
      name: psc-neg
      region: asia-northeast3
      networkEndpointType: PRIVATE_SERVICE_CONNECT
      pscTargetService: asia-northeast3-cloudkms.googleapis.com

The networkEndpointType switches to PRIVATE_SERVICE_CONNECT for PSC endpoints. The pscTargetService property specifies the Google API endpoint (in this case, Cloud KMS in the asia-northeast3 region). Traffic flows through private VPC connectivity rather than the public internet.

Route to external endpoints by IP and port

Load balancers can distribute traffic to external services identified by IP address and port, enabling hybrid architectures that span GCP and external infrastructure.

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

const _default = new gcp.compute.Network("default", {name: "network"});
const regionNetworkEndpointGroupInternetIpPort = new gcp.compute.RegionNetworkEndpointGroup("region_network_endpoint_group_internet_ip_port", {
    name: "ip-port-neg",
    region: "us-central1",
    network: _default.id,
    networkEndpointType: "INTERNET_IP_PORT",
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.Network("default", name="network")
region_network_endpoint_group_internet_ip_port = gcp.compute.RegionNetworkEndpointGroup("region_network_endpoint_group_internet_ip_port",
    name="ip-port-neg",
    region="us-central1",
    network=default.id,
    network_endpoint_type="INTERNET_IP_PORT")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := compute.NewNetwork(ctx, "default", &compute.NetworkArgs{
			Name: pulumi.String("network"),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewRegionNetworkEndpointGroup(ctx, "region_network_endpoint_group_internet_ip_port", &compute.RegionNetworkEndpointGroupArgs{
			Name:                pulumi.String("ip-port-neg"),
			Region:              pulumi.String("us-central1"),
			Network:             _default.ID(),
			NetworkEndpointType: pulumi.String("INTERNET_IP_PORT"),
		})
		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.Compute.Network("default", new()
    {
        Name = "network",
    });

    var regionNetworkEndpointGroupInternetIpPort = new Gcp.Compute.RegionNetworkEndpointGroup("region_network_endpoint_group_internet_ip_port", new()
    {
        Name = "ip-port-neg",
        Region = "us-central1",
        Network = @default.Id,
        NetworkEndpointType = "INTERNET_IP_PORT",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroup;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroupArgs;
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 Network("default", NetworkArgs.builder()
            .name("network")
            .build());

        var regionNetworkEndpointGroupInternetIpPort = new RegionNetworkEndpointGroup("regionNetworkEndpointGroupInternetIpPort", RegionNetworkEndpointGroupArgs.builder()
            .name("ip-port-neg")
            .region("us-central1")
            .network(default_.id())
            .networkEndpointType("INTERNET_IP_PORT")
            .build());

    }
}
resources:
  regionNetworkEndpointGroupInternetIpPort:
    type: gcp:compute:RegionNetworkEndpointGroup
    name: region_network_endpoint_group_internet_ip_port
    properties:
      name: ip-port-neg
      region: us-central1
      network: ${default.id}
      networkEndpointType: INTERNET_IP_PORT
  default:
    type: gcp:compute:Network
    properties:
      name: network

The INTERNET_IP_PORT endpoint type routes traffic to external IP:port combinations. The network property specifies which VPC network the NEG belongs to. You add individual endpoints separately using the RegionNetworkEndpoint resource.

Route to external endpoints by FQDN and port

When external services use DNS names rather than static IPs, FQDN-based NEGs automatically resolve hostnames and track IP changes.

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

const _default = new gcp.compute.Network("default", {name: "network"});
const regionNetworkEndpointGroupInternetFqdnPort = new gcp.compute.RegionNetworkEndpointGroup("region_network_endpoint_group_internet_fqdn_port", {
    name: "ip-port-neg",
    region: "us-central1",
    network: _default.id,
    networkEndpointType: "INTERNET_FQDN_PORT",
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.Network("default", name="network")
region_network_endpoint_group_internet_fqdn_port = gcp.compute.RegionNetworkEndpointGroup("region_network_endpoint_group_internet_fqdn_port",
    name="ip-port-neg",
    region="us-central1",
    network=default.id,
    network_endpoint_type="INTERNET_FQDN_PORT")
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := compute.NewNetwork(ctx, "default", &compute.NetworkArgs{
			Name: pulumi.String("network"),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewRegionNetworkEndpointGroup(ctx, "region_network_endpoint_group_internet_fqdn_port", &compute.RegionNetworkEndpointGroupArgs{
			Name:                pulumi.String("ip-port-neg"),
			Region:              pulumi.String("us-central1"),
			Network:             _default.ID(),
			NetworkEndpointType: pulumi.String("INTERNET_FQDN_PORT"),
		})
		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.Compute.Network("default", new()
    {
        Name = "network",
    });

    var regionNetworkEndpointGroupInternetFqdnPort = new Gcp.Compute.RegionNetworkEndpointGroup("region_network_endpoint_group_internet_fqdn_port", new()
    {
        Name = "ip-port-neg",
        Region = "us-central1",
        Network = @default.Id,
        NetworkEndpointType = "INTERNET_FQDN_PORT",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroup;
import com.pulumi.gcp.compute.RegionNetworkEndpointGroupArgs;
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 Network("default", NetworkArgs.builder()
            .name("network")
            .build());

        var regionNetworkEndpointGroupInternetFqdnPort = new RegionNetworkEndpointGroup("regionNetworkEndpointGroupInternetFqdnPort", RegionNetworkEndpointGroupArgs.builder()
            .name("ip-port-neg")
            .region("us-central1")
            .network(default_.id())
            .networkEndpointType("INTERNET_FQDN_PORT")
            .build());

    }
}
resources:
  regionNetworkEndpointGroupInternetFqdnPort:
    type: gcp:compute:RegionNetworkEndpointGroup
    name: region_network_endpoint_group_internet_fqdn_port
    properties:
      name: ip-port-neg
      region: us-central1
      network: ${default.id}
      networkEndpointType: INTERNET_FQDN_PORT
  default:
    type: gcp:compute:Network
    properties:
      name: network

The INTERNET_FQDN_PORT endpoint type works like INTERNET_IP_PORT but accepts fully qualified domain names instead of IP addresses. The NEG resolves DNS automatically and adapts to IP changes without manual updates.

Beyond these examples

These snippets focus on specific regional NEG features: serverless backend integration, Private Service Connect for Google APIs, and external endpoint routing. They’re intentionally minimal rather than full load balancing configurations.

The examples may reference pre-existing infrastructure such as Cloud Run services, Cloud Functions, App Engine versions, VPC networks and subnetworks, and Service Attachments for PSC. They focus on configuring the NEG rather than provisioning the complete load balancing stack.

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

  • Port mapping for GCE VM instances (GCE_VM_IP_PORTMAP)
  • PSC Service Attachment configuration with pscData
  • Subnetwork specification for PSC NEGs
  • Network endpoint management and health checks

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

Let's configure GCP Regional Network Endpoint Groups

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & NEG Types
What are the different types of Regional Network Endpoint Groups?
Regional NEGs support five types via networkEndpointType: SERVERLESS (default, for Cloud Functions/Run/App Engine), PRIVATE_SERVICE_CONNECT (for PSC connections), INTERNET_IP_PORT and INTERNET_FQDN_PORT (for external backends), and GCE_VM_IP_PORTMAP (for port mapping).
Which properties can I use with each NEG type?
Properties are type-specific: appEngine, cloudFunction, cloudRun, and serverlessDeployment only work with SERVERLESS NEGs. pscData and subnetwork only work with PRIVATE_SERVICE_CONNECT NEGs. network and pscTargetService work with both PRIVATE_SERVICE_CONNECT and INTERNET NEGs.
What network does my NEG use if I don't specify one?
The network property defaults to the “default” project network when unspecified. This applies to PSC and INTERNET NEGs.
Serverless Backends
Can I configure multiple serverless backends for a single NEG?
No, you can only configure one serverless backend. Setting multiple backends (cloudRun, appEngine, cloudFunction, or serverlessDeployment) simultaneously causes a configuration error.
How do I configure a NEG for Cloud Functions?
Set networkEndpointType to SERVERLESS and configure cloudFunction with the function name, as shown in the Cloud Functions example.
How do I configure a NEG for Cloud Run?
Set networkEndpointType to SERVERLESS and configure cloudRun with the service name, as shown in the Cloud Run example.
How do I configure a NEG for App Engine?
Set networkEndpointType to SERVERLESS and configure appEngine with the service and version. You can also leave appEngine empty to use the default service.
Private Service Connect
How do I configure a NEG for Private Service Connect?
Set networkEndpointType to PRIVATE_SERVICE_CONNECT and specify pscTargetService with either a Google API URL (like asia-northeast3-cloudkms.googleapis.com) or a service attachment self-link. For service attachments, you can also configure pscData with a producer port and specify a subnetwork.
Immutability & Lifecycle
What properties can I change after creating a Regional NEG?
Nearly all properties are immutable, including name, network, region, networkEndpointType, appEngine, cloudFunction, cloudRun, pscData, pscTargetService, serverlessDeployment, subnetwork, and description. Changes to these properties force resource recreation.
What are the naming requirements for Regional NEGs?
The name must be 1-63 characters long and match the regex a-z?, meaning it starts with a lowercase letter, followed by dashes, lowercase letters, or digits, and cannot end with a dash. This complies with RFC1035.

Using a different cloud?

Explore networking guides for other cloud providers: