Blog / DevOps
DevOpsdns 5 min min read

Managing DNS Zones as Code

10.09.2026 · Peter Hudec

Manual DNS edits leave no history and no easy undo. dnscontrol treats zones as code: declarative config, and a dry-run before every change. git brings the history revision.

Managing DNS Zones as Code
Photo by Hal Gatewood on Unsplash

If you run more than a handful of domains, you know the drill: log into a web console, find the right zone, add a record, hope you didn’t typo a hostname. There’s no history of who changed what, no review before it goes live, and no undo if it breaks production.

That’s exactly the gap dnscontrol and git close.

dnscontrol solves this by treating DNS zones as code: you describe your records declaratively in JavaScript configuration files, commit them to git, and let a tool compute and apply the diff against your actual DNS provider(s). It’s the same idea as infrastructure-as-code applied to DNS specifically.

The dnscontrol model

At the core, dnscontrol works with two commands:

dnscontrol preview
dnscontrol push

dnscontrol preview computes the difference between what’s declared in your config and what’s actually live at the provider, and prints it - without touching anything. dnscontrol push applies that same diff for real. This separation means you always get a dry-run: you can read exactly which records will be added, changed, or removed before anything happens.

Importing an existing zone

Bringing an existing domain under dnscontrol doesn’t mean hand-transcribing every record. dnscontrol can import a zone straight from the current provider and generate the equivalent configuration file automatically, ready to review and commit as the new source of truth.

Reusing repetitive records with macros

Because a dnscontrol config is just JavaScript, you’re not stuck writing every record out inline for every domain. Anything that repeats across zones - nameservers, CAA policy, mail server MX/SRV records, SPF/DMARC boilerplate - can be factored into a plain variable or function, defined once, and reused everywhere.

In this repo’s dnsconfig.js, shared record sets are declared as arrays up top:

var CAA_5OK_DEFAULT = [
    CAA_BUILDER({
        label: "@",
        iodef: "hostmaster@5ok.sk",
        issue: ["letsencrypt.org"],
        issuewild: ["letsencrypt.org"],
    }),
];

var MX_5OK_GW02 = [
    MX("@", 5, "mail-gw02.5ok.network."),
    MX("@", 10, "fire.5ok.network."),
];

and then dropped straight into a D(...)/D_EXTEND(...) call as if they were individual records, e.g. in config/zones/sk.5ok.js:

D("5ok.sk", REG_NONE,
    DnsProvider(DNS_BIND),
    DefaultTTL(600),
    NS_5OK_HE,
    CAA_5OK_DEFAULT,
    MX_5OK_GW02,
    ...
);

The payoff shows up the first time one of these needs to change. When the mail gateway migrates, the CAA-authorized issuer changes, or an SPF/DMARC rule needs tightening, it’s a one-line edit to the shared variable or function - every domain referencing it picks up the change on the next dnscontrol push. Compare that to hunting down and editing the same boilerplate copy-pasted across a dozen zone files, and inevitably missing one.

Why this beats manual edits

A few concrete benefits fall out of putting DNS in git and behind dnscontrol:

  • Full change history. Every record change is a git commit. git log and git blame tell you exactly who changed what, when, and - if commit messages are used well - why. Try getting that out of a typical DNS provider’s web UI.
  • Review and approval workflows. Because changes are just commits, they can go through the same pull-request review your team already uses for application code. A second person can look at a diff like + TXT("@", "v=spf1 ...") and catch a mistake before it’s live, instead of after customers start reporting broken email.
  • Safe, easy rollback. If a change turns out to be wrong, git revert gets you back to a known-good state, and dnscontrol push applies it. No need to remember what the old value was or dig through provider audit logs (if they even exist).
  • A diffable dry-run before every change. dnscontrol preview shows precisely what’s about to change, in a readable format, before dnscontrol push makes it real. Manual UI edits give you no equivalent safety net.
  • Multiple people, one source of truth. Several people can propose DNS changes concurrently via branches/PRs without stepping on each other or silently overwriting one another’s edits in a shared web console.

Conclusion

None of this is DNS-specific magic - it’s the same discipline that makes infrastructure-as-code valuable everywhere else: a single declarative source of truth, versioned history, and a dry-run before every apply. dnscontrol just brings that discipline to a part of the stack that, for a lot of teams, still lives entirely in a web browser tab.

Written by
Peter Hudec
Share