All Use Cases

CMS Content at Edge Cache Speed

Serve headless CMS content from the DNS caching layer. NULL records for up to 64KB. Global TTL, zero origin load, sub-5ms delivery.

The Problem

Your headless CMS serves content to millions of visitors. Every page load hits your API. CDN helps, but origin is still hammered during cache misses and invalidations. Content over 4KB needs separate blob storage. Previews require separate infrastructure. Updates need cache purges across regions.

The Solution

ResolveDB publishes CMS content as DNS records. Small content uses TXT records; larger content (up to 64KB) uses NULL records with TCP fallback. Hash-addressed queries (h- prefix) ensure content integrity and enable 7-day immutable caching. Draft previews use NBA pattern for cryptographic access control.

Key Benefits

  • Content-addressed integrity - SHA-256 hash prefix prevents cache poisoning
  • Zero origin load for popular content - DNS caching handles traffic spikes
  • 64KB per record (NULL) - most articles fit in a single query
  • Immutable addressing - hash changes = new cache entry, no invalidation needed

Use Cases

Published Articles & Pages

HTML/JSON content stored directly in NULL records. Hash-addressed for immutability. 7-day cache means viral posts served from DNS resolvers worldwide, not your origin.

get.h-a3f2e8c1d4b5a678...posts.myblog.v1.resolvedb.net TYPE=NULL

Draft Previews

Draft content uses NBA pattern for authenticated access. 60-second TTL ensures editors see updates quickly. Cryptographic namespace binding prevents unauthorized preview access.

get.sig-<sig>-t-<ts>.auth-h-<jwt>.draft-123.preview.myblog.v1.resolvedb.net

Asset Manifests

Image/video metadata (URLs, dimensions, alt text, responsive variants) served via DNS. Actual binaries on CDN. Manifest cached 24 hours; assets have their own cache headers.

get.manifest.hero-image.assets.myblog.v1.resolvedb.net → {"thumb":"...","large":"..."}

Localized Content (i18n)

Each locale is explicit in the query - no Accept-Language header inference. Same query = same result globally. Each locale-hash combo cached independently.

get.locale-es.h-abc123...article.myblog.v1.resolvedb.net

Content Versioning

Every publish creates a new content hash. "Latest" pointer (short TTL) redirects to current version. Rollback is instant - update the pointer. Old versions remain accessible forever.

get.latest.my-article.myblog.v1.resolvedb.net → redirect to h-<current-hash>

Design Tokens & Components

Shared UI tokens (colors, spacing, typography) distributed globally. Version-pinned queries ensure consistent rendering. 7-day cache for versioned tokens.

get.h-tokens2024q4.design.myblog.v1.resolvedb.net → {"primary":"#FF5722"}

Security Pattern

h- for integrity, sig- for draftsHybrid: Content-Addressed (h-) + NBA (sig-)

Public content uses h-<sha256> prefix - client verifies SHA256(response) matches query. Drafts use NBA for cryptographic access control. Combined patterns prevent both cache poisoning and unauthorized preview access.

Try It Live

Live DNS Query
Query breakdown:
operation:getparams:h-a3f2e8c1d4b5a678901234567890abcd.homepageresource:contentnamespace:myblogversion:v1

Code Examples

Terminal
# Fetch published article by content hash (7-day cache)
dig TXT get.h-a3f2e8c1d4b5a678901234567890abcdef12345678901234567890abcdef12.posts.myblog.v1.resolvedb.net +short

# Large content (>4KB) - use NULL record over TCP
dig +tcp NULL get.h-a3f2e8c1d4b5a678901234567890abcd.article.myblog.v1.resolvedb.net

# Get latest version pointer (follows redirect)
dig TXT get.latest.my-article.posts.myblog.v1.resolvedb.net +short
# Returns redirect to current hash

# Asset manifest
dig TXT get.manifest.hero-image.assets.myblog.v1.resolvedb.net +short
# {"variants":{"thumb":"https://cdn.example/t.webp","large":"https://cdn.example/l.webp"}}
Python
from resolvedb import ResolveDB
import hashlib

db = ResolveDB(namespace="myblog")

# Fetch with automatic integrity verification
def fetch_article(slug: str, content_hash: str) -> dict:
    """Fetch article with SHA-256 verification."""
    article = db.content.get_by_hash(content_hash)

    # SDK verifies automatically, but you can double-check:
    actual_hash = hashlib.sha256(article.raw).hexdigest()
    if actual_hash != content_hash:
        raise ValueError("Content integrity check failed")

    return article.data

# Get latest version (follows redirect)
latest = db.content.get_latest("my-article")
print(f"Title: {latest['title']}")

# Localized content
spanish = db.content.get("my-article", locale="es")

# Preview draft (requires auth)
db_auth = ResolveDB(namespace="myblog", tenant_key="preview-key")
draft = db_auth.preview.get("draft-123", auth=jwt_token)
JavaScript
import { ResolveDB } from '@resolvedb/client';
import crypto from 'crypto';

const db = new ResolveDB({ namespace: 'myblog' });

// Public content with integrity verification
async function fetchArticle(contentHash: string) {
  const article = await db.content.getByHash(contentHash);

  // SDK verifies automatically, throws on mismatch
  return article;
}

// Get latest version (auto-follows redirect)
const latest = await db.content.getLatest('my-article');
console.log('Title:', latest.title);

// Localized content - explicit locale, no Accept-Language
const spanish = await db.content.get('my-article', { locale: 'es' });

// Preview draft (NBA pattern auto-applied)
const authDb = new ResolveDB({
  namespace: 'myblog',
  tenantKey: 'preview-key'
});
const draft = await authDb.preview.get('draft-123', { auth: jwtToken });
Go
package main

import (
    "crypto/sha256"
    "encoding/hex"
    "github.com/resolvedb/go-client"
)

func main() {
    db := resolvedb.New(resolvedb.Config{
        Namespace: "myblog",
    })

    // Fetch with integrity verification
    article, _ := db.Content.GetByHash(
        "a3f2e8c1d4b5a678901234567890abcdef12345678901234567890abcdef12",
    )
    // SDK verifies SHA256 automatically

    // Get latest version
    latest, _ := db.Content.GetLatest("my-article")
    fmt.Println("Title:", latest["title"])

    // Localized content
    spanish, _ := db.Content.Get("my-article", resolvedb.Opts{
        Locale: "es",
    })

    // Preview draft (with auth)
    authDb := resolvedb.New(resolvedb.Config{
        Namespace: "myblog",
        TenantKey: "preview-key",
    })
    draft, _ := authDb.Preview.Get("draft-123", resolvedb.WithAuth(jwtToken))
}

Comparison

FeatureResolveDBAlternative
Global cachingDNS layer (free)CDN required ($$$)
Cache invalidationHash change = new entryPurge API calls
Content integritySHA-256 verified (h-)Trust the CDN
Large content (>4KB)NULL records (64KB)Separate blob storage
Draft previewsCryptographic (NBA)Secret URL or API key
Version rollbackUpdate pointer (instant)Cache purge (minutes)

Frequently Asked Questions

How do I prevent cache poisoning?

ALWAYS use the h-<sha256> prefix for content queries. The client verifies SHA256(response) matches the queried hash. Any mismatch indicates cache poisoning and should be rejected. The SDK does this automatically.

What about content larger than 64KB?

Use the chunking protocol - fetch manifest first, then retrieve chunks in parallel. Each chunk has its own hash for integrity. Alternatively, store large assets on CDN and serve manifest (URLs, metadata) via DNS.

Why is TCP required for NULL records?

UDP DNS has no source IP verification - attackers can spoof IPs and trigger 64KB responses to victims (2048x amplification). TCP handshake verifies the client actually wants the response. All compliant resolvers retry over TCP automatically when they receive TC=1 (truncated) response.

How does rollback work?

Every version is stored by hash and never deleted. To rollback: update the "latest" pointer to the previous hash via API. Within one TTL period (default 5 min for pointers), all readers get the old version. Old hashes remain accessible for audit/recovery.

How do drafts prevent unauthorized access?

Drafts use NBA pattern - the query includes a cryptographic signature bound to your namespace. Even with a valid JWT, queries to other namespaces fail mathematically. Enable privacy mode to prevent draft enumeration via error differentiation.

How do I handle multiple languages?

Use explicit locale parameters: get.locale-es.h-<hash>.content... This follows UQRP design principles - same query always returns same result, regardless of Accept-Language headers. Each locale is cached independently.

Ready to get started?

Create an account and start storing data in under a minute.