dns plugin extends datumctl with commands for creating DNS zones, pointing your domain at Datum, and editing records — all from the terminal. Once you install it, datumctl dns behaves like any other datumctl command and inherits your current organization, project, and credentials.
The plugin is a preview release. The current published version is
v0.7.0-dev.1, so expect commands, flags, and output to change before a stable release.Install the plugin
1
Install from the official catalog
The plugin ships in the official datum catalog, so no extra catalog registration is needed:This installs the version the catalog recommends. To pin a specific one instead, see pinning a version.
2
Verify the install
version runs entirely offline — no credentials, no project, and no API call — so it is the first command to run whenever something else fails.3
Select a project
Every other command acts on a project. Set a context once, or pass The plugin never guesses a project. See Contexts & scoping for how scope is resolved.
--project per command:If you build the plugin yourself and put a
datumctl-dns binary on your PATH, datumctl blocks it until you run datumctl plugin trust dns. Trust is recorded against the binary’s fingerprint, so rebuilding it means trusting it again.Create a zone
A zone holds the records for one domain. Create one by domain name:--timeout, or skip the wait entirely:
Point your domain at Datum
Creating a zone does not make the domain resolve through Datum. Your registrar has to publish the nameservers Datum assigned to the zone.--check, the command compares against what the control plane last reconciled. --check queries public DNS live, as a second and independent source of truth: it observes what the internet resolves right now rather than trusting stored state, which is what tells you whether delegation actually works. Use --timeout to change the per-query timeout.
The command reports delegation as one of four states:
Unknown is not a failure, and the summary line says which of its three causes applies:
no nameservers assigned yet— the zone does not have its nameservers yet. This is normal for the first few minutes after you create a zone.the registrar's nameservers have not been checked yet— the zone has a linked domain, but nobody has looked at what the registrar publishes.no linked domain to check the registrar against— there is no domain object to compare against at all.
unknown rather than not set at registrar while the state is Unknown.
Registrar changes take time to propagate. Allow for the parent zone’s TTL before you treat a change as failed.
List and inspect zones
--status ok|pending|error, add -o wide for extra columns, and pass --no-headers to drop the header row.
For one zone in detail — its status, its delegation, and what it contains — use describe:
Delete a zone
The confirmation asks for the zone name typed in full, and the command refuses to run non-interactively without--yes:
Add and change records
Give the zone, the name, the type, and one or more values. Names are relative to the zone:www, *, _dmarc, or @ for the domain itself.
create appends — the values already at that name stay, and an exact duplicate is refused:
set overwrites — every value already at that name and type is removed and the ones you give take their place:
set is the “change my A record” verb and create is the “add a second A record” verb. They are separate because one command cannot express both intents safely.
Both accept --dry-run to validate and show the change without applying it, and --wait to block until the DNS backend has programmed the record (--timeout bounds the wait).
Two rules catch most mistakes:
- Names are relative. Use
www, notwww.example.com. Use@for the domain itself. - Targets are absolute. End every hostname inside a value with a dot:
mail.example.com., notmail.
Enter record values
Flat types take their value positionally. Repeat the argument for several values:
Both notations work for every type, so a value pasted out of a provider export or
dig output needs no translation. Mixing the two notations for one value is an error, not a merge.
--data reads a file with @path or standard input with -:
Datum manages a few records for you — the zone’s SOA, its apex NS records, and anything a Gateway creates. Editing or deleting one requires
--force, and a platform-managed record you overwrite reverts.Set a TTL
--ttl takes seconds or a duration, and the units combine: --ttl 300, --ttl 5m, --ttl 1h30m. Omit it and the record uses Auto, which the backend resolves to 300 seconds. TTLs are stored as written and are not rounded onto a preset ladder.
List and inspect records
Records are listed one row per value, with the name, type, TTL, value, and status:--status accepts programmed, pending, conflict, not-owner, error, and rejected; the first word alone also works, so not selects Not owner. STATUS is the per-owner-name condition, not the rolled-up one on the record set — the interesting outcomes only exist per name.
describe shows the values at one name both in presentation format and broken out into named fields, along with the backend’s own status message. Omit the type to see every type at that name:
A semicolon starts a comment in zone-file syntax, so TXT values containing one display escaped —
v=DMARC1; p=none reads back as "v=DMARC1\; p=none". The stored value is unchanged.Delete a record
Pass a value to remove only that value, or leave it off to remove every value at that name and type. The prompt says how many, so the difference is never a surprise.Import an existing zone
Moving a domain in from another provider starts with the zone file you exported there:--timeout to bound how long --discover waits.
Export and apply a zone file
zone export flattens every record set in the zone back into a BIND zone file:
record apply is the declarative counterpart: it diffs a zone file against the live zone, prints what would change, and converges. Export, edit, and apply is a closed loop — exporting and re-applying an untouched file reports no changes, which makes apply --dry-run usable as a drift check.
apply only adds and updates. --prune also deletes the records the file does not mention. Platform-managed records are never pruned or modified, and what was skipped is always reported. There is no --force on apply — a zone file is not the place to say “yes, delete my delegation”, so use record delete --force where the record is named explicitly.
Script the plugin
Every command accepts-o:
record list -o json and -o yaml emit the raw record set objects rather than the flattened rows, so a script never has to reconstruct them. --no-headers drops the header row from table and wide. Data goes to standard output and everything else to standard error, so -o json > zones.json is always clean.
Useful global flags: --project, --org, -o/--output, -v/--verbose, -q/--quiet, -y/--yes, and --color auto|always|never. For the wider scripting picture, see Output formats & scripting.
Exit codes
A bulk operation that partly fails never exits0.
Errors print a problem, an optional fix, and the exit status:
--verbose to see the underlying cause.
Troubleshoot
Next steps
DNS
Zones, nameservers, record types, and ALIAS/CNAME flattening explained.
Using plugins
How plugins are installed, verified, upgraded, and trusted.
Contexts & scoping
Control which organization and project the plugin acts on.
Output & scripting
Machine-readable output, structured errors, and CI patterns.