Installation
The NexDNS CLI is a single binary with no external dependencies. Choose the installation method that suits your environment.
Install script
curl -sL https://get.nexdns.tech/cli | sh
Detects your platform, downloads the matching release archive, verifies it against the checksums published with the release and installs the binary to /usr/local/bin. Read it first with curl https://get.nexdns.tech/cli if you prefer not to pipe an unread script to a shell.
Install with Go
go install github.com/nexdns/cli/cmd/nexdns@latest
Homebrew
brew tap nexdns/tap
brew install --cask nexdns-cli
The formula is published as a cask, so it installs with <code>--cask</code> rather than the one-line <code>brew install</code> form.
Download a release archive
Prebuilt binaries for Linux, macOS and Windows (amd64 and arm64) are attached to each release on GitHub. Unpack the archive and put nexdns anywhere on your PATH.
Docker
docker pull nexdns/cli
Verify Installation
After installing, confirm the CLI is available and check its version:
nexdns version
Authentication
The CLI requires an API token to communicate with the NexDNS API. You can create a token at nexdns.tech/settings/api-keys.
Plan requirement: the CLI works through the REST API, so it needs an API key, which is available on Pro plans and above. The same applies to the Terraform provider, the OctoDNS provider and the ACME plugins.
Save Token to Config
nexdns auth token nxd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Environment Variable (CI/CD)
export NEXDNS_TOKEN=nxd_xxxxxxxxxxxxxxxxxxxx
Check Authentication Status
nexdns auth status
Config File
The token is stored in ~/.nexdns/config.yaml. The CLI resolves credentials in the following priority order:
--tokenflag (highest priority)NEXDNS_TOKENenvironment variable- Config file
~/.nexdns/config.yaml
Zone Management
Manage DNS zones from the command line. All zone commands are under the nexdns zone subcommand.
List Zones
The list is paginated. Use --all to walk every page, or --search, --page and --per-page to narrow it.
nexdns zone list
nexdns zone list --all
nexdns zone list --search example --per-page 50
Add a Zone
nexdns zone add example.com --ns-group eu
To create a secondary zone that transfers from your own primary, pass --type slave with the primary's public IP address. Secondary zones are available on Pro plans and above.
nexdns zone add example.com --type slave --master-ip 203.0.113.10
Zone Information
nexdns zone info example.com
Export a Zone
Exports the zone in BIND zone-file format, ready to pipe to a file. Pass --format json for a machine-readable inventory instead.
nexdns zone export example.com > example.com.zone
nexdns zone export example.com --format json
Import Zone File
Use --dry-run to preview changes before applying them:
nexdns zone import example.com zone.txt --dry-run
nexdns zone import example.com zone.txt
By default an import only adds what is missing. Add --replace to also delete records the file does not define, which makes the zone match the file exactly. The zone's own nameserver and SOA records are never touched.
nexdns zone import example.com zone.txt --replace
Ensure Zone Exists
Creates the zone only if it does not already exist (idempotent):
nexdns zone ensure example.com
Move a Zone to Another Nameserver Group
Moves the zone into another nameserver group, named by its slug. The zone keeps answering throughout: the new group's nameservers are provisioned before the command returns, and the old ones keep serving while resolvers refresh. Update the delegation at your registrar afterwards - nexdns zone info prints the new nameservers.
nexdns zone move example.com eu --dry-run
nexdns zone move example.com eu
A zone may be moved three times a day. Beyond that the command reports the limit and changes nothing.
Check DNS Propagation
Queries public resolvers directly - not the API - so you see what the internet sees. It exits non-zero when a check fails, which makes it usable as a deployment gate.
nexdns zone check example.com
Delete a Zone
Asks for confirmation first. Add --force to skip the prompt in a script; without a terminal the prompt declines automatically and nothing is deleted.
nexdns zone delete example.com
nexdns zone delete example.com --force
Record Management
Manage DNS records within a zone. All record commands are under the nexdns record subcommand.
List Records
Filter with --type, --name (a label, or @ for the zone apex) or --search, which matches names and content.
nexdns record list example.com
nexdns record list example.com --type MX
nexdns record list example.com --name www
nexdns record list example.com --search 203.0.113
Add Records
The content argument carries the primary value only. Everything else a record type needs - priority, weight, port, CAA tag and flags, DS and TLSA parameters - is a separate flag, so nothing has to be assembled by hand.
# A record
nexdns record add example.com A www 1.2.3.4 --ttl 300
# MX record with priority
nexdns record add example.com MX @ mail.example.com --priority 10
# SRV: priority, weight and port are separate flags
nexdns record add example.com SRV _sip._tcp sip.example.com --priority 10 --weight 60 --port 5060
# CAA: the value is the CA domain, the rest are flags
nexdns record add example.com CAA @ letsencrypt.org --tag issue --flags 0
# DS and TLSA: content is the bare hex digest
nexdns record add example.com DS child 0123456789abcdef --keytag 12345 --algorithm 13 --digest-type 2
nexdns record add example.com TLSA _443._tcp.www 0123456789abcdef --usage 3 --selector 1 --matching-type 1
TTL applies to the whole record set. Omit --ttl when adding another value to a name that already exists and the existing TTL is kept; pass it and every value at that name is retimed. A brand-new name defaults to 3600 seconds.
Update a Record
Change the content, the TTL, the priority or the label. Record IDs are derived from the record itself, so an edit returns a new ID - always read it back from the response rather than reusing the old one.
nexdns record update example.com <record-id> --content 5.6.7.8
nexdns record update example.com <record-id> --ttl 600
nexdns record update example.com <record-id> --record-name api
Create Record If Missing
Creates the record only if it does not already exist (an exact match of type, name and content). Existing records with different content are left untouched – safe for round-robin setups. Idempotent:
nexdns record ensure example.com A www 1.2.3.4
Delete a Record
nexdns record delete example.com <record-id>
DNSSEC
Manage DNSSEC signing for your zones.
Check DNSSEC Status
nexdns dnssec status example.com
Enable DNSSEC
nexdns dnssec enable example.com
Get DS Records
Retrieve DS records to configure at your domain registrar:
nexdns dnssec ds-records example.com
Disable DNSSEC
Asks for confirmation, since disabling signing on a delegated zone breaks validation until the DS record is withdrawn at your registrar. Add --force in a script.
nexdns dnssec disable example.com --force
DNS-as-Code
Define your DNS infrastructure declaratively in a nexdns.yaml file and manage it with version control. The CLI compares your local configuration against the live state and applies only the necessary changes.
Configuration Format
zones:
example.com:
dnssec: true
records:
- type: A
name: "@"
content: "1.2.3.4"
ttl: 300
- type: CNAME
name: www
content: example.com
Preview Changes
Show a diff of what would change without applying anything:
nexdns apply
Apply Changes
Apply the changes after reviewing the diff:
nexdns apply --confirm
Diff Only
nexdns diff
Remove Records That Left the File
A record deleted from nexdns.yaml is left in place unless you ask for deletions explicitly. This is deliberate: it keeps a partial file from emptying a zone. Add --delete to make the file authoritative.
nexdns diff --delete
nexdns apply --confirm --delete
Choose the File and the Zone
Use --file for a config outside the working directory and --zone to act on a single zone from a multi-zone file. A --zone that names no zone in the file is an error, not a silent no-op.
nexdns apply --file production.yaml --zone example.com --confirm
Pull Live State
Generate a nexdns.yaml from the current live DNS configuration:
nexdns pull example.com
nexdns pull example.com --file nexdns.yaml
nexdns pull other.example --file nexdns.yaml --append
Environment Variable Substitution
Use ${VARIABLE} syntax in your configuration file. The CLI substitutes environment variables at apply time, making it easy to reuse configs across environments:
zones:
${DOMAIN}:
records:
- type: A
name: "@"
content: "${SERVER_IP}"
Webhooks
Subscribe an endpoint to the events your zones emit, and manage those subscriptions from the terminal. Webhooks are available on Pro plans and above; the API key needs the webhooks.read and webhooks.write scopes.
Subscribe an Endpoint
The signing secret is printed once, on creation, and cannot be retrieved afterwards - store it where your receiver can read it. Every delivery carries an HMAC signature computed with that secret, so the receiver can verify the request really came from us.
nexdns webhook create https://example.com/hooks/dns \
--events zone.created,zone.deleted,record.created \
--description "production"
Available Events
zone.created, zone.updated, zone.deleted, record.created, record.updated, record.deleted, dnssec.enabled, dnssec.disabled, zone.health.problem, zone.health.resolved
Inspect Subscriptions
show adds the ten most recent delivery attempts with their status code and, when one failed, the error - which is usually enough to tell a wrong URL from a receiver that is rejecting the payload.
nexdns webhook list
nexdns webhook show <webhook-id>
Send a Test Event
Queues a test delivery. A success here means the platform accepted the event, not that your endpoint answered - read the outcome back with nexdns webhook show.
nexdns webhook test <webhook-id>
Change or Pause a Subscription
Pass only what changes; the command reads the current subscription and re-sends the rest. Use --active=false to stop deliveries without deleting the endpoint, and --force to delete without the confirmation prompt.
nexdns webhook update <webhook-id> --events zone.created,dnssec.enabled
nexdns webhook update <webhook-id> --active=false
nexdns webhook delete <webhook-id> --force
Account & Configuration
Read back which account a token belongs to, which plan it carries and which API keys exist.
nexdns account info
nexdns account api-keys
Persisted Settings
The config file holds five settings - api-url, token, output, color and timeout - and all of them can be read and written from the CLI. config view prints the effective configuration, including where the token came from.
nexdns config view
nexdns config set output json
nexdns config set timeout 60
nexdns config get api-url
Environment Variables
Every setting also has an environment variable, which is what CI runners usually use. NEXDNS_CONFIG points at an alternative config file, which is handy when several accounts are driven from one machine.
export NEXDNS_TOKEN=nxd_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export NEXDNS_API_URL=https://api.nexdns.tech/v1
export NEXDNS_TIMEOUT=60
export NEXDNS_CONFIG=/etc/nexdns/config.yaml
Remove a Saved Token
Clears the token from the config file. The file itself, and any API URL saved in it, are left in place.
nexdns auth logout
Shell Completion
Completion scripts are generated for bash, zsh, fish and PowerShell.
nexdns completion bash > /etc/bash_completion.d/nexdns
nexdns completion zsh > "${fpath[1]}/_nexdns"
Scripting & CI
The CLI is built to be driven by pipelines: every failure is a distinct exit code, prompts decline rather than hang, and nothing destructive happens without being asked for.
Exit Codes
| Code | Meaning |
|---|---|
0 | The command completed without an error. A declined confirmation prompt also exits 0 - nothing failed, and nothing changed. |
1 | A runtime failure - authentication, a rejected request, a failed propagation check. |
2 | The command line itself was wrong: an unknown command or subcommand, an unknown flag, a missing argument. |
A mistyped subcommand exits 2 rather than printing help and succeeding, so a typo in a pipeline cannot pass for a completed operation.
Confirmation Prompts
Destructive commands ask before acting. Without a terminal - which is every CI runner - the prompt declines and the command exits 0 having changed nothing, so pass --force when you mean it.
Failures That Used to Pass Quietly
- An unresolved
${VAR}innexdns.yamlstops the run and names every variable that had no value, rather than writing the literal text into a record. - A
--zonethat names no zone in the file is an error. zone checkexits non-zero when a propagation check fails.apply --confirmexits non-zero when any operation failed, and reports how many.
Rate Limits and Bulk Work
The API budget is per account and per plan, in a sliding one-minute window. The CLI reads the budget from every response and waits for the window to roll over before it would exceed it, so a large import finishes intact rather than losing records - it simply takes longer. A limit with a longer window, such as the cap on how often one zone may change nameserver group, is reported instead of waited out.
Docker
The CLI is available as a Docker image. Pass your API token via the NEXDNS_TOKEN environment variable.
Run Commands
docker run --rm -e NEXDNS_TOKEN=nxd_xxx nexdns/cli zone list
Import a Zone File
Mount a local directory to pass zone files into the container:
docker run --rm -e NEXDNS_TOKEN=nxd_xxx \
-v "$PWD/zones:/zones" \
nexdns/cli zone import example.com /zones/example.com.zone
Global Flags
The following flags are available on all commands:
| Flag | Description |
|---|---|
--token |
API token (overrides config file and environment variable) |
--api-url |
Override the API base URL. To point the CLI at this instance for good, save it once with nexdns config set api-url https://api.nexdns.tech/v1, or pass it to nexdns auth token, which stores it alongside the token. |
--output, -o |
Output format: table (default), json, yaml, csv |
--color |
Colour mode: auto (default), always or never. |
--quiet, -q |
Suppress non-essential output |
--verbose, -v |
Show the HTTP requests and responses, including the rate-limit headers. |
--dry-run |
Preview changes without applying them |
--timeout |
Request timeout in seconds (default: 30) |
--config |
Path to the config file (default: ~/.nexdns/config.yaml). |
--version, -V |
Print the version and exit. |
Each of these also reads an environment variable: NEXDNS_TOKEN, NEXDNS_API_URL, NEXDNS_TIMEOUT and NEXDNS_CONFIG. NO_COLOR disables colour regardless of --color.
Terraform
The NexDNS Terraform provider lets you manage zones and records as Terraform resources. Install the provider from the Terraform Registry and configure it with your API token.
terraform {
required_providers {
nexdns = {
source = "nexdns/nexdns"
}
}
}
provider "nexdns" {
api_token = var.nexdns_token
}
resource "nexdns_zone" "main" {
name = "example.com"
ns_group = "eu"
}
resource "nexdns_record" "www" {
zone_id = nexdns_zone.main.id
type = "A"
name = "www"
content = "1.2.3.4"
}
DNSControl
DNSControl is a DNS-as-code tool by Stack Overflow. Use the NexDNS provider to manage your zones declaratively. The provider ships with DNSControl 4.46.0 and later.
creds.json
{
"nexdns": {
"TYPE": "NEXDNS",
"api_token": "nxd_xxxxxxxxxxxxxxxxxxxx"
}
}
dnsconfig.js
var REG_NONE = NewRegistrar("none");
var DSP_NEXDNS = NewDnsProvider("nexdns");
D("example.com", REG_NONE, DnsProvider(DSP_NEXDNS),
A("@", "1.2.3.4"),
A("www", "1.2.3.4"),
MX("@", 10, "mail.example.com."),
CNAME("blog", "example.com.")
);
OctoDNS
OctoDNS is a DNS-as-code tool by GitHub. Install the NexDNS provider and configure it as a source or target in your OctoDNS config.
Install Provider
pip install octodns-nexdns
config/production.yaml
providers:
config:
class: octodns.provider.yaml.YamlProvider
directory: ./config
nexdns:
class: octodns_nexdns.NexdnsProvider
token: env/NEXDNS_API_TOKEN
zones:
example.com.:
sources:
- config
targets:
- nexdns
zones/example.com.yaml
"":
type: A
value: 1.2.3.4
www:
type: A
value: 1.2.3.4
blog:
type: CNAME
value: example.com.