dnsx: a pipe-friendly DNS prober built on retryabledns, and where its sharp edges are
dnsx is a fast and multi-purpose DNS toolkit allow to run multiple DNS queries of your choice with a list of user-supplied resolvers.
At a glance
- What is it?
- dnsx is ProjectDiscovery's MIT-licensed Go command line tool for running bulk DNS queries against your own resolver list, filtering live hosts, pulling records and brute-forcing subdomains. It works best as one stage in a shell pipeline; its strict Go toolchain requirement and template-only output customisation are the parts to plan around.
- Who is it for?
- dnsx fits security researchers and infrastructure teams who already chain command line tools such as subfinder and want a fast way to resolve, filter and extract DNS records from large host lists using resolvers they choose, over TCP, UDP, DoH or DoT. It is a poor fit for someone who wants a single interactive lookup with full packet detail, or who cannot run a recent Go toolchain or a Docker image.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- projectdiscovery/dnsx2,922 ★ · +34
| Repository | 2026-10-04 | 2026-11-14 |
|---|---|---|
| projectdiscovery/dnsx | 2.9k | 2.9k |
34 Stars in the last 41 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Every query goes through the retryabledns library
dnsx is a thin, fast front end over ProjectDiscovery's retryabledns library, which handles the actual DNS exchange and retries. The go.mod pins github.com/projectdiscovery/retryabledns v1.0.118, alongside github.com/miekg/dns v1.1.73 for the wire format. That split is useful to know when something misbehaves: a resolver timeout or retry decision lives in retryabledns, while the record parsing comes from miekg/dns.
The tool answers a narrow question at scale: given many hostnames, which ones resolve, and to what. It supports A, AAAA, CNAME, PTR, NS, MX, TXT, SRV and SOA queries, plain resolution and brute-force mode, custom resolver input, resolvers over TCP, UDP, DoH and DoT, stdin and stdout, and automatic wildcard handling in the style of shuffledns. The project is MIT licensed, written in Go, and its last push landed on 2 November 2026, with v1.3.1 released on 31 August 2026.
Check the Go toolchain requirement before installing
The source install is a single command:
go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latestCheck the Go requirement in the module version being installed: the development branch and the release resolved by @latest may differ. A module’s go directive sets a minimum, not an exact version. Depending on GOTOOLCHAIN, Go may select or download a newer toolchain; if switching is disabled or unavailable, install a suitable version first.
Two other details follow from the repository layout. The default branch is dev, but @latest resolves to the newest tagged release rather than whatever sits on dev, so a fix merged recently may not be in your binary yet. And because @latest moves, two machines installing on different days can end up with different versions; the release tags (v1.2.3, v1.3.0, v1.3.1) are the stable reference points if you need repeatable results in CI.
The Docker image wraps a prebuilt binary rather than compiling one
The Dockerfile starts from alpine:latest, upgrades packages, and adds bind-tools and ca-certificates. It then copies a binary from $TARGETPLATFORM/dnsx into /usr/local/bin and sets dnsx as the entrypoint. Nothing in that file compiles Go code, so running docker build against a fresh clone will not produce a working image; the file expects a binary already built for the target platform, which is what the release tooling in .goreleaser.yml is there to produce.
For a local build, the Makefile runs go build with -ldflags set to -s -w on macOS, and to -extldflags "-static" on every other platform, producing a statically linked dnsx from cmd/dnsx/dnsx.go. make test runs go test across all packages. The repository also keeps integration_tests/, internal/ and libs/ directories, plus a MULLVAD.md file at the top level.
Three input flags decide between resolving and brute-forcing
dnsx -h prints the full switch list. The input side has three flags that change what the tool does. -l or -list takes a list of subdomains or hosts to resolve, from a file or stdin. -d or -domain takes domains to brute-force, from a file, a comma separated list, or stdin. -w or -wordlist supplies the words to combine with those domains, in the same three forms.
With no explicit list flag, dnsx reads hosts from stdin, which is how it slots behind a subdomain finder:
subfinder -silent -d hackerone.com | dnsx -silentThat pipeline takes passive results from subfinder and prints only the names that actually resolve. The query flags pick the record type: -a is the default, and -aaaa, -cname, -ns, -txt, -srv and -ptr switch to other types. Without -resp, dnsx prints just the hostname, which is handy for filtering but hides the answer.
-resp and -resp-only change what the next tool in the pipe receives
Output shape matters more than it looks, because dnsx output is usually another tool's input. -resp keeps the hostname and appends the answer in brackets, so a line reads like www.hackerone.com [104.16.100.52]. -resp-only drops the hostname and prints only the answer values, one per line:
subfinder -silent -d hackerone.com | dnsx -silent -a -resp-onlyThat form feeds a port scanner or an IP deduplication step directly, but you lose the mapping back to which host produced each address, and the same IP repeats once per host that points at it. The same flags work with other record types; -cname -resp shows where each subdomain is aliased, which surfaces third-party services behind a domain. -asn tags each host with its autonomous system, and -rcode noerror,servfail,refused filters by DNS status code, so you can isolate names that return SERVFAIL or REFUSED instead of NOERROR.
PTR sweeps accept a CIDR range or an ASN on stdin
Reverse lookups are where dnsx goes beyond a resolver list. Piping a network range into -ptr walks every address and returns the names that have PTR records:
echo 173.0.84.0/24 | dnsx -silent -resp-only -ptrPiping an autonomous system number does the same across the whole ASN:
echo AS17012 | dnsx -silent -resp-only -ptrThe go.mod pulls in projectdiscovery/mapcidr for range expansion and projectdiscovery/asnmap for ASN data. The consequence is scale: an ASN can cover a very large address space, and dnsx will issue a query for each address. Against shared public resolvers that volume can trigger rate limits or blocks, so a custom resolver list, and the projectdiscovery/ratelimit dependency the tool carries, matter far more for PTR sweeps than for resolving a short host list.
Custom output is a template, not a field selector
When neither the bracketed format nor -resp-only fits, -output-template, or -ot, replaces the default layout with a template you write on the command line. The variables match the field names of the JSONL output from -json: host, a, aaaa, cname, ns, txt, mx, srv, ptr, soa, caa, ttl, resolver, status_code, cdn-name, cdn-type, asn and query-time. An extra {{ip}} alias combines the A and AAAA records.
echo example.com | dnsx -silent -a -ot '{{host}} {{a}}'That prints example.com 104.20.23.154,172.66.147.243. The limit is in that comma: records with multiple values are joined inside a single field, so a host with several A records stays on one line. If downstream tooling expects one address per line, you either split the field yourself or use -resp-only. For structured processing, -json with a proper JSON parser is safer than a template, because TXT records can contain characters that break a space-separated format.
Editorial conclusion
dnsx fits security researchers and infrastructure teams who already chain command line tools such as subfinder and want a fast way to resolve, filter and extract DNS records from large host lists using resolvers they choose, over TCP, UDP, DoH or DoT. It is a poor fit for someone who wants a single interactive lookup with full packet detail, or who cannot run a recent Go toolchain or a Docker image. Before relying on it, check the Go requirement of the release you install and whether automatic toolchain switching is available, pin a release such as v1.3.1 instead of @latest for repeatable scans, and only point it at domains and address ranges you are authorised to enumerate.
Frequently asked questions
What does dnsx do?
dnsx is a Go command line toolkit from ProjectDiscovery that runs many DNS queries at once against resolvers you supply. It filters live hosts from a list, extracts A, AAAA, CNAME, NS, TXT, SRV, PTR and other records, brute-forces subdomains with a wordlist, and handles wildcard DNS.
How do I install dnsx?
Run go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latest. Check the Go version required by the selected release; depending on GOTOOLCHAIN, Go may switch to or download a newer toolchain. The repository also ships a Dockerfile.
Can dnsx print a custom output format?
Yes. The -output-template (-ot) flag takes a template such as '{{host}} {{a}}' using the same field names as the -json output, and records with several values are comma-joined in one field.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/projectdiscovery-dnsx)Star history chart for your README
[](https://hysenlabs.com/projects/projectdiscovery-dnsx)Was this useful?