Developers → DNS as code
Keep your zone in one YAML or JSON file next to your code. Review DNS changes in pull requests, see exactly what will change before it does, and apply it in one step.
$ nameocean dns export example.com > dns.yaml $ $EDITOR dns.yaml $ nameocean dns plan -f dns.yaml + CNAME blog example.netlify.app ~ A @ 203.0.113.10 ttl 1h → 5m - A old 203.0.113.9 example.com: 1 to add, 1 to change, 1 to delete, 6 unchanged. $ nameocean dns apply -f dns.yaml Apply these changes? [y/N] y Applied: 1 added, 1 changed, 1 deleted. example.com is at serial 214.
# yaml-language-server: $schema=https://nameocean.net/schemas/dns-zone.json
zone: example.com
records:
- name: "@"
type: A
value: 203.0.113.10
ttl: 5m
- name: www
type: CNAME
value: "@"
- name: "@"
type: MX
value: mail.example.com
priority: 10
- name: "@"
type: TXT
value: "v=spf1 mx -all"
- name: _sip._tcp
type: SRV
value: sip.example.com
priority: 10
weight: 5
port: 5060
- name: old
type: REDIRECT
value: https://example.com/new
name is @ for the zone itself or a name relative to it (www, _dmarc); a fully qualified name with the trailing dot works too.ttl is 5m, 15m, 30m, 1h or 1d; without it a record gets the file's ttl, or 1h. MX takes priority (default 10), SRV priority, weight and port, REDIRECT save_path (default true).The file is the whole zone: a record that is in the zone but not in the file is deleted. Pass --keep-unlisted (prune=false in the API) to only add and change.
A, AAAA, MX and TXT records are matched by name and value (and priority for MX), since one name can carry several of them. CNAME, SRV, PTR and REDIRECT records are matched by name. A different ttl, or SRV priority, weight or port, is a change; everything else is an add or a delete.
Apply runs in one transaction: deletes first, then changes, then new records, so a CNAME can replace an A record in the same file. If one record is refused, nothing is changed. If someone changes the zone between the plan and the apply, the apply is refused and you plan again.
Records NameOcean keeps for itself, the address behind an HTTP redirect and the ACME challenges for SSL, are never exported, planned or deleted.
Create an API key with dns:write (or only dns:read for a job that plans) and save it as the NAMEOCEAN_API_KEY secret.
name: dns
on:
pull_request: {paths: [dns.yaml]}
push: {branches: [main], paths: [dns.yaml]}
jobs:
dns:
runs-on: ubuntu-latest
env:
NAMEOCEAN_API_KEY: ${{ secrets.NAMEOCEAN_API_KEY }}
steps:
- uses: actions/checkout@v4
- run: curl -fsSL https://nameocean.net/install.sh | sh
- run: nameocean dns plan -f dns.yaml
- if: github.event_name == 'push'
run: nameocean dns apply -f dns.yaml --yes
dns plan --detailed-exitcode exits 2 when there are changes, for jobs that should only report drift.
| GET /dns/{zone}/export?output=yaml | The zone as a file (JSON without output=yaml); the X-Zone-Serial header is its serial |
| POST /dns/{zone}/plan | What apply would do; changes nothing and needs only dns:read |
| POST /dns/{zone}/apply?serial=N | Make the zone match the file; 409 zone_changed if it is not at the plan's serial any more |
$ curl -X POST https://nameocean.net/api/v1/dns/example.com/plan \ -H "Authorization: Bearer $NAMEOCEAN_API_KEY" \ -H "Content-Type: application/yaml" --data-binary @dns.yaml
Send YAML with Content-Type: application/yaml or the same document as JSON. A file the server cannot accept answers 400 invalid_zone_file with an errors list naming each record and field. All of it is in the API reference.
Over MCP an assistant can export a zone, plan a change to many records at once with plan_dns_zone and, after showing you the plan, apply it with apply_dns_zone.