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 with matching destination ranges should be forwarded. This guide focuses on three capabilities: IP-based next hops, internal load balancer routing, and cross-VPC routing via network peering.
Routes belong to VPC networks and reference next hop targets that must exist separately. The examples are intentionally small. Combine them with your own VPC infrastructure, load balancers, and network peering.
Route traffic to a specific IP address
VPCs need custom routes when traffic should bypass the default gateway and go directly to a network appliance or proxy server.
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 (15.0.0.0/24), the route forwards it to the nextHopIp (10.132.1.5) instead of using the default gateway. The priority property (100) determines which route wins when multiple routes match the same destination; lower values take precedence.
Route through an internal load balancer
Applications that need to distribute traffic across multiple backends use internal load balancers as next hops, leveraging health checking and automatic failover.
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 references a ForwardingRule with loadBalancingScheme set to INTERNAL. Traffic matching the destRange (0.0.0.0/0, a default route) flows through the load balancer, which distributes it across healthy backends. The route’s priority (2000) ensures it doesn’t override more specific routes.
Route across peered networks using load balancer VIP
When networks are peered, routes can reference an internal load balancer’s IP address from the peered network, enabling traffic to flow between VPCs.
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}
The nextHopIlb property accepts either a forwarding rule ID or its IP address. Here, it uses the load balancer’s ipAddress from the producer network. The dependsOn ensures both peering connections are established before creating the route. The tags property applies this route only to VMs with matching tags.
Beyond these examples
These snippets focus on specific route-level features: next hop types (IP address, internal load balancer, VIP), network peering integration, and priority-based routing. They’re intentionally minimal rather than full network architectures.
The examples rely on pre-existing infrastructure such as VPC networks and subnets, internal load balancers (health checks, backend services, forwarding rules), and network peering connections. They focus on configuring the route rather than provisioning the surrounding infrastructure.
To keep things focused, common route patterns are omitted, including:
- Internet gateway routing (nextHopGateway)
- Instance-based routing (nextHopInstance)
- VPN tunnel routing (nextHopVpnTunnel)
- Tag-based route application for selective VM routing
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
Configuration & Requirements
destRange, name, network, all nextHop* fields, priority, and tags. Any changes require recreating the route.nextHopGateway, nextHopInstance, nextHopIp, nextHopVpnTunnel, or nextHopIlb.destRange property only supports IPv4 addresses.Next Hop Configuration
10.128.0.56) or a forwarding rule URL. With the beta provider, IP addresses work for forwarding rules in the same VPC or peered VPCs when destRange is a public (non-RFC 1918) IP CIDR.nextHopInstance with a short instance name. Omit nextHopInstanceZone if you provide the instance as a full or partial URL.default-internet-gateway. Valid formats include https://www.googleapis.com/compute/v1/projects/project/global/gateways/default-internet-gateway, projects/project/global/gateways/default-internet-gateway, or global/gateways/default-internet-gateway.Routing Behavior
priority value wins (default is 1000, valid range 0-65535). If still tied, layer 3 and 4 packet headers determine the final route.tags property specifies which instance tags this route applies to, forming part of each VM’s routing table.Using a different cloud?
Explore networking guides for other cloud providers: