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 reference 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
Service mesh deployments often start by defining routes that match incoming requests based on headers and apply retry policies for 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 the specified header, the route applies the retry policy. The retryConditions property lists gRPC status codes that trigger retries (here, “cancelled”). The numRetries property limits retry attempts. The hostnames property defines which service names this route handles.
Test resilience with fault injection and method matching
Teams testing service resilience inject delays and errors into specific gRPC methods to validate timeout handling and circuit breaker behavior.
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 narrows matching to specific gRPC service and method combinations. The faultInjectionPolicy injects artificial delays (fixedDelay) and errors (abort with httpStatus) into a percentage of matching requests. This configuration extends the basic example by adding method-level matching and fault injection alongside retry policies.
Apply fault injection without request matching
Some testing scenarios require injecting faults into all traffic to a service, regardless of headers or method names.
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 fault injection applies to all requests to the specified hostnames. The delay property adds latency (1 second here), while the abort property returns HTTP 500 errors. Both use percentage to control what fraction of requests experience the fault. This demonstrates action-only rules that don’t filter by request characteristics.
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 service mesh configurations.
The examples assume pre-existing infrastructure such as a GCP project with Network Services API enabled, and Mesh or Gateway resources that are referenced but not created. They focus on route configuration rather than provisioning the surrounding mesh or gateway infrastructure.
To keep things focused, common routing patterns are omitted, including:
- Gateway and Mesh attachment (gateways, meshes properties)
- Traffic splitting and weighted destinations
- Timeout configuration
- CORS policies and request/response transformations
These omissions are intentional: the goal is to illustrate how each gRPC route feature is wired, not provide drop-in service mesh 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 & Constraints
global is currently supported. The location property defaults to global if omitted.name, location, and project properties are immutable and cannot be changed after creation.name, hostnames, and rules. The project is also required but defaults to the provider project if not specified.Labels & Metadata
labels field is non-authoritative and only manages labels present in your configuration. Use effectiveLabels to see all labels on the resource, including those set by other clients and services.Integration & Attachment
gateways property to attach to gateways, or the meshes property to attach to meshes. You can use either or both properties.Using a different cloud?
Explore networking guides for other cloud providers: