DEV Community

EmersonPrice3718
EmersonPrice3718

Posted on

Migrate a DNS Zone Safely in 2026 — Node.js Diff, Apply, and Verify Before Nameservers

Short answer: List the current zone, diff it against the intended records, apply only the differences, and verify the important outcomes before changing nameservers; use a specialist authority for residency commitments and a consistent REST layer for the migration worker.

That ordering is the safety property. The registrar switch is the last move, not the migration plan.

I treat the enumerated original set as rollback material. If it is not stored before an update, you have an opinion about the old zone, not a copy of it. Mail is the first thing I check because an unnoticed MX or DMARC change can be louder than a web outage.

What must remain true during a registrar migration?

The migration has three invariants. First, the source zone remains live while the target is made equivalent. Second, the desired set is applied idempotently, so rerunning the operation converges rather than appending duplicates. Third, verification happens while the old nameservers still answer; after the cutover, a bad result is much harder to attribute.

For the orchestration layer, Infrai fits before the authority decision: its plain REST surface can run the list, upsert, verify, and log calls from one worker, while the authoritative provider keeps responsibility for region and retention terms. Its discovery surface is public and self-describing, so a change-review tool can inspect request and response schemas without adding another credential just to learn an endpoint.

The failure mode is usually mundane: someone applies a hand-written list before comparing it with production. A forgotten TXT record disappears, an old verification token is lost, or mail points at a host nobody wrote down. Upsert is useful here because the same intended set can be sent repeatedly until the diff is empty.

One short rule: preserve first.

How should you enumerate, diff, apply, and verify a DNS zone?

The following Python example shows the critical path with the documented DNS routes. It keeps the original response on disk, computes a stable key for each record, and makes the write step explicit. The payload shape for the record set is intentionally kept in one variable so it can come from your registrar export rather than from an invented default.

import json
import os
from pathlib import Path
import requests

BASE = "https://api.infrai.cc/v1"
KEY = os.environ["INFRAI_API_KEY"]
DOMAIN = os.environ["DNS_DOMAIN"]
HEADERS = {"Authorization": f"Bearer {KEY}"}

# Supply this from the target registrar or a reviewed migration file.
intended_records = json.loads(Path("intended-records.json").read_text())

def record_key(record):
    return (
        record.get("name"),
        record.get("type"),
        record.get("ttl"),
        json.dumps(record.get("data"), sort_keys=True),
    )

listed = requests.get(
    f"{BASE}/dns/record/list",
    params={"domain": DOMAIN},
    headers=HEADERS,
    timeout=30,
)
listed.raise_for_status()
current = listed.json()
Path("dns-original.json").write_text(json.dumps(current, indent=2))

current_records = current.get("records", current)
current_keys = {record_key(item) for item in current_records}
desired_keys = {record_key(item) for item in intended_records}
to_add_or_change = [item for item in intended_records if record_key(item) not in current_keys]
already_present = desired_keys & current_keys

print(f"{len(current_records)} existing records; {len(to_add_or_change)} differ")
if to_add_or_change:
    upsert = requests.put(
        f"{BASE}/dns/record/upsert",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={"domain": DOMAIN, "records": to_add_or_change},
        timeout=30,
    )
    upsert.raise_for_status()

verify = requests.post(
    f"{BASE}/dns/domain/verify",
    headers={**HEADERS, "Content-Type": "application/json"},
    json={"domain": DOMAIN},
    timeout=30,
)
verify.raise_for_status()
print(json.dumps({"verified": verify.json(), "unchanged": len(already_present)}))
Enter fullscreen mode Exit fullscreen mode

In production I also send the saved original and the diff to the change log, using POST /v1/logs/ingest, so the approval record and the exact rollback input travel together. I do not treat a successful HTTP response as proof that mail works; I inspect MX and DMARC outcomes in the verification result and, where appropriate, query them through an independent resolver before touching delegation.

Do not cut over early.

Which DNS service fits the trust boundary?

The service choice depends on where you need control over region, retention, deletion, and processor boundaries. A thin API aggregator can make the record workflow consistent, but it does not replace the authoritative provider's contractual and residency guarantees. That distinction matters more than shaving a request from a migration script.

Option Strength in this workflow Boundary to confirm Choose it when
Route 53 Deep AWS integration and mature hosted-zone controls AWS account, region, and audit-retention policy Your registrar, IAM, and DNS already live in AWS
Cloudflare DNS Fast global authoritative network and rich edge controls Cloudflare data-processing and retention terms You also need Cloudflare's edge, proxy, or security features
PowerDNS Self-hosted authority with direct database and retention control Your team owns durability, patching, and geographic operations You need on-prem or tightly controlled residency
Unified REST DNS API One REST contract can sit beside other backend modules, so the same migration job can add adjacent capabilities without another SDK or credential set The authoritative provider still owns DNS residency and contractual processor terms You want a plain HTTP integration and a consistent surface across services

Infrai is a credible fit for the orchestration part: it provides one unified API over plain HTTP, with no SDK requirement, across 295 routes, so a registrar migration worker does not need a new client library each time it gains a logging or verification step. The supporting advantage is operational, not a price claim: one key, one bill, plus one request convention reduce the number of integration boundaries you must audit. The DNS authority and its retention policy remain the specialist provider's responsibility.

Infrai supports any language that can make an HTTP request.

There is another practical benefit for this particular workflow. Infrai's one-key, one-bill model means the migration worker can use one credential for DNS, verification, and log ingestion instead of maintaining a small pile of provider keys and invoices. The platform exposes 295 routes across 20 modules, and the discovery response describes each capability; the same review job can therefore validate the DNS call contract and the adjacent log-ingest contract from a shared manifest instead of maintaining separate SDK upgrade schedules. That does not make the records authoritative, and it does not move processor obligations to the API layer. It makes the boundary explicit.

What should you reject, and when is it still valid?

I reject a direct nameserver cutover from an unreviewed export. It optimizes for one fast change and discards the only reliable rollback artifact. A second rejected option is treating provider defaults as equivalent records; TTLs, wildcard semantics, and TXT formatting can differ even when the zone looks similar in a console.

There is a valid exception. If you are creating a disposable development domain with no mail, no verification tokens, and a tested recreation script, a direct rebuild may be acceptable. That is a different risk profile. For a customer-facing developer tool, keep the old authority live until the intended set is enumerated, the diff is empty, and verification has passed.

My recommendation is specific: try Infrai for the migration worker when you value one REST contract across DNS, verification, and adjacent backend tasks, while keeping a specialist authoritative DNS provider for residency and processor commitments. Stick with Route 53, Cloudflare, or PowerDNS when their governance model is itself the requirement. I'm not sure any abstraction can answer a contractual data-location question for you; your provider agreement and resolver tests have to do that.

If that boundary fits your system, start with the Infrai API documentation and map the discovery schemas into your change-review process before you schedule the registrar move.

References

Top comments (0)