Dynamic response
Dynamic response selects which records from an RRset are returned for a DNS query. Pickers define how records are selected, while metadata provides the values compared per query — country, ASN, subnet, coordinates, or weight.
The Continent picker with continents: Africa metadata, for instance, returns that record only to clients in Africa.
Configure dynamic response
- 1
Create a record set
Create a DNS record set in advanced mode (steps 1–4).
- 2
Enable the Dynamic response toggle
Turn on Dynamic response.
- 3
Select pickers
Select a preset, or add pickers manually. Pickers run in the order shown, top to bottom — drag to change priority.

- 4
Specify the record value
Enter the DNS record value that this metadata applies to.
- 5
Set metadata
Add the metadata required by the selected pickers and specify its value. Use + to add another metadata field to the same record.
- 6
Add more records (optional)
Click Add record to add more records and repeat steps 4 and 5.
- 7
Save the configuration
Click Create.
Available pickers
Select pickers to define routing logic. Presets are editable — select a preset and then adjust picker order or add pickers manually.
Available metadata
Each record can carry one or more metadata fields. Add the fields required by the selected pickers.
Examples of preset settings
With the "Geo DNS" preset, metadata of different types can be added to each record.
The latlong and weight metadata are ignored if the corresponding pickers are not added from the list.
CDB evaluates matching metadata in picker order: IP → ASN → country → continent → region. If no criterion matches, it uses a record with fallback=true; if no fallback exists, the response is formed from the remaining records according to First N. Unhealthy records are excluded first when Health Checks are configured.
Example: The "Geo DNS" preset is selected with one record per response in the First N.

Two records are added with IP metadata:
- For
10.0.0.0record, subnet 192.168.1.0/24 - For
10.0.0.1record, subnet 192.0.2.0/24

A client with an IP from subnet 192.168.1.0/24 receives the record 10.0.0.0. A client from subnet 192.0.2.0/24 receives the record 10.0.0.1.
With the "Geo distance" preset, the resolver analyzes the proximity of the request's geolocation to the latlong (latitude and longitude) specified in the record's metadata. Clients receive the record with the nearest coordinates.
Example: The "Geo distance" preset is selected with one record per response in the First N.

Two records are added with the following coordinates:
- For the
10.0.0.0record, latlong 51.52318152049715/-0.13458412218999416 (central London) - For the
10.0.0.1record, latlong 48.859741241898114/2.3415648470109653 (central Paris)

A client closer to 51.52318152049715/-0.13458412218999416 (central London) receives an A record with the value 10.0.0.0. A client closer to 48.859741241898114/2.3415648470109653 (central Paris) receives an A record with the value 10.0.0.1.
With the "Weighted shuffle" preset, the probability of a particular record appearing in the answer is controlled by specifying its weight.
If the metadata field "weight" is left empty, a default value of 50, 33.3, or 25 is applied depending on the number of records. Each record without an explicit weight has equal probability.
When the number of resource records exceeds First N, probability determines which records appear per response. A record's probability is its weight divided by the sum of the weights of all participating records:
P1= W1 / Sumi(Wi)
Example: The "Weighted shuffle" preset is enabled with max one record per response in the First N:

Metadata is specified as follows:
- 1.2.3.4 with the "weight" 90, probability = 0.6
- 4.5.6.7 with the "weight" 10, probability = 0.06(6)
- 7.8.9.0 with the "weight" empty (i.e., set by default to 50), probability = 0.3(3)

Over the course of 300 answers, each record appears with the following frequency:
~180responses with the record1.2.3.4(weight 90)~20responses with the record4.5.6.7(weight 10)~100responses with the record7.8.9.0(weight 50)
Dynamic response is configured on the RRset level. Each record in resource_records carries a meta object with routing criteria, and the pickers array defines the strategy the resolver uses to select a record per query. The first_n picker controls how many records appear in each response.
An API token is required.
Export these variables:
export GCORE_API_KEY="{YOUR_API_KEY}"
export ZONE_NAME="{YOUR_ZONE_NAME}"
export RECORD_NAME="{RECORD_FQDN}"
RECORD_NAME is the fully qualified domain name (FQDN) of the record. For an apex record it equals ZONE_NAME; for a subdomain it is the full FQDN — www.example.com.
Weighted shuffle
Weighted shuffle distributes queries across records based on their weight metadata value — higher weight means the record appears more often, proportional to its weight relative to the total. Use the weighted_shuffle picker together with first_n to limit the number of records per response.
import os
from gcore import CDB
client = CDB()
rrset = client.dns.zones.rrsets.create(
"A",
zone_name=os.environ["ZONE_NAME"],
rrset_name=os.environ["RECORD_NAME"],
resource_records=[
{"content": ["1.2.3.4"], "meta": {"weight": 90}},
{"content": ["4.5.6.7"], "meta": {"weight": 10}},
{"content": ["7.8.9.0"], "meta": {"weight": 50}},
],
pickers=[
{"type": "weighted_shuffle"},
{"type": "first_n", "limit": 1},
],
ttl=300,
)
print(rrset.name, rrset.pickers)
package main
import (
"context"
"fmt"
"os"
gcore "github.com/G-Core/gcore-go"
"github.com/G-Core/gcore-go/dns"
)
func main() {
client := gcore.NewClient()
ctx := context.Background()
rrset, err := client.DNS.Zones.Rrsets.New(ctx, "A", dns.ZoneRrsetNewParams{
ZoneName: os.Getenv("ZONE_NAME"),
RrsetName: os.Getenv("RECORD_NAME"),
ResourceRecords: []dns.ZoneRrsetNewParamsResourceRecord{
{Content: []any{"1.2.3.4"}, Meta: map[string]any{"weight": 90}},
{Content: []any{"4.5.6.7"}, Meta: map[string]any{"weight": 10}},
{Content: []any{"7.8.9.0"}, Meta: map[string]any{"weight": 50}},
},
Pickers: []dns.ZoneRrsetNewParamsPicker{
{Type: "weighted_shuffle"},
{Type: "first_n", Limit: gcore.Int(1)},
},
Ttl: gcore.Int(300),
})
if err != nil {
panic(err)
}
fmt.Println(rrset.Name, rrset.Pickers)
}
curl -X POST "https://api.cdb-staging.cdn.orange.com/dns/v2/zones/${ZONE_NAME}/${RECORD_NAME}/A" \
-H "Authorization: APIKey $GCORE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ttl": 300,
"resource_records": [
{"content": ["1.2.3.4"], "meta": {"weight": 90}},
{"content": ["4.5.6.7"], "meta": {"weight": 10}},
{"content": ["7.8.9.0"], "meta": {"weight": 50}}
],
"pickers": [
{"type": "weighted_shuffle"},
{"type": "first_n", "limit": 1}
]
}'
The API returns the created RRset with its picker configuration:
{
"name": "example.com",
"type": "A",
"ttl": 300,
"pickers": [
{"type": "weighted_shuffle", "strict": false},
{"type": "first_n", "limit": 1, "strict": false}
],
"resource_records": [
{"content": ["1.2.3.4"], "enabled": true, "meta": {"weight": 90}},
{"content": ["4.5.6.7"], "enabled": true, "meta": {"weight": 10}},
{"content": ["7.8.9.0"], "enabled": true, "meta": {"weight": 50}}
]
}
Geo DNS
Geo DNS routes queries based on the client's geolocation. The resolver evaluates IP, ASN, country, continent, and region metadata in that order and uses the first criterion that produces a match. Add a record with "fallback": true to handle queries that match no other criteria. Use first_n to limit how many matching records appear in the response. Set meta.countries to two-letter ISO 3166-1 alpha-2 country codes.
import os
from gcore import CDB
client = CDB()
rrset = client.dns.zones.rrsets.create(
"A",
zone_name=os.environ["ZONE_NAME"],
rrset_name=os.environ["RECORD_NAME"],
resource_records=[
{"content": ["10.0.0.1"], "meta": {"countries": ["de", "at"]}},
{"content": ["10.0.0.2"], "meta": {"countries": ["fr", "be"]}},
{"content": ["10.0.0.3"], "meta": {"fallback": True}},
],
pickers=[
{"type": "geodns"},
{"type": "first_n", "limit": 1},
],
ttl=300,
)
print(rrset.name, rrset.pickers)
package main
import (
"context"
"fmt"
"os"
gcore "github.com/G-Core/gcore-go"
"github.com/G-Core/gcore-go/dns"
)
func main() {
client := gcore.NewClient()
ctx := context.Background()
rrset, err := client.DNS.Zones.Rrsets.New(ctx, "A", dns.ZoneRrsetNewParams{
ZoneName: os.Getenv("ZONE_NAME"),
RrsetName: os.Getenv("RECORD_NAME"),
ResourceRecords: []dns.ZoneRrsetNewParamsResourceRecord{
{Content: []any{"10.0.0.1"}, Meta: map[string]any{"countries": []string{"de", "at"}}},
{Content: []any{"10.0.0.2"}, Meta: map[string]any{"countries": []string{"fr", "be"}}},
{Content: []any{"10.0.0.3"}, Meta: map[string]any{"fallback": true}},
},
Pickers: []dns.ZoneRrsetNewParamsPicker{
{Type: "geodns"},
{Type: "first_n", Limit: gcore.Int(1)},
},
Ttl: gcore.Int(300),
})
if err != nil {
panic(err)
}
fmt.Println(rrset.Name, rrset.Pickers)
}
curl -X POST "https://api.cdb-staging.cdn.orange.com/dns/v2/zones/${ZONE_NAME}/${RECORD_NAME}/A" \
-H "Authorization: APIKey $GCORE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ttl": 300,
"resource_records": [
{"content": ["10.0.0.1"], "meta": {"countries": ["de", "at"]}},
{"content": ["10.0.0.2"], "meta": {"countries": ["fr", "be"]}},
{"content": ["10.0.0.3"], "meta": {"fallback": true}}
],
"pickers": [
{"type": "geodns"},
{"type": "first_n", "limit": 1}
]
}'
The API returns:
{
"name": "example.com",
"type": "A",
"ttl": 300,
"pickers": [
{"type": "geodns", "strict": false},
{"type": "first_n", "limit": 1, "strict": false}
],
"resource_records": [
{"content": ["10.0.0.1"], "enabled": true, "meta": {"countries": ["de", "at"]}},
{"content": ["10.0.0.2"], "enabled": true, "meta": {"countries": ["fr", "be"]}},
{"content": ["10.0.0.3"], "enabled": true, "meta": {"fallback": true}}
]
}
Geo distance
Geo distance routes queries to the record whose coordinates are closest to the client's geolocation. Use the geodistance picker with meta.latlong set to a two-element array [latitude, longitude] in decimal degrees.
import os
from gcore import CDB
client = CDB()
rrset = client.dns.zones.rrsets.create(
"A",
zone_name=os.environ["ZONE_NAME"],
rrset_name=os.environ["RECORD_NAME"],
resource_records=[
{"content": ["10.0.0.1"], "meta": {"latlong": [51.52, -0.13]}},
{"content": ["10.0.0.2"], "meta": {"latlong": [48.86, 2.34]}},
],
pickers=[
{"type": "geodistance"},
{"type": "first_n", "limit": 1},
],
ttl=300,
)
print(rrset.name, rrset.pickers)
package main
import (
"context"
"fmt"
"os"
gcore "github.com/G-Core/gcore-go"
"github.com/G-Core/gcore-go/dns"
)
func main() {
client := gcore.NewClient()
ctx := context.Background()
rrset, err := client.DNS.Zones.Rrsets.New(ctx, "A", dns.ZoneRrsetNewParams{
ZoneName: os.Getenv("ZONE_NAME"),
RrsetName: os.Getenv("RECORD_NAME"),
ResourceRecords: []dns.ZoneRrsetNewParamsResourceRecord{
{Content: []any{"10.0.0.1"}, Meta: map[string]any{"latlong": []float64{51.52, -0.13}}},
{Content: []any{"10.0.0.2"}, Meta: map[string]any{"latlong": []float64{48.86, 2.34}}},
},
Pickers: []dns.ZoneRrsetNewParamsPicker{
{Type: "geodistance"},
{Type: "first_n", Limit: gcore.Int(1)},
},
Ttl: gcore.Int(300),
})
if err != nil {
panic(err)
}
fmt.Println(rrset.Name, rrset.Pickers)
}
curl -X POST "https://api.cdb-staging.cdn.orange.com/dns/v2/zones/${ZONE_NAME}/${RECORD_NAME}/A" \
-H "Authorization: APIKey $GCORE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ttl": 300,
"resource_records": [
{"content": ["10.0.0.1"], "meta": {"latlong": [51.52, -0.13]}},
{"content": ["10.0.0.2"], "meta": {"latlong": [48.86, 2.34]}}
],
"pickers": [
{"type": "geodistance"},
{"type": "first_n", "limit": 1}
]
}'
The API returns:
{
"name": "example.com",
"type": "A",
"ttl": 300,
"pickers": [
{"type": "geodistance", "strict": false},
{"type": "first_n", "limit": 1, "strict": false}
],
"resource_records": [
{"content": ["10.0.0.1"], "enabled": true, "meta": {"latlong": [51.52, -0.13]}},
{"content": ["10.0.0.2"], "enabled": true, "meta": {"latlong": [48.86, 2.34]}}
]
}
Configure dynamic DNS responses using the gcore_dns_zone_rrset resource from the CDB Terraform provider v2. Pickers are declared in the pickers block; per-record routing criteria go in resource_records[].meta. The meta field is a map of strings — array-type values (countries, continents, latlong) must be JSON-encoded with jsonencode().
Weighted shuffle
Weighted shuffle distributes queries across records based on the weight metadata value. Higher weight means higher probability. Pair it with first_n to limit the number of records returned per response.
resource "gcore_dns_zone" "example" {
name = "yourdomain.com"
}
resource "gcore_dns_zone_rrset" "weighted" {
zone_name = gcore_dns_zone.example.name
rrset_name = gcore_dns_zone.example.name
rrset_type = "A"
ttl = 300
pickers = [
{ type = "weighted_shuffle" },
{ type = "first_n", limit = 1 },
]
resource_records = [
{
content = ["1.2.3.4"]
meta = { weight = "90" }
},
{
content = ["4.5.6.7"]
meta = { weight = "10" }
},
{
content = ["7.8.9.0"]
meta = { weight = "50" }
},
]
# terraform import gcore_dns_zone_rrset.weighted yourdomain.com/yourdomain.com/A
}
Geo DNS
Geo DNS routes queries based on the client's location. The resolver matches IP, ASN, country, continent, and region metadata in that order and uses the first match. Add a record with fallback = "true" to handle queries that match no other criteria.
resource "gcore_dns_zone_rrset" "geodns" {
zone_name = gcore_dns_zone.example.name
rrset_name = "geo.${gcore_dns_zone.example.name}"
rrset_type = "A"
ttl = 300
pickers = [
{ type = "geodns" },
{ type = "first_n", limit = 1 },
]
resource_records = [
{
content = ["10.0.0.1"]
meta = { countries = jsonencode(["de", "at"]) }
},
{
content = ["10.0.0.2"]
meta = { countries = jsonencode(["fr", "be"]) }
},
{
content = ["10.0.0.3"]
meta = { fallback = "true" }
},
]
# terraform import gcore_dns_zone_rrset.geodns yourdomain.com/geo.yourdomain.com/A
}
Set meta.countries to two-letter ISO 3166-1 alpha-2 country codes. Country codes are listed in the dynamic response article.
Geo distance
Geo distance routes queries to the record with coordinates nearest to the client. Set meta.latlong to a JSON-encoded two-element array [latitude, longitude] in decimal degrees.
resource "gcore_dns_zone_rrset" "geodistance" {
zone_name = gcore_dns_zone.example.name
rrset_name = "cdn.${gcore_dns_zone.example.name}"
rrset_type = "A"
ttl = 300
pickers = [
{ type = "geodistance" },
{ type = "first_n", limit = 1 },
]
resource_records = [
{
content = ["10.0.0.1"]
meta = { latlong = jsonencode([51.52, -0.13]) } # London
},
{
content = ["10.0.0.2"]
meta = { latlong = jsonencode([48.86, 2.34]) } # Paris
},
]
# terraform import gcore_dns_zone_rrset.geodistance yourdomain.com/cdn.yourdomain.com/A
}
Delete a dynamic record
Remove the resource block — Terraform detects the missing declaration and deletes the RRset on the next terraform apply.
# Remove or comment out the resource block:
# resource "gcore_dns_zone_rrset" "weighted" { ... }
terraform apply