A small, scriptable Amazon Route 53 CLI for hosted zones and DNS records.
r53ctl is intentionally small: list and manage hosted zones, upsert/delete basic record sets, and export records in JSON or BIND-style text.
Contents
Why r53ctl?
- Small surface area: focused on Route 53 hosted zones and basic DNS records.
- Automation-friendly: JSON output, explicit destructive operations, and predictable exit codes.
- Cross-platform: Linux, macOS, and Windows builds for
amd64 and arm64.
- Native AWS auth: uses the standard AWS credential chain, profiles, and optional role assumption.
- Release-ready: GitHub Releases, checksums, Linux packages, and a Homebrew cask.
Install
Homebrew
brew install --cask kespineira/tap/r53ctl
Install script
Linux and macOS:
curl -fsSL https://raw.githubusercontent.com/kespineira/r53ctl/main/scripts/install.sh | sh
Install a specific version:
curl -fsSL https://raw.githubusercontent.com/kespineira/r53ctl/main/scripts/install.sh | R53CTL_VERSION=v0.1.0 sh
Go install
go install github.com/kespineira/r53ctl/cmd/r53ctl@latest
The project targets Go 1.26.3 or newer.
Download artifacts
Every release publishes:
.tar.gz archives for Linux and macOS
.zip archives for Windows
.deb, .rpm, and .apk Linux packages
checksums.txt, signed with cosign (checksums.txt.sig, checksums.txt.pem)
See https://github.com/kespineira/r53ctl/releases.
Verify the checksums signature (keyless, GitHub OIDC):
cosign verify-blob \
--certificate checksums.txt.pem \
--signature checksums.txt.sig \
--certificate-identity-regexp '^https://github.com/kespineira/r53ctl/\.github/workflows/release\.yml@refs/tags/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
checksums.txt
The install script runs this check automatically when cosign is installed
(set R53CTL_SKIP_COSIGN=1 to bypass).
Authentication
r53ctl uses the AWS SDK credential chain:
- environment variables such as
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN
- shared config and credentials files
- AWS SSO profiles
- instance or task roles
Select a profile or assume a role:
r53ctl --profile prod zones list
r53ctl --profile tooling --role-arn arn:aws:iam::123456789012:role/dns-admin zones list
Use a custom endpoint for local testing:
r53ctl --endpoint-url http://localhost:4566 zones list
Configuration
Persist default profile, region, and output so you don't repeat flags.
r53ctl stores them in $XDG_CONFIG_HOME/r53ctl/config.json (default
~/.config/r53ctl/config.json; Windows uses the OS config directory). Override
the location with --config <path>.
r53ctl config set profile Domains
r53ctl config set region eu-west-1
r53ctl config set output json
r53ctl config view
r53ctl config unset region
r53ctl config path
After setting a default profile, plain commands use it automatically:
r53ctl zones list # uses the saved profile
r53ctl --profile prod zones list # the flag overrides the saved profile
Precedence, highest first:
- Explicit command-line flag (
--profile, --region, --output).
- Environment variable (
AWS_PROFILE, AWS_REGION / AWS_DEFAULT_REGION).
config.json value.
- Built-in default (
output → table, region → us-east-1, profile from the AWS credential chain).
If the config file is hand-edited into invalid JSON, r53ctl reports a parse error naming the path; fix or delete the file to recover.
Quick start
List hosted zones:
r53ctl zones list
Create a zone:
r53ctl zones create example.com --comment "managed by r53ctl"
Upsert an A record:
r53ctl records upsert example.com \
--name www.example.com \
--type A \
--ttl 300 \
--value 192.0.2.10
Export records:
r53ctl records export example.com --format bind
r53ctl records export example.com --format json
Use JSON output for scripts:
r53ctl --output json records list example.com --type A
Commands
r53ctl zones list
r53ctl zones create <domain> [--comment <text>]
r53ctl zones delete <zone-id-or-name> --yes
r53ctl records list <zone-id-or-name> [--name <fqdn>] [--type <type>]
r53ctl records upsert <zone-id-or-name> --name <fqdn> --type <type> --ttl <seconds> --value <value>
r53ctl records delete <zone-id-or-name> --name <fqdn> --type <type> --yes
r53ctl records export <zone-id-or-name> --format bind|json
r53ctl config view
r53ctl config get <key>
r53ctl config set <key> <value>
r53ctl config unset <key>
r53ctl config path
Global flags:
--profile <name> AWS shared config profile
--region <region> AWS region for SDK configuration
--role-arn <arn> Role ARN to assume before calling Route 53
--endpoint-url <url> Custom Route 53 endpoint URL
--output table|json Output format
--config <path> Path to r53ctl config file
Supported records
Record upserts currently support:
| Type |
Notes |
A |
IPv4 addresses |
AAAA |
IPv6 addresses |
CAA |
<flag> <tag> <value>; the value is quoted automatically |
CNAME |
Canonical names |
MX |
Mail exchange values in <priority> <exchange> format (priority 0–65535) |
NS |
Name server records |
SRV |
Service records in <priority> <weight> <port> <target> format (numeric fields 0–65535) |
TXT |
Quoted automatically and split into 255-byte strings when needed |
records list can filter any Route 53 record type returned by AWS, including records that r53ctl does not yet upsert.
Release channels
Releases are built with GoReleaser and GitHub Actions.
git tag v0.1.0
git push origin v0.1.0
The release workflow builds multi-platform archives, Linux packages, checksums, release notes, and the Homebrew cask. See docs/releasing.md.
Roadmap
- BIND zone file import
- Alias record upserts
- Private hosted zone creation
- Route 53 routing policies: weighted, failover, geolocation, and latency
- Safer diff and dry-run workflows for bulk changes
Contributing
Issues and pull requests are welcome. Start with CONTRIBUTING.md for local setup, test commands, and release expectations.
Security
Please do not report security issues in public issues. See SECURITY.md.
Built with
License
MIT License. See LICENSE.