The gcp:networkservices/grpcRoute:GrpcRoute resource, part of the Pulumi GCP provider, defines how gRPC traffic is routed by Mesh or Gateway resources: matching rules, retry policies, and fault injection. This guide focuses on three capabilities: header and method-based request matching, retry policies for transient failures, and fault injection for resilience testing.
Routes attach to Mesh or Gateway resources that must exist separately. The examples are intentionally small. Combine them with your own Mesh or Gateway configuration and backend services.
Route gRPC traffic with header matching and retries
Most gRPC routing starts by matching requests based on headers and applying retry policies to handle transient failures.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.GrpcRoute("default", {
name: "my-grpc-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
rules: [{
matches: [{
headers: [{
key: "key",
value: "value",
}],
}],
action: {
retryPolicy: {
retryConditions: ["cancelled"],
numRetries: 1,
},
},
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.GrpcRoute("default",
name="my-grpc-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
rules=[{
"matches": [{
"headers": [{
"key": "key",
"value": "value",
}],
}],
"action": {
"retry_policy": {
"retry_conditions": ["cancelled"],
"num_retries": 1,
},
},
}])
package main
import (
"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 {
_, err := networkservices.NewGrpcRoute(ctx, "default", &networkservices.GrpcRouteArgs{
Name: pulumi.String("my-grpc-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Rules: networkservices.GrpcRouteRuleArray{
&networkservices.GrpcRouteRuleArgs{
Matches: networkservices.GrpcRouteRuleMatchArray{
&networkservices.GrpcRouteRuleMatchArgs{
Headers: networkservices.GrpcRouteRuleMatchHeaderArray{
&networkservices.GrpcRouteRuleMatchHeaderArgs{
Key: pulumi.String("key"),
Value: pulumi.String("value"),
},
},
},
},
Action: &networkservices.GrpcRouteRuleActionArgs{
RetryPolicy: &networkservices.GrpcRouteRuleActionRetryPolicyArgs{
RetryConditions: pulumi.StringArray{
pulumi.String("cancelled"),
},
NumRetries: pulumi.Int(1),
},
},
},
},
})
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.NetworkServices.GrpcRoute("default", new()
{
Name = "my-grpc-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleArgs
{
Matches = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchArgs
{
Headers = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchHeaderArgs
{
Key = "key",
Value = "value",
},
},
},
},
Action = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionArgs
{
RetryPolicy = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionRetryPolicyArgs
{
RetryConditions = new[]
{
"cancelled",
},
NumRetries = 1,
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.GrpcRoute;
import com.pulumi.gcp.networkservices.GrpcRouteArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionRetryPolicyArgs;
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 GrpcRoute("default", GrpcRouteArgs.builder()
.name("my-grpc-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.rules(GrpcRouteRuleArgs.builder()
.matches(GrpcRouteRuleMatchArgs.builder()
.headers(GrpcRouteRuleMatchHeaderArgs.builder()
.key("key")
.value("value")
.build())
.build())
.action(GrpcRouteRuleActionArgs.builder()
.retryPolicy(GrpcRouteRuleActionRetryPolicyArgs.builder()
.retryConditions("cancelled")
.numRetries(1)
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:GrpcRoute
properties:
name: my-grpc-route
labels:
foo: bar
description: my description
hostnames:
- example
rules:
- matches:
- headers:
- key: key
value: value
action:
retryPolicy:
retryConditions:
- cancelled
numRetries: 1
When a request arrives with matching headers, the route applies the configured retry policy. The retryConditions property specifies which gRPC status codes trigger retries; numRetries limits retry attempts. The hostnames property defines which service names this route handles.
Combine method matching with fault injection testing
Testing service resilience often requires injecting delays and errors into specific gRPC methods without modifying application code.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.GrpcRoute("default", {
name: "my-grpc-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
rules: [{
matches: [
{
headers: [{
key: "key",
value: "value",
}],
},
{
headers: [{
key: "key",
value: "value",
}],
method: {
grpcService: "foo",
grpcMethod: "bar",
caseSensitive: true,
},
},
],
action: {
faultInjectionPolicy: {
delay: {
fixedDelay: "1s",
percentage: 1,
},
abort: {
httpStatus: 500,
percentage: 1,
},
},
retryPolicy: {
retryConditions: ["cancelled"],
numRetries: 1,
},
},
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.GrpcRoute("default",
name="my-grpc-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
rules=[{
"matches": [
{
"headers": [{
"key": "key",
"value": "value",
}],
},
{
"headers": [{
"key": "key",
"value": "value",
}],
"method": {
"grpc_service": "foo",
"grpc_method": "bar",
"case_sensitive": True,
},
},
],
"action": {
"fault_injection_policy": {
"delay": {
"fixed_delay": "1s",
"percentage": 1,
},
"abort": {
"http_status": 500,
"percentage": 1,
},
},
"retry_policy": {
"retry_conditions": ["cancelled"],
"num_retries": 1,
},
},
}])
package main
import (
"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 {
_, err := networkservices.NewGrpcRoute(ctx, "default", &networkservices.GrpcRouteArgs{
Name: pulumi.String("my-grpc-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Rules: networkservices.GrpcRouteRuleArray{
&networkservices.GrpcRouteRuleArgs{
Matches: networkservices.GrpcRouteRuleMatchArray{
&networkservices.GrpcRouteRuleMatchArgs{
Headers: networkservices.GrpcRouteRuleMatchHeaderArray{
&networkservices.GrpcRouteRuleMatchHeaderArgs{
Key: pulumi.String("key"),
Value: pulumi.String("value"),
},
},
},
&networkservices.GrpcRouteRuleMatchArgs{
Headers: networkservices.GrpcRouteRuleMatchHeaderArray{
&networkservices.GrpcRouteRuleMatchHeaderArgs{
Key: pulumi.String("key"),
Value: pulumi.String("value"),
},
},
Method: &networkservices.GrpcRouteRuleMatchMethodArgs{
GrpcService: pulumi.String("foo"),
GrpcMethod: pulumi.String("bar"),
CaseSensitive: pulumi.Bool(true),
},
},
},
Action: &networkservices.GrpcRouteRuleActionArgs{
FaultInjectionPolicy: &networkservices.GrpcRouteRuleActionFaultInjectionPolicyArgs{
Delay: &networkservices.GrpcRouteRuleActionFaultInjectionPolicyDelayArgs{
FixedDelay: pulumi.String("1s"),
Percentage: pulumi.Int(1),
},
Abort: &networkservices.GrpcRouteRuleActionFaultInjectionPolicyAbortArgs{
HttpStatus: pulumi.Int(500),
Percentage: pulumi.Int(1),
},
},
RetryPolicy: &networkservices.GrpcRouteRuleActionRetryPolicyArgs{
RetryConditions: pulumi.StringArray{
pulumi.String("cancelled"),
},
NumRetries: pulumi.Int(1),
},
},
},
},
})
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.NetworkServices.GrpcRoute("default", new()
{
Name = "my-grpc-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleArgs
{
Matches = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchArgs
{
Headers = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchHeaderArgs
{
Key = "key",
Value = "value",
},
},
},
new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchArgs
{
Headers = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchHeaderArgs
{
Key = "key",
Value = "value",
},
},
Method = new Gcp.NetworkServices.Inputs.GrpcRouteRuleMatchMethodArgs
{
GrpcService = "foo",
GrpcMethod = "bar",
CaseSensitive = true,
},
},
},
Action = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionArgs
{
FaultInjectionPolicy = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionFaultInjectionPolicyArgs
{
Delay = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionFaultInjectionPolicyDelayArgs
{
FixedDelay = "1s",
Percentage = 1,
},
Abort = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionFaultInjectionPolicyAbortArgs
{
HttpStatus = 500,
Percentage = 1,
},
},
RetryPolicy = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionRetryPolicyArgs
{
RetryConditions = new[]
{
"cancelled",
},
NumRetries = 1,
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.GrpcRoute;
import com.pulumi.gcp.networkservices.GrpcRouteArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionFaultInjectionPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionFaultInjectionPolicyDelayArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionFaultInjectionPolicyAbortArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionRetryPolicyArgs;
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 GrpcRoute("default", GrpcRouteArgs.builder()
.name("my-grpc-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.rules(GrpcRouteRuleArgs.builder()
.matches(
GrpcRouteRuleMatchArgs.builder()
.headers(GrpcRouteRuleMatchHeaderArgs.builder()
.key("key")
.value("value")
.build())
.build(),
GrpcRouteRuleMatchArgs.builder()
.headers(GrpcRouteRuleMatchHeaderArgs.builder()
.key("key")
.value("value")
.build())
.method(GrpcRouteRuleMatchMethodArgs.builder()
.grpcService("foo")
.grpcMethod("bar")
.caseSensitive(true)
.build())
.build())
.action(GrpcRouteRuleActionArgs.builder()
.faultInjectionPolicy(GrpcRouteRuleActionFaultInjectionPolicyArgs.builder()
.delay(GrpcRouteRuleActionFaultInjectionPolicyDelayArgs.builder()
.fixedDelay("1s")
.percentage(1)
.build())
.abort(GrpcRouteRuleActionFaultInjectionPolicyAbortArgs.builder()
.httpStatus(500)
.percentage(1)
.build())
.build())
.retryPolicy(GrpcRouteRuleActionRetryPolicyArgs.builder()
.retryConditions("cancelled")
.numRetries(1)
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:GrpcRoute
properties:
name: my-grpc-route
labels:
foo: bar
description: my description
hostnames:
- example
rules:
- matches:
- headers:
- key: key
value: value
- headers:
- key: key
value: value
method:
grpcService: foo
grpcMethod: bar
caseSensitive: true
action:
faultInjectionPolicy:
delay:
fixedDelay: 1s
percentage: 1
abort:
httpStatus: 500
percentage: 1
retryPolicy:
retryConditions:
- cancelled
numRetries: 1
The method property matches specific gRPC service and method combinations. The faultInjectionPolicy injects artificial delays (fixedDelay) and errors (abort with httpStatus) into a percentage of matching requests. This lets you test how clients handle failures before they occur in production.
Apply fault injection without request matching
Some testing scenarios need to inject faults into all traffic to a service, regardless of headers or methods.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.networkservices.GrpcRoute("default", {
name: "my-grpc-route",
labels: {
foo: "bar",
},
description: "my description",
hostnames: ["example"],
rules: [{
action: {
faultInjectionPolicy: {
delay: {
fixedDelay: "1s",
percentage: 1,
},
abort: {
httpStatus: 500,
percentage: 1,
},
},
retryPolicy: {
retryConditions: ["cancelled"],
numRetries: 1,
},
},
}],
});
import pulumi
import pulumi_gcp as gcp
default = gcp.networkservices.GrpcRoute("default",
name="my-grpc-route",
labels={
"foo": "bar",
},
description="my description",
hostnames=["example"],
rules=[{
"action": {
"fault_injection_policy": {
"delay": {
"fixed_delay": "1s",
"percentage": 1,
},
"abort": {
"http_status": 500,
"percentage": 1,
},
},
"retry_policy": {
"retry_conditions": ["cancelled"],
"num_retries": 1,
},
},
}])
package main
import (
"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 {
_, err := networkservices.NewGrpcRoute(ctx, "default", &networkservices.GrpcRouteArgs{
Name: pulumi.String("my-grpc-route"),
Labels: pulumi.StringMap{
"foo": pulumi.String("bar"),
},
Description: pulumi.String("my description"),
Hostnames: pulumi.StringArray{
pulumi.String("example"),
},
Rules: networkservices.GrpcRouteRuleArray{
&networkservices.GrpcRouteRuleArgs{
Action: &networkservices.GrpcRouteRuleActionArgs{
FaultInjectionPolicy: &networkservices.GrpcRouteRuleActionFaultInjectionPolicyArgs{
Delay: &networkservices.GrpcRouteRuleActionFaultInjectionPolicyDelayArgs{
FixedDelay: pulumi.String("1s"),
Percentage: pulumi.Int(1),
},
Abort: &networkservices.GrpcRouteRuleActionFaultInjectionPolicyAbortArgs{
HttpStatus: pulumi.Int(500),
Percentage: pulumi.Int(1),
},
},
RetryPolicy: &networkservices.GrpcRouteRuleActionRetryPolicyArgs{
RetryConditions: pulumi.StringArray{
pulumi.String("cancelled"),
},
NumRetries: pulumi.Int(1),
},
},
},
},
})
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.NetworkServices.GrpcRoute("default", new()
{
Name = "my-grpc-route",
Labels =
{
{ "foo", "bar" },
},
Description = "my description",
Hostnames = new[]
{
"example",
},
Rules = new[]
{
new Gcp.NetworkServices.Inputs.GrpcRouteRuleArgs
{
Action = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionArgs
{
FaultInjectionPolicy = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionFaultInjectionPolicyArgs
{
Delay = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionFaultInjectionPolicyDelayArgs
{
FixedDelay = "1s",
Percentage = 1,
},
Abort = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionFaultInjectionPolicyAbortArgs
{
HttpStatus = 500,
Percentage = 1,
},
},
RetryPolicy = new Gcp.NetworkServices.Inputs.GrpcRouteRuleActionRetryPolicyArgs
{
RetryConditions = new[]
{
"cancelled",
},
NumRetries = 1,
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.networkservices.GrpcRoute;
import com.pulumi.gcp.networkservices.GrpcRouteArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionFaultInjectionPolicyArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionFaultInjectionPolicyDelayArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionFaultInjectionPolicyAbortArgs;
import com.pulumi.gcp.networkservices.inputs.GrpcRouteRuleActionRetryPolicyArgs;
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 GrpcRoute("default", GrpcRouteArgs.builder()
.name("my-grpc-route")
.labels(Map.of("foo", "bar"))
.description("my description")
.hostnames("example")
.rules(GrpcRouteRuleArgs.builder()
.action(GrpcRouteRuleActionArgs.builder()
.faultInjectionPolicy(GrpcRouteRuleActionFaultInjectionPolicyArgs.builder()
.delay(GrpcRouteRuleActionFaultInjectionPolicyDelayArgs.builder()
.fixedDelay("1s")
.percentage(1)
.build())
.abort(GrpcRouteRuleActionFaultInjectionPolicyAbortArgs.builder()
.httpStatus(500)
.percentage(1)
.build())
.build())
.retryPolicy(GrpcRouteRuleActionRetryPolicyArgs.builder()
.retryConditions("cancelled")
.numRetries(1)
.build())
.build())
.build())
.build());
}
}
resources:
default:
type: gcp:networkservices:GrpcRoute
properties:
name: my-grpc-route
labels:
foo: bar
description: my description
hostnames:
- example
rules:
- action:
faultInjectionPolicy:
delay:
fixedDelay: 1s
percentage: 1
abort:
httpStatus: 500
percentage: 1
retryPolicy:
retryConditions:
- cancelled
numRetries: 1
Without a matches block, the route applies fault injection to every request. This configuration tests service-wide resilience by introducing delays and errors across all traffic patterns.
Beyond these examples
These snippets focus on specific gRPC route features: header and method-based request matching, retry policies and fault injection, and global location configuration. They’re intentionally minimal rather than full traffic management solutions.
The examples may reference pre-existing infrastructure such as GCP projects with Network Services API enabled, and Mesh or Gateway resources (referenced but not created). They focus on configuring the route rather than provisioning the surrounding infrastructure.
To keep things focused, common route patterns are omitted, including:
- Gateway and Mesh attachment (gateways, meshes properties)
- Timeout configuration for route actions
- Destination routing and traffic splitting
- Case-insensitive method matching
These omissions are intentional: the goal is to illustrate how each route feature is wired, not provide drop-in traffic management modules. See the GrpcRoute resource reference for all available configuration options.
Let's configure GCP gRPC Routes
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Immutability
name, project, and location fields are immutable and cannot be modified after creation. Plan these values carefully, or recreate the resource if changes are needed.global is currently supported. The location field defaults to global if omitted.Labels & Metadata
labels field is non-authoritative and only manages labels present in your configuration. It won’t remove labels added by other clients or services. Use effectiveLabels to see all labels present on the resource.Routing & Attachment
gateways to attach the route to Gateway resources, or meshes to attach to Mesh resources. Both define how the GrpcRoute participates in routing requests served by those resources.hostnames (service hostnames with optional port), name, project, and rules (defining how traffic is routed and handled).Traffic Management
faultInjectionPolicy in the rule’s action with delay (using fixedDelay and percentage) and/or abort (using httpStatus and percentage).retryPolicy in the rule’s action with retryConditions (like cancelled) and numRetries to specify retry attempts.method field in matches with grpcService and grpcMethod. Set caseSensitive to true for case-sensitive matching.Using a different cloud?
Explore networking guides for other cloud providers: