# DNSControl: DNS as code, one dnsconfig.js to 74 providers

> DNSControl is the MIT-licensed Go tool describing DNS as infrastructure as code in a JavaScript-compatible configuration language, with provider plugins speaking to 74 DNS providers and registrars including Route 53, Cloudflare and Gandi, and the ability to push the same records to multiple providers. Preview computes the changes, push applies them, dnscontrol init bootstraps credentials from live zones, and releases land on the v5 line about weekly.

**DNSControl/dnscontrol** — Infrastructure as code for DNS!

- Repository: https://github.com/DNSControl/dnscontrol
- Website: https://dnscontrol.org/
- Stars: 3,960 · Forks: 545
- Language: Go
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/dnscontrol-dnscontrol

## The config language, one zone in nine lines

DNSControl is infrastructure as code for DNS, with a full-featured configuration language that is JavaScript-compatible, plus plugins speaking to DNS provider APIs. The example dnsconfig.js is the whole model in miniature, NewRegistrar and NewDnsProvider bind named credentials from creds.json, and the D function declares example.com with its registrar, its DNS provider, and the records, an A record on the apex, a CNAME from www, an MX record with priority five, and a test A record. The language being JavaScript means macros, loops and variables work in zone definitions, so hundreds of similar zones collapse into functions, which is the leverage the bind-file world never had.

## preview, push, and the correction of drift

The workflow is two verbs with distinct risk profiles. Running dnscontrol preview talks to the providers, in the example name.com as registrar and Route 53 as DNS host, and determines what changes need to be made, the dry run that makes the tool reviewable in pull requests. Running dnscontrol push makes those changes so the records update correctly. Because desired state lives in the file and actual state is fetched from providers, drift is detected as a diff rather than discovered by outage, and the same records can be sent to multiple providers, the dual-provider pattern behind many DNS failover setups, from one declaration. The preview-push split is what makes DNS safe to change in CI, a pull request carries the config diff, preview runs in CI against the real provider APIs producing the record-level change list as a comment, and push only happens on merge, so the review unit is exactly the records that will move.

## dnscontrol init imports what exists

The quickest start is dnscontrol init, an interactive wizard that asks for the DNS provider and registrar, verifies credentials, and writes a working creds.json and dnsconfig.js including the records that already exist in the zones. That last clause matters for adoption, the classic barrier to DNS-as-code is bootstrapping hundreds of existing records into the declarative format by hand, and the importer removes it, so a team starts from a faithful snapshot of reality rather than an aspirational file. The documentation site's Getting Started page walks the full path, and for teams wanting GitOps from the first commit, the dns-config starter repository clones a ready structure. Because init verifies credentials as part of the wizard, the first run also proves the creds.json format is right for the provider, catching the authentication errors at setup time rather than mid-migration.

## Seventy-four providers, registrar and host distinguished

The provider table lists 74 DNS providers and registrars, from the expected cloud set, Route 53, Azure DNS, Google Cloud, Cloudflare, DigitalOcean, Linode, Vultr, Oracle and Scaleway, through registrars like Namecheap, Namecheap.com, Porkbun, OpenSRS and Realtime Register, to the self-hosted edge, BIND, PowerDNS, AdGuard Home, Mikrotik, OpenWrt and Unifi. Footnotes carry the load-bearing distinction, superscript one marks providers also supporting registrar functions, superscript two marks registrar-only entries, and the rest are DNS hosts. AXFRDDNS and DNSOVERHTTPS appear among them, meaning zone transfer and DNS-over-HTTPS endpoints can act as providers. The provider model is extensible, so more can be added, and the table is generated into the README between markers. The BIND entry in that table is worth noting for migrations, a BIND zone file can act as a provider, so an existing file-based DNS estate can be imported and later moved to an API provider with the config unchanged except for the provider binding.

## The dependency list is the provider list

The go.mod makes the abstraction's cost visible, direct requirements include the AWS SDK with route53 and route53domains services, the Cloudflare cloudflare-go client, Azure's DNS and private DNS resource manager SDKs, DigitalOcean's godo, DNSimple's v8 client, Exoscale's egoscale, Gandi's client, Akamai's edgegrid, Aliyun's SDK, G-Core's DNS SDK, a DoH client, and miekg's dns library for the wire-format providers, each a provider plugin's vocabulary. The module is github.com/DNSControl/dnscontrol/v5 on Go 1.27, and the binary runs anywhere Go runs, Linux, macOS and Windows, with the Docker container as the easiest path per the README. The puppeteer entry in the root package.json's allowScripts belongs to the documentation toolchain rather than the binary, marking where a browser is permitted to download for docs rendering, a deliberate allowlist in a project otherwise careful about its supply chain.

## The container, and what it ships

The Docker invocation is one line mounting the working directory over /dns:

```shell
docker run --rm -it -v "$(pwd):/dns"  ghcr.io/dnscontrol/dnscontrol preview
```

The Dockerfile is minimal by design, alpine pinned by digest, tzdata added because Go's time handling needs it externally for providers like TRANSIP, ca-certificates for HTTPS, and the platform-specific binary copied in with dnscontrol as the entrypoint. The image carries no provider-specific extras, since all provider logic is compiled into the single static binary, so the container is a delivery wrapper rather than an environment. The tzdata dependency comment names its reason, some providers such as TRANSIP need external timezone data, the kind of runtime detail that only surfaces after a provider-specific failure, recorded here so the next packager does not rediscover it.

## A project managed like its own tooling

The repository shows the discipline of a mature infrastructure project, commitlint enforcing conventional commits, prettier and a linkspector configuration checking the documentation's links, golangci-lint and staticcheck for Go quality, goreleaser for releases, and a REFACTORING_PROJECTS.md tracking internal cleanup as first-class work. The benefits section states the case with comparisons, less error-prone than editing a BIND zone file, more reproducible than clicking buttons on a web page, and the release train is active, v5.0.4 on September 8, v5.1.0 on September 16 and v5.2.0 on 2026-09-22, with the main branch pushed 2026-09-29, the day before this writing. The docs live separately under docs.dnscontrol.org with the documentation and documentation directories in the repo feeding them, and the Google discussion group linked at the top remains the community venue beside the issue tracker.

## Conclusion

Use DNSControl when DNS zones span providers, when changes should be reviewed as diffs before touching production records, or when DNS belongs in Git like the rest of the infrastructure, since its configuration language, provider abstraction and preview-push flow are built for exactly that. It manages DNS through provider APIs, not a DNS server itself. Before adopting, start with dnscontrol init to import existing zones rather than hand-writing the config, check the provider table's footnotes for registrar versus DNS host capability, and use the dns-config starter repo if you want the GitOps structure ready-made.

## FAQ

### what is dns control?

In this context, DNSControl is an infrastructure-as-code tool for DNS, a Go binary with a JavaScript-compatible configuration language and provider plugins for 74 DNS providers and registrars. dnscontrol preview reports what would change against the live providers, and dnscontrol push applies those changes.

### Should I use Cname or A?

In DNSControl's configuration both are record types you declare, A maps a name to an address and CNAME aliases one name to another, as the example zone shows with A on the apex and CNAME from www to the apex. The choice is DNS semantics, an A record answers with an IP directly while a CNAME delegates to another name.

### Which providers does DNSControl support?

74 DNS providers and registrars are supported, including Route 53, Cloudflare, Azure DNS, Google Cloud, Gandi, Namecheap, BIND, PowerDNS, AdGuard Home, Mikrotik and Unifi. Footnotes distinguish providers that also support registrar functions from registrar-only entries, and the provider model is extensible for adding more.

## Sources

- [DNSControl/dnscontrol on GitHub](https://github.com/DNSControl/dnscontrol)
- [License: MIT](https://github.com/DNSControl/dnscontrol/blob/main/LICENSE)
- [Project website](https://dnscontrol.org/)
- [README](https://github.com/DNSControl/dnscontrol/blob/main/README.md)
- [Releases](https://github.com/DNSControl/dnscontrol/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dnscontrol-dnscontrol
