Andrew Mercer
on this page

1. What octoDNS Is

octoDNS is a tool from GitHub for managing DNS records as code, across one or more DNS providers, from a single declarative source of truth. It doesn't run as a DNS server itself (unlike everything else in this set of guides) — it's a synchronization tool: you describe the records you want in YAML, and octoDNS pushes (or diffs, or pulls) that state to/from real DNS providers via their APIs — Route 53, Cloudflare, Google Cloud DNS, Azure DNS, NS1, PowerDNS, and dozens more, including plain BIND zone files as a provider.

The core problem it solves: DNS records managed by hand through provider web consoles or ad hoc API scripts drift, go undocumented, and have no change history or review process. octoDNS treats zone data the way infrastructure-as-code tools treat infrastructure — version-controlled, diffable, reviewable in a pull request, and reproducibly applied.

2. Installation

python3 -m venv env
source env/bin/activate
pip install octodns
# Provider-specific plugins are separate packages, e.g.:
pip install octodns-route53 octodns-cloudflare

3. Core Concepts

  • Config file (config.yaml) — defines providers and which zones each is a source/target for.
  • Zone files (one YAML file per zone, e.g. example.com.yaml) — the actual declarative record data.
  • Providers — a Python-plugin abstraction over each DNS backend's API, each implementing the same source/target interface so octoDNS's diff/apply logic doesn't need to know provider-specific quirks.
  • Sources vs. targets — a provider can be a source (read records from) and/or a target (write records to). This is what makes multi-provider replication and migration workflows possible: read from one provider, write to another, or read from a YAML file and write to several providers simultaneously for redundant/multi-vendor DNS hosting.

4. Example Configuration

config.yaml

providers:
  config:
    class: octodns.provider.yaml.YamlProvider
    directory: ./config
    default_ttl: 3600
    enforce_order: false

  route53:
    class: octodns_route53.Route53Provider
    access_key_id: env/AWS_ACCESS_KEY_ID
    secret_access_key: env/AWS_SECRET_ACCESS_KEY

zones:
  example.com.:
    sources:
      - config
    targets:
      - route53

config/example.com.yaml

'':
  - type: A
    values:
      - 192.0.2.10
      - 192.0.2.11
  - type: MX
    values:
      - exchange: 10
        preference: 10
        # (octodns MX format: 'value: 10 mail.example.com.')

www:
  type: CNAME
  value: example.com.

mail:
  type: A
  value: 192.0.2.20

_dmarc:
  type: TXT
  value: "v=DMARC1; p=reject;"

'' (empty string) represents the zone apex, the same role @ plays in a BIND zone file. Note credentials are referenced as env/AWS_ACCESS_KEY_ID rather than embedded in the YAML — octoDNS resolves these from environment variables at runtime, keeping secrets out of the version-controlled config.

5. The Plan/Apply Workflow

octoDNS's defining safety feature, directly analogous to Terraform's plan/apply:

# Compute and print a diff between desired (YAML) and actual (provider) state — no changes made
octodns-sync --config-file=config.yaml

# Apply the changes shown by the plan
octodns-sync --config-file=config.yaml --doit

Without --doit, octoDNS only ever shows what it would change — added, removed, and modified records, per provider — making it safe to run in CI on every pull request for review before a human (or an automated merge-triggered apply) commits to the change. This plan-before-apply discipline is the main practical advantage over editing records directly in a provider's console: every DNS change becomes a reviewable, revertible diff instead of an unaudited click.

6. Multi-Provider and Migration Use Cases

Because sources and targets are decoupled, common patterns include:

  • Multi-provider redundancy: define records once, push identically to two independent DNS providers (e.g., Route 53 and NS1) so a single vendor's outage doesn't take down resolution — the same resilience goal BIND's multi-secondary setup targets, but across vendors rather than just servers.
  • Provider migration: set an existing provider as the source to pull current live records into YAML automatically (octodns-dump), review/clean the result, then add the new provider as a target and cut over — avoiding a manual, error-prone re-entry of every record during a DNS provider switch.
  • Zone file interop: the YamlProvider can coexist with a zonefile-format provider, letting octoDNS bridge a hand-maintained BIND zone file into the same reviewable pipeline as cloud-hosted zones.

7. Dynamic Records / Provider-Specific Features

Cloud DNS providers support routing features beyond plain static records — Route 53's weighted/latency/geolocation routing (see the dedicated geolocation-routing guide), Cloudflare's proxying — and octoDNS exposes these through provider-specific YAML extensions (octodns.dynamic blocks) rather than forcing everything into a lowest-common-denominator record model:

www:
  type: A
  dynamic:
    pools:
      us-east:
        values:
          - value: 192.0.2.10
      eu-west:
        values:
          - value: 192.0.2.20
    rules:
      - geos:
          - NA
        pool: us-east
      - pool: eu-west
  value: 192.0.2.10   # fallback/default

Not every provider supports every dynamic feature, and octoDNS will refuse (rather than silently degrade) to apply a construct the target provider can't represent — worth checking a given provider's plugin documentation before assuming a feature like this is portable across providers.

8. CI/CD Integration

A typical workflow: DNS YAML lives in a Git repo; a CI pipeline runs octodns-sync (plan mode) on every pull request and posts the diff as a PR comment for review; merging to the main branch triggers a second pipeline run with --doit against the real providers. This turns DNS changes into the same reviewed, auditable process as any other infrastructure change, with the repo's Git history serving as the change log BIND/Unbound configs don't have natively.

9. octoDNS vs. Running Your Own Server

octoDNS is orthogonal to, not a replacement for, the servers covered in the other guides — it's a management layer above DNS hosting, not a resolver or authoritative daemon itself:

octoDNS BIND / CoreDNS / cloud DNS
Role Declarative config management, plan/apply Actually answers DNS queries
Runs continuously? No — invoked on demand / in CI Yes — a running daemon or managed service
Data source of truth YAML in version control Whatever the provider/zone file holds live

A BIND zone file can be an octoDNS target (YamlProvider writing zone-file syntax, or specific zonefile-format providers), meaning octoDNS can manage even a self-hosted BIND setup's zone files in the same reviewable pipeline as cloud providers — useful if you want IaC-style discipline without moving off self-hosted authoritative servers.

  • Project repository: https://github.com/octodns/octodns
  • Provider plugin list: https://github.com/octodns/octodns#providers