Configure GCP TCP Routes

The gcp:networkservices/tcpRoute:TcpRoute resource, part of the Pulumi GCP provider, defines how TCP traffic is routed by Mesh or Gateway resources: match criteria, destination services, and connection behavior. This guide focuses on three capabilities: address and port-based routing, connection timeout configuration, and mesh and gateway attachment.

TcpRoute resources reference backend services and attach to either Mesh or Gateway resources that must exist separately. The examples are intentionally small. Combine them with your own backend services and routing infrastructure.

Route TCP traffic with address and port matching

Most TCP routing starts by defining match criteria and directing traffic to backend services.

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

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "backend-service-health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
    name: "my-backend-service",
    healthChecks: defaultHttpHealthCheck.id,
});
const defaultTcpRoute = new gcp.networkservices.TcpRoute("default", {
    name: "my-tcp-route",
    labels: {
        foo: "bar",
    },
    description: "my description",
    rules: [{
        matches: [{
            address: "10.0.0.1/32",
            port: "8081",
        }],
        action: {
            destinations: [{
                serviceName: _default.id,
                weight: 1,
            }],
            originalDestination: false,
        },
    }],
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="backend-service-health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default = gcp.compute.BackendService("default",
    name="my-backend-service",
    health_checks=default_http_health_check.id)
default_tcp_route = gcp.networkservices.TcpRoute("default",
    name="my-tcp-route",
    labels={
        "foo": "bar",
    },
    description="my description",
    rules=[{
        "matches": [{
            "address": "10.0.0.1/32",
            "port": "8081",
        }],
        "action": {
            "destinations": [{
                "service_name": default.id,
                "weight": 1,
            }],
            "original_destination": False,
        },
    }])
package main

import (
	"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 {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("backend-service-health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("my-backend-service"),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		_, err = networkservices.NewTcpRoute(ctx, "default", &networkservices.TcpRouteArgs{
			Name: pulumi.String("my-tcp-route"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Rules: networkservices.TcpRouteRuleArray{
				&networkservices.TcpRouteRuleArgs{
					Matches: networkservices.TcpRouteRuleMatchArray{
						&networkservices.TcpRouteRuleMatchArgs{
							Address: pulumi.String("10.0.0.1/32"),
							Port:    pulumi.String("8081"),
						},
					},
					Action: &networkservices.TcpRouteRuleActionArgs{
						Destinations: networkservices.TcpRouteRuleActionDestinationArray{
							&networkservices.TcpRouteRuleActionDestinationArgs{
								ServiceName: _default.ID(),
								Weight:      pulumi.Int(1),
							},
						},
						OriginalDestination: pulumi.Bool(false),
					},
				},
			},
		})
		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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "backend-service-health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var @default = new Gcp.Compute.BackendService("default", new()
    {
        Name = "my-backend-service",
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var defaultTcpRoute = new Gcp.NetworkServices.TcpRoute("default", new()
    {
        Name = "my-tcp-route",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Rules = new[]
        {
            new Gcp.NetworkServices.Inputs.TcpRouteRuleArgs
            {
                Matches = new[]
                {
                    new Gcp.NetworkServices.Inputs.TcpRouteRuleMatchArgs
                    {
                        Address = "10.0.0.1/32",
                        Port = "8081",
                    },
                },
                Action = new Gcp.NetworkServices.Inputs.TcpRouteRuleActionArgs
                {
                    Destinations = new[]
                    {
                        new Gcp.NetworkServices.Inputs.TcpRouteRuleActionDestinationArgs
                        {
                            ServiceName = @default.Id,
                            Weight = 1,
                        },
                    },
                    OriginalDestination = false,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.networkservices.TcpRoute;
import com.pulumi.gcp.networkservices.TcpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleActionArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("backend-service-health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var default_ = new BackendService("default", BackendServiceArgs.builder()
            .name("my-backend-service")
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var defaultTcpRoute = new TcpRoute("defaultTcpRoute", TcpRouteArgs.builder()
            .name("my-tcp-route")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .rules(TcpRouteRuleArgs.builder()
                .matches(TcpRouteRuleMatchArgs.builder()
                    .address("10.0.0.1/32")
                    .port("8081")
                    .build())
                .action(TcpRouteRuleActionArgs.builder()
                    .destinations(TcpRouteRuleActionDestinationArgs.builder()
                        .serviceName(default_.id())
                        .weight(1)
                        .build())
                    .originalDestination(false)
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:compute:BackendService
    properties:
      name: my-backend-service
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: backend-service-health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  defaultTcpRoute:
    type: gcp:networkservices:TcpRoute
    name: default
    properties:
      name: my-tcp-route
      labels:
        foo: bar
      description: my description
      rules:
        - matches:
            - address: 10.0.0.1/32
              port: '8081'
          action:
            destinations:
              - serviceName: ${default.id}
                weight: 1
            originalDestination: false

When a TCP connection arrives, the route evaluates the matches array to find the first rule where the source address and port match. The action.destinations array specifies which backend services receive the traffic, with weight controlling load distribution. The serviceName references a BackendService that handles the actual request processing.

Configure connection timeout behavior

Long-lived TCP connections need explicit timeout configuration to manage idle connections.

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

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "backend-service-health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
    name: "my-backend-service",
    healthChecks: defaultHttpHealthCheck.id,
});
const defaultTcpRoute = new gcp.networkservices.TcpRoute("default", {
    name: "my-tcp-route",
    labels: {
        foo: "bar",
    },
    description: "my description",
    rules: [{
        action: {
            destinations: [{
                serviceName: _default.id,
                weight: 1,
            }],
            originalDestination: false,
            idleTimeout: "60s",
        },
    }],
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="backend-service-health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default = gcp.compute.BackendService("default",
    name="my-backend-service",
    health_checks=default_http_health_check.id)
default_tcp_route = gcp.networkservices.TcpRoute("default",
    name="my-tcp-route",
    labels={
        "foo": "bar",
    },
    description="my description",
    rules=[{
        "action": {
            "destinations": [{
                "service_name": default.id,
                "weight": 1,
            }],
            "original_destination": False,
            "idle_timeout": "60s",
        },
    }])
package main

import (
	"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 {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("backend-service-health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("my-backend-service"),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		_, err = networkservices.NewTcpRoute(ctx, "default", &networkservices.TcpRouteArgs{
			Name: pulumi.String("my-tcp-route"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Rules: networkservices.TcpRouteRuleArray{
				&networkservices.TcpRouteRuleArgs{
					Action: &networkservices.TcpRouteRuleActionArgs{
						Destinations: networkservices.TcpRouteRuleActionDestinationArray{
							&networkservices.TcpRouteRuleActionDestinationArgs{
								ServiceName: _default.ID(),
								Weight:      pulumi.Int(1),
							},
						},
						OriginalDestination: pulumi.Bool(false),
						IdleTimeout:         pulumi.String("60s"),
					},
				},
			},
		})
		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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "backend-service-health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var @default = new Gcp.Compute.BackendService("default", new()
    {
        Name = "my-backend-service",
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var defaultTcpRoute = new Gcp.NetworkServices.TcpRoute("default", new()
    {
        Name = "my-tcp-route",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Rules = new[]
        {
            new Gcp.NetworkServices.Inputs.TcpRouteRuleArgs
            {
                Action = new Gcp.NetworkServices.Inputs.TcpRouteRuleActionArgs
                {
                    Destinations = new[]
                    {
                        new Gcp.NetworkServices.Inputs.TcpRouteRuleActionDestinationArgs
                        {
                            ServiceName = @default.Id,
                            Weight = 1,
                        },
                    },
                    OriginalDestination = false,
                    IdleTimeout = "60s",
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.networkservices.TcpRoute;
import com.pulumi.gcp.networkservices.TcpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleActionArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("backend-service-health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var default_ = new BackendService("default", BackendServiceArgs.builder()
            .name("my-backend-service")
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var defaultTcpRoute = new TcpRoute("defaultTcpRoute", TcpRouteArgs.builder()
            .name("my-tcp-route")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .rules(TcpRouteRuleArgs.builder()
                .action(TcpRouteRuleActionArgs.builder()
                    .destinations(TcpRouteRuleActionDestinationArgs.builder()
                        .serviceName(default_.id())
                        .weight(1)
                        .build())
                    .originalDestination(false)
                    .idleTimeout("60s")
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:compute:BackendService
    properties:
      name: my-backend-service
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: backend-service-health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  defaultTcpRoute:
    type: gcp:networkservices:TcpRoute
    name: default
    properties:
      name: my-tcp-route
      labels:
        foo: bar
      description: my description
      rules:
        - action:
            destinations:
              - serviceName: ${default.id}
                weight: 1
            originalDestination: false
            idleTimeout: 60s

The idleTimeout property controls how long a TCP connection can remain idle before being closed. This prevents resource exhaustion from abandoned connections. The originalDestination flag determines whether the route preserves the original destination address or rewrites it to the backend service address.

Attach routes to service mesh infrastructure

Service mesh deployments apply routing rules across sidecar proxies for consistent traffic management.

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

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "backend-service-health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
    name: "my-backend-service",
    healthChecks: defaultHttpHealthCheck.id,
});
const defaultMesh = new gcp.networkservices.Mesh("default", {
    name: "my-tcp-route",
    labels: {
        foo: "bar",
    },
    description: "my description",
});
const defaultTcpRoute = new gcp.networkservices.TcpRoute("default", {
    name: "my-tcp-route",
    labels: {
        foo: "bar",
    },
    description: "my description",
    meshes: [defaultMesh.id],
    rules: [{
        matches: [{
            address: "10.0.0.1/32",
            port: "8081",
        }],
        action: {
            destinations: [{
                serviceName: _default.id,
                weight: 1,
            }],
            originalDestination: false,
        },
    }],
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="backend-service-health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default = gcp.compute.BackendService("default",
    name="my-backend-service",
    health_checks=default_http_health_check.id)
default_mesh = gcp.networkservices.Mesh("default",
    name="my-tcp-route",
    labels={
        "foo": "bar",
    },
    description="my description")
default_tcp_route = gcp.networkservices.TcpRoute("default",
    name="my-tcp-route",
    labels={
        "foo": "bar",
    },
    description="my description",
    meshes=[default_mesh.id],
    rules=[{
        "matches": [{
            "address": "10.0.0.1/32",
            "port": "8081",
        }],
        "action": {
            "destinations": [{
                "service_name": default.id,
                "weight": 1,
            }],
            "original_destination": False,
        },
    }])
package main

import (
	"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 {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("backend-service-health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("my-backend-service"),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		defaultMesh, err := networkservices.NewMesh(ctx, "default", &networkservices.MeshArgs{
			Name: pulumi.String("my-tcp-route"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
		})
		if err != nil {
			return err
		}
		_, err = networkservices.NewTcpRoute(ctx, "default", &networkservices.TcpRouteArgs{
			Name: pulumi.String("my-tcp-route"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Meshes: pulumi.StringArray{
				defaultMesh.ID(),
			},
			Rules: networkservices.TcpRouteRuleArray{
				&networkservices.TcpRouteRuleArgs{
					Matches: networkservices.TcpRouteRuleMatchArray{
						&networkservices.TcpRouteRuleMatchArgs{
							Address: pulumi.String("10.0.0.1/32"),
							Port:    pulumi.String("8081"),
						},
					},
					Action: &networkservices.TcpRouteRuleActionArgs{
						Destinations: networkservices.TcpRouteRuleActionDestinationArray{
							&networkservices.TcpRouteRuleActionDestinationArgs{
								ServiceName: _default.ID(),
								Weight:      pulumi.Int(1),
							},
						},
						OriginalDestination: pulumi.Bool(false),
					},
				},
			},
		})
		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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "backend-service-health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var @default = new Gcp.Compute.BackendService("default", new()
    {
        Name = "my-backend-service",
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var defaultMesh = new Gcp.NetworkServices.Mesh("default", new()
    {
        Name = "my-tcp-route",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
    });

    var defaultTcpRoute = new Gcp.NetworkServices.TcpRoute("default", new()
    {
        Name = "my-tcp-route",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Meshes = new[]
        {
            defaultMesh.Id,
        },
        Rules = new[]
        {
            new Gcp.NetworkServices.Inputs.TcpRouteRuleArgs
            {
                Matches = new[]
                {
                    new Gcp.NetworkServices.Inputs.TcpRouteRuleMatchArgs
                    {
                        Address = "10.0.0.1/32",
                        Port = "8081",
                    },
                },
                Action = new Gcp.NetworkServices.Inputs.TcpRouteRuleActionArgs
                {
                    Destinations = new[]
                    {
                        new Gcp.NetworkServices.Inputs.TcpRouteRuleActionDestinationArgs
                        {
                            ServiceName = @default.Id,
                            Weight = 1,
                        },
                    },
                    OriginalDestination = false,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.networkservices.Mesh;
import com.pulumi.gcp.networkservices.MeshArgs;
import com.pulumi.gcp.networkservices.TcpRoute;
import com.pulumi.gcp.networkservices.TcpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleActionArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("backend-service-health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var default_ = new BackendService("default", BackendServiceArgs.builder()
            .name("my-backend-service")
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var defaultMesh = new Mesh("defaultMesh", MeshArgs.builder()
            .name("my-tcp-route")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .build());

        var defaultTcpRoute = new TcpRoute("defaultTcpRoute", TcpRouteArgs.builder()
            .name("my-tcp-route")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .meshes(defaultMesh.id())
            .rules(TcpRouteRuleArgs.builder()
                .matches(TcpRouteRuleMatchArgs.builder()
                    .address("10.0.0.1/32")
                    .port("8081")
                    .build())
                .action(TcpRouteRuleActionArgs.builder()
                    .destinations(TcpRouteRuleActionDestinationArgs.builder()
                        .serviceName(default_.id())
                        .weight(1)
                        .build())
                    .originalDestination(false)
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:compute:BackendService
    properties:
      name: my-backend-service
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: backend-service-health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  defaultMesh:
    type: gcp:networkservices:Mesh
    name: default
    properties:
      name: my-tcp-route
      labels:
        foo: bar
      description: my description
  defaultTcpRoute:
    type: gcp:networkservices:TcpRoute
    name: default
    properties:
      name: my-tcp-route
      labels:
        foo: bar
      description: my description
      meshes:
        - ${defaultMesh.id}
      rules:
        - matches:
            - address: 10.0.0.1/32
              port: '8081'
          action:
            destinations:
              - serviceName: ${default.id}
                weight: 1
            originalDestination: false

The meshes property attaches the route to a Mesh resource, making the routing rules available to all services in the mesh. The Mesh must be of type SIDECAR. Traffic matching the rules flows through the mesh’s sidecar proxies to the specified backend services.

Attach routes to gateway infrastructure

Gateway-based deployments route ingress traffic through centralized infrastructure at the network edge.

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

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "backend-service-health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
    name: "my-backend-service",
    healthChecks: defaultHttpHealthCheck.id,
});
const defaultGateway = new gcp.networkservices.Gateway("default", {
    name: "my-tcp-route",
    labels: {
        foo: "bar",
    },
    description: "my description",
    scope: "my-scope",
    type: "OPEN_MESH",
    ports: [443],
});
const defaultTcpRoute = new gcp.networkservices.TcpRoute("default", {
    name: "my-tcp-route",
    labels: {
        foo: "bar",
    },
    description: "my description",
    gateways: [defaultGateway.id],
    rules: [{
        matches: [{
            address: "10.0.0.1/32",
            port: "8081",
        }],
        action: {
            destinations: [{
                serviceName: _default.id,
                weight: 1,
            }],
            originalDestination: false,
        },
    }],
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="backend-service-health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default = gcp.compute.BackendService("default",
    name="my-backend-service",
    health_checks=default_http_health_check.id)
default_gateway = gcp.networkservices.Gateway("default",
    name="my-tcp-route",
    labels={
        "foo": "bar",
    },
    description="my description",
    scope="my-scope",
    type="OPEN_MESH",
    ports=[443])
default_tcp_route = gcp.networkservices.TcpRoute("default",
    name="my-tcp-route",
    labels={
        "foo": "bar",
    },
    description="my description",
    gateways=[default_gateway.id],
    rules=[{
        "matches": [{
            "address": "10.0.0.1/32",
            "port": "8081",
        }],
        "action": {
            "destinations": [{
                "service_name": default.id,
                "weight": 1,
            }],
            "original_destination": False,
        },
    }])
package main

import (
	"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 {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("backend-service-health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("my-backend-service"),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		defaultGateway, err := networkservices.NewGateway(ctx, "default", &networkservices.GatewayArgs{
			Name: pulumi.String("my-tcp-route"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Scope:       pulumi.String("my-scope"),
			Type:        pulumi.String("OPEN_MESH"),
			Ports: pulumi.IntArray{
				pulumi.Int(443),
			},
		})
		if err != nil {
			return err
		}
		_, err = networkservices.NewTcpRoute(ctx, "default", &networkservices.TcpRouteArgs{
			Name: pulumi.String("my-tcp-route"),
			Labels: pulumi.StringMap{
				"foo": pulumi.String("bar"),
			},
			Description: pulumi.String("my description"),
			Gateways: pulumi.StringArray{
				defaultGateway.ID(),
			},
			Rules: networkservices.TcpRouteRuleArray{
				&networkservices.TcpRouteRuleArgs{
					Matches: networkservices.TcpRouteRuleMatchArray{
						&networkservices.TcpRouteRuleMatchArgs{
							Address: pulumi.String("10.0.0.1/32"),
							Port:    pulumi.String("8081"),
						},
					},
					Action: &networkservices.TcpRouteRuleActionArgs{
						Destinations: networkservices.TcpRouteRuleActionDestinationArray{
							&networkservices.TcpRouteRuleActionDestinationArgs{
								ServiceName: _default.ID(),
								Weight:      pulumi.Int(1),
							},
						},
						OriginalDestination: pulumi.Bool(false),
					},
				},
			},
		})
		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 defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "backend-service-health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var @default = new Gcp.Compute.BackendService("default", new()
    {
        Name = "my-backend-service",
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var defaultGateway = new Gcp.NetworkServices.Gateway("default", new()
    {
        Name = "my-tcp-route",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Scope = "my-scope",
        Type = "OPEN_MESH",
        Ports = new[]
        {
            443,
        },
    });

    var defaultTcpRoute = new Gcp.NetworkServices.TcpRoute("default", new()
    {
        Name = "my-tcp-route",
        Labels = 
        {
            { "foo", "bar" },
        },
        Description = "my description",
        Gateways = new[]
        {
            defaultGateway.Id,
        },
        Rules = new[]
        {
            new Gcp.NetworkServices.Inputs.TcpRouteRuleArgs
            {
                Matches = new[]
                {
                    new Gcp.NetworkServices.Inputs.TcpRouteRuleMatchArgs
                    {
                        Address = "10.0.0.1/32",
                        Port = "8081",
                    },
                },
                Action = new Gcp.NetworkServices.Inputs.TcpRouteRuleActionArgs
                {
                    Destinations = new[]
                    {
                        new Gcp.NetworkServices.Inputs.TcpRouteRuleActionDestinationArgs
                        {
                            ServiceName = @default.Id,
                            Weight = 1,
                        },
                    },
                    OriginalDestination = false,
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.networkservices.Gateway;
import com.pulumi.gcp.networkservices.GatewayArgs;
import com.pulumi.gcp.networkservices.TcpRoute;
import com.pulumi.gcp.networkservices.TcpRouteArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.TcpRouteRuleActionArgs;
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 defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("backend-service-health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var default_ = new BackendService("default", BackendServiceArgs.builder()
            .name("my-backend-service")
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var defaultGateway = new Gateway("defaultGateway", GatewayArgs.builder()
            .name("my-tcp-route")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .scope("my-scope")
            .type("OPEN_MESH")
            .ports(443)
            .build());

        var defaultTcpRoute = new TcpRoute("defaultTcpRoute", TcpRouteArgs.builder()
            .name("my-tcp-route")
            .labels(Map.of("foo", "bar"))
            .description("my description")
            .gateways(defaultGateway.id())
            .rules(TcpRouteRuleArgs.builder()
                .matches(TcpRouteRuleMatchArgs.builder()
                    .address("10.0.0.1/32")
                    .port("8081")
                    .build())
                .action(TcpRouteRuleActionArgs.builder()
                    .destinations(TcpRouteRuleActionDestinationArgs.builder()
                        .serviceName(default_.id())
                        .weight(1)
                        .build())
                    .originalDestination(false)
                    .build())
                .build())
            .build());

    }
}
resources:
  default:
    type: gcp:compute:BackendService
    properties:
      name: my-backend-service
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: backend-service-health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  defaultGateway:
    type: gcp:networkservices:Gateway
    name: default
    properties:
      name: my-tcp-route
      labels:
        foo: bar
      description: my description
      scope: my-scope
      type: OPEN_MESH
      ports:
        - 443
  defaultTcpRoute:
    type: gcp:networkservices:TcpRoute
    name: default
    properties:
      name: my-tcp-route
      labels:
        foo: bar
      description: my description
      gateways:
        - ${defaultGateway.id}
      rules:
        - matches:
            - address: 10.0.0.1/32
              port: '8081'
          action:
            destinations:
              - serviceName: ${default.id}
                weight: 1
            originalDestination: false

The gateways property attaches the route to a Gateway resource, applying the routing rules to traffic entering through that gateway. The Gateway defines the ports and protocols it accepts; the TcpRoute defines where matching traffic goes.

Beyond these examples

These snippets focus on specific TcpRoute features: address and port-based routing, connection timeout configuration, and mesh and gateway attachment. They’re intentionally minimal rather than full traffic management solutions.

The examples reference pre-existing infrastructure such as backend services with health checks, and Mesh or Gateway resources for route attachment. They focus on configuring the route rather than provisioning the complete routing infrastructure.

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

  • Multiple destination weighting and load balancing
  • Original destination preservation (originalDestination flag)
  • Multiple match rules and rule ordering
  • Label-based organization and filtering

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

Let's configure GCP TCP Routes

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Routing & Rules
What happens when I define multiple routing rules?
When multiple rules are defined, the action from the first matching rule is taken. Order your rules carefully, placing the most specific matches first.
How many routing rules do I need to define?
At least one RouteRule must be supplied in the rules property.
How do I route TCP traffic to backend services?
Define rules with matches (address and port) and action containing destinations with serviceName and weight properties.
Attachment & Integration
Can I attach a TcpRoute to both gateways and meshes?
Yes, you can specify both gateways and meshes properties, though the examples show them used separately for different routing scenarios.
What format should my gateway and mesh references use?
Gateway references must match projects/*/locations/global/gateways/<gateway_name>, and mesh references must match projects/*/locations/global/meshes/<mesh_name>.
What type of mesh can I attach to a TcpRoute?
The attached mesh must be of type SIDECAR.
Configuration & Immutability
What properties can't be changed after creation?
Both name and project are immutable and cannot be changed after the TcpRoute is created.
Why don't I see all labels in my Pulumi state?
The labels field is non-authoritative and only manages labels present in your configuration. Use effectiveLabels to see all labels present on the resource in GCP, including those set by other clients and services.

Using a different cloud?

Explore networking guides for other cloud providers: