DNS caching means 10,000 users checking a flag = 1 origin request. Works in shell scripts, cron jobs, edge functions - anywhere DNS works.
Feature flag services charge per monthly active user. At 100K users, you're paying thousands per year for what amounts to boolean lookups. Every SDK adds cold-start latency. Shell scripts and edge functions can't easily use traditional flag services. And when you need to kill a feature fast, you're waiting for SDK polling intervals.
ResolveDB serves feature flags as DNS TXT records. Simple flags work with just `dig` - no SDK required. For user targeting, the Cohort Token Pattern (CTP) encrypts user context into an opaque token; the server evaluates targeting rules and returns only the results. DNS caching means your flag service handles 1 request per TTL, not 1 per user.
Disable a broken feature across all services in 30 seconds. No deployment, no SDK update, no coordination. Change the flag, wait for TTL expiry, done.
get.payments-v2.flags.myapp.v1.resolvedb.net → {"enabled":false}One flag checked by 50 microservices. With traditional flags, that's 50 SDK connections. With ResolveDB, it's one cached DNS response per TTL.
get.maintenance.flags.myapp.v1.resolvedb.net → {"enabled":true,"message":"Back in 10 mins"}Your deployment script needs to check if a feature is ready. No npm install, no pip install. Just dig.
if dig TXT get.deploy-v2.flags.myapp.v1.resolvedb.net +short | grep -q '"enabled":true'; then deploy_v2; fiCloudflare Workers and Lambda@Edge have milliseconds to respond and no persistent state. DNS-over-HTTPS completes before your function cold starts.
fetch("https://dns.google/resolve?name=get.dark-mode.flags.myapp.v1.resolvedb.net&type=TXT")Roll out to 10% of users, then 25%, then 50%. CTP tokens encode user tier; server evaluates rollout percentage. Cache-friendly because users in the same tier get the same response.
get.ctp-<encrypted-token>.new-checkout.flags.myapp.v1.resolvedb.net → {"enabled":true}ctp-Cohort Token Pattern (CTP)AES-256-GCM encrypted segment bitmap for user targeting. 5-minute expiry. Server-side rule evaluation - targeting logic never exposed in queries.
# Kill switch check in deployment script
FLAG=$(dig TXT get.payments-v2.flags.acme.v1.resolvedb.net +short 2>/dev/null)
if echo "$FLAG" | grep -q '"enabled":false'; then
echo "payments-v2 is disabled, skipping deployment"
exit 0
fi
# Maintenance mode in cron job
if dig TXT get.maintenance.flags.acme.v1.resolvedb.net +short | grep -q '"enabled":true'; then
echo "Maintenance mode - skipping batch job"
exit 0
fi
# Simple flag check (any language with DNS works)
dig TXT get.dark-mode.flags.myapp.v1.resolvedb.net +short
# "v=rdb1;s=ok;f=json;ttl=60;d={\"enabled\":true}"import dns.resolver
import json
def get_flag(flag_name: str, namespace: str = "myapp") -> dict:
"""Get feature flag - no SDK required."""
fqdn = f"get.{flag_name}.flags.{namespace}.v1.resolvedb.net"
answers = dns.resolver.resolve(fqdn, 'TXT')
response = str(answers[0]).strip('"')
parts = dict(p.split('=', 1) for p in response.split(';') if '=' in p)
return json.loads(parts.get('d', '{}'))
# Kill switch check
if not get_flag("payments-v2")["enabled"]:
print("Feature disabled")
sys.exit(0)
# With SDK for user targeting (optional)
from resolvedb import ResolveDB
db = ResolveDB(namespace="myapp", secret="your-secret")
# CTP auto-encrypts user context
flags = db.flags.get_for_user("new-checkout", user={
"id": "user-123", "premium": True, "region": "na"
})
print(f"New checkout: {flags['enabled']}")import dns from 'dns/promises';
// No SDK required - just DNS
async function getFlag(flagName: string): Promise<{enabled: boolean}> {
const fqdn = `get.${flagName}.flags.myapp.v1.resolvedb.net`;
const records = await dns.resolveTxt(fqdn);
const response = records.flat().join('');
const match = response.match(/d=(.+?)(?:;|$)/);
return match ? JSON.parse(match[1]) : { enabled: false };
}
// Edge function (Cloudflare Workers)
async function handleRequest(request: Request) {
// DoH - works in edge runtime
const res = await fetch(
'https://dns.google/resolve?name=get.maintenance.flags.myapp.v1.resolvedb.net&type=TXT'
);
const data = await res.json();
if (data.Answer?.[0]?.data?.includes('"enabled":true')) {
return new Response('Maintenance mode', { status: 503 });
}
// Continue with request...
}package main
import (
"encoding/json"
"net"
"strings"
)
func getFlag(flagName, namespace string) (map[string]any, error) {
fqdn := fmt.Sprintf("get.%s.flags.%s.v1.resolvedb.net", flagName, namespace)
records, err := net.LookupTXT(fqdn)
if err != nil { return nil, err }
response := strings.Join(records, "")
for _, seg := range strings.Split(response, ";") {
if strings.HasPrefix(seg, "d=") {
var result map[string]any
json.Unmarshal([]byte(seg[2:]), &result)
return result, nil
}
}
return nil, nil
}
// Kill switch check
flag, _ := getFlag("payments-v2", "myapp")
if enabled, ok := flag["enabled"].(bool); !ok || !enabled {
log.Fatal("Feature disabled")
}| Feature | ResolveDB | Alternative |
|---|---|---|
| Cost at 100K MAU | ~$10/month (fixed) | $1,000+/month (per-seat) |
| 10K concurrent users | 1 origin request/TTL | 10K SDK connections |
| Shell script support | Native (dig) | REST API workaround |
| Edge function support | DoH in 1 line | SDK may not work |
| Cold start latency | 0ms (DNS in stdlib) | 50-500ms (SDK init) |
| Kill switch propagation | 30-60s (TTL) | 1-5min (SDK polling) |
ResolveDB is simpler and cheaper at scale. LaunchDarkly excels at sophisticated targeting (50+ attributes), built-in experimentation, and enterprise compliance. ResolveDB is ideal for simple on/off flags, kill switches, and environments where SDKs don't work (shell scripts, edge functions). At scale, the pricing difference is significant.
Use Cohort Token Pattern (CTP) for basic segmentation. The SDK encrypts user attributes (premium, region, tier) into a token. The server evaluates rules and returns results. For sophisticated 50-attribute rules, use a dedicated feature flag service.
Update the flag via API, and it propagates globally within one TTL period (default 60 seconds). For faster propagation during incidents, use a shorter TTL (30s) or implement a local SDK cache bypass.
Absolutely. Simple flags work with just dig or any DNS library. The examples show raw DNS queries. The SDK is optional convenience for response parsing and CTP token generation.
Rotate the secret immediately via API. Old tokens become invalid (can't decrypt). This is a P0 incident - treat CTP secrets like database credentials. For access control, always combine CTP with JWT authentication.
Create an account and start storing data in under a minute.