nextdnsctl
A community-driven CLI tool for managing NextDNS profiles declaratively.
Disclaimer: This is an unofficial tool, not affiliated with NextDNS. Built by a user, for users.
Note: While
nextdnsctlhandles API rate limiting and retries, it is not recommended for importing very large blocklists. For large-scale filtering, prefer using NextDNS's built-in curated blocklists under the Privacy tab, and use thedenylistfeature for specific overrides or fine-tuning.
Features
- Bulk add/remove domains to the NextDNS denylist and allowlist
- Import domains from a file or URL
- Export current list to a file for backup
- List and clear all entries in a list
- Delta-aware add/import/remove operations that skip unchanged entries
- Parallel API requests for faster bulk operations
- Dry-run mode to preview changes before applying
- Use profile names or IDs interchangeably
Installation
pip install nextdnsctl
Requires Python 3.10+.
Quick Start
# Authenticate (find your API key at https://my.nextdns.io/account)
nextdnsctl auth
# List your profiles
nextdnsctl profile-list
# Add domains to denylist (using profile name or ID)
nextdnsctl denylist add "My Profile" bad.com evil.com
# Preview changes without applying them
nextdnsctl --dry-run denylist import myprofile blocklist.txt
Authentication
The API key can be provided in two ways (in order of priority):
-
Environment variable (recommended for CI/CD):
export NEXTDNS_API_KEY=your-api-key nextdnsctl profile-list
-
Config file (created by
authcommand):nextdnsctl auth # prompts for the key without echoing it # or: pbpaste | nextdnsctl auth # Stored in ~/.nextdnsctl/config.json with secure permissions
Passing the key as an argument (
nextdnsctl auth <key>) still works, but stores it in your shell history.
Global Options
| Option | Description |
|---|---|
--concurrency N |
Number of parallel API requests (1-20, default: 5) |
--dry-run |
Show what would be done without making changes |
--retry-attempts N |
Number of retry attempts for API calls (default: 4) |
--retry-delay N |
Initial delay between retries in seconds (default: 1) |
--timeout N |
Request timeout in seconds (default: 10) |
Profile Identification
All commands accept either a profile ID or profile name (case-insensitive):
# Using profile ID
nextdnsctl denylist list abc123
# Using profile name
nextdnsctl denylist list "My Profile"
Denylist Commands
List entries
nextdnsctl denylist list <profile>
nextdnsctl denylist list <profile> --active-only
nextdnsctl denylist list <profile> --inactive-only
Add domains
nextdnsctl denylist add <profile> domain1.com domain2.com
nextdnsctl denylist add <profile> domain.com --inactive
nextdnsctl denylist add <profile> domain.com --update-existing
Add operations fetch the current list first and only create missing domains. Domains
already present with the requested active/inactive state are skipped. If a domain is
already present with the opposite state, it is reported and left unchanged unless
--update-existing is passed.
Remove domains
nextdnsctl denylist remove <profile> domain1.com domain2.com
Remove operations compare against the current list first and skip domains that are not present.
Import from file or URL
nextdnsctl denylist import <profile> /path/to/blocklist.txt
nextdnsctl denylist import <profile> https://example.com/blocklist.txt
nextdnsctl denylist import <profile> blocklist.txt --inactive
nextdnsctl denylist import <profile> blocklist.txt --update-existing
The import file format supports:
- One domain per line
- Comments starting with
# - Inline comments (e.g.,
example.com # reason) - Empty lines (ignored)
Domains are normalised the way NextDNS expects them: lowercased, internationalized names
converted to punycode (münchen.de → xn--mnchen-3ya.de), and a trailing dot removed.
Invalid lines are skipped and listed. In 2.0 they will make the import fail instead.
Import is delta-aware: nextdnsctl fetches the current list once, deduplicates the
input, and only sends API writes for missing domains. This reduces rate-limit pressure
when re-importing the same or overlapping lists.
Export to file
nextdnsctl denylist export <profile> backup.txt
nextdnsctl denylist export <profile> # outputs to stdout
nextdnsctl denylist export <profile> --active-only > active.txt
Clear all entries
nextdnsctl denylist clear <profile> # asks for confirmation
nextdnsctl denylist clear <profile> --yes # skip confirmation
Allowlist Commands
All denylist commands are available for allowlist with the same syntax:
nextdnsctl allowlist list <profile>
nextdnsctl allowlist add <profile> good.com trusted.com
nextdnsctl allowlist remove <profile> domain.com
nextdnsctl allowlist import <profile> allowlist.txt
nextdnsctl allowlist export <profile> backup.txt
nextdnsctl allowlist clear <profile> --yes
Parallel Requests
By default, bulk operations run 5 concurrent API requests. Adjust with --concurrency:
# Faster (more concurrent requests)
nextdnsctl --concurrency 10 denylist import myprofile blocklist.txt
# Sequential mode (verbose per-domain output, like v0.2.0)
nextdnsctl --concurrency 1 denylist import myprofile blocklist.txt
Dry-Run Mode
Preview changes before applying them:
$ nextdnsctl --dry-run denylist add myprofile bad.com evil.com
[DRY-RUN] Denylist plan:
New domains to add: 2
- bad.com
- evil.com
[DRY-RUN] No changes made.
Contributing
Pull requests welcome! See docs/contributing.md for details.
License
MIT License - see LICENSE.
Metadata
Release files for nextdnsctl 1.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nextdnsctl-1.4.0.tar.gz | 27.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nextdnsctl-1.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 45.5 kB
Release files / nextdnsctl-1.4.0.tar.gz
| Download URL | nextdnsctl-1.4.0.tar.gz |
|---|---|
| Size | 27.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1188e73c95bb50477a07ae44154647895bbe8855e7a7de398ecf330eb8379edc
|
|
BLAKE2b-256 checksum How to use checksums |
55b89ad88a16dfcc7ac9a058ff8f15be16c65eeb58215a050d2ba3b9f7509a12
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / nextdnsctl-1.4.0-py3-none-any.whl
| Download URL | nextdnsctl-1.4.0-py3-none-any.whl |
|---|---|
| Size | 18.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ed8fdf3171f816fe4ceb0f09e9d7ce3407eb500ee7703e96815836614ddf6a92
|
|
BLAKE2b-256 checksum How to use checksums |
843beb03ef95cef446fa69f9342fd763dc97696053ba609a8c8e5430e52c6fdb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency log