The aws:route53/record:Record resource, part of the Pulumi AWS provider, defines DNS records within Route 53 hosted zones: their names, types, values, and routing behavior. This guide focuses on four capabilities: simple A and CNAME records, weighted routing for traffic splitting, alias records for AWS services, and NS record management with allowOverwrite.
DNS records belong to hosted zones and often point to AWS resources like load balancers or accelerators. The examples are intentionally small. Combine them with your own hosted zones and target infrastructure.
Point a domain to an IP address
Most DNS configurations start with simple A records that map domain names to IP addresses, making services accessible via human-readable names.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const www = new aws.route53.Record("www", {
zoneId: primary.zoneId,
name: "www.example.com",
type: aws.route53.RecordType.A,
ttl: 300,
records: [lb.publicIp],
});
import pulumi
import pulumi_aws as aws
www = aws.route53.Record("www",
zone_id=primary["zoneId"],
name="www.example.com",
type=aws.route53.RecordType.A,
ttl=300,
records=[lb["publicIp"]])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := route53.NewRecord(ctx, "www", &route53.RecordArgs{
ZoneId: pulumi.Any(primary.ZoneId),
Name: pulumi.String("www.example.com"),
Type: pulumi.String(route53.RecordTypeA),
Ttl: pulumi.Int(300),
Records: pulumi.StringArray{
lb.PublicIp,
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var www = new Aws.Route53.Record("www", new()
{
ZoneId = primary.ZoneId,
Name = "www.example.com",
Type = Aws.Route53.RecordType.A,
Ttl = 300,
Records = new[]
{
lb.PublicIp,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.route53.Record;
import com.pulumi.aws.route53.RecordArgs;
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 www = new Record("www", RecordArgs.builder()
.zoneId(primary.zoneId())
.name("www.example.com")
.type("A")
.ttl(300)
.records(lb.publicIp())
.build());
}
}
resources:
www:
type: aws:route53:Record
properties:
zoneId: ${primary.zoneId}
name: www.example.com
type: A
ttl: 300
records:
- ${lb.publicIp}
The name property sets the domain name, type specifies the record type (A for IPv4 addresses), and records contains the IP addresses to return. The ttl property controls how long DNS resolvers cache this answer (300 seconds here). The zoneId ties the record to a specific hosted zone.
Split traffic between environments with weighted routing
Teams running blue-green deployments or gradual rollouts use weighted routing to control what percentage of traffic reaches each environment.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const www_dev = new aws.route53.Record("www-dev", {
zoneId: primary.zoneId,
name: "www",
type: aws.route53.RecordType.CNAME,
ttl: 5,
weightedRoutingPolicies: [{
weight: 10,
}],
setIdentifier: "dev",
records: ["dev.example.com"],
});
const www_live = new aws.route53.Record("www-live", {
zoneId: primary.zoneId,
name: "www",
type: aws.route53.RecordType.CNAME,
ttl: 5,
weightedRoutingPolicies: [{
weight: 90,
}],
setIdentifier: "live",
records: ["live.example.com"],
});
import pulumi
import pulumi_aws as aws
www_dev = aws.route53.Record("www-dev",
zone_id=primary["zoneId"],
name="www",
type=aws.route53.RecordType.CNAME,
ttl=5,
weighted_routing_policies=[{
"weight": 10,
}],
set_identifier="dev",
records=["dev.example.com"])
www_live = aws.route53.Record("www-live",
zone_id=primary["zoneId"],
name="www",
type=aws.route53.RecordType.CNAME,
ttl=5,
weighted_routing_policies=[{
"weight": 90,
}],
set_identifier="live",
records=["live.example.com"])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := route53.NewRecord(ctx, "www-dev", &route53.RecordArgs{
ZoneId: pulumi.Any(primary.ZoneId),
Name: pulumi.String("www"),
Type: pulumi.String(route53.RecordTypeCNAME),
Ttl: pulumi.Int(5),
WeightedRoutingPolicies: route53.RecordWeightedRoutingPolicyArray{
&route53.RecordWeightedRoutingPolicyArgs{
Weight: pulumi.Int(10),
},
},
SetIdentifier: pulumi.String("dev"),
Records: pulumi.StringArray{
pulumi.String("dev.example.com"),
},
})
if err != nil {
return err
}
_, err = route53.NewRecord(ctx, "www-live", &route53.RecordArgs{
ZoneId: pulumi.Any(primary.ZoneId),
Name: pulumi.String("www"),
Type: pulumi.String(route53.RecordTypeCNAME),
Ttl: pulumi.Int(5),
WeightedRoutingPolicies: route53.RecordWeightedRoutingPolicyArray{
&route53.RecordWeightedRoutingPolicyArgs{
Weight: pulumi.Int(90),
},
},
SetIdentifier: pulumi.String("live"),
Records: pulumi.StringArray{
pulumi.String("live.example.com"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var www_dev = new Aws.Route53.Record("www-dev", new()
{
ZoneId = primary.ZoneId,
Name = "www",
Type = Aws.Route53.RecordType.CNAME,
Ttl = 5,
WeightedRoutingPolicies = new[]
{
new Aws.Route53.Inputs.RecordWeightedRoutingPolicyArgs
{
Weight = 10,
},
},
SetIdentifier = "dev",
Records = new[]
{
"dev.example.com",
},
});
var www_live = new Aws.Route53.Record("www-live", new()
{
ZoneId = primary.ZoneId,
Name = "www",
Type = Aws.Route53.RecordType.CNAME,
Ttl = 5,
WeightedRoutingPolicies = new[]
{
new Aws.Route53.Inputs.RecordWeightedRoutingPolicyArgs
{
Weight = 90,
},
},
SetIdentifier = "live",
Records = new[]
{
"live.example.com",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.route53.Record;
import com.pulumi.aws.route53.RecordArgs;
import com.pulumi.aws.route53.inputs.RecordWeightedRoutingPolicyArgs;
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 www_dev = new Record("www-dev", RecordArgs.builder()
.zoneId(primary.zoneId())
.name("www")
.type("CNAME")
.ttl(5)
.weightedRoutingPolicies(RecordWeightedRoutingPolicyArgs.builder()
.weight(10)
.build())
.setIdentifier("dev")
.records("dev.example.com")
.build());
var www_live = new Record("www-live", RecordArgs.builder()
.zoneId(primary.zoneId())
.name("www")
.type("CNAME")
.ttl(5)
.weightedRoutingPolicies(RecordWeightedRoutingPolicyArgs.builder()
.weight(90)
.build())
.setIdentifier("live")
.records("live.example.com")
.build());
}
}
resources:
www-dev:
type: aws:route53:Record
properties:
zoneId: ${primary.zoneId}
name: www
type: CNAME
ttl: 5
weightedRoutingPolicies:
- weight: 10
setIdentifier: dev
records:
- dev.example.com
www-live:
type: aws:route53:Record
properties:
zoneId: ${primary.zoneId}
name: www
type: CNAME
ttl: 5
weightedRoutingPolicies:
- weight: 90
setIdentifier: live
records:
- live.example.com
Weighted routing requires multiple records with the same name and type but different setIdentifier values. The weight property determines traffic distribution: here, 10% goes to dev (weight 10) and 90% to live (weight 90). Route 53 randomly selects a target based on these proportions.
Create alias records for AWS load balancers
AWS services like ELB, CloudFront, and API Gateway expose DNS names that change over time. Alias records point your domain to these services without hardcoding IP addresses.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const main = new aws.elb.LoadBalancer("main", {
name: "foobar-elb",
availabilityZones: ["us-east-1c"],
listeners: [{
instancePort: 80,
instanceProtocol: "http",
lbPort: 80,
lbProtocol: "http",
}],
});
const www = new aws.route53.Record("www", {
zoneId: primary.zoneId,
name: "example.com",
type: aws.route53.RecordType.A,
aliases: [{
name: main.dnsName,
zoneId: main.zoneId,
evaluateTargetHealth: true,
}],
});
import pulumi
import pulumi_aws as aws
main = aws.elb.LoadBalancer("main",
name="foobar-elb",
availability_zones=["us-east-1c"],
listeners=[{
"instance_port": 80,
"instance_protocol": "http",
"lb_port": 80,
"lb_protocol": "http",
}])
www = aws.route53.Record("www",
zone_id=primary["zoneId"],
name="example.com",
type=aws.route53.RecordType.A,
aliases=[{
"name": main.dns_name,
"zone_id": main.zone_id,
"evaluate_target_health": True,
}])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/elb"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
main, err := elb.NewLoadBalancer(ctx, "main", &elb.LoadBalancerArgs{
Name: pulumi.String("foobar-elb"),
AvailabilityZones: pulumi.StringArray{
pulumi.String("us-east-1c"),
},
Listeners: elb.LoadBalancerListenerArray{
&elb.LoadBalancerListenerArgs{
InstancePort: pulumi.Int(80),
InstanceProtocol: pulumi.String("http"),
LbPort: pulumi.Int(80),
LbProtocol: pulumi.String("http"),
},
},
})
if err != nil {
return err
}
_, err = route53.NewRecord(ctx, "www", &route53.RecordArgs{
ZoneId: pulumi.Any(primary.ZoneId),
Name: pulumi.String("example.com"),
Type: pulumi.String(route53.RecordTypeA),
Aliases: route53.RecordAliasArray{
&route53.RecordAliasArgs{
Name: main.DnsName,
ZoneId: main.ZoneId,
EvaluateTargetHealth: pulumi.Bool(true),
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var main = new Aws.Elb.LoadBalancer("main", new()
{
Name = "foobar-elb",
AvailabilityZones = new[]
{
"us-east-1c",
},
Listeners = new[]
{
new Aws.Elb.Inputs.LoadBalancerListenerArgs
{
InstancePort = 80,
InstanceProtocol = "http",
LbPort = 80,
LbProtocol = "http",
},
},
});
var www = new Aws.Route53.Record("www", new()
{
ZoneId = primary.ZoneId,
Name = "example.com",
Type = Aws.Route53.RecordType.A,
Aliases = new[]
{
new Aws.Route53.Inputs.RecordAliasArgs
{
Name = main.DnsName,
ZoneId = main.ZoneId,
EvaluateTargetHealth = true,
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.elb.LoadBalancer;
import com.pulumi.aws.elb.LoadBalancerArgs;
import com.pulumi.aws.elb.inputs.LoadBalancerListenerArgs;
import com.pulumi.aws.route53.Record;
import com.pulumi.aws.route53.RecordArgs;
import com.pulumi.aws.route53.inputs.RecordAliasArgs;
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 main = new LoadBalancer("main", LoadBalancerArgs.builder()
.name("foobar-elb")
.availabilityZones("us-east-1c")
.listeners(LoadBalancerListenerArgs.builder()
.instancePort(80)
.instanceProtocol("http")
.lbPort(80)
.lbProtocol("http")
.build())
.build());
var www = new Record("www", RecordArgs.builder()
.zoneId(primary.zoneId())
.name("example.com")
.type("A")
.aliases(RecordAliasArgs.builder()
.name(main.dnsName())
.zoneId(main.zoneId())
.evaluateTargetHealth(true)
.build())
.build());
}
}
resources:
main:
type: aws:elb:LoadBalancer
properties:
name: foobar-elb
availabilityZones:
- us-east-1c
listeners:
- instancePort: 80
instanceProtocol: http
lbPort: 80
lbProtocol: http
www:
type: aws:route53:Record
properties:
zoneId: ${primary.zoneId}
name: example.com
type: A
aliases:
- name: ${main.dnsName}
zoneId: ${main.zoneId}
evaluateTargetHealth: true
Alias records use the aliases property instead of records and ttl. The name and zoneId come from the target AWS resource (here, an ELB). The evaluateTargetHealth property tells Route 53 whether to check the load balancer’s health before routing traffic. Alias records always use a 60-second TTL managed by AWS.
Manage zone NS records with allowOverwrite
When Route 53 creates a hosted zone, it automatically generates NS and SOA records. The allowOverwrite property lets you manage these records without importing existing state.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const example = new aws.route53.Zone("example", {name: "test.example.com"});
const exampleRecord = new aws.route53.Record("example", {
allowOverwrite: true,
name: "test.example.com",
ttl: 172800,
type: aws.route53.RecordType.NS,
zoneId: example.zoneId,
records: [
example.nameServers[0],
example.nameServers[1],
example.nameServers[2],
example.nameServers[3],
],
});
import pulumi
import pulumi_aws as aws
example = aws.route53.Zone("example", name="test.example.com")
example_record = aws.route53.Record("example",
allow_overwrite=True,
name="test.example.com",
ttl=172800,
type=aws.route53.RecordType.NS,
zone_id=example.zone_id,
records=[
example.name_servers[0],
example.name_servers[1],
example.name_servers[2],
example.name_servers[3],
])
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/route53"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
example, err := route53.NewZone(ctx, "example", &route53.ZoneArgs{
Name: pulumi.String("test.example.com"),
})
if err != nil {
return err
}
_, err = route53.NewRecord(ctx, "example", &route53.RecordArgs{
AllowOverwrite: pulumi.Bool(true),
Name: pulumi.String("test.example.com"),
Ttl: pulumi.Int(172800),
Type: pulumi.String(route53.RecordTypeNS),
ZoneId: example.ZoneId,
Records: pulumi.StringArray{
example.NameServers.ApplyT(func(nameServers []string) (string, error) {
return nameServers[0], nil
}).(pulumi.StringOutput),
example.NameServers.ApplyT(func(nameServers []string) (string, error) {
return nameServers[1], nil
}).(pulumi.StringOutput),
example.NameServers.ApplyT(func(nameServers []string) (string, error) {
return nameServers[2], nil
}).(pulumi.StringOutput),
example.NameServers.ApplyT(func(nameServers []string) (string, error) {
return nameServers[3], nil
}).(pulumi.StringOutput),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var example = new Aws.Route53.Zone("example", new()
{
Name = "test.example.com",
});
var exampleRecord = new Aws.Route53.Record("example", new()
{
AllowOverwrite = true,
Name = "test.example.com",
Ttl = 172800,
Type = Aws.Route53.RecordType.NS,
ZoneId = example.ZoneId,
Records = new[]
{
example.NameServers.Apply(nameServers => nameServers[0]),
example.NameServers.Apply(nameServers => nameServers[1]),
example.NameServers.Apply(nameServers => nameServers[2]),
example.NameServers.Apply(nameServers => nameServers[3]),
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.route53.Zone;
import com.pulumi.aws.route53.ZoneArgs;
import com.pulumi.aws.route53.Record;
import com.pulumi.aws.route53.RecordArgs;
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 example = new Zone("example", ZoneArgs.builder()
.name("test.example.com")
.build());
var exampleRecord = new Record("exampleRecord", RecordArgs.builder()
.allowOverwrite(true)
.name("test.example.com")
.ttl(172800)
.type("NS")
.zoneId(example.zoneId())
.records(
example.nameServers().applyValue(_nameServers -> _nameServers[0]),
example.nameServers().applyValue(_nameServers -> _nameServers[1]),
example.nameServers().applyValue(_nameServers -> _nameServers[2]),
example.nameServers().applyValue(_nameServers -> _nameServers[3]))
.build());
}
}
resources:
example:
type: aws:route53:Zone
properties:
name: test.example.com
exampleRecord:
type: aws:route53:Record
name: example
properties:
allowOverwrite: true
name: test.example.com
ttl: 172800
type: NS
zoneId: ${example.zoneId}
records:
- ${example.nameServers[0]}
- ${example.nameServers[1]}
- ${example.nameServers[2]}
- ${example.nameServers[3]}
The allowOverwrite property permits this record to replace the auto-generated NS record. The nameServers output from the zone resource provides the values. This pattern works for both NS and SOA records, letting you customize zone-level DNS configuration in a single deployment.
Beyond these examples
These snippets focus on specific record-level features: simple A and CNAME records with TTL, weighted routing for traffic distribution, and alias records for AWS services. They’re intentionally minimal rather than full DNS configurations.
The examples may reference pre-existing infrastructure such as Route 53 hosted zones, and load balancers, accelerators, or other AWS services with DNS names. They focus on configuring the record rather than provisioning the surrounding infrastructure.
To keep things focused, common routing patterns are omitted, including:
- Health checks and failover routing (healthCheckId, failoverRoutingPolicies)
- Geographic routing (geolocationRoutingPolicies, geoproximityRoutingPolicy)
- Latency-based routing (latencyRoutingPolicies)
- CIDR-based routing (cidrRoutingPolicy)
These omissions are intentional: the goal is to illustrate how each record feature is wired, not provide drop-in DNS modules. See the Route 53 Record resource reference for all available configuration options.
Let's configure AWS Route 53 DNS Records
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Alias Records
aliases property, while regular records use the records property for explicit values. You must use exactly one of these properties, never both.ttl property when creating alias records, as it conflicts with the aliases property.aliases property with the load balancer’s dnsName and zoneId, and set evaluateTargetHealth as needed. Omit both ttl and records properties.Routing Policies
setIdentifier property is required whenever you use any routing policy: cidrRoutingPolicy, failoverRoutingPolicy, geolocationRoutingPolicy, geoproximityRoutingPolicy, latencyRoutingPolicy, multivalueAnswerRoutingPolicy, or weightedRoutingPolicy.name and type, each with different weightedRoutingPolicies weights and unique setIdentifier values (e.g., “dev” with weight 10, “live” with weight 90).Record Configuration
name, type, and zoneId properties are immutable. Changing any of these requires recreating the record.\"\" inside the string to concatenate segments: "first255characters\"\"morecharacters".Zone Management
allowOverwrite: true on the record to manage zone-default NS and SOA records in a single deployment. This allows overwriting the automatically created records.allowOverwrite is not recommended for most environments. It’s primarily intended for managing NS and SOA records. The default value is false.Using a different cloud?
Explore networking guides for other cloud providers: