natesales/q: A Tiny DNS Client That Speaks UDP, DoT, DoH, DoQ and ODoH
A tiny command line DNS client with support for UDP, TCP, DoT, DoH, DoQ and ODoH.
At a glance
- What is it?
- q is a Go command line DNS client that puts every modern DNS transport behind one flag set. It is a good fit for engineers who need to query DoH, DoQ or ODoH endpoints without writing throwaway scripts, and a poor fit for anyone who needs a full DNS debugging suite.
- Who is it for?
- Adopt q if you spend time querying encrypted DNS endpoints by hand or from scripts and want one binary that covers UDP, TCP, DoT, DoH, DoQ and ODoH. Do not adopt it if you need a full debugging suite with zone-file tooling or a permissive licence for a closed-source product.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 95 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 October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap q fills between dig and a hand-written HTTP client
dig covers plain DNS well. It does not speak DoH, DoQ or ODoH, and getting a JSON answer out of it means parsing its text output. The alternative most engineers reach for is curl against a DoH endpoint, which means base64url-encoding the DNS wire format yourself and decoding the response. q removes that step. It is a single Go binary that accepts a name, a list of record types and a server, and handles the transport selection internally.
The audience is narrow and specific. It is for network engineers, SREs and developers who need to ask a question of an encrypted resolver and see the answer in a form a script can consume. The README's own examples show the intended shape: a bare domain, a domain with record types, a domain with an explicit server, and the same query sent over HTTPS. The project does not try to be a zone editor or a packet capture tool.
How the transport layer is selected from the server argument
The mechanism is visible in the repository layout. There is a resolver.go at the top level and a transport/ directory beside it, with registry/ and output/ as separate packages. That split suggests the resolver parses the server string, picks a transport from the registry, and hands the response to an output formatter. The README's example line makes the selection rule explicit: q example.com MX @https://dns.quad9.net sends the query over HTTPS, while the parenthetical notes that TCP, TLS, QUIC or ODoH are equally available.
The server argument is not limited to a hostname. The README shows a DNS Stamp form, q @sdns://AgcAAAAAAAAAAAAHOS45LjkuOQA, which means the client can decode a stamp and derive the endpoint and protocol from it. go.mod lists github.com/jedisct1/go-dnsstamps as a direct dependency, which is consistent with that behaviour. The same file lists github.com/miekg/dns, github.com/quic-go/quic-go and github.com/sthorne/odoh-go, covering the plain, QUIC and Oblivious DoH paths respectively.
Connection handling is configurable rather than fixed. The usage text documents --reuse-conn (default true), --id-check (default true), --http2 and --http3 for DoH, and --quic-length-prefix (default true) for the RFC 9250 length prefix. Those defaults matter: a client that reuses connections and checks response IDs is doing the safe thing by default, and the flags exist for the cases where that interferes.
Installing q and running a first query
The README does not contain an install section. It links to GitHub releases through the release badge, and the repository ships a .goreleaser.yml plus a Dockerfile, so the two supported paths visible in the repository are a release binary and a container image. The Dockerfile is minimal: it copies a binary named q into /usr/bin/q and sets it as the entrypoint. That means the image expects the binary to be built or placed alongside the Dockerfile first; it is not a build-from-source Dockerfile.
Once you have the binary, the first query is the one from the README. This asks for MX and SOA records for example.com using the default server:
q example.com MX SOATo point the same query at a specific server over HTTPS, pass the server with an @ prefix. The scheme in the URL is what selects DoH:
q example.com MX @https://dns.quad9.netFor scripted use, switch the output format. The README lists pretty, column, json, yaml and raw as valid values, with pretty as the default:
q example.com MX --format=jsonThe raw format is described as dig-compatible, which is the right choice when you want to paste output into a ticket or compare it against an existing dig transcript. The JSON and YAML formats are the ones to reach for when another program reads the result.
Where q stops being the right tool
q is a query client. The usage text includes --recaxfr for recursive AXFR, and there is an xfr.go file at the repository root, so zone transfer is present in some form. But the README does not document what the client does with a partial transfer, how it reports a refused AXFR, or how it handles a zone that exceeds memory. If zone transfer is your primary use case, that gap is a real risk.
The verification flags deserve the same caution. --tls-insecure-skip-verify exists and disables certificate verification, and the usage text sets --tls-min-version to 1.0 by default. TLS 1.0 as a floor is a compatibility choice, not a security posture. The README does not explain why that default was chosen, and it does not warn against the insecure-skip-verify flag. A team that adopts q for encrypted DNS should set --tls-min-version explicitly rather than inherit the default.
The project is also GPL-3.0. For internal tooling and interactive use that is unremarkable. For a product that links the code or ships a modified binary, the licence terms apply. The README does not discuss this, which is expected for a CLI tool, but it is the kind of thing worth checking before vendoring.
q against dig, kdig and dog
The closest comparison is dig itself. dig is the reference implementation for plain DNS and its output format is what everyone has learned to read. q's --format=raw exists precisely because that familiarity is valuable. The difference is transport coverage: dig does not speak DoH, DoQ or ODoH, and q does. If your work is entirely plain DNS against local resolvers, dig is already installed and does the job.
kdig, from the Knot DNS project, also covers DoT and DoH and adds zone transfer and DNSSEC validation tooling. The README does not claim DNSSEC validation, only the ability to set the DO bit with -d. That is a meaningful distinction: q can ask for DNSSEC records, but the documentation does not show it validating signatures.
dog is the other common modern client, and its output is closer to a structured record view. q's advantage here is breadth: ODoH with a --odoh-proxy argument, DNS Stamps, EDNS0 client subnet, NSID, cookies, padding and Extended DNS Errors (RFC 8914) are all exposed as flags. That is a wide surface for a small binary, and it is the reason to pick q over the alternatives.
Release cadence, maintenance and upgrade cost
The last push to the repository was on 2026-06-28. The most recent tagged release is v0.19.12 from 2026-02-27, preceded by v0.19.11 on 2025-11-09 and v0.19.10 on 2025-11-04. The version numbers sit in the 0.19.x range, which signals that the project has not committed to a 1.0 API. For a CLI that matters less than for a library, because the interface is the flag set rather than a Go API, but the flag set is not frozen either.
go.mod targets Go 1.25.5 and pins a set of direct dependencies that includes quic-go, odoh-go and dnscrypt/v2. Those are the libraries most likely to need attention when protocol drafts change. Upgrading q means rebuilding against whatever those modules resolve to at that point, which is the normal cost of a Go CLI that tracks moving protocols.
The licence is GPL-3.0, and the repository carries a LICENSE file at the root. The Dockerfile copies a prebuilt binary rather than building from source, so anyone distributing a container built from it should confirm how the GPL applies to their distribution. That is a question for whoever handles licensing, not something the README answers.
Editorial conclusion
Adopt q if you spend time querying encrypted DNS endpoints by hand or from scripts and want one binary that covers UDP, TCP, DoT, DoH, DoQ and ODoH. Do not adopt it if you need a full debugging suite with zone-file tooling or a permissive licence for a closed-source product. Before relying on it, run q example.com MX --format=json against your own resolver and confirm the JSON shape your pipeline expects.
Frequently asked questions
Does q support DNS over HTTPS and DNS over QUIC?
Yes. The README lists UDP, TCP, DoT, DoH, DoQ and ODoH as supported transports, and shows a DoH example using @https://dns.quad9.net. DoQ is handled through the quic-go dependency, with --quic-alpn-tokens defaulting to doq and doq-i11.
How do I get q?
The README has no install section. It links to GitHub releases through a release badge, and the repository contains a .goreleaser.yml and a Dockerfile, so a release binary or a container image are the paths the repository supports. The Dockerfile copies a binary named q into /usr/bin/q and uses it as the entrypoint.
What output formats does q produce?
The usage text lists pretty, column, json, yaml and raw, with pretty as the default. The README describes raw as dig format and shows --format=json and --format=yaml as alternatives.
Is q actively maintained?
The repository is not archived and the last push was on 2026-06-28. The most recent release is v0.19.12 from 2026-02-27. Version numbers remain in the 0.19.x range, so no 1.0 stability commitment is visible.
What licence does q use?
The repository is licensed GPL-3.0 and carries a LICENSE file at the root. The README does not discuss licence implications for redistribution or for linking the code into another product.
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/natesales-q)