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 backends, 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 existing BackendService resources and attach to Mesh or Gateway resources for traffic management. The examples are intentionally small. Combine them with your own backend services, health checks, and mesh or gateway 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 destination port match. The action.destinations property lists backend services to receive traffic, with weight controlling load distribution. Here, all matching traffic goes to a single backend service.

Configure connection timeout behavior

Long-lived TCP connections need explicit timeout configuration to handle 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 the proxy closes it. This example sets a 60-second timeout. The originalDestination flag determines whether the route preserves the original destination IP address; setting it to false means the proxy rewrites the destination to the backend service address.

Attach routes to service mesh configurations

Service mesh deployments use TcpRoute to define how sidecar proxies route TCP traffic between 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 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 this route to a Mesh resource, making it part of the service mesh routing configuration. Sidecar proxies within the mesh use these rules to route TCP connections between services. The Mesh must be of type SIDECAR.

Attach routes to gateway configurations

Gateway deployments use TcpRoute to define how ingress gateways route external TCP traffic.

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 this route to a Gateway resource, making it part of the gateway’s routing configuration. The gateway evaluates incoming TCP connections against the route’s match rules and forwards traffic to the specified backend services.

Beyond these examples

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

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

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

  • Multiple destination backends with weighted routing
  • Original destination preservation (originalDestination flag)
  • Multiple match rules per route
  • 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

Configuration & Routing
How do routing rules work when multiple rules are defined?
The first rule to match is applied. At least one RouteRule must be supplied in the rules array.
How do I configure routing rules with traffic matching?
Define rules with matches specifying address and port, and action containing destinations with serviceName and weight.
How do I set an idle timeout for TCP connections?
Configure idleTimeout within the rule’s action property, such as "60s".
What's the maximum length for the description field?
The description field has a maximum length of 1024 characters.
Attachment & Integration
What's the difference between attaching to gateways and meshes?
Use gateways to route requests served by a gateway, or meshes to route requests served by a mesh. Both are optional and use different reference patterns.
How do I attach a TcpRoute to a mesh?
Use the meshes property with references matching projects/*/locations/global/meshes/<mesh_name>.
What type of mesh can I attach a TcpRoute to?
The attached mesh must be of type SIDECAR.
Resource Management
What properties can't I change after creating a TcpRoute?
The name and project properties are immutable and cannot be changed after creation without replacing the resource.
Why aren't all my labels being managed by Pulumi?
The labels field is non-authoritative and only manages labels present in your configuration. Use effectiveLabels to see all labels on the resource.
What import formats are supported for TcpRoute?
You can import using projects/{{project}}/locations/global/tcpRoutes/{{name}}, {{project}}/{{name}}, or just {{name}}.

Using a different cloud?

Explore networking guides for other cloud providers: