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.
In one line:
example.com. TXT "v=spf1 include:_spf.example.com ~all"
└── this name ┘ └type┘ └── carries this free text| Type number | 16 |
| RFC | RFC 1035 §3.3.14 |
| RDATA | One 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..."The name
txt.example.isitdns.netcarries a free-text note. TXT records hold whatever a human or a protocol wants to park in DNS: proofs of ownership, mail policy, or a message like this one.
When to use it#
The four big uses:
| Purpose | Pattern |
|---|---|
| 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.1Server: 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
digoutput for everyone. See query-types for how resolvers and caches expose every answer they receive.
dig example#
Apex SPF#
dig @1.1.1.1 example.com TXT +short"v=spf1 -all"
"_k2n1y4vw3qtb4skdx9e7dxt97qrmmq9"nslookup -type=TXT example.com 1.1.1.1Server: 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.1Server: 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 +shortfor 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.1Server: 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-DnsNameuses the system-configured DoH resolver when the OS is set up for encrypted DNS; there is no-DnsOverHttpsparameter and it does not accept an arbitrary endpoint as-Server. To probe a specific DoH service, use thecurlform 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
SPFRRtype (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-challengeTTL 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.