Caching & TTL

Leverage the global DNS caching infrastructure as a distributed cache

The Caching Multiplier Effect

When you set a TTL on a ResolveDB response, you are not just caching at one layer. DNS responses are cached at every level of the resolution hierarchy, creating a multiplicative effect that dramatically reduces load on your origin.

Your Application
                            |
                            v
              +-----------------------------+
              |      Browser Cache          |  <-- TTL: 300s (5 min)
              |   (per-user, local)         |
              +-------------+---------------+
                            | Cache miss
                            v
              +-----------------------------+
              |      OS DNS Cache           |  <-- TTL: 300s
              |   (per-machine, local)      |
              +-------------+---------------+
                            | Cache miss
                            v
              +-----------------------------+
              |   Corporate DNS Server      |  <-- TTL: 300s
              |   (per-network, shared)     |      ~1000 users
              +-------------+---------------+
                            | Cache miss
                            v
              +-----------------------------+
              |      ISP DNS Resolver       |  <-- TTL: 300s
              |   (per-ISP, millions)       |      ~1M users
              +-------------+---------------+
                            | Cache miss
                            v
              +-----------------------------+
              |   Public DNS (8.8.8.8)      |  <-- TTL: 300s
              |   (global, billions)        |      ~100M users
              +-------------+---------------+
                            | Cache miss
                            v
              +-----------------------------+
              |        ResolveDB            |  <-- Origin
              |    (your data source)       |
              +-----------------------------+

With a 5-minute TTL, a piece of data accessed by millions of users might only hit your origin a few times per hour globally.

TTL Classes

ResolveDB provides predefined TTL classes to help you choose appropriate cache durations:

ClassTTLUse CaseExample
immutable7 daysContent that never changesHash-addressed data, versioned releases
stable24 hoursRarely changing reference dataDocumentation, configuration
standard1 hourDefault for most dataFeature flags, product info
dynamic5 minFrequently changing contentUser preferences, session data
volatile30-60 secNear real-time dataHealth checks, status indicators
nocache0Always fetch from originWrite confirmations, errors

Default TTLs by Operation

OperationDefault TTLNotes
get3600 (1 hour)Per-resource override based on data classification
put0Write confirmation, not cacheable
delete0Delete confirmation, not cacheable
info3600Metadata is stable
list300 (5 min)Listings change with additions
search60Results may be contextual
health30Must reflect current state
geoip300Location data is relatively stable
watch0Streaming endpoint, not DNS-cacheable

Setting TTL in Responses

# Response with 1-hour TTL (standard)
v=rdb1;s=ok;t=data;ttl=3600;d={"feature":"enabled"}

# Response with 7-day TTL (immutable, content-addressed)
v=rdb1;s=ok;t=data;ttl=604800;d={"version":"1.2.3","hash":"sha256-abc123"}

# Response with no caching
v=rdb1;s=ok;t=data;ttl=0;d={"error":"Invalid input"}

Cache Invalidation Strategies

DNS caching is excellent for performance but challenging for invalidation. ResolveDB provides several strategies:

1. Version-Based Keys

Embed version information in the resource path. When data changes, increment the resource version.

# Original config - cached for 24 hours
get.config-rev1.myapp.user.v1.resolvedb.net

# Updated config - new cache key, instant update
get.config-rev2.myapp.user.v1.resolvedb.net

2. Content-Addressed Data

Use hash-based addressing for immutable content.

# Content-addressed query (immutable, 7-day cache safe)
get.h-sha256abc123def456.assets.public.v1.resolvedb.net

3. Pointer + Data Pattern

Use a short-TTL pointer to a long-TTL immutable data location.

# Step 1: Fetch pointer (5 min TTL)
get.latest.config.myapp.v1.resolvedb.net
-> v=rdb1;s=ok;ttl=300;d={"ref":"v1.2.3"}

# Step 2: Fetch immutable data (7 day TTL)
get.v1-2-3.config.myapp.v1.resolvedb.net
-> v=rdb1;s=ok;ttl=604800;d={...full config...}

4. Graceful Degradation

Accept that some users will see stale data. Design your application to handle gradual rollouts.

Cache Security

ResolveDB implements several security measures:

  • TTL Classes: TTLs range from 0 (nocache) to 604800 seconds (7 days for immutable content)
  • Authenticated Query Exclusion: Queries with auth- tokens are never cached (fail-secure: if parsing fails, assume authenticated)
  • Rate Limit TTL: ratelimit responses use TTL=1 to signal immediate retry

Negative Caching

Per RFC 2308, non-existent resources are cached to prevent repeated queries:

ResponseTTLNotes
NXDOMAIN (name doesn't exist)3600 (1 hour)Per SOA MINIMUM
NODATA (type doesn't exist)3600 (1 hour)Per SOA MINIMUM
Server errors0Don't cache failures

Resolver Behavior

Different DNS resolvers handle TTL values differently:

ResolverTTL=0 BehaviorMax TTL
Google (8.8.8.8)May serve stale1 day
Cloudflare (1.1.1.1)Respects TTL=07 days
BINDCaches briefly (~1s)Configurable
Browser cachesOften apply minimumVaries

Implication: For truly uncacheable operations (put, delete), use TTL=0 but verify via response signatures rather than assuming zero latency.

Best Practices

  1. Start with Standard TTL - Begin with 1-hour and adjust based on needs
  2. Use Immutable for Static Assets - Content-addressed data should use 7-day TTL
  3. Avoid Zero TTL - Only use for write confirmations and errors
  4. Design for Eventual Consistency - Assume some users will see stale data
  5. Monitor Cache Hit Rates - Aim for 90%+ cache hits at aggregate level

Complete Example

// JavaScript client with TTL-aware caching
async function fetchConfig(appId, version = 'latest') {
  // Pointer query - short TTL for freshness
  const pointerQuery = `get.${version}.config.${appId}.v1.resolvedb.net`;
  const pointer = await dnsQuery(pointerQuery);

  // If version is "latest", follow the pointer to immutable data
  if (version === 'latest' && pointer.ref) {
    const dataQuery = `get.${pointer.ref}.config.${appId}.v1.resolvedb.net`;
    return await dnsQuery(dataQuery);
  }

  return pointer;
}

// TTL classes in your application
const TTL = {
  IMMUTABLE: 604800,  // 7 days
  STABLE: 86400,      // 24 hours
  STANDARD: 3600,     // 1 hour
  DYNAMIC: 300,       // 5 minutes
  VOLATILE: 60,       // 1 minute
  NOCACHE: 0
};

Next Steps