---
title: 'DNS Record Types'
source: 'https://academia.sh/en/courses/how-the-internet-works/dns-record-types'
course: 'How the Internet Works'
language: en
updated: '2026-08-17T18:07:03+00:00'
license: 'CC BY-SA 4.0'
---

# DNS Record Types

Address, alias, mail, name server and text records; which problem each type answers and the combination limits on alias records.

The previous lesson showed that a record consists of name, time to live, class, type and
data fields, and passed over the type field with a single example, `A`. Yet a name does
not hold only an address underneath it.

This lesson covers the values the type field can take. Each type answers a distinct
problem; seeing why each type exists shows that the domain name system is more than an
address book.

## The Zone and the Zone File

The full set of records a single authoritative server is responsible for is called a
**zone**. The zone written out in text form is called a **zone file**; each line is one
record.

The zone for the name `example.test` might look like this:

```
example.test.        3600  IN  A      192.0.2.10
example.test.        3600  IN  AAAA   2001:db8::10
www.example.test.    3600  IN  CNAME  example.test.
example.test.        3600  IN  MX     10 mail.example.test.
mail.example.test.   3600  IN  A      192.0.2.20
example.test.         600  IN  TXT    "verification=abc123"
example.test.       86400  IN  NS     ns1.example.test.
```

Every line follows the same five-field layout. The program below verifies this: it
splits the lines into fields and rewrites them keyed by the type field.

```python
ZONE = """\
example.test.        3600  IN  A      192.0.2.10
example.test.        3600  IN  AAAA   2001:db8::10
www.example.test.    3600  IN  CNAME  example.test.
example.test.        3600  IN  MX     10 mail.example.test.
mail.example.test.   3600  IN  A      192.0.2.20
example.test.         600  IN  TXT    "verification=abc123"
example.test.       86400  IN  NS     ns1.example.test.
"""


def parse_record(line: str) -> tuple[str, int, str, str, str]:
    name, ttl, record_class, record_type, *data = line.split()
    return name, int(ttl), record_class, record_type, " ".join(data)


for line in ZONE.strip().splitlines():
    name, ttl, record_class, record_type, data = parse_record(line)
    print(f"{record_type:<6} name={name:<19} ttl={ttl:<6} data={data}")

print()
types = sorted({parse_record(l)[3] for l in ZONE.strip().splitlines()})
print("record types in zone:", len(types))
print("types:", types)
```

```
A      name=example.test.       ttl=3600   data=192.0.2.10
AAAA   name=example.test.       ttl=3600   data=2001:db8::10
CNAME  name=www.example.test.   ttl=3600   data=example.test.
MX     name=example.test.       ttl=3600   data=10 mail.example.test.
A      name=mail.example.test.  ttl=3600   data=192.0.2.20
TXT    name=example.test.       ttl=600    data="verification=abc123"
NS     name=example.test.       ttl=86400  data=ns1.example.test.

record types in zone: 6
types: ['A', 'AAAA', 'CNAME', 'MX', 'NS', 'TXT']
```

That the parser is identical for every type is a feature of the design: the type field
only says how the data field should be interpreted; it does not change the record's
frame. Defining a new type does not stop existing servers from carrying the record.

The relationship between a record's name and the name being looked up deserves
attention: a single zone can hold multiple records for the same name. A query is made
with the name **and** type together.

## Address Records

An `A` record carries an IPv4 address, an `AAAA` record an IPv6 address. The two are
distinct types, and a single name can have both; in the zone above, both are defined for
`example.test`.

A single name can be given multiple address records. In that case the resolver returns
all of them, and the client picks one. This is the simplest way to distribute requests
across multiple servers.

The limit of this method is clear: the domain name system does not know which of the
addresses is actually up. When a server fails, its record stays in the rotation until it
is removed by hand, and even after removal it keeps living in caches for as long as the
time to live. This is a direct consequence of the time-to-live trade-off established in
the previous lesson.

## Alias Records

A `CNAME` record does not point to an address but to **another name**. When
`www.example.test` is queried, the answer is "this name's counterpart is the name
`example.test`," and the resolver continues the lookup through that name.

The reason to use it applies the indirection idea from the previous lesson one layer
further: the address is defined in one place, and other names attach to it. When the
address changes, a single record is updated.

This type has two constraints, and both come from the same source: an alias record
hands off the **entirety** of the name to another name.

**No other record can exist at the same name.** If a name has an alias record, no other
type of record can be defined for that name. If it could, a contradiction would arise:
the name would say both "my counterpart is this name" and "my address is this."

**It cannot be used at a zone's root name.** The name `example.test` itself cannot be an
alias, because that name already must hold records that are required to exist — the
authority and name server records covered below. Under the first constraint, these
cannot coexist with an alias.

This second constraint is a common obstacle in practice: the name `www.example.test` can
be aliased to a provider's name, but the same cannot be done for `example.test`, which
requires an address record written directly at it.

## Mail Records

An `MX` record says which server delivers mail sent to that domain name. Its data field
has two parts: a priority number and a server name.

```
example.test.        3600  IN  MX     10 mail.example.test.
```

A **lower** priority number is preferred. When multiple mail records are defined, the
sending side tries the lowest-numbered server first and moves to the next if it cannot
be reached. The number itself carries no other meaning; it exists only for ordering.

The existence of this record shows an important distinction: a domain name's web traffic
and mail traffic can go to different servers. The page for `example.test` may come from
`192.0.2.10` while the same name's mail is delivered to `192.0.2.20` via
`mail.example.test`. A domain name names an **administrative domain**, not a single
machine.

The name a mail record points to should not be an alias; it must carry an address record
directly.

## Name Server and Authority Records

An `NS` record declares which servers a zone's authority belongs to. The "ask this one"
answer received at every step of the previous lesson's resolution chain is exactly this
record.

This record exists in two places at once: within the zone itself and in the zone one
level up. The copy at the level above is the record that signals delegation; it is what
was reported to the registry during registration in the earlier lesson. A mismatch
between the two copies leads to inconsistencies that are hard to diagnose during
resolution.

Every zone also carries an `SOA` record. This record holds the zone's administrative
information: the primary name server, a responsible address, the zone's serial number,
and the intervals that determine how often secondary servers refresh their copies. The
serial number lets secondary servers tell whether the zone has changed.

## Text Records

A `TXT` record carries free text. It has no fixed function of its own, which makes it a
common tool for schemes that want to prove ownership of a name.

The usage pattern is this: a service asks the name owner to place a specific piece of
text in its zone. Once the text appears, control over that name's management is proven.
This rests on the authority delegation established in the previous lesson — whoever can
write a record into the zone is the authority for that name.

Mail verification schemes also operate through this record type, writing text that
follows a defined syntax. The details of these schemes are the subject of the
Application Layer Protocols course.

## Choosing a Type

| Type | Question it answers |
|---|---|
| `A` | What is this name's IPv4 address |
| `AAAA` | What is this name's IPv6 address |
| `CNAME` | Which name does this name stand in for |
| `MX` | Where is this name's mail delivered |
| `NS` | Who holds authority over this zone |
| `SOA` | What is this zone's administrative information |
| `TXT` | What free text is attached to this name |

The order followed when designing a zone follows from this: authority records are
required for the zone to exist, address records are needed for the service to be
reachable, alias records reduce maintenance, and mail and text records define other
services tied to the domain name.

## Summary

- A zone is the full set of records a single authoritative server is responsible for;
  every record follows the same five-field layout, and the type field only determines
  how the data field is interpreted.
- `A` and `AAAA` carry addresses; a name can be given multiple addresses to distribute
  requests, but the system does not know the servers' health.
- `CNAME` hands a name off to another name; because no other record can exist at the
  same name, it cannot be used at a zone's root name.
- `MX` reports the server mail is delivered to, in priority order; a domain name's web
  and mail traffic can go to different servers.
- `NS` declares authority and appears both in the zone and one level up; `SOA` carries
  the zone's administrative information.
- `TXT` carries free text and is used to prove authority over a name.

## Next Step

This lesson established at the record level that the name `example.test` points to the
address `192.0.2.10`. What remains is the question of what is at that address: a machine
must be there, running continuously, waiting for the request. The next lesson covers how
that machine is provisioned, how the same address can serve multiple domain names, and
the trade-offs among hosting options.
