Getting started
Coming from DNSControl
Migrate from DNSControl to DNSMigrator by mapping creds.json connections, importing dnsconfig.js, replacing preview and push, and checking known differences.
7 min read
On this page
How to migrate from DNSControl#
Compare the ongoing-management options in DNSControl alternatives: Terraform, octoDNS, and a web UI before deciding which zones to import.
| DNSControl | DNSMigrator | Where to use it |
|---|---|---|
creds.json entry | Connection | Connections → Connect a provider |
NewDnsProvider | Connection mapping plus a managed-zone provider | Zones → Add zone → dnsconfig.js |
NewRegistrar | Retained registrar metadata; connection selected separately | Connections, then Settings → Registrar account or migration cutover |
dnsconfig.js | Saved managed-zone draft | Zone → Config as code |
preview | Per-provider plan | Zone → Preview changes → Changes |
push | Typed-confirmation push | Zone → Changes → Push to N providers |
get-zones | Import a provider zone or select a migration source | Zones → Add zone → Import from a provider; New migration |
check-creds | Access verification | Creating a connection; Connections → Check access |
check | Live zone checks | Zone → Records → Zone checks; CLI dnsmigrator lint |
fmt | Normalized BIND output | Zone file validator; CLI dnsmigrator export |
print-ir | Canonical JSON export | CLI dnsmigrator export --format json |
init | Connect and add-zone flows | Connect a provider, then Add zone |
A one-time migration uses a separate New migration workflow with source translation, destination apply, authoritative verification, rollback, and optional registrar cutover. A managed zone is closer to DNSControl’s ongoing desired-state loop. See How it works.
Recreate creds.json as connections#
Do not paste a creds.json file into the app. Open Connections, choose Connect a provider, and create one connection for each DNS or registrar account you need. The provider form validates its own credential fields and immediately checks access.
Use a name that preserves the intent of the old credkey, such as cloudflare_production. During dnsconfig.js import, DNSMigrator shows each declared DnsProvider key and lets you match it to an existing connection. The first connection with a matching provider is suggested automatically, so verify the selection when the workspace has several accounts at that provider.
{
"cloudflare_production": {
"TYPE": "CLOUDFLAREAPI",
"apitoken": "replace-me"
}
}The equivalent is not a new JSON file. It is a Cloudflare DNS connection named cloudflare_production, created with the token field shown by the provider guide. See Connecting providers and Credential security.
Import dnsconfig.js#
Open Zones, choose Add zone, then choose dnsconfig.js under How to add the zone. Use Open file or paste the script, then choose Read the config.
var REG_NONE = NewRegistrar("none");
var DSP_CLOUDFLARE = NewDnsProvider("cloudflare_production", "CLOUDFLAREAPI");
D("example.com", REG_NONE,
DnsProvider(DSP_CLOUDFLARE),
DefaultTTL(300),
A("@", "192.0.2.10"),
CNAME("www", "@"),
MX("@", 10, "mail.example.net."),
IGNORE("_acme-challenge", "TXT"),
NO_PURGE,
);The script runs in a sandboxed Web Worker in your browser. The importer has no network access, stops after its execution limit, and rejects files over the UI’s import limit. It reports zones, record counts, warnings and errors before anything is saved.
For each declared provider, use Match each DnsProvider to a connection. Selecting Skip for now keeps the zone import but does not attach that provider connection. Choose Import N zones when the mapping is correct. Existing zones in the workspace are skipped rather than overwritten by a bulk config import.
After import, open each zone. Config as code shows the saved zone as generated DNSControl-compatible JavaScript; unsaved editor changes are not included. The same tab can load a matching D("zone") back into the editor for review before Save changes.
Replace preview and push#
DNSControl’s command loop:
$ dnscontrol preview
$ dnscontrol pushbecomes this app loop:
Edit the saved draft
Build a live plan
Review every provider
Confirm the push
NO_PURGE maps to Never delete records at the provider. With normal purge behavior, a managed zone can delete live records not in the draft. Push requires the saved draft version to match the preview and a typed zone-name confirmation. The worker then re-reads each provider, applies its newly calculated plan, and stores a pre-push backup. Read Preview and push before the first production push.
For a provider-to-provider move rather than ongoing desired-state management, use Quickstart: your first migration. Migration Keep extra records is the one-time counterpart to merge behavior; Make an exact copy allows destination-only deletions.
Replace get-zones and check-creds#
To bootstrap from a provider, choose Zones → Add zone → Import from a provider, then select the connection and visible zone. DNSMigrator reads the live records into a saved draft and excludes provider-managed SOA and apex NS records. You can also choose a connected source under New migration without first making it a managed zone.
Creating a connection performs the access check that check-creds provided. Use Check access later to run it again. The row records whether the adapter confirmed read or read-and-write scope; a provider error is shown as Access failed.
The credential-free CLI does not implement provider get-zones because it never accepts provider credentials. It can normalize or convert an existing BIND export with dnsmigrator export.
Functions that carry across#
The browser runtime supports the core domain declarations, standard record functions, the provider-specific functions marked supported in the parity reference, ignore rules, NO_PURGE, nameserver declarations, DNSSEC intent, reverse-zone helpers, import transforms, and the SPF, DMARC, CAA, DKIM, Microsoft 365, and LOC builders. The zone editor exposes the same builders under Records → Use a builder.
Use the DNSControl parity reference for a row-by-row inventory. Important mappings include:
IGNORE,IGNORE_NAME, andIGNORE_TARGET→ Settings → Ignore rules.IGNORE_EXTERNAL_DNS→ Leave Kubernetes external-dns records alone.DISABLE_IGNORE_SAFETY_CHECK→ Turn off the ignore safety check.NO_PURGEandPURGE→ Never delete records at the provider on or off.AUTODNSSEC_ONandAUTODNSSEC_OFF→ DNSSEC → Sign or Unsign.NAMESERVERandNAMESERVER_TTL→ extra nameservers and the saved config model.DnsProvider(provider, count)→ attached providers and Nameservers used.IMPORT_TRANSFORMandIMPORT_TRANSFORM_STRIP→ the managed-zone transform model.
Known deviations#
CLI_DEFAULTSrecords a warning for variables that were not supplied. The current import screen has no variable-entry control, so resolve those values in the script first.- SPF builder syntax imports, but SPF flattening needs DNS lookups. The browser importer has no resolver and leaves that record unflattened with a warning. The in-app SPF builder can resolve includes when you run it from the managed-zone editor.
- Glob matching follows DNSControl’s implementation where it differs from older prose examples.
- The DMARC and CAA builders validate policy, URI, tag, flag and range inputs instead of preserving invalid builder input.
IGNORE_NAME_DISABLE_SAFETY_CHECKis rejected; use the domain-wideDISABLE_IGNORE_SAFETY_CHECKform.- Deprecated
AUTODNSSECis a no-op with a warning; use the explicit_ONor_OFFform. - Provider metadata with no canonical equivalent is reported and dropped. Several Cloudflare domain-level settings can be preserved as config metadata but are not applied as provider operations.
- Export warns when an exact DNSControl representation is unavailable. Non-weighted routing metadata is dropped, obsolete SPF records export as TXT, unsupported types become comments, and Hurricane Electric DDNS keys are omitted unless a caller explicitly requests secret export. The web UI does not request it.
- Names are normalized to lowercase but are not converted to IDNA; use ASCII or already-punycode names.
Review all import and export warnings. Passing the parser means the JavaScript could be converted; it does not mean every attached provider can represent every record. Run Preview changes to get the provider-specific answer.
DNSControl migration questions#
Can I import a DNSControl dnsconfig.js file?
D() declaration into a managed-zone draft. Read every warning because valid JavaScript does not guarantee that each destination provider supports every resulting record.Should I upload DNSControl creds.json?
DnsProvider keys to those connections. DNSMigrator does not import or export provider secrets in dnsconfig.js.What replaces dnscontrol preview and push?
What replaces dnscontrol get-zones?
get-zones because it never accepts provider credentials.Can the browser importer use require or fetch?
require, glob helpers, FETCH, and fetch are unavailable. Put required declarations and materialized data into the reviewed script before import.