The gcp:compute/route:Route resource, part of the Pulumi GCP provider, defines custom routing rules that override default VPC routing behavior by specifying how packets matching a destination range should be forwarded. This guide focuses on three capabilities: IP-based routing, internal load balancer integration, and cross-VPC routing through peering.
Routes belong to VPC networks and reference next-hop targets like IP addresses, load balancers, or instances that must exist separately. The examples are intentionally small. Combine them with your own VPC infrastructure and routing requirements.
Route traffic to a specific IP address
VPC networks need custom routes when traffic should bypass default routing rules, such as directing packets to a specific appliance or gateway IP.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const defaultNetwork = new gcp.compute.Network("default", {name: "compute-network"});
const _default = new gcp.compute.Route("default", {
name: "network-route",
destRange: "15.0.0.0/24",
network: defaultNetwork.name,
nextHopIp: "10.132.1.5",
priority: 100,
});
import pulumi
import pulumi_gcp as gcp
default_network = gcp.compute.Network("default", name="compute-network")
default = gcp.compute.Route("default",
name="network-route",
dest_range="15.0.0.0/24",
network=default_network.name,
next_hop_ip="10.132.1.5",
priority=100)
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 {
defaultNetwork, err := compute.NewNetwork(ctx, "default", &compute.NetworkArgs{
Name: pulumi.String("compute-network"),
})
if err != nil {
return err
}
_, err = compute.NewRoute(ctx, "default", &compute.RouteArgs{
Name: pulumi.String("network-route"),
DestRange: pulumi.String("15.0.0.0/24"),
Network: defaultNetwork.Name,
NextHopIp: pulumi.String("10.132.1.5"),
Priority: pulumi.Int(100),
})
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 defaultNetwork = new Gcp.Compute.Network("default", new()
{
Name = "compute-network",
});
var @default = new Gcp.Compute.Route("default", new()
{
Name = "network-route",
DestRange = "15.0.0.0/24",
Network = defaultNetwork.Name,
NextHopIp = "10.132.1.5",
Priority = 100,
});
});
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.Route;
import com.pulumi.gcp.compute.RouteArgs;
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 defaultNetwork = new Network("defaultNetwork", NetworkArgs.builder()
.name("compute-network")
.build());
var default_ = new Route("default", RouteArgs.builder()
.name("network-route")
.destRange("15.0.0.0/24")
.network(defaultNetwork.name())
.nextHopIp("10.132.1.5")
.priority(100)
.build());
}
}
resources:
default:
type: gcp:compute:Route
properties:
name: network-route
destRange: 15.0.0.0/24
network: ${defaultNetwork.name}
nextHopIp: 10.132.1.5
priority: 100
defaultNetwork:
type: gcp:compute:Network
name: default
properties:
name: compute-network
When a packet’s destination matches the destRange, GCP forwards it to the IP specified in nextHopIp. The priority property breaks ties when multiple routes match the same destination; lower values win. This route applies to all instances in the network unless you add tags to restrict it.
Route through an internal load balancer
Applications that need to distribute traffic across backend instances often route packets through an internal load balancer rather than directly to instances.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.compute.Network("default", {
name: "compute-network",
autoCreateSubnetworks: false,
});
const defaultSubnetwork = new gcp.compute.Subnetwork("default", {
name: "compute-subnet",
ipCidrRange: "10.0.1.0/24",
region: "us-central1",
network: _default.id,
});
const hc = new gcp.compute.HealthCheck("hc", {
name: "proxy-health-check",
checkIntervalSec: 1,
timeoutSec: 1,
tcpHealthCheck: {
port: 80,
},
});
const backend = new gcp.compute.RegionBackendService("backend", {
name: "compute-backend",
region: "us-central1",
healthChecks: hc.id,
});
const defaultForwardingRule = new gcp.compute.ForwardingRule("default", {
name: "compute-forwarding-rule",
region: "us-central1",
loadBalancingScheme: "INTERNAL",
backendService: backend.id,
allPorts: true,
network: _default.name,
subnetwork: defaultSubnetwork.name,
});
const route_ilb = new gcp.compute.Route("route-ilb", {
name: "route-ilb",
destRange: "0.0.0.0/0",
network: _default.name,
nextHopIlb: defaultForwardingRule.id,
priority: 2000,
});
import pulumi
import pulumi_gcp as gcp
default = gcp.compute.Network("default",
name="compute-network",
auto_create_subnetworks=False)
default_subnetwork = gcp.compute.Subnetwork("default",
name="compute-subnet",
ip_cidr_range="10.0.1.0/24",
region="us-central1",
network=default.id)
hc = gcp.compute.HealthCheck("hc",
name="proxy-health-check",
check_interval_sec=1,
timeout_sec=1,
tcp_health_check={
"port": 80,
})
backend = gcp.compute.RegionBackendService("backend",
name="compute-backend",
region="us-central1",
health_checks=hc.id)
default_forwarding_rule = gcp.compute.ForwardingRule("default",
name="compute-forwarding-rule",
region="us-central1",
load_balancing_scheme="INTERNAL",
backend_service=backend.id,
all_ports=True,
network=default.name,
subnetwork=default_subnetwork.name)
route_ilb = gcp.compute.Route("route-ilb",
name="route-ilb",
dest_range="0.0.0.0/0",
network=default.name,
next_hop_ilb=default_forwarding_rule.id,
priority=2000)
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("compute-network"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
defaultSubnetwork, err := compute.NewSubnetwork(ctx, "default", &compute.SubnetworkArgs{
Name: pulumi.String("compute-subnet"),
IpCidrRange: pulumi.String("10.0.1.0/24"),
Region: pulumi.String("us-central1"),
Network: _default.ID(),
})
if err != nil {
return err
}
hc, err := compute.NewHealthCheck(ctx, "hc", &compute.HealthCheckArgs{
Name: pulumi.String("proxy-health-check"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
TcpHealthCheck: &compute.HealthCheckTcpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
backend, err := compute.NewRegionBackendService(ctx, "backend", &compute.RegionBackendServiceArgs{
Name: pulumi.String("compute-backend"),
Region: pulumi.String("us-central1"),
HealthChecks: hc.ID(),
})
if err != nil {
return err
}
defaultForwardingRule, err := compute.NewForwardingRule(ctx, "default", &compute.ForwardingRuleArgs{
Name: pulumi.String("compute-forwarding-rule"),
Region: pulumi.String("us-central1"),
LoadBalancingScheme: pulumi.String("INTERNAL"),
BackendService: backend.ID(),
AllPorts: pulumi.Bool(true),
Network: _default.Name,
Subnetwork: defaultSubnetwork.Name,
})
if err != nil {
return err
}
_, err = compute.NewRoute(ctx, "route-ilb", &compute.RouteArgs{
Name: pulumi.String("route-ilb"),
DestRange: pulumi.String("0.0.0.0/0"),
Network: _default.Name,
NextHopIlb: defaultForwardingRule.ID(),
Priority: pulumi.Int(2000),
})
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 = "compute-network",
AutoCreateSubnetworks = false,
});
var defaultSubnetwork = new Gcp.Compute.Subnetwork("default", new()
{
Name = "compute-subnet",
IpCidrRange = "10.0.1.0/24",
Region = "us-central1",
Network = @default.Id,
});
var hc = new Gcp.Compute.HealthCheck("hc", new()
{
Name = "proxy-health-check",
CheckIntervalSec = 1,
TimeoutSec = 1,
TcpHealthCheck = new Gcp.Compute.Inputs.HealthCheckTcpHealthCheckArgs
{
Port = 80,
},
});
var backend = new Gcp.Compute.RegionBackendService("backend", new()
{
Name = "compute-backend",
Region = "us-central1",
HealthChecks = hc.Id,
});
var defaultForwardingRule = new Gcp.Compute.ForwardingRule("default", new()
{
Name = "compute-forwarding-rule",
Region = "us-central1",
LoadBalancingScheme = "INTERNAL",
BackendService = backend.Id,
AllPorts = true,
Network = @default.Name,
Subnetwork = defaultSubnetwork.Name,
});
var route_ilb = new Gcp.Compute.Route("route-ilb", new()
{
Name = "route-ilb",
DestRange = "0.0.0.0/0",
Network = @default.Name,
NextHopIlb = defaultForwardingRule.Id,
Priority = 2000,
});
});
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.Subnetwork;
import com.pulumi.gcp.compute.SubnetworkArgs;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckTcpHealthCheckArgs;
import com.pulumi.gcp.compute.RegionBackendService;
import com.pulumi.gcp.compute.RegionBackendServiceArgs;
import com.pulumi.gcp.compute.ForwardingRule;
import com.pulumi.gcp.compute.ForwardingRuleArgs;
import com.pulumi.gcp.compute.Route;
import com.pulumi.gcp.compute.RouteArgs;
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("compute-network")
.autoCreateSubnetworks(false)
.build());
var defaultSubnetwork = new Subnetwork("defaultSubnetwork", SubnetworkArgs.builder()
.name("compute-subnet")
.ipCidrRange("10.0.1.0/24")
.region("us-central1")
.network(default_.id())
.build());
var hc = new HealthCheck("hc", HealthCheckArgs.builder()
.name("proxy-health-check")
.checkIntervalSec(1)
.timeoutSec(1)
.tcpHealthCheck(HealthCheckTcpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var backend = new RegionBackendService("backend", RegionBackendServiceArgs.builder()
.name("compute-backend")
.region("us-central1")
.healthChecks(hc.id())
.build());
var defaultForwardingRule = new ForwardingRule("defaultForwardingRule", ForwardingRuleArgs.builder()
.name("compute-forwarding-rule")
.region("us-central1")
.loadBalancingScheme("INTERNAL")
.backendService(backend.id())
.allPorts(true)
.network(default_.name())
.subnetwork(defaultSubnetwork.name())
.build());
var route_ilb = new Route("route-ilb", RouteArgs.builder()
.name("route-ilb")
.destRange("0.0.0.0/0")
.network(default_.name())
.nextHopIlb(defaultForwardingRule.id())
.priority(2000)
.build());
}
}
resources:
default:
type: gcp:compute:Network
properties:
name: compute-network
autoCreateSubnetworks: false
defaultSubnetwork:
type: gcp:compute:Subnetwork
name: default
properties:
name: compute-subnet
ipCidrRange: 10.0.1.0/24
region: us-central1
network: ${default.id}
hc:
type: gcp:compute:HealthCheck
properties:
name: proxy-health-check
checkIntervalSec: 1
timeoutSec: 1
tcpHealthCheck:
port: '80'
backend:
type: gcp:compute:RegionBackendService
properties:
name: compute-backend
region: us-central1
healthChecks: ${hc.id}
defaultForwardingRule:
type: gcp:compute:ForwardingRule
name: default
properties:
name: compute-forwarding-rule
region: us-central1
loadBalancingScheme: INTERNAL
backendService: ${backend.id}
allPorts: true
network: ${default.name}
subnetwork: ${defaultSubnetwork.name}
route-ilb:
type: gcp:compute:Route
properties:
name: route-ilb
destRange: 0.0.0.0/0
network: ${default.name}
nextHopIlb: ${defaultForwardingRule.id}
priority: 2000
The nextHopIlb property points to a forwarding rule with loadBalancingScheme set to INTERNAL. When packets match the destRange, GCP sends them to the load balancer, which distributes them across healthy backends. This pattern centralizes traffic management and enables health-based routing.
Route across peered VPCs using load balancer IP
When VPCs are peered, routes can direct traffic from one network to a load balancer in another network using the load balancer’s IP address.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const producer = new gcp.compute.Network("producer", {
name: "producer-vpc",
autoCreateSubnetworks: false,
});
const producerSubnetwork = new gcp.compute.Subnetwork("producer", {
name: "producer-subnet",
ipCidrRange: "10.0.1.0/24",
region: "us-central1",
network: producer.id,
});
const consumer = new gcp.compute.Network("consumer", {
name: "consumer-vpc",
autoCreateSubnetworks: false,
});
const consumerSubnetwork = new gcp.compute.Subnetwork("consumer", {
name: "consumer-subnet",
ipCidrRange: "10.0.2.0/24",
region: "us-central1",
network: consumer.id,
});
const peering1 = new gcp.compute.NetworkPeering("peering1", {
name: "peering-producer-to-consumer",
network: consumer.id,
peerNetwork: producer.id,
});
const peering2 = new gcp.compute.NetworkPeering("peering2", {
name: "peering-consumer-to-producer",
network: producer.id,
peerNetwork: consumer.id,
});
const hc = new gcp.compute.HealthCheck("hc", {
name: "proxy-health-check",
checkIntervalSec: 1,
timeoutSec: 1,
tcpHealthCheck: {
port: 80,
},
});
const backend = new gcp.compute.RegionBackendService("backend", {
name: "compute-backend",
region: "us-central1",
healthChecks: hc.id,
});
const _default = new gcp.compute.ForwardingRule("default", {
name: "compute-forwarding-rule",
region: "us-central1",
loadBalancingScheme: "INTERNAL",
backendService: backend.id,
allPorts: true,
network: producer.name,
subnetwork: producerSubnetwork.name,
});
const route_ilb = new gcp.compute.Route("route-ilb", {
name: "route-ilb",
destRange: "0.0.0.0/0",
network: consumer.name,
nextHopIlb: _default.ipAddress,
priority: 2000,
tags: [
"tag1",
"tag2",
],
}, {
dependsOn: [
peering1,
peering2,
],
});
import pulumi
import pulumi_gcp as gcp
producer = gcp.compute.Network("producer",
name="producer-vpc",
auto_create_subnetworks=False)
producer_subnetwork = gcp.compute.Subnetwork("producer",
name="producer-subnet",
ip_cidr_range="10.0.1.0/24",
region="us-central1",
network=producer.id)
consumer = gcp.compute.Network("consumer",
name="consumer-vpc",
auto_create_subnetworks=False)
consumer_subnetwork = gcp.compute.Subnetwork("consumer",
name="consumer-subnet",
ip_cidr_range="10.0.2.0/24",
region="us-central1",
network=consumer.id)
peering1 = gcp.compute.NetworkPeering("peering1",
name="peering-producer-to-consumer",
network=consumer.id,
peer_network=producer.id)
peering2 = gcp.compute.NetworkPeering("peering2",
name="peering-consumer-to-producer",
network=producer.id,
peer_network=consumer.id)
hc = gcp.compute.HealthCheck("hc",
name="proxy-health-check",
check_interval_sec=1,
timeout_sec=1,
tcp_health_check={
"port": 80,
})
backend = gcp.compute.RegionBackendService("backend",
name="compute-backend",
region="us-central1",
health_checks=hc.id)
default = gcp.compute.ForwardingRule("default",
name="compute-forwarding-rule",
region="us-central1",
load_balancing_scheme="INTERNAL",
backend_service=backend.id,
all_ports=True,
network=producer.name,
subnetwork=producer_subnetwork.name)
route_ilb = gcp.compute.Route("route-ilb",
name="route-ilb",
dest_range="0.0.0.0/0",
network=consumer.name,
next_hop_ilb=default.ip_address,
priority=2000,
tags=[
"tag1",
"tag2",
],
opts = pulumi.ResourceOptions(depends_on=[
peering1,
peering2,
]))
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 {
producer, err := compute.NewNetwork(ctx, "producer", &compute.NetworkArgs{
Name: pulumi.String("producer-vpc"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
producerSubnetwork, err := compute.NewSubnetwork(ctx, "producer", &compute.SubnetworkArgs{
Name: pulumi.String("producer-subnet"),
IpCidrRange: pulumi.String("10.0.1.0/24"),
Region: pulumi.String("us-central1"),
Network: producer.ID(),
})
if err != nil {
return err
}
consumer, err := compute.NewNetwork(ctx, "consumer", &compute.NetworkArgs{
Name: pulumi.String("consumer-vpc"),
AutoCreateSubnetworks: pulumi.Bool(false),
})
if err != nil {
return err
}
_, err = compute.NewSubnetwork(ctx, "consumer", &compute.SubnetworkArgs{
Name: pulumi.String("consumer-subnet"),
IpCidrRange: pulumi.String("10.0.2.0/24"),
Region: pulumi.String("us-central1"),
Network: consumer.ID(),
})
if err != nil {
return err
}
peering1, err := compute.NewNetworkPeering(ctx, "peering1", &compute.NetworkPeeringArgs{
Name: pulumi.String("peering-producer-to-consumer"),
Network: consumer.ID(),
PeerNetwork: producer.ID(),
})
if err != nil {
return err
}
peering2, err := compute.NewNetworkPeering(ctx, "peering2", &compute.NetworkPeeringArgs{
Name: pulumi.String("peering-consumer-to-producer"),
Network: producer.ID(),
PeerNetwork: consumer.ID(),
})
if err != nil {
return err
}
hc, err := compute.NewHealthCheck(ctx, "hc", &compute.HealthCheckArgs{
Name: pulumi.String("proxy-health-check"),
CheckIntervalSec: pulumi.Int(1),
TimeoutSec: pulumi.Int(1),
TcpHealthCheck: &compute.HealthCheckTcpHealthCheckArgs{
Port: pulumi.Int(80),
},
})
if err != nil {
return err
}
backend, err := compute.NewRegionBackendService(ctx, "backend", &compute.RegionBackendServiceArgs{
Name: pulumi.String("compute-backend"),
Region: pulumi.String("us-central1"),
HealthChecks: hc.ID(),
})
if err != nil {
return err
}
_default, err := compute.NewForwardingRule(ctx, "default", &compute.ForwardingRuleArgs{
Name: pulumi.String("compute-forwarding-rule"),
Region: pulumi.String("us-central1"),
LoadBalancingScheme: pulumi.String("INTERNAL"),
BackendService: backend.ID(),
AllPorts: pulumi.Bool(true),
Network: producer.Name,
Subnetwork: producerSubnetwork.Name,
})
if err != nil {
return err
}
_, err = compute.NewRoute(ctx, "route-ilb", &compute.RouteArgs{
Name: pulumi.String("route-ilb"),
DestRange: pulumi.String("0.0.0.0/0"),
Network: consumer.Name,
NextHopIlb: _default.IpAddress,
Priority: pulumi.Int(2000),
Tags: pulumi.StringArray{
pulumi.String("tag1"),
pulumi.String("tag2"),
},
}, pulumi.DependsOn([]pulumi.Resource{
peering1,
peering2,
}))
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 producer = new Gcp.Compute.Network("producer", new()
{
Name = "producer-vpc",
AutoCreateSubnetworks = false,
});
var producerSubnetwork = new Gcp.Compute.Subnetwork("producer", new()
{
Name = "producer-subnet",
IpCidrRange = "10.0.1.0/24",
Region = "us-central1",
Network = producer.Id,
});
var consumer = new Gcp.Compute.Network("consumer", new()
{
Name = "consumer-vpc",
AutoCreateSubnetworks = false,
});
var consumerSubnetwork = new Gcp.Compute.Subnetwork("consumer", new()
{
Name = "consumer-subnet",
IpCidrRange = "10.0.2.0/24",
Region = "us-central1",
Network = consumer.Id,
});
var peering1 = new Gcp.Compute.NetworkPeering("peering1", new()
{
Name = "peering-producer-to-consumer",
Network = consumer.Id,
PeerNetwork = producer.Id,
});
var peering2 = new Gcp.Compute.NetworkPeering("peering2", new()
{
Name = "peering-consumer-to-producer",
Network = producer.Id,
PeerNetwork = consumer.Id,
});
var hc = new Gcp.Compute.HealthCheck("hc", new()
{
Name = "proxy-health-check",
CheckIntervalSec = 1,
TimeoutSec = 1,
TcpHealthCheck = new Gcp.Compute.Inputs.HealthCheckTcpHealthCheckArgs
{
Port = 80,
},
});
var backend = new Gcp.Compute.RegionBackendService("backend", new()
{
Name = "compute-backend",
Region = "us-central1",
HealthChecks = hc.Id,
});
var @default = new Gcp.Compute.ForwardingRule("default", new()
{
Name = "compute-forwarding-rule",
Region = "us-central1",
LoadBalancingScheme = "INTERNAL",
BackendService = backend.Id,
AllPorts = true,
Network = producer.Name,
Subnetwork = producerSubnetwork.Name,
});
var route_ilb = new Gcp.Compute.Route("route-ilb", new()
{
Name = "route-ilb",
DestRange = "0.0.0.0/0",
Network = consumer.Name,
NextHopIlb = @default.IpAddress,
Priority = 2000,
Tags = new[]
{
"tag1",
"tag2",
},
}, new CustomResourceOptions
{
DependsOn =
{
peering1,
peering2,
},
});
});
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.Subnetwork;
import com.pulumi.gcp.compute.SubnetworkArgs;
import com.pulumi.gcp.compute.NetworkPeering;
import com.pulumi.gcp.compute.NetworkPeeringArgs;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckTcpHealthCheckArgs;
import com.pulumi.gcp.compute.RegionBackendService;
import com.pulumi.gcp.compute.RegionBackendServiceArgs;
import com.pulumi.gcp.compute.ForwardingRule;
import com.pulumi.gcp.compute.ForwardingRuleArgs;
import com.pulumi.gcp.compute.Route;
import com.pulumi.gcp.compute.RouteArgs;
import com.pulumi.resources.CustomResourceOptions;
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 producer = new Network("producer", NetworkArgs.builder()
.name("producer-vpc")
.autoCreateSubnetworks(false)
.build());
var producerSubnetwork = new Subnetwork("producerSubnetwork", SubnetworkArgs.builder()
.name("producer-subnet")
.ipCidrRange("10.0.1.0/24")
.region("us-central1")
.network(producer.id())
.build());
var consumer = new Network("consumer", NetworkArgs.builder()
.name("consumer-vpc")
.autoCreateSubnetworks(false)
.build());
var consumerSubnetwork = new Subnetwork("consumerSubnetwork", SubnetworkArgs.builder()
.name("consumer-subnet")
.ipCidrRange("10.0.2.0/24")
.region("us-central1")
.network(consumer.id())
.build());
var peering1 = new NetworkPeering("peering1", NetworkPeeringArgs.builder()
.name("peering-producer-to-consumer")
.network(consumer.id())
.peerNetwork(producer.id())
.build());
var peering2 = new NetworkPeering("peering2", NetworkPeeringArgs.builder()
.name("peering-consumer-to-producer")
.network(producer.id())
.peerNetwork(consumer.id())
.build());
var hc = new HealthCheck("hc", HealthCheckArgs.builder()
.name("proxy-health-check")
.checkIntervalSec(1)
.timeoutSec(1)
.tcpHealthCheck(HealthCheckTcpHealthCheckArgs.builder()
.port(80)
.build())
.build());
var backend = new RegionBackendService("backend", RegionBackendServiceArgs.builder()
.name("compute-backend")
.region("us-central1")
.healthChecks(hc.id())
.build());
var default_ = new ForwardingRule("default", ForwardingRuleArgs.builder()
.name("compute-forwarding-rule")
.region("us-central1")
.loadBalancingScheme("INTERNAL")
.backendService(backend.id())
.allPorts(true)
.network(producer.name())
.subnetwork(producerSubnetwork.name())
.build());
var route_ilb = new Route("route-ilb", RouteArgs.builder()
.name("route-ilb")
.destRange("0.0.0.0/0")
.network(consumer.name())
.nextHopIlb(default_.ipAddress())
.priority(2000)
.tags(
"tag1",
"tag2")
.build(), CustomResourceOptions.builder()
.dependsOn(
peering1,
peering2)
.build());
}
}
resources:
producer:
type: gcp:compute:Network
properties:
name: producer-vpc
autoCreateSubnetworks: false
producerSubnetwork:
type: gcp:compute:Subnetwork
name: producer
properties:
name: producer-subnet
ipCidrRange: 10.0.1.0/24
region: us-central1
network: ${producer.id}
consumer:
type: gcp:compute:Network
properties:
name: consumer-vpc
autoCreateSubnetworks: false
consumerSubnetwork:
type: gcp:compute:Subnetwork
name: consumer
properties:
name: consumer-subnet
ipCidrRange: 10.0.2.0/24
region: us-central1
network: ${consumer.id}
peering1:
type: gcp:compute:NetworkPeering
properties:
name: peering-producer-to-consumer
network: ${consumer.id}
peerNetwork: ${producer.id}
peering2:
type: gcp:compute:NetworkPeering
properties:
name: peering-consumer-to-producer
network: ${producer.id}
peerNetwork: ${consumer.id}
hc:
type: gcp:compute:HealthCheck
properties:
name: proxy-health-check
checkIntervalSec: 1
timeoutSec: 1
tcpHealthCheck:
port: '80'
backend:
type: gcp:compute:RegionBackendService
properties:
name: compute-backend
region: us-central1
healthChecks: ${hc.id}
default:
type: gcp:compute:ForwardingRule
properties:
name: compute-forwarding-rule
region: us-central1
loadBalancingScheme: INTERNAL
backendService: ${backend.id}
allPorts: true
network: ${producer.name}
subnetwork: ${producerSubnetwork.name}
route-ilb:
type: gcp:compute:Route
properties:
name: route-ilb
destRange: 0.0.0.0/0
network: ${consumer.name}
nextHopIlb: ${default.ipAddress}
priority: 2000
tags:
- tag1
- tag2
options:
dependsOn:
- ${peering1}
- ${peering2}
This configuration creates a route in the consumer VPC that forwards traffic to a load balancer in the producer VPC. The nextHopIlb property uses the forwarding rule’s ipAddress rather than its ID. The dependsOn ensures both peering connections are established before creating the route. The tags property restricts this route to instances with matching tags.
Beyond these examples
These snippets focus on specific route-level features: IP-based and load balancer routing, VPC peering integration, and route priority and tagging. They’re intentionally minimal rather than full network architectures.
The examples may reference pre-existing infrastructure such as VPC networks and subnets, health checks and backend services, and forwarding rules for load balancers. They focus on configuring the route rather than provisioning everything around it.
To keep things focused, common route patterns are omitted, including:
- Gateway-based routing (nextHopGateway for internet gateway)
- Instance-based routing (nextHopInstance)
- VPN tunnel routing (nextHopVpnTunnel)
- Route descriptions and metadata
These omissions are intentional: the goal is to illustrate how each route feature is wired, not provide drop-in networking modules. See the Compute Route resource reference for all available configuration options.
Let's configure GCP Compute Routes
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Route Configuration & Next Hops
nextHopGateway, nextHopInstance, nextHopIp, nextHopVpnTunnel, or nextHopIlb. Choose based on your routing target: gateway for internet, instance for a specific VM, IP for a network address, VPN tunnel for VPN traffic, or ILB for internal load balancer.10.128.0.56) or a full/partial URL (e.g., regions/region/forwardingRules/forwardingRule). Note that IP addresses only work when destRange is a public (non-RFC 1918) CIDR range.nextHopInstanceZone when using nextHopInstance with just the instance name or a partial URL. Omit it if you’re using the full instance URL.Immutability & Lifecycle
destRange, name, network, all nextHop* fields, priority, tags, and description. Changing any of these requires destroying and recreating the route.destRange is immutable. You’ll need to create a new route with the desired destination range and delete the old one.Route Selection & Priority
Advanced Scenarios
nextHopIlb with the forwarding rule’s IP address and add dependsOn for the network peering resources to ensure peering is established before the route is created.tags property with a list of instance tags. The route will only apply to VMs that have matching tags.a-z?. The first character must be a lowercase letter, followed by dashes, lowercase letters, or digits, and the last character cannot be a dash.Using a different cloud?
Explore networking guides for other cloud providers: