Configure GCP URL Maps for Load Balancing

The gcp:compute/uRLMap:URLMap resource, part of the Pulumi GCP provider, defines routing rules that direct incoming HTTP(S) requests to backend services or Cloud Storage based on hostname, path, headers, and query parameters. This guide focuses on five capabilities: host and path-based routing, header and query parameter matching, request transformation and traffic policies, path template matching and URL rewriting, and custom error page handling.

URL maps route to backend services and backend buckets that must exist separately, along with their health checks and Cloud Storage buckets. The examples are intentionally small. Combine them with your own backend infrastructure and load balancer configuration.

Route requests across backend services and storage buckets

Most load balancers start by routing traffic to different backends based on hostname and path, directing requests to backend services for dynamic content or backend buckets for static assets.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.compute.HttpHealthCheck("default", {
    name: "health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const login = new gcp.compute.BackendService("login", {
    name: "login",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: _default.id,
});
const staticBucket = new gcp.storage.Bucket("static", {
    name: "static-asset-bucket",
    location: "US",
});
const static = new gcp.compute.BackendBucket("static", {
    name: "static-asset-backend-bucket",
    bucketName: staticBucket.name,
    enableCdn: true,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "a description",
    defaultService: static.id,
    hostRules: [
        {
            hosts: ["mysite.com"],
            pathMatcher: "mysite",
        },
        {
            hosts: ["myothersite.com"],
            pathMatcher: "otherpaths",
        },
    ],
    pathMatchers: [
        {
            name: "mysite",
            defaultService: static.id,
            pathRules: [
                {
                    paths: ["/home"],
                    service: static.id,
                },
                {
                    paths: ["/login"],
                    service: login.id,
                },
                {
                    paths: ["/static"],
                    service: static.id,
                },
            ],
        },
        {
            name: "otherpaths",
            defaultService: static.id,
        },
    ],
    tests: [{
        service: static.id,
        host: "example.com",
        path: "/home",
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.HttpHealthCheck("default",
    name="health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
login = gcp.compute.BackendService("login",
    name="login",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default.id)
static_bucket = gcp.storage.Bucket("static",
    name="static-asset-bucket",
    location="US")
static = gcp.compute.BackendBucket("static",
    name="static-asset-backend-bucket",
    bucket_name=static_bucket.name,
    enable_cdn=True)
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="a description",
    default_service=static.id,
    host_rules=[
        {
            "hosts": ["mysite.com"],
            "path_matcher": "mysite",
        },
        {
            "hosts": ["myothersite.com"],
            "path_matcher": "otherpaths",
        },
    ],
    path_matchers=[
        {
            "name": "mysite",
            "default_service": static.id,
            "path_rules": [
                {
                    "paths": ["/home"],
                    "service": static.id,
                },
                {
                    "paths": ["/login"],
                    "service": login.id,
                },
                {
                    "paths": ["/static"],
                    "service": static.id,
                },
            ],
        },
        {
            "name": "otherpaths",
            "default_service": static.id,
        },
    ],
    tests=[{
        "service": static.id,
        "host": "example.com",
        "path": "/home",
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		login, err := compute.NewBackendService(ctx, "login", &compute.BackendServiceArgs{
			Name:         pulumi.String("login"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: _default.ID(),
		})
		if err != nil {
			return err
		}
		staticBucket, err := storage.NewBucket(ctx, "static", &storage.BucketArgs{
			Name:     pulumi.String("static-asset-bucket"),
			Location: pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		static, err := compute.NewBackendBucket(ctx, "static", &compute.BackendBucketArgs{
			Name:       pulumi.String("static-asset-backend-bucket"),
			BucketName: staticBucket.Name,
			EnableCdn:  pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("a description"),
			DefaultService: static.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("mysite"),
				},
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("myothersite.com"),
					},
					PathMatcher: pulumi.String("otherpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("mysite"),
					DefaultService: static.ID(),
					PathRules: compute.URLMapPathMatcherPathRuleArray{
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/home"),
							},
							Service: static.ID(),
						},
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/login"),
							},
							Service: login.ID(),
						},
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/static"),
							},
							Service: static.ID(),
						},
					},
				},
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("otherpaths"),
					DefaultService: static.ID(),
				},
			},
			Tests: compute.URLMapTestArray{
				&compute.URLMapTestArgs{
					Service: static.ID(),
					Host:    pulumi.String("example.com"),
					Path:    pulumi.String("/home"),
				},
			},
		})
		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.HttpHealthCheck("default", new()
    {
        Name = "health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var login = new Gcp.Compute.BackendService("login", new()
    {
        Name = "login",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = @default.Id,
    });

    var staticBucket = new Gcp.Storage.Bucket("static", new()
    {
        Name = "static-asset-bucket",
        Location = "US",
    });

    var @static = new Gcp.Compute.BackendBucket("static", new()
    {
        Name = "static-asset-backend-bucket",
        BucketName = staticBucket.Name,
        EnableCdn = true,
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "a description",
        DefaultService = @static.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "mysite",
            },
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "myothersite.com",
                },
                PathMatcher = "otherpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "mysite",
                DefaultService = @static.Id,
                PathRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/home",
                        },
                        Service = @static.Id,
                    },
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/login",
                        },
                        Service = login.Id,
                    },
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/static",
                        },
                        Service = @static.Id,
                    },
                },
            },
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "otherpaths",
                DefaultService = @static.Id,
            },
        },
        Tests = new[]
        {
            new Gcp.Compute.Inputs.URLMapTestArgs
            {
                Service = @static.Id,
                Host = "example.com",
                Path = "/home",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.compute.BackendBucket;
import com.pulumi.gcp.compute.BackendBucketArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapTestArgs;
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 HttpHealthCheck("default", HttpHealthCheckArgs.builder()
            .name("health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var login = new BackendService("login", BackendServiceArgs.builder()
            .name("login")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(default_.id())
            .build());

        var staticBucket = new Bucket("staticBucket", BucketArgs.builder()
            .name("static-asset-bucket")
            .location("US")
            .build());

        var static_ = new BackendBucket("static", BackendBucketArgs.builder()
            .name("static-asset-backend-bucket")
            .bucketName(staticBucket.name())
            .enableCdn(true)
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("a description")
            .defaultService(static_.id())
            .hostRules(            
                URLMapHostRuleArgs.builder()
                    .hosts("mysite.com")
                    .pathMatcher("mysite")
                    .build(),
                URLMapHostRuleArgs.builder()
                    .hosts("myothersite.com")
                    .pathMatcher("otherpaths")
                    .build())
            .pathMatchers(            
                URLMapPathMatcherArgs.builder()
                    .name("mysite")
                    .defaultService(static_.id())
                    .pathRules(                    
                        URLMapPathMatcherPathRuleArgs.builder()
                            .paths("/home")
                            .service(static_.id())
                            .build(),
                        URLMapPathMatcherPathRuleArgs.builder()
                            .paths("/login")
                            .service(login.id())
                            .build(),
                        URLMapPathMatcherPathRuleArgs.builder()
                            .paths("/static")
                            .service(static_.id())
                            .build())
                    .build(),
                URLMapPathMatcherArgs.builder()
                    .name("otherpaths")
                    .defaultService(static_.id())
                    .build())
            .tests(URLMapTestArgs.builder()
                .service(static_.id())
                .host("example.com")
                .path("/home")
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: a description
      defaultService: ${static.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: mysite
        - hosts:
            - myothersite.com
          pathMatcher: otherpaths
      pathMatchers:
        - name: mysite
          defaultService: ${static.id}
          pathRules:
            - paths:
                - /home
              service: ${static.id}
            - paths:
                - /login
              service: ${login.id}
            - paths:
                - /static
              service: ${static.id}
        - name: otherpaths
          defaultService: ${static.id}
      tests:
        - service: ${static.id}
          host: example.com
          path: /home
  login:
    type: gcp:compute:BackendService
    properties:
      name: login
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${default.id}
  default:
    type: gcp:compute:HttpHealthCheck
    properties:
      name: health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  static:
    type: gcp:compute:BackendBucket
    properties:
      name: static-asset-backend-bucket
      bucketName: ${staticBucket.name}
      enableCdn: true
  staticBucket:
    type: gcp:storage:Bucket
    name: static
    properties:
      name: static-asset-bucket
      location: US

The hostRules property maps hostnames to path matchers. Each pathMatcher defines a defaultService and pathRules that route specific paths to different backends. The paths array specifies URL patterns, and service points to the backend that handles matching requests. This configuration routes /home and /static to Cloud Storage while sending /login to a backend service.

Route traffic based on HTTP headers

A/B testing and canary deployments often route users to different backend services based on request headers.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
    name: "default",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const service_a = new gcp.compute.BackendService("service-a", {
    name: "service-a",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const service_b = new gcp.compute.BackendService("service-b", {
    name: "service-b",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "header-based routing example",
    defaultService: _default.id,
    hostRules: [{
        hosts: ["*"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: _default.id,
        routeRules: [
            {
                priority: 1,
                service: service_a.id,
                matchRules: [{
                    prefixMatch: "/",
                    ignoreCase: true,
                    headerMatches: [{
                        headerName: "abtest",
                        exactMatch: "a",
                    }],
                }],
            },
            {
                priority: 2,
                service: service_b.id,
                matchRules: [{
                    ignoreCase: true,
                    prefixMatch: "/",
                    headerMatches: [{
                        headerName: "abtest",
                        exactMatch: "b",
                    }],
                }],
            },
        ],
    }],
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default = gcp.compute.BackendService("default",
    name="default",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
service_a = gcp.compute.BackendService("service-a",
    name="service-a",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
service_b = gcp.compute.BackendService("service-b",
    name="service-b",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="header-based routing example",
    default_service=default.id,
    host_rules=[{
        "hosts": ["*"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": default.id,
        "route_rules": [
            {
                "priority": 1,
                "service": service_a.id,
                "match_rules": [{
                    "prefix_match": "/",
                    "ignore_case": True,
                    "header_matches": [{
                        "header_name": "abtest",
                        "exact_match": "a",
                    }],
                }],
            },
            {
                "priority": 2,
                "service": service_b.id,
                "match_rules": [{
                    "ignore_case": True,
                    "prefix_match": "/",
                    "header_matches": [{
                        "header_name": "abtest",
                        "exact_match": "b",
                    }],
                }],
            },
        ],
    }])
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 {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("default"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		service_a, err := compute.NewBackendService(ctx, "service-a", &compute.BackendServiceArgs{
			Name:         pulumi.String("service-a"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		service_b, err := compute.NewBackendService(ctx, "service-b", &compute.BackendServiceArgs{
			Name:         pulumi.String("service-b"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("header-based routing example"),
			DefaultService: _default.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("*"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: _default.ID(),
					RouteRules: compute.URLMapPathMatcherRouteRuleArray{
						&compute.URLMapPathMatcherRouteRuleArgs{
							Priority: pulumi.Int(1),
							Service:  service_a.ID(),
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									PrefixMatch: pulumi.String("/"),
									IgnoreCase:  pulumi.Bool(true),
									HeaderMatches: compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs{
											HeaderName: pulumi.String("abtest"),
											ExactMatch: pulumi.String("a"),
										},
									},
								},
							},
						},
						&compute.URLMapPathMatcherRouteRuleArgs{
							Priority: pulumi.Int(2),
							Service:  service_b.ID(),
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									IgnoreCase:  pulumi.Bool(true),
									PrefixMatch: pulumi.String("/"),
									HeaderMatches: compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs{
											HeaderName: pulumi.String("abtest"),
											ExactMatch: pulumi.String("b"),
										},
									},
								},
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var @default = new Gcp.Compute.BackendService("default", new()
    {
        Name = "default",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var service_a = new Gcp.Compute.BackendService("service-a", new()
    {
        Name = "service-a",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var service_b = new Gcp.Compute.BackendService("service-b", new()
    {
        Name = "service-b",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "header-based routing example",
        DefaultService = @default.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "*",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = @default.Id,
                RouteRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        Priority = 1,
                        Service = service_a.Id,
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                PrefixMatch = "/",
                                IgnoreCase = true,
                                HeaderMatches = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs
                                    {
                                        HeaderName = "abtest",
                                        ExactMatch = "a",
                                    },
                                },
                            },
                        },
                    },
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        Priority = 2,
                        Service = service_b.Id,
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                IgnoreCase = true,
                                PrefixMatch = "/",
                                HeaderMatches = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs
                                    {
                                        HeaderName = "abtest",
                                        ExactMatch = "b",
                                    },
                                },
                            },
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var default_ = new BackendService("default", BackendServiceArgs.builder()
            .name("default")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var service_a = new BackendService("service-a", BackendServiceArgs.builder()
            .name("service-a")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var service_b = new BackendService("service-b", BackendServiceArgs.builder()
            .name("service-b")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("header-based routing example")
            .defaultService(default_.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("*")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(default_.id())
                .routeRules(                
                    URLMapPathMatcherRouteRuleArgs.builder()
                        .priority(1)
                        .service(service_a.id())
                        .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                            .prefixMatch("/")
                            .ignoreCase(true)
                            .headerMatches(URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs.builder()
                                .headerName("abtest")
                                .exactMatch("a")
                                .build())
                            .build())
                        .build(),
                    URLMapPathMatcherRouteRuleArgs.builder()
                        .priority(2)
                        .service(service_b.id())
                        .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                            .ignoreCase(true)
                            .prefixMatch("/")
                            .headerMatches(URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs.builder()
                                .headerName("abtest")
                                .exactMatch("b")
                                .build())
                            .build())
                        .build())
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: header-based routing example
      defaultService: ${default.id}
      hostRules:
        - hosts:
            - '*'
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${default.id}
          routeRules:
            - priority: 1
              service: ${["service-a"].id}
              matchRules:
                - prefixMatch: /
                  ignoreCase: true
                  headerMatches:
                    - headerName: abtest
                      exactMatch: a
            - priority: 2
              service: ${["service-b"].id}
              matchRules:
                - ignoreCase: true
                  prefixMatch: /
                  headerMatches:
                    - headerName: abtest
                      exactMatch: b
  default:
    type: gcp:compute:BackendService
    properties:
      name: default
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  service-a:
    type: gcp:compute:BackendService
    properties:
      name: service-a
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  service-b:
    type: gcp:compute:BackendService
    properties:
      name: service-b
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1

The routeRules property defines ordered routing logic. Each rule has a priority (lower numbers evaluate first) and matchRules that inspect request properties. The headerMatches array checks header values; when the abtest header equals a, traffic goes to service_a. The prefixMatch ensures the rule applies to all paths starting with /.

Route traffic based on query parameters

Similar to header-based routing, query parameters can control which backend receives a request, enabling feature flags and gradual rollouts controlled via URL parameters.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const defaultHttpHealthCheck = new gcp.compute.HttpHealthCheck("default", {
    name: "health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const _default = new gcp.compute.BackendService("default", {
    name: "default",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const service_a = new gcp.compute.BackendService("service-a", {
    name: "service-a",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const service_b = new gcp.compute.BackendService("service-b", {
    name: "service-b",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: defaultHttpHealthCheck.id,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "parameter-based routing example",
    defaultService: _default.id,
    hostRules: [{
        hosts: ["*"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: _default.id,
        routeRules: [
            {
                priority: 1,
                service: service_a.id,
                matchRules: [{
                    prefixMatch: "/",
                    ignoreCase: true,
                    queryParameterMatches: [{
                        name: "abtest",
                        exactMatch: "a",
                    }],
                }],
            },
            {
                priority: 2,
                service: service_b.id,
                matchRules: [{
                    ignoreCase: true,
                    prefixMatch: "/",
                    queryParameterMatches: [{
                        name: "abtest",
                        exactMatch: "b",
                    }],
                }],
            },
        ],
    }],
});
import pulumi
import pulumi_gcp as gcp

default_http_health_check = gcp.compute.HttpHealthCheck("default",
    name="health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
default = gcp.compute.BackendService("default",
    name="default",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
service_a = gcp.compute.BackendService("service-a",
    name="service-a",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
service_b = gcp.compute.BackendService("service-b",
    name="service-b",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default_http_health_check.id)
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="parameter-based routing example",
    default_service=default.id,
    host_rules=[{
        "hosts": ["*"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": default.id,
        "route_rules": [
            {
                "priority": 1,
                "service": service_a.id,
                "match_rules": [{
                    "prefix_match": "/",
                    "ignore_case": True,
                    "query_parameter_matches": [{
                        "name": "abtest",
                        "exact_match": "a",
                    }],
                }],
            },
            {
                "priority": 2,
                "service": service_b.id,
                "match_rules": [{
                    "ignore_case": True,
                    "prefix_match": "/",
                    "query_parameter_matches": [{
                        "name": "abtest",
                        "exact_match": "b",
                    }],
                }],
            },
        ],
    }])
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 {
		defaultHttpHealthCheck, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		_default, err := compute.NewBackendService(ctx, "default", &compute.BackendServiceArgs{
			Name:         pulumi.String("default"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		service_a, err := compute.NewBackendService(ctx, "service-a", &compute.BackendServiceArgs{
			Name:         pulumi.String("service-a"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		service_b, err := compute.NewBackendService(ctx, "service-b", &compute.BackendServiceArgs{
			Name:         pulumi.String("service-b"),
			PortName:     pulumi.String("http"),
			Protocol:     pulumi.String("HTTP"),
			TimeoutSec:   pulumi.Int(10),
			HealthChecks: defaultHttpHealthCheck.ID(),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("parameter-based routing example"),
			DefaultService: _default.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("*"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: _default.ID(),
					RouteRules: compute.URLMapPathMatcherRouteRuleArray{
						&compute.URLMapPathMatcherRouteRuleArgs{
							Priority: pulumi.Int(1),
							Service:  service_a.ID(),
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									PrefixMatch: pulumi.String("/"),
									IgnoreCase:  pulumi.Bool(true),
									QueryParameterMatches: compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs{
											Name:       pulumi.String("abtest"),
											ExactMatch: pulumi.String("a"),
										},
									},
								},
							},
						},
						&compute.URLMapPathMatcherRouteRuleArgs{
							Priority: pulumi.Int(2),
							Service:  service_b.ID(),
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									IgnoreCase:  pulumi.Bool(true),
									PrefixMatch: pulumi.String("/"),
									QueryParameterMatches: compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs{
											Name:       pulumi.String("abtest"),
											ExactMatch: pulumi.String("b"),
										},
									},
								},
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;

return await Deployment.RunAsync(() => 
{
    var defaultHttpHealthCheck = new Gcp.Compute.HttpHealthCheck("default", new()
    {
        Name = "health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var @default = new Gcp.Compute.BackendService("default", new()
    {
        Name = "default",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var service_a = new Gcp.Compute.BackendService("service-a", new()
    {
        Name = "service-a",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var service_b = new Gcp.Compute.BackendService("service-b", new()
    {
        Name = "service-b",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = defaultHttpHealthCheck.Id,
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "parameter-based routing example",
        DefaultService = @default.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "*",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = @default.Id,
                RouteRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        Priority = 1,
                        Service = service_a.Id,
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                PrefixMatch = "/",
                                IgnoreCase = true,
                                QueryParameterMatches = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs
                                    {
                                        Name = "abtest",
                                        ExactMatch = "a",
                                    },
                                },
                            },
                        },
                    },
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        Priority = 2,
                        Service = service_b.Id,
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                IgnoreCase = true,
                                PrefixMatch = "/",
                                QueryParameterMatches = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs
                                    {
                                        Name = "abtest",
                                        ExactMatch = "b",
                                    },
                                },
                            },
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var defaultHttpHealthCheck = new HttpHealthCheck("defaultHttpHealthCheck", HttpHealthCheckArgs.builder()
            .name("health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var default_ = new BackendService("default", BackendServiceArgs.builder()
            .name("default")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var service_a = new BackendService("service-a", BackendServiceArgs.builder()
            .name("service-a")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var service_b = new BackendService("service-b", BackendServiceArgs.builder()
            .name("service-b")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(defaultHttpHealthCheck.id())
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("parameter-based routing example")
            .defaultService(default_.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("*")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(default_.id())
                .routeRules(                
                    URLMapPathMatcherRouteRuleArgs.builder()
                        .priority(1)
                        .service(service_a.id())
                        .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                            .prefixMatch("/")
                            .ignoreCase(true)
                            .queryParameterMatches(URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs.builder()
                                .name("abtest")
                                .exactMatch("a")
                                .build())
                            .build())
                        .build(),
                    URLMapPathMatcherRouteRuleArgs.builder()
                        .priority(2)
                        .service(service_b.id())
                        .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                            .ignoreCase(true)
                            .prefixMatch("/")
                            .queryParameterMatches(URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs.builder()
                                .name("abtest")
                                .exactMatch("b")
                                .build())
                            .build())
                        .build())
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: parameter-based routing example
      defaultService: ${default.id}
      hostRules:
        - hosts:
            - '*'
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${default.id}
          routeRules:
            - priority: 1
              service: ${["service-a"].id}
              matchRules:
                - prefixMatch: /
                  ignoreCase: true
                  queryParameterMatches:
                    - name: abtest
                      exactMatch: a
            - priority: 2
              service: ${["service-b"].id}
              matchRules:
                - ignoreCase: true
                  prefixMatch: /
                  queryParameterMatches:
                    - name: abtest
                      exactMatch: b
  default:
    type: gcp:compute:BackendService
    properties:
      name: default
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  service-a:
    type: gcp:compute:BackendService
    properties:
      name: service-a
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  service-b:
    type: gcp:compute:BackendService
    properties:
      name: service-b
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${defaultHttpHealthCheck.id}
  defaultHttpHealthCheck:
    type: gcp:compute:HttpHealthCheck
    name: default
    properties:
      name: health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1

The queryParameterMatches array inspects URL query strings. When the abtest parameter equals a, the load balancer routes to service_a. This provides an alternative to header-based routing that users can control directly through URLs.

Transform requests with header manipulation and redirects

Traffic Director configurations often need to modify requests in flight, adding or removing headers before forwarding to backends or redirecting to different URLs.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.compute.HealthCheck("default", {
    name: "health-check",
    httpHealthCheck: {
        port: 80,
    },
});
const home = new gcp.compute.BackendService("home", {
    name: "home",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: _default.id,
    loadBalancingScheme: "INTERNAL_SELF_MANAGED",
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "a description",
    defaultService: home.id,
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: home.id,
        routeRules: [{
            priority: 1,
            headerAction: {
                requestHeadersToRemoves: ["RemoveMe2"],
                requestHeadersToAdds: [{
                    headerName: "AddSomethingElse",
                    headerValue: "MyOtherValue",
                    replace: true,
                }],
                responseHeadersToRemoves: ["RemoveMe3"],
                responseHeadersToAdds: [{
                    headerName: "AddMe",
                    headerValue: "MyValue",
                    replace: false,
                }],
            },
            matchRules: [{
                fullPathMatch: "a full path",
                headerMatches: [{
                    headerName: "someheader",
                    exactMatch: "match this exactly",
                    invertMatch: true,
                }],
                ignoreCase: true,
                metadataFilters: [{
                    filterMatchCriteria: "MATCH_ANY",
                    filterLabels: [{
                        name: "PLANET",
                        value: "MARS",
                    }],
                }],
                queryParameterMatches: [{
                    name: "a query parameter",
                    presentMatch: true,
                }],
            }],
            urlRedirect: {
                hostRedirect: "A host",
                httpsRedirect: false,
                pathRedirect: "some/path",
                redirectResponseCode: "TEMPORARY_REDIRECT",
                stripQuery: true,
            },
        }],
    }],
    tests: [{
        service: home.id,
        host: "hi.com",
        path: "/home",
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.HealthCheck("default",
    name="health-check",
    http_health_check={
        "port": 80,
    })
home = gcp.compute.BackendService("home",
    name="home",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default.id,
    load_balancing_scheme="INTERNAL_SELF_MANAGED")
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="a description",
    default_service=home.id,
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": home.id,
        "route_rules": [{
            "priority": 1,
            "header_action": {
                "request_headers_to_removes": ["RemoveMe2"],
                "request_headers_to_adds": [{
                    "header_name": "AddSomethingElse",
                    "header_value": "MyOtherValue",
                    "replace": True,
                }],
                "response_headers_to_removes": ["RemoveMe3"],
                "response_headers_to_adds": [{
                    "header_name": "AddMe",
                    "header_value": "MyValue",
                    "replace": False,
                }],
            },
            "match_rules": [{
                "full_path_match": "a full path",
                "header_matches": [{
                    "header_name": "someheader",
                    "exact_match": "match this exactly",
                    "invert_match": True,
                }],
                "ignore_case": True,
                "metadata_filters": [{
                    "filter_match_criteria": "MATCH_ANY",
                    "filter_labels": [{
                        "name": "PLANET",
                        "value": "MARS",
                    }],
                }],
                "query_parameter_matches": [{
                    "name": "a query parameter",
                    "present_match": True,
                }],
            }],
            "url_redirect": {
                "host_redirect": "A host",
                "https_redirect": False,
                "path_redirect": "some/path",
                "redirect_response_code": "TEMPORARY_REDIRECT",
                "strip_query": True,
            },
        }],
    }],
    tests=[{
        "service": home.id,
        "host": "hi.com",
        "path": "/home",
    }])
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.NewHealthCheck(ctx, "default", &compute.HealthCheckArgs{
			Name: pulumi.String("health-check"),
			HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
				Port: pulumi.Int(80),
			},
		})
		if err != nil {
			return err
		}
		home, err := compute.NewBackendService(ctx, "home", &compute.BackendServiceArgs{
			Name:                pulumi.String("home"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			HealthChecks:        _default.ID(),
			LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("a description"),
			DefaultService: home.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: home.ID(),
					RouteRules: compute.URLMapPathMatcherRouteRuleArray{
						&compute.URLMapPathMatcherRouteRuleArgs{
							Priority: pulumi.Int(1),
							HeaderAction: &compute.URLMapPathMatcherRouteRuleHeaderActionArgs{
								RequestHeadersToRemoves: pulumi.StringArray{
									pulumi.String("RemoveMe2"),
								},
								RequestHeadersToAdds: compute.URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArray{
									&compute.URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArgs{
										HeaderName:  pulumi.String("AddSomethingElse"),
										HeaderValue: pulumi.String("MyOtherValue"),
										Replace:     pulumi.Bool(true),
									},
								},
								ResponseHeadersToRemoves: pulumi.StringArray{
									pulumi.String("RemoveMe3"),
								},
								ResponseHeadersToAdds: compute.URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArray{
									&compute.URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArgs{
										HeaderName:  pulumi.String("AddMe"),
										HeaderValue: pulumi.String("MyValue"),
										Replace:     pulumi.Bool(false),
									},
								},
							},
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									FullPathMatch: pulumi.String("a full path"),
									HeaderMatches: compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs{
											HeaderName:  pulumi.String("someheader"),
											ExactMatch:  pulumi.String("match this exactly"),
											InvertMatch: pulumi.Bool(true),
										},
									},
									IgnoreCase: pulumi.Bool(true),
									MetadataFilters: compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArgs{
											FilterMatchCriteria: pulumi.String("MATCH_ANY"),
											FilterLabels: compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArray{
												&compute.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArgs{
													Name:  pulumi.String("PLANET"),
													Value: pulumi.String("MARS"),
												},
											},
										},
									},
									QueryParameterMatches: compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArray{
										&compute.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs{
											Name:         pulumi.String("a query parameter"),
											PresentMatch: pulumi.Bool(true),
										},
									},
								},
							},
							UrlRedirect: &compute.URLMapPathMatcherRouteRuleUrlRedirectArgs{
								HostRedirect:         pulumi.String("A host"),
								HttpsRedirect:        pulumi.Bool(false),
								PathRedirect:         pulumi.String("some/path"),
								RedirectResponseCode: pulumi.String("TEMPORARY_REDIRECT"),
								StripQuery:           pulumi.Bool(true),
							},
						},
					},
				},
			},
			Tests: compute.URLMapTestArray{
				&compute.URLMapTestArgs{
					Service: home.ID(),
					Host:    pulumi.String("hi.com"),
					Path:    pulumi.String("/home"),
				},
			},
		})
		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.HealthCheck("default", new()
    {
        Name = "health-check",
        HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
        {
            Port = 80,
        },
    });

    var home = new Gcp.Compute.BackendService("home", new()
    {
        Name = "home",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = @default.Id,
        LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "a description",
        DefaultService = home.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = home.Id,
                RouteRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        Priority = 1,
                        HeaderAction = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleHeaderActionArgs
                        {
                            RequestHeadersToRemoves = new[]
                            {
                                "RemoveMe2",
                            },
                            RequestHeadersToAdds = new[]
                            {
                                new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArgs
                                {
                                    HeaderName = "AddSomethingElse",
                                    HeaderValue = "MyOtherValue",
                                    Replace = true,
                                },
                            },
                            ResponseHeadersToRemoves = new[]
                            {
                                "RemoveMe3",
                            },
                            ResponseHeadersToAdds = new[]
                            {
                                new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArgs
                                {
                                    HeaderName = "AddMe",
                                    HeaderValue = "MyValue",
                                    Replace = false,
                                },
                            },
                        },
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                FullPathMatch = "a full path",
                                HeaderMatches = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs
                                    {
                                        HeaderName = "someheader",
                                        ExactMatch = "match this exactly",
                                        InvertMatch = true,
                                    },
                                },
                                IgnoreCase = true,
                                MetadataFilters = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArgs
                                    {
                                        FilterMatchCriteria = "MATCH_ANY",
                                        FilterLabels = new[]
                                        {
                                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArgs
                                            {
                                                Name = "PLANET",
                                                Value = "MARS",
                                            },
                                        },
                                    },
                                },
                                QueryParameterMatches = new[]
                                {
                                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs
                                    {
                                        Name = "a query parameter",
                                        PresentMatch = true,
                                    },
                                },
                            },
                        },
                        UrlRedirect = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleUrlRedirectArgs
                        {
                            HostRedirect = "A host",
                            HttpsRedirect = false,
                            PathRedirect = "some/path",
                            RedirectResponseCode = "TEMPORARY_REDIRECT",
                            StripQuery = true,
                        },
                    },
                },
            },
        },
        Tests = new[]
        {
            new Gcp.Compute.Inputs.URLMapTestArgs
            {
                Service = home.Id,
                Host = "hi.com",
                Path = "/home",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapTestArgs;
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 HealthCheck("default", HealthCheckArgs.builder()
            .name("health-check")
            .httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
                .port(80)
                .build())
            .build());

        var home = new BackendService("home", BackendServiceArgs.builder()
            .name("home")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(default_.id())
            .loadBalancingScheme("INTERNAL_SELF_MANAGED")
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("a description")
            .defaultService(home.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(home.id())
                .routeRules(URLMapPathMatcherRouteRuleArgs.builder()
                    .priority(1)
                    .headerAction(URLMapPathMatcherRouteRuleHeaderActionArgs.builder()
                        .requestHeadersToRemoves("RemoveMe2")
                        .requestHeadersToAdds(URLMapPathMatcherRouteRuleHeaderActionRequestHeadersToAddArgs.builder()
                            .headerName("AddSomethingElse")
                            .headerValue("MyOtherValue")
                            .replace(true)
                            .build())
                        .responseHeadersToRemoves("RemoveMe3")
                        .responseHeadersToAdds(URLMapPathMatcherRouteRuleHeaderActionResponseHeadersToAddArgs.builder()
                            .headerName("AddMe")
                            .headerValue("MyValue")
                            .replace(false)
                            .build())
                        .build())
                    .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                        .fullPathMatch("a full path")
                        .headerMatches(URLMapPathMatcherRouteRuleMatchRuleHeaderMatchArgs.builder()
                            .headerName("someheader")
                            .exactMatch("match this exactly")
                            .invertMatch(true)
                            .build())
                        .ignoreCase(true)
                        .metadataFilters(URLMapPathMatcherRouteRuleMatchRuleMetadataFilterArgs.builder()
                            .filterMatchCriteria("MATCH_ANY")
                            .filterLabels(URLMapPathMatcherRouteRuleMatchRuleMetadataFilterFilterLabelArgs.builder()
                                .name("PLANET")
                                .value("MARS")
                                .build())
                            .build())
                        .queryParameterMatches(URLMapPathMatcherRouteRuleMatchRuleQueryParameterMatchArgs.builder()
                            .name("a query parameter")
                            .presentMatch(true)
                            .build())
                        .build())
                    .urlRedirect(URLMapPathMatcherRouteRuleUrlRedirectArgs.builder()
                        .hostRedirect("A host")
                        .httpsRedirect(false)
                        .pathRedirect("some/path")
                        .redirectResponseCode("TEMPORARY_REDIRECT")
                        .stripQuery(true)
                        .build())
                    .build())
                .build())
            .tests(URLMapTestArgs.builder()
                .service(home.id())
                .host("hi.com")
                .path("/home")
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: a description
      defaultService: ${home.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${home.id}
          routeRules:
            - priority: 1
              headerAction:
                requestHeadersToRemoves:
                  - RemoveMe2
                requestHeadersToAdds:
                  - headerName: AddSomethingElse
                    headerValue: MyOtherValue
                    replace: true
                responseHeadersToRemoves:
                  - RemoveMe3
                responseHeadersToAdds:
                  - headerName: AddMe
                    headerValue: MyValue
                    replace: false
              matchRules:
                - fullPathMatch: a full path
                  headerMatches:
                    - headerName: someheader
                      exactMatch: match this exactly
                      invertMatch: true
                  ignoreCase: true
                  metadataFilters:
                    - filterMatchCriteria: MATCH_ANY
                      filterLabels:
                        - name: PLANET
                          value: MARS
                  queryParameterMatches:
                    - name: a query parameter
                      presentMatch: true
              urlRedirect:
                hostRedirect: A host
                httpsRedirect: false
                pathRedirect: some/path
                redirectResponseCode: TEMPORARY_REDIRECT
                stripQuery: true
      tests:
        - service: ${home.id}
          host: hi.com
          path: /home
  home:
    type: gcp:compute:BackendService
    properties:
      name: home
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${default.id}
      loadBalancingScheme: INTERNAL_SELF_MANAGED
  default:
    type: gcp:compute:HealthCheck
    properties:
      name: health-check
      httpHealthCheck:
        port: 80

The headerAction property modifies requests and responses. The requestHeadersToAdds array adds headers to backend requests; requestHeadersToRemoves strips headers. The responseHeadersToAdds and responseHeadersToRemoves arrays modify responses before returning to clients. The urlRedirect property sends HTTP redirects instead of proxying to a backend. The matchRules property controls when these actions apply, checking fullPathMatch, headerMatches, and queryParameterMatches.

Apply advanced routing policies to specific paths

Production traffic often requires sophisticated handling: CORS policies for browser requests, fault injection for testing, request mirroring for validation, and retry logic for resilience.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.compute.HealthCheck("default", {
    name: "health-check",
    httpHealthCheck: {
        port: 80,
    },
});
const home = new gcp.compute.BackendService("home", {
    name: "home",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    healthChecks: _default.id,
    loadBalancingScheme: "INTERNAL_SELF_MANAGED",
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "a description",
    defaultService: home.id,
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "allpaths",
    }],
    pathMatchers: [{
        name: "allpaths",
        defaultService: home.id,
        pathRules: [{
            paths: ["/home"],
            routeAction: {
                corsPolicy: {
                    allowCredentials: true,
                    allowHeaders: ["Allowed content"],
                    allowMethods: ["GET"],
                    allowOriginRegexes: ["abc.*"],
                    allowOrigins: ["Allowed origin"],
                    exposeHeaders: ["Exposed header"],
                    maxAge: 30,
                    disabled: false,
                },
                faultInjectionPolicy: {
                    abort: {
                        httpStatus: 234,
                        percentage: 5.6,
                    },
                    delay: {
                        fixedDelay: {
                            seconds: "0",
                            nanos: 50000,
                        },
                        percentage: 7.8,
                    },
                },
                requestMirrorPolicy: {
                    backendService: home.id,
                },
                retryPolicy: {
                    numRetries: 4,
                    perTryTimeout: {
                        seconds: "30",
                    },
                    retryConditions: [
                        "5xx",
                        "deadline-exceeded",
                    ],
                },
                timeout: {
                    seconds: "20",
                    nanos: 750000000,
                },
                urlRewrite: {
                    hostRewrite: "dev.example.com",
                    pathPrefixRewrite: "/v1/api/",
                },
                weightedBackendServices: [{
                    backendService: home.id,
                    weight: 400,
                    headerAction: {
                        requestHeadersToRemoves: ["RemoveMe"],
                        requestHeadersToAdds: [{
                            headerName: "AddMe",
                            headerValue: "MyValue",
                            replace: true,
                        }],
                        responseHeadersToRemoves: ["RemoveMe"],
                        responseHeadersToAdds: [{
                            headerName: "AddMe",
                            headerValue: "MyValue",
                            replace: false,
                        }],
                    },
                }],
            },
        }],
    }],
    tests: [{
        service: home.id,
        host: "hi.com",
        path: "/home",
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.HealthCheck("default",
    name="health-check",
    http_health_check={
        "port": 80,
    })
home = gcp.compute.BackendService("home",
    name="home",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    health_checks=default.id,
    load_balancing_scheme="INTERNAL_SELF_MANAGED")
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="a description",
    default_service=home.id,
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "allpaths",
    }],
    path_matchers=[{
        "name": "allpaths",
        "default_service": home.id,
        "path_rules": [{
            "paths": ["/home"],
            "route_action": {
                "cors_policy": {
                    "allow_credentials": True,
                    "allow_headers": ["Allowed content"],
                    "allow_methods": ["GET"],
                    "allow_origin_regexes": ["abc.*"],
                    "allow_origins": ["Allowed origin"],
                    "expose_headers": ["Exposed header"],
                    "max_age": 30,
                    "disabled": False,
                },
                "fault_injection_policy": {
                    "abort": {
                        "http_status": 234,
                        "percentage": 5.6,
                    },
                    "delay": {
                        "fixed_delay": {
                            "seconds": "0",
                            "nanos": 50000,
                        },
                        "percentage": 7.8,
                    },
                },
                "request_mirror_policy": {
                    "backend_service": home.id,
                },
                "retry_policy": {
                    "num_retries": 4,
                    "per_try_timeout": {
                        "seconds": "30",
                    },
                    "retry_conditions": [
                        "5xx",
                        "deadline-exceeded",
                    ],
                },
                "timeout": {
                    "seconds": "20",
                    "nanos": 750000000,
                },
                "url_rewrite": {
                    "host_rewrite": "dev.example.com",
                    "path_prefix_rewrite": "/v1/api/",
                },
                "weighted_backend_services": [{
                    "backend_service": home.id,
                    "weight": 400,
                    "header_action": {
                        "request_headers_to_removes": ["RemoveMe"],
                        "request_headers_to_adds": [{
                            "header_name": "AddMe",
                            "header_value": "MyValue",
                            "replace": True,
                        }],
                        "response_headers_to_removes": ["RemoveMe"],
                        "response_headers_to_adds": [{
                            "header_name": "AddMe",
                            "header_value": "MyValue",
                            "replace": False,
                        }],
                    },
                }],
            },
        }],
    }],
    tests=[{
        "service": home.id,
        "host": "hi.com",
        "path": "/home",
    }])
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.NewHealthCheck(ctx, "default", &compute.HealthCheckArgs{
			Name: pulumi.String("health-check"),
			HttpHealthCheck: &compute.HealthCheckHttpHealthCheckArgs{
				Port: pulumi.Int(80),
			},
		})
		if err != nil {
			return err
		}
		home, err := compute.NewBackendService(ctx, "home", &compute.BackendServiceArgs{
			Name:                pulumi.String("home"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			HealthChecks:        _default.ID(),
			LoadBalancingScheme: pulumi.String("INTERNAL_SELF_MANAGED"),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("a description"),
			DefaultService: home.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("allpaths"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("allpaths"),
					DefaultService: home.ID(),
					PathRules: compute.URLMapPathMatcherPathRuleArray{
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/home"),
							},
							RouteAction: &compute.URLMapPathMatcherPathRuleRouteActionArgs{
								CorsPolicy: &compute.URLMapPathMatcherPathRuleRouteActionCorsPolicyArgs{
									AllowCredentials: pulumi.Bool(true),
									AllowHeaders: pulumi.StringArray{
										pulumi.String("Allowed content"),
									},
									AllowMethods: pulumi.StringArray{
										pulumi.String("GET"),
									},
									AllowOriginRegexes: pulumi.StringArray{
										pulumi.String("abc.*"),
									},
									AllowOrigins: pulumi.StringArray{
										pulumi.String("Allowed origin"),
									},
									ExposeHeaders: pulumi.StringArray{
										pulumi.String("Exposed header"),
									},
									MaxAge:   pulumi.Int(30),
									Disabled: pulumi.Bool(false),
								},
								FaultInjectionPolicy: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyArgs{
									Abort: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortArgs{
										HttpStatus: pulumi.Int(234),
										Percentage: pulumi.Float64(5.6),
									},
									Delay: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayArgs{
										FixedDelay: &compute.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayArgs{
											Seconds: pulumi.String("0"),
											Nanos:   pulumi.Int(50000),
										},
										Percentage: pulumi.Float64(7.8),
									},
								},
								RequestMirrorPolicy: &compute.URLMapPathMatcherPathRuleRouteActionRequestMirrorPolicyArgs{
									BackendService: home.ID(),
								},
								RetryPolicy: &compute.URLMapPathMatcherPathRuleRouteActionRetryPolicyArgs{
									NumRetries: pulumi.Int(4),
									PerTryTimeout: &compute.URLMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutArgs{
										Seconds: pulumi.String("30"),
									},
									RetryConditions: pulumi.StringArray{
										pulumi.String("5xx"),
										pulumi.String("deadline-exceeded"),
									},
								},
								Timeout: &compute.URLMapPathMatcherPathRuleRouteActionTimeoutArgs{
									Seconds: pulumi.String("20"),
									Nanos:   pulumi.Int(750000000),
								},
								UrlRewrite: &compute.URLMapPathMatcherPathRuleRouteActionUrlRewriteArgs{
									HostRewrite:       pulumi.String("dev.example.com"),
									PathPrefixRewrite: pulumi.String("/v1/api/"),
								},
								WeightedBackendServices: compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArray{
									&compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArgs{
										BackendService: home.ID(),
										Weight:         pulumi.Int(400),
										HeaderAction: &compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionArgs{
											RequestHeadersToRemoves: pulumi.StringArray{
												pulumi.String("RemoveMe"),
											},
											RequestHeadersToAdds: compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArray{
												&compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArgs{
													HeaderName:  pulumi.String("AddMe"),
													HeaderValue: pulumi.String("MyValue"),
													Replace:     pulumi.Bool(true),
												},
											},
											ResponseHeadersToRemoves: pulumi.StringArray{
												pulumi.String("RemoveMe"),
											},
											ResponseHeadersToAdds: compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArray{
												&compute.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArgs{
													HeaderName:  pulumi.String("AddMe"),
													HeaderValue: pulumi.String("MyValue"),
													Replace:     pulumi.Bool(false),
												},
											},
										},
									},
								},
							},
						},
					},
				},
			},
			Tests: compute.URLMapTestArray{
				&compute.URLMapTestArgs{
					Service: home.ID(),
					Host:    pulumi.String("hi.com"),
					Path:    pulumi.String("/home"),
				},
			},
		})
		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.HealthCheck("default", new()
    {
        Name = "health-check",
        HttpHealthCheck = new Gcp.Compute.Inputs.HealthCheckHttpHealthCheckArgs
        {
            Port = 80,
        },
    });

    var home = new Gcp.Compute.BackendService("home", new()
    {
        Name = "home",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        HealthChecks = @default.Id,
        LoadBalancingScheme = "INTERNAL_SELF_MANAGED",
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "a description",
        DefaultService = home.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "allpaths",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "allpaths",
                DefaultService = home.Id,
                PathRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/home",
                        },
                        RouteAction = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionArgs
                        {
                            CorsPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionCorsPolicyArgs
                            {
                                AllowCredentials = true,
                                AllowHeaders = new[]
                                {
                                    "Allowed content",
                                },
                                AllowMethods = new[]
                                {
                                    "GET",
                                },
                                AllowOriginRegexes = new[]
                                {
                                    "abc.*",
                                },
                                AllowOrigins = new[]
                                {
                                    "Allowed origin",
                                },
                                ExposeHeaders = new[]
                                {
                                    "Exposed header",
                                },
                                MaxAge = 30,
                                Disabled = false,
                            },
                            FaultInjectionPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyArgs
                            {
                                Abort = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortArgs
                                {
                                    HttpStatus = 234,
                                    Percentage = 5.6,
                                },
                                Delay = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayArgs
                                {
                                    FixedDelay = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayArgs
                                    {
                                        Seconds = "0",
                                        Nanos = 50000,
                                    },
                                    Percentage = 7.8,
                                },
                            },
                            RequestMirrorPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionRequestMirrorPolicyArgs
                            {
                                BackendService = home.Id,
                            },
                            RetryPolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionRetryPolicyArgs
                            {
                                NumRetries = 4,
                                PerTryTimeout = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutArgs
                                {
                                    Seconds = "30",
                                },
                                RetryConditions = new[]
                                {
                                    "5xx",
                                    "deadline-exceeded",
                                },
                            },
                            Timeout = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionTimeoutArgs
                            {
                                Seconds = "20",
                                Nanos = 750000000,
                            },
                            UrlRewrite = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionUrlRewriteArgs
                            {
                                HostRewrite = "dev.example.com",
                                PathPrefixRewrite = "/v1/api/",
                            },
                            WeightedBackendServices = new[]
                            {
                                new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArgs
                                {
                                    BackendService = home.Id,
                                    Weight = 400,
                                    HeaderAction = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionArgs
                                    {
                                        RequestHeadersToRemoves = new[]
                                        {
                                            "RemoveMe",
                                        },
                                        RequestHeadersToAdds = new[]
                                        {
                                            new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArgs
                                            {
                                                HeaderName = "AddMe",
                                                HeaderValue = "MyValue",
                                                Replace = true,
                                            },
                                        },
                                        ResponseHeadersToRemoves = new[]
                                        {
                                            "RemoveMe",
                                        },
                                        ResponseHeadersToAdds = new[]
                                        {
                                            new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArgs
                                            {
                                                HeaderName = "AddMe",
                                                HeaderValue = "MyValue",
                                                Replace = false,
                                            },
                                        },
                                    },
                                },
                            },
                        },
                    },
                },
            },
        },
        Tests = new[]
        {
            new Gcp.Compute.Inputs.URLMapTestArgs
            {
                Service = home.Id,
                Host = "hi.com",
                Path = "/home",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HealthCheck;
import com.pulumi.gcp.compute.HealthCheckArgs;
import com.pulumi.gcp.compute.inputs.HealthCheckHttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapTestArgs;
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 HealthCheck("default", HealthCheckArgs.builder()
            .name("health-check")
            .httpHealthCheck(HealthCheckHttpHealthCheckArgs.builder()
                .port(80)
                .build())
            .build());

        var home = new BackendService("home", BackendServiceArgs.builder()
            .name("home")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .healthChecks(default_.id())
            .loadBalancingScheme("INTERNAL_SELF_MANAGED")
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("a description")
            .defaultService(home.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("allpaths")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("allpaths")
                .defaultService(home.id())
                .pathRules(URLMapPathMatcherPathRuleArgs.builder()
                    .paths("/home")
                    .routeAction(URLMapPathMatcherPathRuleRouteActionArgs.builder()
                        .corsPolicy(URLMapPathMatcherPathRuleRouteActionCorsPolicyArgs.builder()
                            .allowCredentials(true)
                            .allowHeaders("Allowed content")
                            .allowMethods("GET")
                            .allowOriginRegexes("abc.*")
                            .allowOrigins("Allowed origin")
                            .exposeHeaders("Exposed header")
                            .maxAge(30)
                            .disabled(false)
                            .build())
                        .faultInjectionPolicy(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyArgs.builder()
                            .abort(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyAbortArgs.builder()
                                .httpStatus(234)
                                .percentage(5.6)
                                .build())
                            .delay(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayArgs.builder()
                                .fixedDelay(URLMapPathMatcherPathRuleRouteActionFaultInjectionPolicyDelayFixedDelayArgs.builder()
                                    .seconds("0")
                                    .nanos(50000)
                                    .build())
                                .percentage(7.8)
                                .build())
                            .build())
                        .requestMirrorPolicy(URLMapPathMatcherPathRuleRouteActionRequestMirrorPolicyArgs.builder()
                            .backendService(home.id())
                            .build())
                        .retryPolicy(URLMapPathMatcherPathRuleRouteActionRetryPolicyArgs.builder()
                            .numRetries(4)
                            .perTryTimeout(URLMapPathMatcherPathRuleRouteActionRetryPolicyPerTryTimeoutArgs.builder()
                                .seconds("30")
                                .build())
                            .retryConditions(                            
                                "5xx",
                                "deadline-exceeded")
                            .build())
                        .timeout(URLMapPathMatcherPathRuleRouteActionTimeoutArgs.builder()
                            .seconds("20")
                            .nanos(750000000)
                            .build())
                        .urlRewrite(URLMapPathMatcherPathRuleRouteActionUrlRewriteArgs.builder()
                            .hostRewrite("dev.example.com")
                            .pathPrefixRewrite("/v1/api/")
                            .build())
                        .weightedBackendServices(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceArgs.builder()
                            .backendService(home.id())
                            .weight(400)
                            .headerAction(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionArgs.builder()
                                .requestHeadersToRemoves("RemoveMe")
                                .requestHeadersToAdds(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionRequestHeadersToAddArgs.builder()
                                    .headerName("AddMe")
                                    .headerValue("MyValue")
                                    .replace(true)
                                    .build())
                                .responseHeadersToRemoves("RemoveMe")
                                .responseHeadersToAdds(URLMapPathMatcherPathRuleRouteActionWeightedBackendServiceHeaderActionResponseHeadersToAddArgs.builder()
                                    .headerName("AddMe")
                                    .headerValue("MyValue")
                                    .replace(false)
                                    .build())
                                .build())
                            .build())
                        .build())
                    .build())
                .build())
            .tests(URLMapTestArgs.builder()
                .service(home.id())
                .host("hi.com")
                .path("/home")
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: a description
      defaultService: ${home.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: allpaths
      pathMatchers:
        - name: allpaths
          defaultService: ${home.id}
          pathRules:
            - paths:
                - /home
              routeAction:
                corsPolicy:
                  allowCredentials: true
                  allowHeaders:
                    - Allowed content
                  allowMethods:
                    - GET
                  allowOriginRegexes:
                    - abc.*
                  allowOrigins:
                    - Allowed origin
                  exposeHeaders:
                    - Exposed header
                  maxAge: 30
                  disabled: false
                faultInjectionPolicy:
                  abort:
                    httpStatus: 234
                    percentage: 5.6
                  delay:
                    fixedDelay:
                      seconds: 0
                      nanos: 50000
                    percentage: 7.8
                requestMirrorPolicy:
                  backendService: ${home.id}
                retryPolicy:
                  numRetries: 4
                  perTryTimeout:
                    seconds: 30
                  retryConditions:
                    - 5xx
                    - deadline-exceeded
                timeout:
                  seconds: 20
                  nanos: 7.5e+08
                urlRewrite:
                  hostRewrite: dev.example.com
                  pathPrefixRewrite: /v1/api/
                weightedBackendServices:
                  - backendService: ${home.id}
                    weight: 400
                    headerAction:
                      requestHeadersToRemoves:
                        - RemoveMe
                      requestHeadersToAdds:
                        - headerName: AddMe
                          headerValue: MyValue
                          replace: true
                      responseHeadersToRemoves:
                        - RemoveMe
                      responseHeadersToAdds:
                        - headerName: AddMe
                          headerValue: MyValue
                          replace: false
      tests:
        - service: ${home.id}
          host: hi.com
          path: /home
  home:
    type: gcp:compute:BackendService
    properties:
      name: home
      portName: http
      protocol: HTTP
      timeoutSec: 10
      healthChecks: ${default.id}
      loadBalancingScheme: INTERNAL_SELF_MANAGED
  default:
    type: gcp:compute:HealthCheck
    properties:
      name: health-check
      httpHealthCheck:
        port: 80

The routeAction property on pathRules enables advanced traffic management. The corsPolicy configures cross-origin resource sharing for browser requests. The faultInjectionPolicy injects delays and errors for chaos testing. The requestMirrorPolicy duplicates traffic to a second backend for validation. The retryPolicy configures automatic retries with backoff. The weightedBackendServices array distributes traffic across multiple backends with specified weights.

Match and rewrite URLs using path templates

RESTful APIs often need to extract path segments and transform them. Path templates capture variables from incoming URLs and rewrite them into different formats.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.compute.HttpHealthCheck("default", {
    name: "health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const cart_backend = new gcp.compute.BackendService("cart-backend", {
    name: "cart-service",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    loadBalancingScheme: "EXTERNAL_MANAGED",
    healthChecks: _default.id,
});
const user_backend = new gcp.compute.BackendService("user-backend", {
    name: "user-service",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    loadBalancingScheme: "EXTERNAL_MANAGED",
    healthChecks: _default.id,
});
const staticBucket = new gcp.storage.Bucket("static", {
    name: "static-asset-bucket",
    location: "US",
});
const static = new gcp.compute.BackendBucket("static", {
    name: "static-asset-backend-bucket",
    bucketName: staticBucket.name,
    enableCdn: true,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "a description",
    defaultService: static.id,
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "mysite",
    }],
    pathMatchers: [{
        name: "mysite",
        defaultService: static.id,
        routeRules: [
            {
                matchRules: [{
                    pathTemplateMatch: "/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}",
                }],
                service: cart_backend.id,
                priority: 1,
                routeAction: {
                    urlRewrite: {
                        pathTemplateRewrite: "/{username}-{cartid}/",
                    },
                },
            },
            {
                matchRules: [{
                    pathTemplateMatch: "/xyzwebservices/v2/xyz/users/*/accountinfo/*",
                }],
                service: user_backend.id,
                priority: 2,
            },
        ],
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.HttpHealthCheck("default",
    name="health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
cart_backend = gcp.compute.BackendService("cart-backend",
    name="cart-service",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    load_balancing_scheme="EXTERNAL_MANAGED",
    health_checks=default.id)
user_backend = gcp.compute.BackendService("user-backend",
    name="user-service",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    load_balancing_scheme="EXTERNAL_MANAGED",
    health_checks=default.id)
static_bucket = gcp.storage.Bucket("static",
    name="static-asset-bucket",
    location="US")
static = gcp.compute.BackendBucket("static",
    name="static-asset-backend-bucket",
    bucket_name=static_bucket.name,
    enable_cdn=True)
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="a description",
    default_service=static.id,
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "mysite",
    }],
    path_matchers=[{
        "name": "mysite",
        "default_service": static.id,
        "route_rules": [
            {
                "match_rules": [{
                    "path_template_match": "/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}",
                }],
                "service": cart_backend.id,
                "priority": 1,
                "route_action": {
                    "url_rewrite": {
                        "path_template_rewrite": "/{username}-{cartid}/",
                    },
                },
            },
            {
                "match_rules": [{
                    "path_template_match": "/xyzwebservices/v2/xyz/users/*/accountinfo/*",
                }],
                "service": user_backend.id,
                "priority": 2,
            },
        ],
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		cart_backend, err := compute.NewBackendService(ctx, "cart-backend", &compute.BackendServiceArgs{
			Name:                pulumi.String("cart-service"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
			HealthChecks:        _default.ID(),
		})
		if err != nil {
			return err
		}
		user_backend, err := compute.NewBackendService(ctx, "user-backend", &compute.BackendServiceArgs{
			Name:                pulumi.String("user-service"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
			HealthChecks:        _default.ID(),
		})
		if err != nil {
			return err
		}
		staticBucket, err := storage.NewBucket(ctx, "static", &storage.BucketArgs{
			Name:     pulumi.String("static-asset-bucket"),
			Location: pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		static, err := compute.NewBackendBucket(ctx, "static", &compute.BackendBucketArgs{
			Name:       pulumi.String("static-asset-backend-bucket"),
			BucketName: staticBucket.Name,
			EnableCdn:  pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("a description"),
			DefaultService: static.ID(),
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("mysite"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("mysite"),
					DefaultService: static.ID(),
					RouteRules: compute.URLMapPathMatcherRouteRuleArray{
						&compute.URLMapPathMatcherRouteRuleArgs{
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									PathTemplateMatch: pulumi.String("/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}"),
								},
							},
							Service:  cart_backend.ID(),
							Priority: pulumi.Int(1),
							RouteAction: &compute.URLMapPathMatcherRouteRuleRouteActionArgs{
								UrlRewrite: &compute.URLMapPathMatcherRouteRuleRouteActionUrlRewriteArgs{
									PathTemplateRewrite: pulumi.String("/{username}-{cartid}/"),
								},
							},
						},
						&compute.URLMapPathMatcherRouteRuleArgs{
							MatchRules: compute.URLMapPathMatcherRouteRuleMatchRuleArray{
								&compute.URLMapPathMatcherRouteRuleMatchRuleArgs{
									PathTemplateMatch: pulumi.String("/xyzwebservices/v2/xyz/users/*/accountinfo/*"),
								},
							},
							Service:  user_backend.ID(),
							Priority: pulumi.Int(2),
						},
					},
				},
			},
		})
		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.HttpHealthCheck("default", new()
    {
        Name = "health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var cart_backend = new Gcp.Compute.BackendService("cart-backend", new()
    {
        Name = "cart-service",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        LoadBalancingScheme = "EXTERNAL_MANAGED",
        HealthChecks = @default.Id,
    });

    var user_backend = new Gcp.Compute.BackendService("user-backend", new()
    {
        Name = "user-service",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        LoadBalancingScheme = "EXTERNAL_MANAGED",
        HealthChecks = @default.Id,
    });

    var staticBucket = new Gcp.Storage.Bucket("static", new()
    {
        Name = "static-asset-bucket",
        Location = "US",
    });

    var @static = new Gcp.Compute.BackendBucket("static", new()
    {
        Name = "static-asset-backend-bucket",
        BucketName = staticBucket.Name,
        EnableCdn = true,
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "a description",
        DefaultService = @static.Id,
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "mysite",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "mysite",
                DefaultService = @static.Id,
                RouteRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                PathTemplateMatch = "/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}",
                            },
                        },
                        Service = cart_backend.Id,
                        Priority = 1,
                        RouteAction = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleRouteActionArgs
                        {
                            UrlRewrite = new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleRouteActionUrlRewriteArgs
                            {
                                PathTemplateRewrite = "/{username}-{cartid}/",
                            },
                        },
                    },
                    new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleArgs
                    {
                        MatchRules = new[]
                        {
                            new Gcp.Compute.Inputs.URLMapPathMatcherRouteRuleMatchRuleArgs
                            {
                                PathTemplateMatch = "/xyzwebservices/v2/xyz/users/*/accountinfo/*",
                            },
                        },
                        Service = user_backend.Id,
                        Priority = 2,
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.compute.BackendBucket;
import com.pulumi.gcp.compute.BackendBucketArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
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 HttpHealthCheck("default", HttpHealthCheckArgs.builder()
            .name("health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var cart_backend = new BackendService("cart-backend", BackendServiceArgs.builder()
            .name("cart-service")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .loadBalancingScheme("EXTERNAL_MANAGED")
            .healthChecks(default_.id())
            .build());

        var user_backend = new BackendService("user-backend", BackendServiceArgs.builder()
            .name("user-service")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .loadBalancingScheme("EXTERNAL_MANAGED")
            .healthChecks(default_.id())
            .build());

        var staticBucket = new Bucket("staticBucket", BucketArgs.builder()
            .name("static-asset-bucket")
            .location("US")
            .build());

        var static_ = new BackendBucket("static", BackendBucketArgs.builder()
            .name("static-asset-backend-bucket")
            .bucketName(staticBucket.name())
            .enableCdn(true)
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("a description")
            .defaultService(static_.id())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("mysite")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("mysite")
                .defaultService(static_.id())
                .routeRules(                
                    URLMapPathMatcherRouteRuleArgs.builder()
                        .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                            .pathTemplateMatch("/xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}")
                            .build())
                        .service(cart_backend.id())
                        .priority(1)
                        .routeAction(URLMapPathMatcherRouteRuleRouteActionArgs.builder()
                            .urlRewrite(URLMapPathMatcherRouteRuleRouteActionUrlRewriteArgs.builder()
                                .pathTemplateRewrite("/{username}-{cartid}/")
                                .build())
                            .build())
                        .build(),
                    URLMapPathMatcherRouteRuleArgs.builder()
                        .matchRules(URLMapPathMatcherRouteRuleMatchRuleArgs.builder()
                            .pathTemplateMatch("/xyzwebservices/v2/xyz/users/*/accountinfo/*")
                            .build())
                        .service(user_backend.id())
                        .priority(2)
                        .build())
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: a description
      defaultService: ${static.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: mysite
      pathMatchers:
        - name: mysite
          defaultService: ${static.id}
          routeRules:
            - matchRules:
                - pathTemplateMatch: /xyzwebservices/v2/xyz/users/{username=*}/carts/{cartid=**}
              service: ${["cart-backend"].id}
              priority: 1
              routeAction:
                urlRewrite:
                  pathTemplateRewrite: /{username}-{cartid}/
            - matchRules:
                - pathTemplateMatch: /xyzwebservices/v2/xyz/users/*/accountinfo/*
              service: ${["user-backend"].id}
              priority: 2
  cart-backend:
    type: gcp:compute:BackendService
    properties:
      name: cart-service
      portName: http
      protocol: HTTP
      timeoutSec: 10
      loadBalancingScheme: EXTERNAL_MANAGED
      healthChecks: ${default.id}
  user-backend:
    type: gcp:compute:BackendService
    properties:
      name: user-service
      portName: http
      protocol: HTTP
      timeoutSec: 10
      loadBalancingScheme: EXTERNAL_MANAGED
      healthChecks: ${default.id}
  default:
    type: gcp:compute:HttpHealthCheck
    properties:
      name: health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  static:
    type: gcp:compute:BackendBucket
    properties:
      name: static-asset-backend-bucket
      bucketName: ${staticBucket.name}
      enableCdn: true
  staticBucket:
    type: gcp:storage:Bucket
    name: static
    properties:
      name: static-asset-bucket
      location: US

The pathTemplateMatch property uses curly braces to capture path segments as variables. Single asterisks (*) match one segment; double asterisks (**) match multiple segments. The pathTemplateRewrite property reconstructs URLs using captured variables. In this example, /xyzwebservices/v2/xyz/users/john/carts/abc123 becomes /john-abc123/ before reaching the backend.

Serve custom error pages from Cloud Storage

When backend services return errors, load balancers can serve custom error pages from Cloud Storage instead of exposing raw error responses to users.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const _default = new gcp.compute.HttpHealthCheck("default", {
    name: "health-check",
    requestPath: "/",
    checkIntervalSec: 1,
    timeoutSec: 1,
});
const example = new gcp.compute.BackendService("example", {
    name: "login",
    portName: "http",
    protocol: "HTTP",
    timeoutSec: 10,
    loadBalancingScheme: "EXTERNAL_MANAGED",
    healthChecks: _default.id,
});
const errorBucket = new gcp.storage.Bucket("error", {
    name: "static-asset-bucket",
    location: "US",
});
const error = new gcp.compute.BackendBucket("error", {
    name: "error-backend-bucket",
    bucketName: errorBucket.name,
    enableCdn: true,
});
const urlmap = new gcp.compute.URLMap("urlmap", {
    name: "urlmap",
    description: "a description",
    defaultService: example.id,
    defaultCustomErrorResponsePolicy: {
        errorResponseRules: [{
            matchResponseCodes: ["5xx"],
            path: "/internal_error.html",
            overrideResponseCode: 502,
        }],
        errorService: error.id,
    },
    hostRules: [{
        hosts: ["mysite.com"],
        pathMatcher: "mysite",
    }],
    pathMatchers: [{
        name: "mysite",
        defaultService: example.id,
        defaultCustomErrorResponsePolicy: {
            errorResponseRules: [
                {
                    matchResponseCodes: [
                        "4xx",
                        "5xx",
                    ],
                    path: "/login_error.html",
                    overrideResponseCode: 404,
                },
                {
                    matchResponseCodes: ["503"],
                    path: "/bad_gateway.html",
                    overrideResponseCode: 502,
                },
            ],
            errorService: error.id,
        },
        pathRules: [{
            paths: ["/private/*"],
            service: example.id,
            customErrorResponsePolicy: {
                errorResponseRules: [{
                    matchResponseCodes: ["4xx"],
                    path: "/login.html",
                    overrideResponseCode: 401,
                }],
                errorService: error.id,
            },
        }],
    }],
});
import pulumi
import pulumi_gcp as gcp

default = gcp.compute.HttpHealthCheck("default",
    name="health-check",
    request_path="/",
    check_interval_sec=1,
    timeout_sec=1)
example = gcp.compute.BackendService("example",
    name="login",
    port_name="http",
    protocol="HTTP",
    timeout_sec=10,
    load_balancing_scheme="EXTERNAL_MANAGED",
    health_checks=default.id)
error_bucket = gcp.storage.Bucket("error",
    name="static-asset-bucket",
    location="US")
error = gcp.compute.BackendBucket("error",
    name="error-backend-bucket",
    bucket_name=error_bucket.name,
    enable_cdn=True)
urlmap = gcp.compute.URLMap("urlmap",
    name="urlmap",
    description="a description",
    default_service=example.id,
    default_custom_error_response_policy={
        "error_response_rules": [{
            "match_response_codes": ["5xx"],
            "path": "/internal_error.html",
            "override_response_code": 502,
        }],
        "error_service": error.id,
    },
    host_rules=[{
        "hosts": ["mysite.com"],
        "path_matcher": "mysite",
    }],
    path_matchers=[{
        "name": "mysite",
        "default_service": example.id,
        "default_custom_error_response_policy": {
            "error_response_rules": [
                {
                    "match_response_codes": [
                        "4xx",
                        "5xx",
                    ],
                    "path": "/login_error.html",
                    "override_response_code": 404,
                },
                {
                    "match_response_codes": ["503"],
                    "path": "/bad_gateway.html",
                    "override_response_code": 502,
                },
            ],
            "error_service": error.id,
        },
        "path_rules": [{
            "paths": ["/private/*"],
            "service": example.id,
            "custom_error_response_policy": {
                "error_response_rules": [{
                    "match_response_codes": ["4xx"],
                    "path": "/login.html",
                    "override_response_code": 401,
                }],
                "error_service": error.id,
            },
        }],
    }])
package main

import (
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
	"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/storage"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_default, err := compute.NewHttpHealthCheck(ctx, "default", &compute.HttpHealthCheckArgs{
			Name:             pulumi.String("health-check"),
			RequestPath:      pulumi.String("/"),
			CheckIntervalSec: pulumi.Int(1),
			TimeoutSec:       pulumi.Int(1),
		})
		if err != nil {
			return err
		}
		example, err := compute.NewBackendService(ctx, "example", &compute.BackendServiceArgs{
			Name:                pulumi.String("login"),
			PortName:            pulumi.String("http"),
			Protocol:            pulumi.String("HTTP"),
			TimeoutSec:          pulumi.Int(10),
			LoadBalancingScheme: pulumi.String("EXTERNAL_MANAGED"),
			HealthChecks:        _default.ID(),
		})
		if err != nil {
			return err
		}
		errorBucket, err := storage.NewBucket(ctx, "error", &storage.BucketArgs{
			Name:     pulumi.String("static-asset-bucket"),
			Location: pulumi.String("US"),
		})
		if err != nil {
			return err
		}
		error, err := compute.NewBackendBucket(ctx, "error", &compute.BackendBucketArgs{
			Name:       pulumi.String("error-backend-bucket"),
			BucketName: errorBucket.Name,
			EnableCdn:  pulumi.Bool(true),
		})
		if err != nil {
			return err
		}
		_, err = compute.NewURLMap(ctx, "urlmap", &compute.URLMapArgs{
			Name:           pulumi.String("urlmap"),
			Description:    pulumi.String("a description"),
			DefaultService: example.ID(),
			DefaultCustomErrorResponsePolicy: &compute.URLMapDefaultCustomErrorResponsePolicyArgs{
				ErrorResponseRules: compute.URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArray{
					&compute.URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArgs{
						MatchResponseCodes: pulumi.StringArray{
							pulumi.String("5xx"),
						},
						Path:                 pulumi.String("/internal_error.html"),
						OverrideResponseCode: pulumi.Int(502),
					},
				},
				ErrorService: error.ID(),
			},
			HostRules: compute.URLMapHostRuleArray{
				&compute.URLMapHostRuleArgs{
					Hosts: pulumi.StringArray{
						pulumi.String("mysite.com"),
					},
					PathMatcher: pulumi.String("mysite"),
				},
			},
			PathMatchers: compute.URLMapPathMatcherArray{
				&compute.URLMapPathMatcherArgs{
					Name:           pulumi.String("mysite"),
					DefaultService: example.ID(),
					DefaultCustomErrorResponsePolicy: &compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs{
						ErrorResponseRules: compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArray{
							&compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs{
								MatchResponseCodes: pulumi.StringArray{
									pulumi.String("4xx"),
									pulumi.String("5xx"),
								},
								Path:                 pulumi.String("/login_error.html"),
								OverrideResponseCode: pulumi.Int(404),
							},
							&compute.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs{
								MatchResponseCodes: pulumi.StringArray{
									pulumi.String("503"),
								},
								Path:                 pulumi.String("/bad_gateway.html"),
								OverrideResponseCode: pulumi.Int(502),
							},
						},
						ErrorService: error.ID(),
					},
					PathRules: compute.URLMapPathMatcherPathRuleArray{
						&compute.URLMapPathMatcherPathRuleArgs{
							Paths: pulumi.StringArray{
								pulumi.String("/private/*"),
							},
							Service: example.ID(),
							CustomErrorResponsePolicy: &compute.URLMapPathMatcherPathRuleCustomErrorResponsePolicyArgs{
								ErrorResponseRules: compute.URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArray{
									&compute.URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArgs{
										MatchResponseCodes: pulumi.StringArray{
											pulumi.String("4xx"),
										},
										Path:                 pulumi.String("/login.html"),
										OverrideResponseCode: pulumi.Int(401),
									},
								},
								ErrorService: error.ID(),
							},
						},
					},
				},
			},
		})
		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.HttpHealthCheck("default", new()
    {
        Name = "health-check",
        RequestPath = "/",
        CheckIntervalSec = 1,
        TimeoutSec = 1,
    });

    var example = new Gcp.Compute.BackendService("example", new()
    {
        Name = "login",
        PortName = "http",
        Protocol = "HTTP",
        TimeoutSec = 10,
        LoadBalancingScheme = "EXTERNAL_MANAGED",
        HealthChecks = @default.Id,
    });

    var errorBucket = new Gcp.Storage.Bucket("error", new()
    {
        Name = "static-asset-bucket",
        Location = "US",
    });

    var error = new Gcp.Compute.BackendBucket("error", new()
    {
        Name = "error-backend-bucket",
        BucketName = errorBucket.Name,
        EnableCdn = true,
    });

    var urlmap = new Gcp.Compute.URLMap("urlmap", new()
    {
        Name = "urlmap",
        Description = "a description",
        DefaultService = example.Id,
        DefaultCustomErrorResponsePolicy = new Gcp.Compute.Inputs.URLMapDefaultCustomErrorResponsePolicyArgs
        {
            ErrorResponseRules = new[]
            {
                new Gcp.Compute.Inputs.URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArgs
                {
                    MatchResponseCodes = new[]
                    {
                        "5xx",
                    },
                    Path = "/internal_error.html",
                    OverrideResponseCode = 502,
                },
            },
            ErrorService = error.Id,
        },
        HostRules = new[]
        {
            new Gcp.Compute.Inputs.URLMapHostRuleArgs
            {
                Hosts = new[]
                {
                    "mysite.com",
                },
                PathMatcher = "mysite",
            },
        },
        PathMatchers = new[]
        {
            new Gcp.Compute.Inputs.URLMapPathMatcherArgs
            {
                Name = "mysite",
                DefaultService = example.Id,
                DefaultCustomErrorResponsePolicy = new Gcp.Compute.Inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs
                {
                    ErrorResponseRules = new[]
                    {
                        new Gcp.Compute.Inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs
                        {
                            MatchResponseCodes = new[]
                            {
                                "4xx",
                                "5xx",
                            },
                            Path = "/login_error.html",
                            OverrideResponseCode = 404,
                        },
                        new Gcp.Compute.Inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs
                        {
                            MatchResponseCodes = new[]
                            {
                                "503",
                            },
                            Path = "/bad_gateway.html",
                            OverrideResponseCode = 502,
                        },
                    },
                    ErrorService = error.Id,
                },
                PathRules = new[]
                {
                    new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleArgs
                    {
                        Paths = new[]
                        {
                            "/private/*",
                        },
                        Service = example.Id,
                        CustomErrorResponsePolicy = new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleCustomErrorResponsePolicyArgs
                        {
                            ErrorResponseRules = new[]
                            {
                                new Gcp.Compute.Inputs.URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArgs
                                {
                                    MatchResponseCodes = new[]
                                    {
                                        "4xx",
                                    },
                                    Path = "/login.html",
                                    OverrideResponseCode = 401,
                                },
                            },
                            ErrorService = error.Id,
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.compute.HttpHealthCheck;
import com.pulumi.gcp.compute.HttpHealthCheckArgs;
import com.pulumi.gcp.compute.BackendService;
import com.pulumi.gcp.compute.BackendServiceArgs;
import com.pulumi.gcp.storage.Bucket;
import com.pulumi.gcp.storage.BucketArgs;
import com.pulumi.gcp.compute.BackendBucket;
import com.pulumi.gcp.compute.BackendBucketArgs;
import com.pulumi.gcp.compute.URLMap;
import com.pulumi.gcp.compute.URLMapArgs;
import com.pulumi.gcp.compute.inputs.URLMapDefaultCustomErrorResponsePolicyArgs;
import com.pulumi.gcp.compute.inputs.URLMapHostRuleArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherArgs;
import com.pulumi.gcp.compute.inputs.URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs;
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 HttpHealthCheck("default", HttpHealthCheckArgs.builder()
            .name("health-check")
            .requestPath("/")
            .checkIntervalSec(1)
            .timeoutSec(1)
            .build());

        var example = new BackendService("example", BackendServiceArgs.builder()
            .name("login")
            .portName("http")
            .protocol("HTTP")
            .timeoutSec(10)
            .loadBalancingScheme("EXTERNAL_MANAGED")
            .healthChecks(default_.id())
            .build());

        var errorBucket = new Bucket("errorBucket", BucketArgs.builder()
            .name("static-asset-bucket")
            .location("US")
            .build());

        var error = new BackendBucket("error", BackendBucketArgs.builder()
            .name("error-backend-bucket")
            .bucketName(errorBucket.name())
            .enableCdn(true)
            .build());

        var urlmap = new URLMap("urlmap", URLMapArgs.builder()
            .name("urlmap")
            .description("a description")
            .defaultService(example.id())
            .defaultCustomErrorResponsePolicy(URLMapDefaultCustomErrorResponsePolicyArgs.builder()
                .errorResponseRules(URLMapDefaultCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
                    .matchResponseCodes("5xx")
                    .path("/internal_error.html")
                    .overrideResponseCode(502)
                    .build())
                .errorService(error.id())
                .build())
            .hostRules(URLMapHostRuleArgs.builder()
                .hosts("mysite.com")
                .pathMatcher("mysite")
                .build())
            .pathMatchers(URLMapPathMatcherArgs.builder()
                .name("mysite")
                .defaultService(example.id())
                .defaultCustomErrorResponsePolicy(URLMapPathMatcherDefaultCustomErrorResponsePolicyArgs.builder()
                    .errorResponseRules(                    
                        URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
                            .matchResponseCodes(                            
                                "4xx",
                                "5xx")
                            .path("/login_error.html")
                            .overrideResponseCode(404)
                            .build(),
                        URLMapPathMatcherDefaultCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
                            .matchResponseCodes("503")
                            .path("/bad_gateway.html")
                            .overrideResponseCode(502)
                            .build())
                    .errorService(error.id())
                    .build())
                .pathRules(URLMapPathMatcherPathRuleArgs.builder()
                    .paths("/private/*")
                    .service(example.id())
                    .customErrorResponsePolicy(URLMapPathMatcherPathRuleCustomErrorResponsePolicyArgs.builder()
                        .errorResponseRules(URLMapPathMatcherPathRuleCustomErrorResponsePolicyErrorResponseRuleArgs.builder()
                            .matchResponseCodes("4xx")
                            .path("/login.html")
                            .overrideResponseCode(401)
                            .build())
                        .errorService(error.id())
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  urlmap:
    type: gcp:compute:URLMap
    properties:
      name: urlmap
      description: a description
      defaultService: ${example.id}
      defaultCustomErrorResponsePolicy:
        errorResponseRules:
          - matchResponseCodes:
              - 5xx
            path: /internal_error.html
            overrideResponseCode: 502
        errorService: ${error.id}
      hostRules:
        - hosts:
            - mysite.com
          pathMatcher: mysite
      pathMatchers:
        - name: mysite
          defaultService: ${example.id}
          defaultCustomErrorResponsePolicy:
            errorResponseRules:
              - matchResponseCodes:
                  - 4xx
                  - 5xx
                path: /login_error.html
                overrideResponseCode: 404
              - matchResponseCodes:
                  - '503'
                path: /bad_gateway.html
                overrideResponseCode: 502
            errorService: ${error.id}
          pathRules:
            - paths:
                - /private/*
              service: ${example.id}
              customErrorResponsePolicy:
                errorResponseRules:
                  - matchResponseCodes:
                      - 4xx
                    path: /login.html
                    overrideResponseCode: 401
                errorService: ${error.id}
  example:
    type: gcp:compute:BackendService
    properties:
      name: login
      portName: http
      protocol: HTTP
      timeoutSec: 10
      loadBalancingScheme: EXTERNAL_MANAGED
      healthChecks: ${default.id}
  default:
    type: gcp:compute:HttpHealthCheck
    properties:
      name: health-check
      requestPath: /
      checkIntervalSec: 1
      timeoutSec: 1
  error:
    type: gcp:compute:BackendBucket
    properties:
      name: error-backend-bucket
      bucketName: ${errorBucket.name}
      enableCdn: true
  errorBucket:
    type: gcp:storage:Bucket
    name: error
    properties:
      name: static-asset-bucket
      location: US

The defaultCustomErrorResponsePolicy property defines error handling at the URL map level. The errorResponseRules array maps response codes to custom pages. The matchResponseCodes array accepts specific codes or ranges like 4xx and 5xx. The path property points to an HTML file in the errorService backend bucket. The overrideResponseCode changes the HTTP status code returned to clients. Path matchers can override these defaults with their own customErrorResponsePolicy.

Beyond these examples

These snippets focus on specific URL map features: path and host-based routing, header and query parameter matching, request transformation and traffic mirroring, and custom error handling. They’re intentionally minimal rather than full load balancer configurations.

The examples reference pre-existing infrastructure such as backend services with health checks, backend buckets for static content or error pages, and Cloud Storage buckets. They focus on configuring the URL map rather than provisioning the complete load balancing stack.

To keep things focused, common URL map patterns are omitted, including:

  • Default route actions and URL redirects (defaultRouteAction, defaultUrlRedirect)
  • Traffic mirroring percentage controls across different scopes
  • HTTP filter configurations for service mesh (httpFilterConfigs, httpFilterMetadatas)
  • Test validation with headers and expected outputs (tests property)

These omissions are intentional: the goal is to illustrate how each routing feature is wired, not provide drop-in load balancer modules. See the URL Map resource reference for all available configuration options.

Let's configure GCP URL Maps for Load Balancing

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Core Routing & Configuration
What's the difference between pathRules and routeRules?
pathRules provide simple path-based routing to services using a paths array. routeRules offer advanced routing with explicit priority, header/query parameter matching, and complex actions like URL rewrites and fault injection.
Can I use both defaultService and defaultRouteAction?
No. If defaultRouteAction specifies weightedBackendServices, you cannot set defaultService. Conversely, if defaultService is set, defaultRouteAction cannot contain weightedBackendServices.
Can I use both defaultRouteAction and defaultUrlRedirect?
No. Only one of defaultRouteAction or defaultUrlRedirect can be set. Use defaultRouteAction for backend routing or defaultUrlRedirect for redirects.
How do hostRules and pathMatchers work together?
hostRules map incoming hostnames to named pathMatchers. Each pathMatcher contains the routing rules (pathRules or routeRules) that apply to requests matching those hosts.
What load balancing schemes support URL maps?
URL maps support INTERNAL_SELF_MANAGED (for Traffic Director), EXTERNAL_MANAGED (for Application Load Balancers), and standard external load balancing. Some features like custom error response policies require EXTERNAL_MANAGED.
Advanced Routing & Matching
How does priority work in routeRules?
Lower priority numbers are evaluated first. Each routeRule must have an explicit priority value. For example, a rule with priority: 1 is evaluated before priority: 2.
How do I route traffic based on HTTP headers?
Use routeRules with matchRules containing headerMatches. For example, route A/B test traffic by matching the abtest header with exactMatch: "a" or exactMatch: "b".
How do I route traffic based on query parameters?
Use routeRules with matchRules containing queryParameterMatches. You can match on parameter name and value, or check for parameter presence with presentMatch: true.
Can I use path templates for dynamic URL routing?
Yes. Use pathTemplateMatch with wildcards (* for single segment, ** for multiple segments) to capture URL parts, then use pathTemplateRewrite to transform them. For example, /users/{username=*}/carts/{cartid=**} can be rewritten to /{username}-{cartid}/.
Error Handling & Resilience
How do custom error response policies cascade through the configuration?
Policies are evaluated from most specific to least specific: PathRule → RouteRule → PathMatcher → UrlMap. The first matching policy for an error code takes effect. For example, a 404 policy in RouteRule overrides the PathMatcher and UrlMap policies.
What happens when both retry policies and custom error policies are configured?
Retries take precedence. The custom error response policy only applies after all retries are exhausted. If the load balancer successfully reaches the service during a retry, the error policy is ignored.
At what levels can I configure request mirroring?
Request mirroring with requestMirrorPolicy can be configured at four levels: defaultRouteAction, pathMatcher defaultRouteAction, pathRule routeAction, and routeRule. Each level can specify a different mirrorPercent.
Configuration Constraints & Validation
What are the naming requirements for URL maps?
The name must be 1-63 characters long, start with a lowercase letter, contain only lowercase letters, digits, or dashes, and cannot end with a dash. The name is immutable after creation.
How do URL map tests work and why might my update fail?
The tests property validates routing behavior. Updates fail if any test doesn’t pass. You can specify up to 100 tests with host, path, expected service, and optional headers, expectedOutputUrl, or expectedRedirectResponseCode.
Can I test URL redirects and custom headers?
Yes. Tests support headers for custom request headers, expectedOutputUrl for redirect validation, and expectedRedirectResponseCode for verifying redirect status codes (e.g., 301, 302).

Using a different cloud?

Explore networking guides for other cloud providers: