is it dns? / wiki ← back to the live monitor

TXT: arbitrary text

A name to a string. TXT was supposed to be a comments field; it grew up to be the carrier for SPF, DKIM, DMARC, ACME challenges, domain ownership proofs, and every other piece of structured metadata that someone decided should live in DNS.

Type number16
RFCRFC 1035 §3.3.14
RDATAOne or more character strings, each up to 255 bytes, concatenated by the consumer

What it holds#

A sequence of <length><bytes> string segments. On the wire each segment is at most 255 bytes; consumers join the segments back together before parsing (display tools like dig show them as separate quoted strings). The string itself is opaque: the meaning is whatever convention the consumer adopts.

txt.example.isitdns.net.        TXT   "It was DNS. It is always DNS."
example.com.                    TXT   "v=spf1 include:_spf.mailprovider.com ~all"
_dmarc.example.com.             TXT   "v=DMARC1; p=none; adkim=r; aspf=r"
_acme-challenge.example.com.    TXT   "abc123..."

When you'll use it#

The four big uses:

PurposePattern
SPF<domain> TXT "v=spf1 ..." (one record per domain max)
DKIM<selector>._domainkey.<domain> TXT "v=DKIM1; k=rsa; p=..."
DMARC_dmarc.<domain> TXT "v=DMARC1; ..."
ACME DNS-01_acme-challenge.<name> TXT "<base64url digest>" (RFC 8555 §8.4): added and removed by your ACME client (certbot etc.) during cert issuance
Domain verification<vendor>=<token> at the apex (Google, Microsoft, Apple, and many more); some vendors want the token at a dedicated underscore subdomain instead, so follow their instructions exactly

A simple example you can query right now:

dig @1.1.1.1 txt.example.isitdns.net TXT +short
"It was DNS. It is always DNS."
nslookup -type=TXT txt.example.isitdns.net 1.1.1.1
Server:         1.1.1.1
Address:        1.1.1.1#53

Non-authoritative answer:
txt.example.isitdns.net text = "It was DNS. It is always DNS."

When not to use it#

  • For machine-discoverable services with well-defined record types (SRV, CAA, HTTPS/SVCB, etc.): don't reach for TXT when a typed record exists.
  • For ownership records that already have a typed alternative: e.g., don't put a host's address in TXT.
  • For anything secret. DNS is public. Putting secrets in TXT is putting them in dig output for everyone. See query-types for how resolvers and caches expose every answer they receive.

dig examples#

Apex SPF#

dig @1.1.1.1 example.com TXT +short
"v=spf1 -all"
"_k2n1y4vw3qtb4skdx9e7dxt97qrmmq9"
nslookup -type=TXT example.com 1.1.1.1
Server:         1.1.1.1
Address:        1.1.1.1#53

Non-authoritative answer:
example.com     text = "v=spf1 -all"
example.com     text = "_k2n1y4vw3qtb4skdx9e7dxt97qrmmq9"

DKIM at a selector#

dig @1.1.1.1 sig1._domainkey.example.com TXT +short
"v=DKIM1; p="
nslookup -type=TXT sig1._domainkey.example.com 1.1.1.1
Server:         1.1.1.1
Address:        1.1.1.1#53

Non-authoritative answer:
sig1._domainkey.example.com     text = "v=DKIM1; p="

An empty p= field means the key has been revoked (RFC 6376 §3.6.1). A validly publishing domain would show a Base64-encoded RSA or Ed25519 public key there.

ACME DNS-01 challenge (mid-renewal)#

dig @1.1.1.1 _acme-challenge.example.com TXT +short
"12Z-wRjmkwPupycBbFJ3ZjujOps9gCGmBPj9BzUSvyA"
"DUB6OB4ruWFHMZ7mVn1z01dC6kZBeCjthZsKCP94VjE"
"EHeiHtGZ-zmDoSCWFUlc59SAmtiZVEDwHB1kos0M76Y"
"Y1I_ADGr2MsnUUJs7A0wu5dnKYzRPz-YcQRIjuSzXN4"

nslookup can show this, but the output is verbose. Use dig +short for scripts.

Multiple tokens appear when several certificates are being validated at once. Wildcards also land here: *.example.com validates at _acme-challenge.example.com with the *. stripped (RFC 8555 §7.1.3), so a combined example.com + *.example.com order leaves two tokens at the same name. The CA accepts when any one of the published records matches its challenge (RFC 8555 §8.4).

DMARC#

dig @1.1.1.1 _dmarc.example.com TXT +short
"v=DMARC1;p=reject;sp=reject;adkim=s;aspf=s"
nslookup -type=TXT _dmarc.example.com 1.1.1.1
Server:         1.1.1.1
Address:        1.1.1.1#53

Non-authoritative answer:
_dmarc.example.com      text = "v=DMARC1;p=reject;sp=reject;adkim=s;aspf=s"

DoH query (HTTPS)#

DoH is just DNS-over-HTTPS. The JSON format uses application/dns-json, a Cloudflare/Google extension not mandated by RFC 8484:

curl -s -H 'accept: application/dns-json' \
  'https://cloudflare-dns.com/dns-query?name=txt.example.isitdns.net&type=TXT' \
  | jq .Answer
[
  {
    "name": "txt.example.isitdns.net",
    "type": 16,
    "TTL": 300,
    "data": "\"It was DNS. It is always DNS.\""
  }
]

The TTL field is the time remaining in the resolver's cache: a cache miss shows the record's full 300, and repeat queries count down from there.

nslookup cannot do DoH/DoT/DoQ. On Windows, Resolve-DnsName uses the system-configured DoH resolver when the OS is set up for encrypted DNS; there is no -DnsOverHttps parameter and it does not accept an arbitrary endpoint as -Server. To probe a specific DoH service, use the curl form above.

Gotchas#

  • 255-byte string limit. A TXT record can hold multiple 255-byte strings, but a single string is capped at 255. Long DKIM public keys (2048-bit RSA) exceed 255 bytes and must be split using quoted-string concatenation in the zone file: ``text selector1._domainkey TXT "v=DKIM1; k=rsa; p=ABC..." "DEF...XYZ" `` Consumers join consecutive strings before parsing. Whether the split happens for you depends on the provider: some management UIs split long strings automatically on input, others (and hand-written zone files) make you write the quoted segments yourself.
  • One SPF per domain. Multiple SPF TXT records at the same name is invalid per RFC 7208 §3.2; receiving servers will (correctly) treat it as a permerror. If you need multiple include rules, combine them: v=spf1 include:a include:b ~all.
  • There is no SPF record type anymore. A dedicated SPF RRtype (type 99) existed during SPF's experimental phase; it was discontinued, and SPF data must be published as TXT only (RFC 7208 §3.1). If your DNS provider still offers a record type named SPF, skip it.
  • Case-insensitive name, case-preserving RDATA. DNS names are case-insensitive; TXT strings are case-sensitive. ACME, DKIM, etc. all care about exact bytes.
  • Quoting and escaping. Spaces inside TXT must be inside quotes. Backslashes escape special characters. A TXT with literal " needs \". Most DNS-management APIs accept the raw string and handle escaping for you.
  • Public. Already said it. Repeating because someone always tries.
  • DMARC must live at _dmarc.<domain>: not at the apex. SPF must live at the apex. DKIM at <selector>._domainkey.<domain>. Misplacing any of these silently disables email auth. See email-records for the full placement rules.
  • TTL matters for ACME. A high TTL (e.g., 3600) lets resolvers cache the old token, or a negative answer from before the record existed, long after your client publishes a fresh one; validation and pre-checks then see stale data until the cache expires. Keep _acme-challenge TTL at 60-300 seconds.
  • Verification tokens accumulate. Apex TXT sets grow one <vendor>=<token> at a time and nobody deletes them. Prune tokens for services you no longer use: every TXT query for the name (including every SPF check) hauls back the whole set.

See also#