Send, receive, and shield emails with PostScale. One API, EU-hosted. PostScale

    Automation

    DNS as Code Best Practices

    A practical guide to managing DNS as code with ownership, review, previews, drift detection, scoped credentials, and safe migration patterns.

    Updated

    TL;DR

    DNS as code works when one repository is the source of truth, every production change has a preview, and provider credentials are scoped tightly. The goal is not just automation. It is reviewable DNS: clear ownership, small diffs, reversible changes, drift detection, and fewer emergency dashboard edits.

    What you'll learn

    • Define the source-of-truth model for DNS as code
    • Choose repository structure and ownership rules
    • Reduce DNS change risk with previews and drift detection
    • Avoid common Terraform and DNSControl mistakes

    DNS as code is not about making DNS clever.

    It is about making DNS boring:

    small diff -> review -> preview -> apply -> audit trail

    That is a better operating model than dashboard edits, screenshots, and "who changed the MX record?"

    Source of Truth

    Pick one source of truth per zone.

    Good:

    example.com -> DNSControl repo
    example.net -> Terraform workspace

    Bad:

    example.com -> dashboard + Terraform + script + support ticket

    Multiple writers create drift. Drift creates surprise. Surprise is how DNS incidents start.

    Repository Structure

    Keep zones easy to find.

    DNSControl example:

    dns/
      dnsconfig.js
      zones/
        example.com.js
        example.net.js
      macros/
        email.js
        web.js

    Terraform example:

    terraform/
      dns/
        zones/
          example-com.tf
          example-net.tf
        modules/
          standard-email/
          static-site/

    Avoid one giant file once more than one team owns records.

    Ownership

    Every production zone needs an owner.

    At minimum:

    example.com
    owner: platform
    reviewers: platform-oncall, security
    high-risk records: MX, DS, CAA, apex

    Ownership matters because DNS records map to business systems:

    • MX records belong with email operations.
    • CAA records belong with certificate owners.
    • DS records belong with whoever manages DNSSEC.
    • Apex records usually belong with platform or edge.
    • Verification TXT records need expiry and cleanup.

    Make Diffs Reviewable

    Reviewers should see records, not noise.

    Prefer stable ordering:

    A / AAAA
    CNAME / ALIAS
    MX
    TXT
    CAA
    SRV
    DNSSEC-sensitive records

    Use comments sparingly but clearly:

    // Required by Microsoft 365 tenant verification. Remove after migration.
    TXT("@", "MS=ms12345678");

    Do not leave stale verification records forever. They are clutter and sometimes risk.

    Preview Before Apply

    Every production change should show a diff before it ships:

    dnscontrol preview
    terraform plan

    Reviewers should look for:

    • deleted records
    • changed targets
    • low TTLs
    • broad TXT edits
    • accidental CNAME conflicts
    • apex changes
    • DNSSEC and delegation changes

    If the preview is too noisy to review, fix the code structure before trusting the automation.

    Use Scoped Credentials

    DNS provider tokens in CI should be boring and limited.

    Prefer:

    token: prod-example-com
    scope: example.com only
    permissions: read/write records

    Avoid:

    token: global-admin
    scope: every zone
    permissions: everything

    If an attacker steals a CI token, the blast radius should be one zone, not the account.

    Separate Environments

    Do not use production DNS as a staging playground.

    Use clear zones:

    example.com          production
    staging.example.com  staging
    dev.example.com      development

    Or use separate domains when policy requires:

    example.com
    example.dev

    Keep production apply credentials out of staging workflows.

    Drift Detection

    Run a scheduled preview against production.

    If the tool says records would change even though no PR merged, you have drift.

    Common response:

    1. Identify the change.
    2. Decide if it was legitimate emergency work.
    3. Backfill it into code or revert it.
    4. Record why it happened.

    Do not blindly overwrite drift. The dashboard change may have restored production during an incident.

    High-Risk Records

    Some records deserve extra review:

    RecordWhy
    NSChanges delegation and provider authority
    DSCan break DNSSEC validation
    DNSKEYDNSSEC chain of trust
    MXControls inbound email
    SPF/DKIM/DMARCControls email authentication
    CAAControls certificate issuance
    Apex A/AAAA/ALIASControls main website traffic
    WildcardsCan hide missing records and change many names at once

    Protect these with CODEOWNERS, required reviewers, or policy checks.

    Rollback

    Rollback should be:

    git revert <commit>

    not:

    panic-edit records in three dashboards

    For major migrations, prepare rollback in advance:

    • old provider still serving
    • old records still known
    • TTLs lowered before cutover
    • DS rollback plan written down
    • monitoring ready

    Terraform Notes

    Terraform is good when DNS is part of wider infrastructure.

    Watch for:

    • state locking
    • workspace boundaries
    • imported records
    • provider drift
    • plan output readability
    • accidental destroy operations

    Use modules for repeated patterns, but do not hide important DNS records behind abstraction so deep reviewers cannot see them.

    DNSControl Notes

    DNSControl is good when DNS is the center of the workflow.

    It is especially useful for:

    • many zones
    • multi-provider DNS
    • DNS-specific macros
    • readable previews
    • keeping providers synchronized

    Keep macros simple. DNS records should remain obvious to people who will debug them at 02:00.

    Baseline Policy

    For production DNS as code:

    1. One source of truth per zone.
    2. Pull request required for every change.
    3. Preview required before merge.
    4. Apply only from protected branch.
    5. Zone-scoped credentials.
    6. Drift check at least daily.
    7. Extra review for NS, DS, MX, CAA, and apex records.
    8. Emergency edits backfilled into code.
    9. Rollback tested before migrations.

    That is enough process to prevent most DNS mistakes without turning DNS into bureaucracy.

    Frequently asked questions

    What does DNS as code mean?
    DNS as code means DNS records are declared in version-controlled files and applied through reviewable automation rather than edited manually in a dashboard.
    What is the main benefit?
    Reviewability. You can see exactly what record changed, who approved it, when it shipped, and how to roll it back.
    Can I still use the DNS dashboard?
    Yes, but avoid routine production edits there. Emergency dashboard changes should be backfilled into code immediately after the incident.
    Should one repo manage all zones?
    For small teams, yes. Larger teams may split by ownership, but they still need clear boundaries so two systems do not manage the same record set.
    How do I handle secrets?
    Use CI secrets or a secret manager, not committed files. Prefer zone-scoped credentials and separate read/preview from write/apply access where possible.
    What records need extra review?
    Apex A/AAAA, CNAME/ALIAS, MX, SPF, DKIM, DMARC, CAA, NS, DS, DNSKEY, and any TTL change before a migration.

    Ready to manage your DNS with confidence?

    DNScale provides anycast DNS hosting with a global network, real-time analytics, and an easy-to-use API.

    Start free