dns-sync
One binary. All your DNS.
A lightweight alternative to OctoDNS built on .NET. A single compiled binary that synchronizes your DNS records across providers and zones — no Python runtime, no complex setup, no lock-in.
What it does
Plan before applying
preview every create, update, and delete across all zones before a single record is touched
GitOps workflow
open a PR, get a diff comment, merge to apply; one uses: line in GitHub Actions
Multi-zone, single source
define records once in a zone file, deploy to every domain automatically
Multi-provider targets
sync to Cloudflare, Route 53, GCP Cloud DNS, Porkbun, and GoDaddy simultaneously
Live provider diff
compare two providers directly with dns-sync diff, no zone file needed
Drift detection
dns-sync drift catches live record changes before they cause incidents, with JSON output for CI alerting
Zone groups
apply one zone file to every domain in a provider automatically, no per-domain config needed
Import from providers
pull live records from any provider into a local YAML zone file
Validate before apply
catch config and zone file errors before any network call is made
Single compiled binary
one self-contained executable, no runtime or dependencies to install
Get started
v0.7.0·Apr 29, 2026# Download the binary (no installation required)
curl -L https://github.com/cl8dep/dns-sync/releases/latest/download/dns-sync-linux-x64 \
-o dns-sync && chmod +x dns-sync
# Preview DNS changes
./dns-sync plan --config dns.yaml
# Apply DNS changes
./dns-sync apply --config dns.yamlFeature spotlight
Multi-zone, single source of truth
Define your DNS records once. Deploy to every domain. Both example.com and example.eu point to the same yaml_source, so the same zone file is applied to all of them — no duplication, no drift.
dns.yaml — config
providers:
yaml_source:
type: yaml
directory: ./domains
cloudflare:
type: cloudflare
api_token: ${CLOUDFLARE_API_TOKEN}
route53:
type: route53
access_key_id: ${AWS_ACCESS_KEY_ID}
secret_access_key: ${AWS_SECRET_ACCESS_KEY}
zones:
example.com.:
source: yaml_source
targets:
- cloudflare
- route53
example.eu.:
source: yaml_source
targets:
- cloudflaredomains/example.yaml — records
# domains/zones.yaml
# One file. Applied to every zone.
www:
type: CNAME
ttl: 3600
value: app.example.com.
api:
type: A
ttl: 60
value: 203.0.113.10Each zone maps to its own YAML file. Add a new domain, create its file, point it to the same source — done.
Feature spotlight
Zone groups — scale without repetition
Managing dozens of domains? zone_groups discovers every domain in a provider and applies your zone files automatically — no per-domain config block required. Mix individual zones and groups in the same config for full control over complex multi-provider setups.
dns.yaml — advanced config
providers:
yaml_source:
type: yaml
directory: ./domains
cloudflare:
type: cloudflare
api_token: ${CLOUDFLARE_API_TOKEN}
gcp:
type: gcp_cloud_dns
project: my-gcp-project
zone_groups:
# Sync all Cloudflare domains that match the pattern
production:
source: yaml_source
targets:
- cloudflare
include_pattern: ".*\.com\.$" # only .com domains
exclude_pattern: "staging\..*" # skip staging domains
# Individual zones for special requirements
zones:
internal.example.com.:
source: yaml_source
targets:
- gcpzone_groups discovers all domains from the provider at runtime. Use include_pattern and exclude_pattern regex filters to control which domains are synced.
Individual zones still work alongside groups — use them for domains that need a different source or special targets.
In action
See the plan before you apply
Run plan to preview every change across all zones — zero surprises when you apply.
$ dns-sync plan -c config.yaml --config-file .env --verbose[DBG] Auto-detected .env in current directory (2 variable(s) set)Loading config from config.yaml✓ Config valid (2 zone(s), 2 provider(s))Running pre-flight checks...✓ Source provider 'source' reachable[DBG] POST https://api.cloudflare.com/client/v4/zones[DBG] ← 200 (312 bytes)[INF] Cloudflare API authenticated successfully✓ Target provider 'cloudflare' reachableZone: example.com. → cloudflare+ example.com. MX 360010 mail.example.com., 20 mail2.example.com.+ example.com. TXT 600"v=spf1 include:_spf.google.com ~all"+ www.example.com. CNAME 3600app.example.com.+ api.example.com. A 300203.0.113.10, 203.0.113.11+ _dmarc.example.com. TXT 600"v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"5 create(s)5 total change(s) — run dns-sync apply to apply.
GitOps workflow
Review before you apply.
Open a PR, see exactly what changes. Merge to deploy.
Commit a change to any zone file and open a pull request.
dns-sync posts a diff comment showing every change before it lands.
Merge and the exact reviewed plan is applied — no re-reads, no drift.
Ready to sync your DNS?
The Getting Started guide walks you through installation, writing your first config, and running your first plan in under 5 minutes.
Compatibility
DNS providers
Multiple DNS providers are fully supported today, with more on the roadmap — contributions welcome.
| Provider | Plan | Apply |
|---|---|---|
Google Cloud DNS | Available | Available |
Cloudflare | Available | Available |
Porkbun | Available | Available |
Amazon Route 53 | Available | Available |
GoDaddy | Available | Available |