The gcp:dns/recordSet:RecordSet resource, part of the Pulumi GCP provider, defines DNS records within a Cloud DNS managed zone: their names, types, data values, and optional routing policies. This guide focuses on three capabilities: standard record types (A, MX, TXT, CNAME), geographic routing, and failover configurations.
Record sets belong to managed zones and may reference compute instances, load balancers, or networks for routing policies. The examples are intentionally small. Combine them with your own managed zones and infrastructure.
Add an A record with static IP addresses
Most DNS configurations start by mapping hostnames to IP addresses using A records.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const a = new gcp.dns.RecordSet("a", {
name: pulumi.interpolate`backend.${prod.dnsName}`,
managedZone: prod.name,
type: "A",
ttl: 300,
rrdatas: ["8.8.8.8"],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
a = gcp.dns.RecordSet("a",
name=prod.dns_name.apply(lambda dns_name: f"backend.{dns_name}"),
managed_zone=prod.name,
type="A",
ttl=300,
rrdatas=["8.8.8.8"])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "a", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("backend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
Rrdatas: pulumi.StringArray{
pulumi.String("8.8.8.8"),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var a = new Gcp.Dns.RecordSet("a", new()
{
Name = prod.DnsName.Apply(dnsName => $"backend.{dnsName}"),
ManagedZone = prod.Name,
Type = "A",
Ttl = 300,
Rrdatas = new[]
{
"8.8.8.8",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var a = new RecordSet("a", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("backend.%s", _dnsName)))
.managedZone(prod.name())
.type("A")
.ttl(300)
.rrdatas("8.8.8.8")
.build());
}
}
resources:
a:
type: gcp:dns:RecordSet
properties:
name: backend.${prod.dnsName}
managedZone: ${prod.name}
type: A
ttl: 300
rrdatas:
- 8.8.8.8
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
The name property sets the fully qualified domain name (must end with a dot). The type property specifies the record type. The rrdatas array contains the IP addresses to return. The ttl property controls how long resolvers cache the record (in seconds).
Configure mail routing with MX records
Email delivery requires MX records that specify mail servers and their priority order, with lower values indicating preferred servers.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const mx = new gcp.dns.RecordSet("mx", {
name: prod.dnsName,
managedZone: prod.name,
type: "MX",
ttl: 3600,
rrdatas: [
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.",
],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
mx = gcp.dns.RecordSet("mx",
name=prod.dns_name,
managed_zone=prod.name,
type="MX",
ttl=3600,
rrdatas=[
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.",
])
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "mx", &dns.RecordSetArgs{
Name: prod.DnsName,
ManagedZone: prod.Name,
Type: pulumi.String("MX"),
Ttl: pulumi.Int(3600),
Rrdatas: pulumi.StringArray{
pulumi.String("1 aspmx.l.google.com."),
pulumi.String("5 alt1.aspmx.l.google.com."),
pulumi.String("5 alt2.aspmx.l.google.com."),
pulumi.String("10 alt3.aspmx.l.google.com."),
pulumi.String("10 alt4.aspmx.l.google.com."),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var mx = new Gcp.Dns.RecordSet("mx", new()
{
Name = prod.DnsName,
ManagedZone = prod.Name,
Type = "MX",
Ttl = 3600,
Rrdatas = new[]
{
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var mx = new RecordSet("mx", RecordSetArgs.builder()
.name(prod.dnsName())
.managedZone(prod.name())
.type("MX")
.ttl(3600)
.rrdatas(
"1 aspmx.l.google.com.",
"5 alt1.aspmx.l.google.com.",
"5 alt2.aspmx.l.google.com.",
"10 alt3.aspmx.l.google.com.",
"10 alt4.aspmx.l.google.com.")
.build());
}
}
resources:
mx:
type: gcp:dns:RecordSet
properties:
name: ${prod.dnsName}
managedZone: ${prod.name}
type: MX
ttl: 3600
rrdatas:
- 1 aspmx.l.google.com.
- 5 alt1.aspmx.l.google.com.
- 5 alt2.aspmx.l.google.com.
- 10 alt3.aspmx.l.google.com.
- 10 alt4.aspmx.l.google.com.
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
Each entry in rrdatas combines a priority number with a mail server hostname. Mail clients attempt delivery to lower-priority servers first, falling back to higher-priority servers if delivery fails. The ttl of 3600 seconds (1 hour) is common for MX records.
Add SPF records for email authentication
SPF records authenticate email senders by listing authorized IP addresses and domains in a TXT record.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const spf = new gcp.dns.RecordSet("spf", {
name: pulumi.interpolate`frontend.${prod.dnsName}`,
managedZone: prod.name,
type: "TXT",
ttl: 300,
rrdatas: ["\"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all\""],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
spf = gcp.dns.RecordSet("spf",
name=prod.dns_name.apply(lambda dns_name: f"frontend.{dns_name}"),
managed_zone=prod.name,
type="TXT",
ttl=300,
rrdatas=["\"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all\""])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "spf", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("frontend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("TXT"),
Ttl: pulumi.Int(300),
Rrdatas: pulumi.StringArray{
pulumi.String("\"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all\""),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var spf = new Gcp.Dns.RecordSet("spf", new()
{
Name = prod.DnsName.Apply(dnsName => $"frontend.{dnsName}"),
ManagedZone = prod.Name,
Type = "TXT",
Ttl = 300,
Rrdatas = new[]
{
"\"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all\"",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var spf = new RecordSet("spf", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("frontend.%s", _dnsName)))
.managedZone(prod.name())
.type("TXT")
.ttl(300)
.rrdatas("\"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all\"")
.build());
}
}
resources:
spf:
type: gcp:dns:RecordSet
properties:
name: frontend.${prod.dnsName}
managedZone: ${prod.name}
type: TXT
ttl: 300
rrdatas:
- '"v=spf1 ip4:111.111.111.111 include:backoff.email-example.com -all"'
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
The type is TXT, not SPF. The rrdatas value must be wrapped in escaped quotes (\") to prevent Cloud DNS from splitting the string on spaces. The SPF syntax (v=spf1) defines which IP addresses and domains can send email on behalf of your domain.
Create aliases with CNAME records
CNAME records create aliases that point one hostname to another, enabling flexible DNS configurations without duplicating IP addresses.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
});
const cname = new gcp.dns.RecordSet("cname", {
name: pulumi.interpolate`frontend.${prod.dnsName}`,
managedZone: prod.name,
type: "CNAME",
ttl: 300,
rrdatas: ["frontend.mydomain.com."],
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.")
cname = gcp.dns.RecordSet("cname",
name=prod.dns_name.apply(lambda dns_name: f"frontend.{dns_name}"),
managed_zone=prod.name,
type="CNAME",
ttl=300,
rrdatas=["frontend.mydomain.com."])
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "cname", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("frontend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("CNAME"),
Ttl: pulumi.Int(300),
Rrdatas: pulumi.StringArray{
pulumi.String("frontend.mydomain.com."),
},
})
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 prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
});
var cname = new Gcp.Dns.RecordSet("cname", new()
{
Name = prod.DnsName.Apply(dnsName => $"frontend.{dnsName}"),
ManagedZone = prod.Name,
Type = "CNAME",
Ttl = 300,
Rrdatas = new[]
{
"frontend.mydomain.com.",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.build());
var cname = new RecordSet("cname", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("frontend.%s", _dnsName)))
.managedZone(prod.name())
.type("CNAME")
.ttl(300)
.rrdatas("frontend.mydomain.com.")
.build());
}
}
resources:
cname:
type: gcp:dns:RecordSet
properties:
name: frontend.${prod.dnsName}
managedZone: ${prod.name}
type: CNAME
ttl: 300
rrdatas:
- frontend.mydomain.com.
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
The rrdatas array should contain exactly one string: the canonical name to which this alias points. CNAME records cannot coexist with other record types for the same name.
Route traffic by geographic location
Applications serving global users often route traffic to regional endpoints based on client location, reducing latency.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const geo = new gcp.dns.RecordSet("geo", {
name: `backend.${prod.dnsName}`,
managedZone: prod.name,
type: "A",
ttl: 300,
routingPolicy: {
geos: [
{
location: "asia-east1",
rrdatas: ["10.128.1.1"],
},
{
location: "us-central1",
rrdatas: ["10.130.1.1"],
},
],
},
});
import pulumi
import pulumi_gcp as gcp
geo = gcp.dns.RecordSet("geo",
name=f"backend.{prod['dnsName']}",
managed_zone=prod["name"],
type="A",
ttl=300,
routing_policy={
"geos": [
{
"location": "asia-east1",
"rrdatas": ["10.128.1.1"],
},
{
"location": "us-central1",
"rrdatas": ["10.130.1.1"],
},
],
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := dns.NewRecordSet(ctx, "geo", &dns.RecordSetArgs{
Name: pulumi.Sprintf("backend.%v", prod.DnsName),
ManagedZone: pulumi.Any(prod.Name),
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
RoutingPolicy: &dns.RecordSetRoutingPolicyArgs{
Geos: dns.RecordSetRoutingPolicyGeoArray{
&dns.RecordSetRoutingPolicyGeoArgs{
Location: pulumi.String("asia-east1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.128.1.1"),
},
},
&dns.RecordSetRoutingPolicyGeoArgs{
Location: pulumi.String("us-central1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.130.1.1"),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var geo = new Gcp.Dns.RecordSet("geo", new()
{
Name = $"backend.{prod.DnsName}",
ManagedZone = prod.Name,
Type = "A",
Ttl = 300,
RoutingPolicy = new Gcp.Dns.Inputs.RecordSetRoutingPolicyArgs
{
Geos = new[]
{
new Gcp.Dns.Inputs.RecordSetRoutingPolicyGeoArgs
{
Location = "asia-east1",
Rrdatas = new[]
{
"10.128.1.1",
},
},
new Gcp.Dns.Inputs.RecordSetRoutingPolicyGeoArgs
{
Location = "us-central1",
Rrdatas = new[]
{
"10.130.1.1",
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyArgs;
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 geo = new RecordSet("geo", RecordSetArgs.builder()
.name(String.format("backend.%s", prod.dnsName()))
.managedZone(prod.name())
.type("A")
.ttl(300)
.routingPolicy(RecordSetRoutingPolicyArgs.builder()
.geos(
RecordSetRoutingPolicyGeoArgs.builder()
.location("asia-east1")
.rrdatas("10.128.1.1")
.build(),
RecordSetRoutingPolicyGeoArgs.builder()
.location("us-central1")
.rrdatas("10.130.1.1")
.build())
.build())
.build());
}
}
resources:
geo:
type: gcp:dns:RecordSet
properties:
name: backend.${prod.dnsName}
managedZone: ${prod.name}
type: A
ttl: 300
routingPolicy:
geos:
- location: asia-east1
rrdatas:
- 10.128.1.1
- location: us-central1
rrdatas:
- 10.130.1.1
The routingPolicy property replaces rrdatas for advanced routing. The geos array maps geographic locations to IP addresses. Cloud DNS returns the IP address matching the client’s location. When you use routingPolicy, you cannot set rrdatas.
Configure failover with primary and backup targets
High-availability deployments use failover routing to automatically redirect traffic when primary endpoints become unavailable.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const prod = new gcp.dns.ManagedZone("prod", {
name: "prod-zone",
dnsName: "prod.mydomain.com.",
visibility: "private",
});
const prodRegionBackendService = new gcp.compute.RegionBackendService("prod", {
name: "prod-backend",
region: "us-central1",
});
const prodNetwork = new gcp.compute.Network("prod", {name: "prod-network"});
const prodForwardingRule = new gcp.compute.ForwardingRule("prod", {
name: "prod-ilb",
region: "us-central1",
loadBalancingScheme: "INTERNAL",
backendService: prodRegionBackendService.id,
allPorts: true,
network: prodNetwork.name,
allowGlobalAccess: true,
});
const a = new gcp.dns.RecordSet("a", {
name: pulumi.interpolate`backend.${prod.dnsName}`,
managedZone: prod.name,
type: "A",
ttl: 300,
routingPolicy: {
primaryBackup: {
trickleRatio: 0.1,
primary: {
internalLoadBalancers: [{
loadBalancerType: "regionalL4ilb",
ipAddress: prodForwardingRule.ipAddress,
port: "80",
ipProtocol: "tcp",
networkUrl: prodNetwork.id,
project: prodForwardingRule.project,
region: prodForwardingRule.region,
}],
},
backupGeos: [
{
location: "asia-east1",
rrdatas: ["10.128.1.1"],
},
{
location: "us-west1",
rrdatas: ["10.130.1.1"],
},
],
},
},
});
import pulumi
import pulumi_gcp as gcp
prod = gcp.dns.ManagedZone("prod",
name="prod-zone",
dns_name="prod.mydomain.com.",
visibility="private")
prod_region_backend_service = gcp.compute.RegionBackendService("prod",
name="prod-backend",
region="us-central1")
prod_network = gcp.compute.Network("prod", name="prod-network")
prod_forwarding_rule = gcp.compute.ForwardingRule("prod",
name="prod-ilb",
region="us-central1",
load_balancing_scheme="INTERNAL",
backend_service=prod_region_backend_service.id,
all_ports=True,
network=prod_network.name,
allow_global_access=True)
a = gcp.dns.RecordSet("a",
name=prod.dns_name.apply(lambda dns_name: f"backend.{dns_name}"),
managed_zone=prod.name,
type="A",
ttl=300,
routing_policy={
"primary_backup": {
"trickle_ratio": 0.1,
"primary": {
"internal_load_balancers": [{
"load_balancer_type": "regionalL4ilb",
"ip_address": prod_forwarding_rule.ip_address,
"port": "80",
"ip_protocol": "tcp",
"network_url": prod_network.id,
"project": prod_forwarding_rule.project,
"region": prod_forwarding_rule.region,
}],
},
"backup_geos": [
{
"location": "asia-east1",
"rrdatas": ["10.128.1.1"],
},
{
"location": "us-west1",
"rrdatas": ["10.130.1.1"],
},
],
},
})
package main
import (
"fmt"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
prod, err := dns.NewManagedZone(ctx, "prod", &dns.ManagedZoneArgs{
Name: pulumi.String("prod-zone"),
DnsName: pulumi.String("prod.mydomain.com."),
Visibility: pulumi.String("private"),
})
if err != nil {
return err
}
prodRegionBackendService, err := compute.NewRegionBackendService(ctx, "prod", &compute.RegionBackendServiceArgs{
Name: pulumi.String("prod-backend"),
Region: pulumi.String("us-central1"),
})
if err != nil {
return err
}
prodNetwork, err := compute.NewNetwork(ctx, "prod", &compute.NetworkArgs{
Name: pulumi.String("prod-network"),
})
if err != nil {
return err
}
prodForwardingRule, err := compute.NewForwardingRule(ctx, "prod", &compute.ForwardingRuleArgs{
Name: pulumi.String("prod-ilb"),
Region: pulumi.String("us-central1"),
LoadBalancingScheme: pulumi.String("INTERNAL"),
BackendService: prodRegionBackendService.ID(),
AllPorts: pulumi.Bool(true),
Network: prodNetwork.Name,
AllowGlobalAccess: pulumi.Bool(true),
})
if err != nil {
return err
}
_, err = dns.NewRecordSet(ctx, "a", &dns.RecordSetArgs{
Name: prod.DnsName.ApplyT(func(dnsName string) (string, error) {
return fmt.Sprintf("backend.%v", dnsName), nil
}).(pulumi.StringOutput),
ManagedZone: prod.Name,
Type: pulumi.String("A"),
Ttl: pulumi.Int(300),
RoutingPolicy: &dns.RecordSetRoutingPolicyArgs{
PrimaryBackup: &dns.RecordSetRoutingPolicyPrimaryBackupArgs{
TrickleRatio: pulumi.Float64(0.1),
Primary: &dns.RecordSetRoutingPolicyPrimaryBackupPrimaryArgs{
InternalLoadBalancers: dns.RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArray{
&dns.RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArgs{
LoadBalancerType: pulumi.String("regionalL4ilb"),
IpAddress: prodForwardingRule.IpAddress,
Port: pulumi.String("80"),
IpProtocol: pulumi.String("tcp"),
NetworkUrl: prodNetwork.ID(),
Project: prodForwardingRule.Project,
Region: prodForwardingRule.Region,
},
},
},
BackupGeos: dns.RecordSetRoutingPolicyPrimaryBackupBackupGeoArray{
&dns.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs{
Location: pulumi.String("asia-east1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.128.1.1"),
},
},
&dns.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs{
Location: pulumi.String("us-west1"),
Rrdatas: pulumi.StringArray{
pulumi.String("10.130.1.1"),
},
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var prod = new Gcp.Dns.ManagedZone("prod", new()
{
Name = "prod-zone",
DnsName = "prod.mydomain.com.",
Visibility = "private",
});
var prodRegionBackendService = new Gcp.Compute.RegionBackendService("prod", new()
{
Name = "prod-backend",
Region = "us-central1",
});
var prodNetwork = new Gcp.Compute.Network("prod", new()
{
Name = "prod-network",
});
var prodForwardingRule = new Gcp.Compute.ForwardingRule("prod", new()
{
Name = "prod-ilb",
Region = "us-central1",
LoadBalancingScheme = "INTERNAL",
BackendService = prodRegionBackendService.Id,
AllPorts = true,
Network = prodNetwork.Name,
AllowGlobalAccess = true,
});
var a = new Gcp.Dns.RecordSet("a", new()
{
Name = prod.DnsName.Apply(dnsName => $"backend.{dnsName}"),
ManagedZone = prod.Name,
Type = "A",
Ttl = 300,
RoutingPolicy = new Gcp.Dns.Inputs.RecordSetRoutingPolicyArgs
{
PrimaryBackup = new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupArgs
{
TrickleRatio = 0.1,
Primary = new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupPrimaryArgs
{
InternalLoadBalancers = new[]
{
new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArgs
{
LoadBalancerType = "regionalL4ilb",
IpAddress = prodForwardingRule.IpAddress,
Port = "80",
IpProtocol = "tcp",
NetworkUrl = prodNetwork.Id,
Project = prodForwardingRule.Project,
Region = prodForwardingRule.Region,
},
},
},
BackupGeos = new[]
{
new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs
{
Location = "asia-east1",
Rrdatas = new[]
{
"10.128.1.1",
},
},
new Gcp.Dns.Inputs.RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs
{
Location = "us-west1",
Rrdatas = new[]
{
"10.130.1.1",
},
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.dns.ManagedZone;
import com.pulumi.gcp.dns.ManagedZoneArgs;
import com.pulumi.gcp.compute.RegionBackendService;
import com.pulumi.gcp.compute.RegionBackendServiceArgs;
import com.pulumi.gcp.compute.Network;
import com.pulumi.gcp.compute.NetworkArgs;
import com.pulumi.gcp.compute.ForwardingRule;
import com.pulumi.gcp.compute.ForwardingRuleArgs;
import com.pulumi.gcp.dns.RecordSet;
import com.pulumi.gcp.dns.RecordSetArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyPrimaryBackupArgs;
import com.pulumi.gcp.dns.inputs.RecordSetRoutingPolicyPrimaryBackupPrimaryArgs;
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 prod = new ManagedZone("prod", ManagedZoneArgs.builder()
.name("prod-zone")
.dnsName("prod.mydomain.com.")
.visibility("private")
.build());
var prodRegionBackendService = new RegionBackendService("prodRegionBackendService", RegionBackendServiceArgs.builder()
.name("prod-backend")
.region("us-central1")
.build());
var prodNetwork = new Network("prodNetwork", NetworkArgs.builder()
.name("prod-network")
.build());
var prodForwardingRule = new ForwardingRule("prodForwardingRule", ForwardingRuleArgs.builder()
.name("prod-ilb")
.region("us-central1")
.loadBalancingScheme("INTERNAL")
.backendService(prodRegionBackendService.id())
.allPorts(true)
.network(prodNetwork.name())
.allowGlobalAccess(true)
.build());
var a = new RecordSet("a", RecordSetArgs.builder()
.name(prod.dnsName().applyValue(_dnsName -> String.format("backend.%s", _dnsName)))
.managedZone(prod.name())
.type("A")
.ttl(300)
.routingPolicy(RecordSetRoutingPolicyArgs.builder()
.primaryBackup(RecordSetRoutingPolicyPrimaryBackupArgs.builder()
.trickleRatio(0.1)
.primary(RecordSetRoutingPolicyPrimaryBackupPrimaryArgs.builder()
.internalLoadBalancers(RecordSetRoutingPolicyPrimaryBackupPrimaryInternalLoadBalancerArgs.builder()
.loadBalancerType("regionalL4ilb")
.ipAddress(prodForwardingRule.ipAddress())
.port("80")
.ipProtocol("tcp")
.networkUrl(prodNetwork.id())
.project(prodForwardingRule.project())
.region(prodForwardingRule.region())
.build())
.build())
.backupGeos(
RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs.builder()
.location("asia-east1")
.rrdatas("10.128.1.1")
.build(),
RecordSetRoutingPolicyPrimaryBackupBackupGeoArgs.builder()
.location("us-west1")
.rrdatas("10.130.1.1")
.build())
.build())
.build())
.build());
}
}
resources:
a:
type: gcp:dns:RecordSet
properties:
name: backend.${prod.dnsName}
managedZone: ${prod.name}
type: A
ttl: 300
routingPolicy:
primaryBackup:
trickleRatio: 0.1
primary:
internalLoadBalancers:
- loadBalancerType: regionalL4ilb
ipAddress: ${prodForwardingRule.ipAddress}
port: '80'
ipProtocol: tcp
networkUrl: ${prodNetwork.id}
project: ${prodForwardingRule.project}
region: ${prodForwardingRule.region}
backupGeos:
- location: asia-east1
rrdatas:
- 10.128.1.1
- location: us-west1
rrdatas:
- 10.130.1.1
prod:
type: gcp:dns:ManagedZone
properties:
name: prod-zone
dnsName: prod.mydomain.com.
visibility: private
prodForwardingRule:
type: gcp:compute:ForwardingRule
name: prod
properties:
name: prod-ilb
region: us-central1
loadBalancingScheme: INTERNAL
backendService: ${prodRegionBackendService.id}
allPorts: true
network: ${prodNetwork.name}
allowGlobalAccess: true
prodRegionBackendService:
type: gcp:compute:RegionBackendService
name: prod
properties:
name: prod-backend
region: us-central1
prodNetwork:
type: gcp:compute:Network
name: prod
properties:
name: prod-network
The primaryBackup configuration defines a primary target (here, an internal load balancer) and backup geographic targets. The trickleRatio controls what percentage of traffic goes to backups even when the primary is healthy (useful for testing). The internalLoadBalancers block references a forwarding rule by IP address, port, and network. When the primary fails, all traffic shifts to the backup geos.
Beyond these examples
These snippets focus on specific record set features: standard record types (A, MX, TXT, CNAME) and geographic and failover routing policies. They’re intentionally minimal rather than full DNS configurations.
The examples may reference pre-existing infrastructure such as Cloud DNS managed zones, and compute instances, load balancers, and networks for routing examples. They focus on configuring the record set rather than provisioning everything around it.
To keep things focused, common record set patterns are omitted, including:
- Weighted round-robin routing (WRR)
- Health check configuration for routing policies
- AAAA records for IPv6 addresses
- NS and SOA record management (handled automatically by Cloud DNS)
These omissions are intentional: the goal is to illustrate how each record set feature is wired, not provide drop-in DNS modules. See the DNS RecordSet resource reference for all available configuration options.
Let's create GCP DNS Record Sets
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Record Management & Behavior
managedZone, name, and project properties are immutable. Changing them requires destroying and recreating the record set.Record Formatting & Data
["\"v=spf1 ip4:111.111.111.111 -all\""]. For values longer than 255 characters (like DKIM), use \" \" as a separator: ["first255characters\" \"morecharacters"].rrdatas: ["frontend.mydomain.com."].rrdatas array, each prefixed with its priority: ["1 aspmx.l.google.com.", "5 alt1.aspmx.l.google.com."].Routing Policies
rrdatas for simple records or routingPolicy for traffic steering (geolocation or failover). They’re mutually exclusive.routingPolicy.geos with a location and rrdatas for each region: geos: [{ location: "asia-east1", rrdatas: ["10.128.1.1"] }].routingPolicy.primaryBackup with primary and backupGeos. For public zones, add a healthCheck to monitor primary availability.Import & Configuration
example.com. not example.com. Use format {{zone}}/{{name}}/{{type}} with the dot.Using a different cloud?
Explore networking guides for other cloud providers: