Type something to search...
What Is a DNS Zone File, and How Do You Read One?

What Is a DNS Zone File, and How Do You Read One?

Every DNS dashboard, from your registrar's simple record list to a cloud provider's API, is ultimately a friendly front end for the same thing: a zone file. Sooner or later you will meet one directly, whether you are exporting records before transferring DNS to another provider, importing a BIND file into a new host, or debugging a server you inherited. Zone files look cryptic at first because they lean heavily on shorthand: missing names, missing TTLs, names with and without trailing dots. Once you know the half-dozen rules behind that shorthand, they become very easy to read. This article walks through the format piece by piece, explains each directive and field, and shows how to validate a zone before you load it. For an overview of the individual record types you will see, refer to What Are DNS Records?

What Is a DNS Zone File?

A DNS zone file is a plain-text file that describes all the resource records in one DNS zone, written in the master file format defined in RFC 1035, section 5. Authoritative servers such as BIND, NSD and Knot load these files to answer queries. Managed DNS providers usually store records in a database, but nearly all of them can import and export this format, which makes it the common language of DNS.

A zone file covers one zone, such as example.com, not necessarily one domain. Subdomains that have been delegated elsewhere live in their own zone files. That distinction is explained in What Is the Difference Between a DNS Zone and a Domain?

A Complete Example

Here is a small but realistic zone file. We will take it apart section by section.

; Zone file for example.com
$ORIGIN example.com.
$TTL 3600

@           IN  SOA   ns1.example.com. hostmaster.example.com. (
                      2026100101 ; serial
                      7200       ; refresh (2 hours)
                      900        ; retry (15 minutes)
                      1209600    ; expire (2 weeks)
                      300 )      ; negative caching TTL (5 minutes)

; Nameservers
            IN  NS    ns1.example.com.
            IN  NS    ns2.example-dns.net.

; Apex addresses
            IN  A     203.0.113.10
            IN  AAAA  2001:db8::10

; Mail
            IN  MX    10 mail.example.com.
            IN  MX    20 backup-mx.example-mail.net.
            IN  TXT   "v=spf1 mx -all"

; Hosts
ns1         IN  A     203.0.113.53
mail        IN  A     203.0.113.25
www   300   IN  CNAME example.com.
api         IN  A     203.0.113.20
            IN  A     203.0.113.21
_dmarc      IN  TXT   "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"

The Building Blocks

Comments

Everything after a semicolon (;) on a line is a comment. Comments are ignored by the server, which makes them ideal for documenting why a record exists. Many outages start with someone deleting a record nobody remembered the purpose of.

Directives

Lines starting with a dollar sign are directives that control how the rest of the file is interpreted, not records themselves.

DirectiveDefined inWhat it does
$ORIGINRFC 1035Sets the domain appended to relative names
$TTLRFC 2308Sets the default TTL for records without an explicit one
$INCLUDERFC 1035Pulls in another file at this point
$GENERATEBIND extensionCreates a series of records from a pattern

$ORIGIN example.com. means any name that does not end with a dot gets .example.com. appended. $TTL 3600 means records with no TTL of their own are cached for an hour. If you want to understand how that number affects changes, read What Is a TTL in DNS?

$GENERATE is handy for repetitive records, though it is specific to BIND and some compatible servers:

$GENERATE 1-20 host-$ IN A 198.51.100.$

This creates host-1 through host-20, pointing at 198.51.100.1 through 198.51.100.20.

The record line

Every resource record follows this shape, though several fields can be omitted:

owner-name   [TTL]   [class]   type   data
  1. Owner name — the name the record belongs to.
  2. TTL — how long resolvers may cache it, in seconds.
  3. Class — almost always IN (Internet).
  4. Type — A, AAAA, MX, CNAME, TXT and so on.
  5. Data (RDATA) — the value, whose format depends on the type.

TTL and class can appear in either order, and both can be left out. Take www 300 IN CNAME example.com. from the example: the owner is www, the TTL is 300 seconds (overriding the $TTL default), the class is IN, the type is CNAME and the data is example.com.

The Shorthand Rules That Confuse Everyone

1. The at sign means the origin

@ stands for the current $ORIGIN. In our file, @ is example.com., so the SOA record belongs to the apex.

2. A blank owner repeats the previous one

If a line starts with whitespace, the record has the same owner as the line above. That is why the NS, A, AAAA, MX and TXT lines under the SOA all belong to example.com. even though no name appears, and why the second api line adds a second A record to api.example.com. This rule is the single most common source of misreading: an accidental leading space attaches a record to the wrong name.

3. The trailing dot makes a name absolute

A name ending in a dot is fully qualified and used exactly as written. A name without a trailing dot is relative and gets the origin appended. The classic mistake looks like this:

www   IN  CNAME  example.com

Without the trailing dot, this means www.example.com. CNAME example.com.example.com., which almost certainly does not exist. The same mistake in an MX or NS record silently breaks mail or delegation. If the idea of a fully qualified name is new, see What Is a Fully Qualified Domain Name?

4. Parentheses allow multi-line records

Parentheses let a record span several lines, which is how the SOA record is usually written for readability. The newlines inside the parentheses are ignored.

5. Missing TTLs inherit

A record without a TTL uses the $TTL value. If there is no $TTL either, older servers fell back to the SOA minimum field, but modern practice (RFC 2308) is to always set $TTL explicitly.

6. Quotes group text

TXT data with spaces must be wrapped in double quotes. A single TXT string is limited to 255 bytes; longer values such as large DKIM keys are written as several quoted strings in a row, which clients join together.

selector1._domainkey  IN  TXT  ( "v=DKIM1; k=rsa; "
                                 "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA" )

Reading the SOA Record

The SOA (Start of Authority) record always comes first and describes the zone itself. In our example:

  • ns1.example.com. is the primary nameserver.
  • hostmaster.example.com. is the contact email, with the first dot standing in for the @, so it means hostmaster@example.com.
  • The five numbers are the serial, refresh, retry, expire and negative caching TTL.

The serial is the most operationally important. Secondaries only fetch an updated copy of the zone if the serial increases, which is why the date-based YYYYMMDDnn format is common. Each field is covered in detail in What Is an SOA Record?, and how secondaries use the serial is explained in What Is a DNS Zone Transfer?

Expanding the Shorthand

A good way to check your reading is to have a tool print the zone in fully expanded form. BIND's named-compilezone does exactly that:

named-compilezone -f text -F text -o - example.com db.example.com

The -o - flag writes output to standard output. Every record comes out with its full owner name, explicit TTL and class (exact ordering and spacing vary slightly between BIND versions):

example.com.                3600 IN SOA   ns1.example.com. hostmaster.example.com. 2026100101 7200 900 1209600 300
example.com.                3600 IN NS    ns1.example.com.
example.com.                3600 IN NS    ns2.example-dns.net.
example.com.                3600 IN A     203.0.113.10
example.com.                3600 IN MX    10 mail.example.com.
example.com.                3600 IN MX    20 backup-mx.example-mail.net.
example.com.                3600 IN TXT   "v=spf1 mx -all"
example.com.                3600 IN AAAA  2001:db8::10
_dmarc.example.com.         3600 IN TXT   "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
api.example.com.            3600 IN A     203.0.113.20
api.example.com.            3600 IN A     203.0.113.21
mail.example.com.           3600 IN A     203.0.113.25
ns1.example.com.            3600 IN A     203.0.113.53
www.example.com.            300  IN CNAME example.com.

Comparing this with the original makes the inheritance rules obvious. You can do the same in Python with dnspython:

import dns.zone
import dns.rdatatype

zone = dns.zone.from_file("db.example.com", origin="example.com", relativize=False)

for name, ttl, rdata in zone.iterate_rdatas():
    print(f"{name.to_text():30} {ttl:>6} IN {dns.rdatatype.to_text(rdata.rdtype):6} {rdata.to_text()}")

dns.zone.from_file parses the file with the same rules a nameserver uses, and iterate_rdatas yields every record with its absolute name and resolved TTL. It raises an exception if the file has syntax errors, which makes it useful in CI checks.

Validating a Zone File Before Loading It

Never load an edited zone file without checking it first. With BIND:

named-checkzone example.com /etc/bind/db.example.com
zone example.com/IN: loaded serial 2026100101
OK

named-checkzone parses the file and reports syntax errors, out-of-zone data, CNAMEs that conflict with other records, and MX or NS targets that point at CNAMEs. Once it passes, reload just that zone:

sudo rndc reload example.com

This tells the running server to re-read the file for example.com without restarting. If you are setting up a server from scratch, How to Run Your Own DNS Server with BIND covers the full configuration.

Exporting and Importing Zone Files

Most managed DNS providers let you export your records as a BIND-format zone file and import one. A few practical points:

  1. Provider-only features disappear. ALIAS records, proxied flags, health-checked records and weighted routing have no standard representation. Exports may flatten them to plain records or omit them.
  2. SOA and NS are often replaced. When you import, the new provider usually substitutes its own SOA and NS records.
  3. TTLs may be normalised. Some providers enforce minimum TTLs on import.
  4. Check relative names. If an export uses relative names without a $ORIGIN, the importer must be told the zone name.

Always diff the expanded output of the old and new zone after a migration.


DNS Zone File FAQ

It is plain text in the master file format defined in RFC 1035 section 5, often called BIND format. Most DNS servers and providers can read and write it.

It stands for the current origin, usually the zone's own name. In the example.com zone, @ means example.com.

A trailing dot marks a fully qualified name that is used as written. Names without a trailing dot are relative, and the origin is appended to them.

The record inherits the owner name from the previous record. This is intentional shorthand, but an accidental leading space can attach a record to the wrong name.

It sets the default time to live for any record in the file that does not specify its own TTL. It was standardised in RFC 2308.

Run named-checkzone with the zone name and file path. It reports syntax errors and common logical mistakes and prints OK if the file is valid.

Yes, if you have secondary nameservers. They only fetch a new copy when the serial increases. Many people use a date-based serial such as 2026100101.

Usually not directly, but most providers let you import and export zone files. Provider-specific record types may not survive the round trip.

Conclusion

A DNS zone file is simply a list of resource records with a few rules that keep it short: $ORIGIN and $TTL set defaults, @ stands for the origin, a blank owner repeats the previous name, a trailing dot makes a name absolute, and parentheses let long records span lines. Once you know those rules, any zone file reads like a table of names, types and values.

The habits that matter most are equally simple: always use trailing dots on fully qualified targets, increment the serial every time you edit, validate with named-checkzone before reloading, and when in doubt, expand the file with named-compilezone or dnspython to see exactly what the server will serve.

Here are some useful references for going deeper on DNS zone files:

  1. RFC 1035: Domain Names - Implementation and Specification — section 5 defines the master file format.
  2. RFC 2308: Negative Caching of DNS Queries — introduces the $TTL directive and redefines the SOA minimum field.
  3. BIND 9 Documentation: BIND 9 Administrator Reference Manual — zone file syntax, $GENERATE, and the named-checkzone and named-compilezone tools.
  4. dnspython Documentation: dnspython — the Python library used above to parse zone files.
  5. Cloudflare Learning Center: What is a DNS zone? — a short explainer of zones and zone files.
Tags :
Share :

Related Posts

What Is the Difference Between Authoritative and Recursive DNS Servers?

What Is the Difference Between Authoritative and Recursive DNS Servers?

When someone says "the DNS server," they could mean two completely different machines doing two completely different jobs. One kind of server holds t

Continue Reading
Can DNS settings affect website speed?

Can DNS settings affect website speed?

Yes, DNS settings can significantly affect the speed at which a website loads for its users. DNS, or Domain Name System, is often likened to the inte

Continue Reading
Can You Use a CNAME Record on the Root Domain?

Can You Use a CNAME Record on the Root Domain?

It is one of the most common DNS questions there is. Your hosting platform says "add a CNAME pointing to myapp.example-cdn.net," it works perfectly

Continue Reading