CoreDNS’s cache plugin is a powerful tool for reducing latency and offloading your upstream DNS servers, but its effectiveness hinges on a few counter-intuitive tuning knobs that most people miss.

Let’s see it in action. Imagine a simple CoreDNS setup serving internal clients.

.:53 {
    errors
    cache 30
    forward . 8.8.8.8 1.1.1.1
}

Here, cache 30 means CoreDNS will hold onto DNS responses for 30 seconds. If a client asks for the same record again within that window, CoreDNS serves it directly from its memory, bypassing the forward plugin and the upstream servers entirely.

This looks simple, but the real magic is in how you tune cache and how it interacts with TTLs (Time To Live) on the DNS records themselves.

The problem CoreDNS cache solves is obvious: every DNS query has to travel from the client to a DNS server, then potentially to an upstream server, and back. This adds latency. If you have many clients asking for the same frequently accessed domains (like internal services or popular external sites), you’re hammering your upstream DNS infrastructure.

Internally, the cache plugin acts as a simple in-memory key-value store. The key is the DNS query (domain name + record type), and the value is the DNS response, including the actual record data and its TTL. When a query arrives, CoreDNS first checks its cache. If a matching entry is found and hasn’t expired, it’s returned immediately. If not, the query proceeds to the next plugin (in this case, forward).

The cache plugin takes a single argument: the default cache TTL. This is the maximum amount of time CoreDNS will hold onto a record if the record itself doesn’t specify a TTL. If a DNS record from an upstream server has a TTL of 60 seconds, CoreDNS will cache it for at most 60 seconds. If that same record has a TTL of 5 seconds, CoreDNS will cache it for at most 5 seconds. If the record has no TTL (which is rare but possible), CoreDNS will cache it for the duration specified in the cache directive. So, cache 30 means "cache records for up to 30 seconds, unless the record itself tells me to cache it for less time."

This is where the common mistake lies: people often set the cache directive to a very high number, thinking "more cache is better." But if your upstream DNS servers are returning records with very low TTLs (e.g., 5 seconds for dynamic internal records), your CoreDNS cache will be constantly invalidated, offering minimal benefit. Conversely, if you have records with very high TTLs (e.g., 1 hour for stable external sites), setting cache 30 is effectively ignoring a lot of potential caching. The optimal cache value should generally be at least as high as the TTLs of the records you expect to cache most frequently. For internal services with dynamic IPs, you might want a lower cache TTL (e.g., cache 10) to ensure clients get updated records quickly. For external, stable services, you can push this much higher (e.g., cache 3600 for an hour, or even cache 86400 for a day, provided the upstream TTLs support it).

The cache directive can also take optional parameters like denial and prefetch. denial caches negative responses (NXDOMAIN) for a specified duration, preventing repeated lookups for non-existent domains. prefetch can proactively refresh cache entries before they expire, further reducing latency for frequently accessed records. For example, cache 300 { denial 60; prefetch 0.5 } caches positive responses for up to 300 seconds, negative responses for 60 seconds, and attempts to refresh 50% of the cache entries 30 seconds before they expire.

The most surprising thing about the cache plugin is how it can actually increase upstream load if misconfigured, not decrease it. This happens when the cache directive’s TTL is set lower than the TTLs of the records being served. If CoreDNS is set to cache 10 and an upstream server returns a record with a TTL of 60 seconds, CoreDNS will only hold that record for 10 seconds before querying upstream again, even though the upstream server would have happily provided it for another 50 seconds. This leads to more frequent upstream queries than necessary.

To truly leverage the cache, you need to understand the TTLs of the records your upstream servers are authoritative for. Tools like dig +nocmd +noall +answer example.com A can show you the TTL of a specific record. If your internal DNS is consistently returning records with TTLs of 5 seconds, setting cache 60 on CoreDNS is far more beneficial than cache 10.

The next step after optimizing your cache is to explore advanced CoreDNS plugins like rewrite to manipulate DNS queries and responses before they hit the cache or upstream, or kubernetes if you’re running in a cluster.

Want structured learning?

Take the full Coredns course →