Examples & Recipes
Real-world use cases with copy-pasteable code examples for ResolveDB.
Try It Live
Experiment with real DNS queries before diving into the examples:
Configuration Storage
Store application configuration accessible via DNS. Perfect for feature flags, environment settings, and dynamic configuration.
Feature Flags
Store feature flags that can be queried from any client without an SDK.
DNS Query:
dig get.features.myapp.v1.resolvedb.net TXT +shortExpected Response:
v=rdb1;s=ok;t=data;f=json;ttl=300;d={"dark_mode":true,"beta_users":false,"max_uploads":10}JavaScript:
const dns = require('dns').promises;
async function getFeatureFlags() {
const records = await dns.resolveTxt('get.features.myapp.v1.resolvedb.net');
const response = records[0].join('');
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}
// Usage
const flags = await getFeatureFlags();
if (flags.dark_mode) {
enableDarkMode();
}Python:
import dns.resolver
import json
import re
def get_feature_flags():
answers = dns.resolver.resolve('get.features.myapp.v1.resolvedb.net', 'TXT')
response = str(answers[0]).strip('"')
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return {}
# Usage
flags = get_feature_flags()
if flags.get('dark_mode'):
enable_dark_mode()Environment Configuration
Different configurations per environment using namespaced queries.
# Production config
dig get.config.myapp-prod.v1.resolvedb.net TXT +short
# Staging config
dig get.config.myapp-staging.v1.resolvedb.net TXT +short
# Development config
dig get.config.myapp-dev.v1.resolvedb.net TXT +shortPublic Data APIs
Access public data sources via DNS queries. Data is cached at the DNS layer for ultra-fast global access.
Weather Data
Query current weather by providing an explicit city name or coordinates.
Privacy by Design: Location must be explicitly provided in the query. The server never infers location from the client's IP address.
DNS Query:
# By city name (explicit parameter)
dig get.city-newyork.weather.public.v1.resolvedb.net TXT +short
# By coordinates (explicit parameters)
# Format: lat-<lat>.lon-<lon> where decimals use 'd' separator
dig get.lat-40d7128.lon--74d0060.weather.public.v1.resolvedb.net TXT +short
# Or use Base64 encoded JSON for coordinates
# {"lat":40.7128,"lon":-74.0060}
dig get.b64-eyJsYXQiOjQwLjcxMjgsImxvbiI6LTc0LjAwNjB9.weather.public.v1.resolvedb.net TXT +shortExpected Response:
v=rdb1;s=ok;t=data;f=json;ttl=300;d={"city":"New York","temp":72,"unit":"F","conditions":"Partly Cloudy"}curl + jq:
# Using DNS-over-HTTPS for JSON output
curl -s "https://dns.google/resolve?name=get.city-newyork.weather.public.v1.resolvedb.net&type=TXT" \
| jq -r '.Answer[0].data' \
| sed 's/.*d=//' \
| jq .JavaScript:
async function getWeather(city) {
const dns = require('dns').promises;
// Explicit city parameter in query
const query = `get.city-${city.toLowerCase()}.weather.public.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}
const weather = await getWeather('newyork');
console.log(`${weather.city}: ${weather.temp}${weather.unit}`);
// Output: New York: 72FStock Prices
Real-time stock quotes with short TTL for frequently updating data.
DNS Query:
dig get.aapl.stocks.public.v1.resolvedb.net TXT +short
dig get.googl.stocks.public.v1.resolvedb.net TXT +shortExpected Response:
v=rdb1;s=ok;t=data;f=json;ttl=60;d={"symbol":"AAPL","price":185.92,"change":2.34,"percent":1.27}Python:
import dns.resolver
import json
import re
def get_stock_price(symbol):
query = f'get.{symbol.lower()}.stocks.public.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return None
stock = get_stock_price('AAPL')
print(f"{stock['symbol']}: ${stock['price']} ({stock['change']:+.2f})")
# Output: AAPL: $185.92 (+2.34)News Headlines
Fetch latest headlines by category.
dig get.tech.headlines.public.v1.resolvedb.net TXT +short
dig get.business.headlines.public.v1.resolvedb.net TXT +shortUser Data Storage
Store and retrieve authenticated user data. Requires JWT authentication via the auth- prefix.
User Preferences
Store per-user settings that sync across devices.
Store Preferences (via API):
curl -X POST https://api.resolvedb.io/api/v1/records \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"record": {
"key": "preferences.user123.v1",
"data": "eyJ0aGVtZSI6ImRhcmsiLCJsYW5nIjoiZW4iLCJub3RpZnkiOnRydWV9",
"visibility": "private"
}
}'Retrieve with Authentication:
# JWT token contains user identity
dig get.auth-<jwt_token>.preferences.user123.v1.resolvedb.net TXT +shortJavaScript:
const dns = require('dns').promises;
async function getUserPreferences(userId, jwtToken) {
const query = `get.auth-${jwtToken}.preferences.${userId}.v1.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Check for auth errors
if (response.includes('s=auth')) {
throw new Error('Authentication required');
}
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}
// Usage
const prefs = await getUserPreferences('user123', myJwtToken);
console.log(prefs);
// Output: { theme: "dark", lang: "en", notify: true }Python:
import dns.resolver
import json
import re
def get_user_preferences(user_id, jwt_token):
query = f'get.auth-{jwt_token}.preferences.{user_id}.v1.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Check for auth errors
if 's=auth' in response:
raise Exception('Authentication required')
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return None
prefs = get_user_preferences('user123', my_jwt_token)
print(prefs)
# Output: {'theme': 'dark', 'lang': 'en', 'notify': True}Large File Handling
DNS TXT records are limited to ~255 bytes per string and ~512 bytes per UDP response. ResolveDB handles larger data through chunking and blob URL fallback.
Chunked Data Retrieval
For data between 512 bytes and 4KB, ResolveDB returns metadata pointing to chunks.
DNS Query:
dig get.largeconfig.myapp.v1.resolvedb.net TXT +shortChunked Response:
v=rdb1;s=partial;t=multi;chunks=3;total=1536;hash=abc123;d=chunk-0.largeconfig.myapp.v1JavaScript - Chunk Reassembly:
const dns = require('dns').promises;
async function getLargeData(key, namespace, version) {
const baseQuery = `get.${key}.${namespace}.${version}.resolvedb.net`;
const records = await dns.resolveTxt(baseQuery);
const response = records[0].join('');
// Check if chunked
if (response.includes('t=multi')) {
const chunks = parseInt(response.match(/chunks=(\d+)/)?.[1] || '0');
// Fetch all chunks in parallel
const chunkPromises = [];
for (let i = 0; i < chunks; i++) {
const chunkQuery = `get.chunk-${i}.${key}.${namespace}.${version}.resolvedb.net`;
chunkPromises.push(dns.resolveTxt(chunkQuery));
}
const chunkResults = await Promise.all(chunkPromises);
const reassembled = chunkResults
.map(r => r[0].join(''))
.map(r => r.match(/d=(.+)$/)?.[1])
.join('');
return JSON.parse(reassembled);
}
// Small data - return directly
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}Blob URL Fallback
For data larger than 4KB, ResolveDB returns a redirect to a CDN-hosted blob.
DNS Query:
dig get.largefile.myapp.v1.resolvedb.net TXT +shortRedirect Response:
v=rdb1;s=redirect;t=url;ttl=3600;d=https://cdn.resolvedb.cloud/blob/abc123def456JavaScript - Handle Redirect:
const dns = require('dns').promises;
async function getData(key, namespace, version) {
const query = `get.${key}.${namespace}.${version}.resolvedb.net`;
const records = await dns.resolveTxt(query);
const response = records[0].join('');
// Check for redirect
if (response.includes('s=redirect')) {
const url = response.match(/d=(.+)$/)?.[1];
// Fetch from CDN
const blobData = await fetch(url).then(r => r.json());
return blobData;
}
// Direct data
const data = response.match(/d=(.+)$/)?.[1];
return JSON.parse(data);
}Python:
import dns.resolver
import json
import re
import requests
def get_data(key, namespace, version):
query = f'get.{key}.{namespace}.{version}.resolvedb.net'
answers = dns.resolver.resolve(query, 'TXT')
response = str(answers[0]).strip('"')
# Check for redirect
if 's=redirect' in response:
match = re.search(r'd=(.+)$', response)
if match:
url = match.group(1)
return requests.get(url).json()
# Direct data
match = re.search(r'd=(.+)$', response)
if match:
return json.loads(match.group(1))
return NoneEncrypted Secrets
Store sensitive data with client-side encryption. ResolveDB never sees the plaintext.
AES-256-GCM Encryption
Encrypt data before storing, decrypt after retrieval.
Store Encrypted Secret (via API):
# Client-side: encrypt data before sending
# encrypted = AES-256-GCM(plaintext, key)
# encoded = base64(nonce + ciphertext + tag)
curl -X POST https://api.resolvedb.io/api/v1/records \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"record": {
"key": "secrets.db-password.prod.v1",
"data": "<base64_encrypted_data>",
"encrypted": true
}
}'JavaScript - Encrypt & Store:
const crypto = require('crypto');
// Encryption key (store securely, e.g., in environment or KMS)
const ENCRYPTION_KEY = Buffer.from(process.env.RESOLVEDB_ENCRYPTION_KEY, 'hex');
function encrypt(plaintext) {
const iv = crypto.randomBytes(12);
const cipher = crypto.createCipheriv('aes-256-gcm', ENCRYPTION_KEY, iv);
let encrypted = cipher.update(plaintext, 'utf8');
encrypted = Buffer.concat([encrypted, cipher.final()]);
const tag = cipher.getAuthTag();
// Combine: iv (12) + encrypted + tag (16)
return Buffer.concat([iv, encrypted, tag]).toString('base64');
}
function decrypt(encryptedBase64) {
const data = Buffer.from(encryptedBase64, 'base64');
const iv = data.subarray(0, 12);
const tag = data.subarray(-16);
const ciphertext = data.subarray(12, -16);
const decipher = crypto.createDecipheriv('aes-256-gcm', ENCRYPTION_KEY, iv);
decipher.setAuthTag(tag);
let decrypted = decipher.update(ciphertext);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted.toString('utf8');
}
// Store secret
const secret = 'my-database-password';
const encrypted = encrypt(secret);
// Send 'encrypted' to ResolveDB API
// Retrieve and decrypt
const response = await getFromResolveDB('secrets.db-password.prod.v1');
const plaintext = decrypt(response);Python:
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
import base64
# Encryption key (32 bytes for AES-256)
ENCRYPTION_KEY = bytes.fromhex(os.environ['RESOLVEDB_ENCRYPTION_KEY'])
def encrypt(plaintext: str) -> str:
aesgcm = AESGCM(ENCRYPTION_KEY)
nonce = os.urandom(12)
ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)
# Combine nonce + ciphertext (includes tag)
return base64.b64encode(nonce + ciphertext).decode()
def decrypt(encrypted_b64: str) -> str:
data = base64.b64decode(encrypted_b64)
nonce = data[:12]
ciphertext = data[12:]
aesgcm = AESGCM(ENCRYPTION_KEY)
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
return plaintext.decode()
# Usage
secret = 'my-database-password'
encrypted = encrypt(secret)
# Store 'encrypted' in ResolveDB
# Later: retrieve and decrypt
plaintext = decrypt(encrypted)Key Management Patterns
Best practices for managing encryption keys:
- Environment-specific keys: Use different encryption keys per environment (dev, staging, prod)
- Key rotation: Store versioned keys, include key version in encrypted data metadata
- Key derivation: Derive per-record keys from master key using HKDF
- Cloud KMS: Use AWS KMS, GCP KMS, or Azure Key Vault for key storage
Key Derivation Example:
const crypto = require('crypto');
function deriveKey(masterKey, recordId) {
return crypto.hkdfSync(
'sha256',
masterKey,
Buffer.from(recordId),
Buffer.from('resolvedb-encryption'),
32
);
}
// Each record gets a unique derived key
const recordKey = deriveKey(masterKey, 'secrets.db-password.prod.v1');Edge Computing / Serverless
ResolveDB is ideal for serverless environments where cold starts matter. DNS resolution happens outside your function, with data already cached at edge locations.
AWS Lambda
Fetch configuration without HTTP client initialization overhead.
JavaScript (Node.js Runtime):
const dns = require('dns').promises;
// DNS is available immediately - no HTTP client needed
exports.handler = async (event) => {
// Resolves in ~1-5ms when cached (vs 50-200ms HTTP cold start)
const records = await dns.resolveTxt('get.config.myapp.v1.resolvedb.net');
const response = records[0].join('');
const config = JSON.parse(response.match(/d=(.+)$/)?.[1]);
// Use config
const threshold = config.rate_limit || 100;
return {
statusCode: 200,
body: JSON.stringify({ processed: true })
};
};Python Runtime:
import dns.resolver
import json
import re
def lambda_handler(event, context):
# DNS resolution is fast - no connection pooling needed
answers = dns.resolver.resolve('get.config.myapp.v1.resolvedb.net', 'TXT')
response = str(answers[0]).strip('"')
match = re.search(r'd=(.+)$', response)
config = json.loads(match.group(1)) if match else {}
# Use config
threshold = config.get('rate_limit', 100)
return {
'statusCode': 200,
'body': json.dumps({'processed': True})
}Cloudflare Workers
Use DNS-over-HTTPS in Workers where native DNS is not available.
export default {
async fetch(request, env) {
// Workers don't have native DNS, use DoH
const dohUrl = 'https://cloudflare-dns.com/dns-query';
const query = 'get.config.myapp.v1.resolvedb.net';
const response = await fetch(
`${dohUrl}?name=${query}&type=TXT`,
{
headers: { 'Accept': 'application/dns-json' }
}
);
const data = await response.json();
const txtRecord = data.Answer?.[0]?.data?.replace(/"/g, '');
const config = JSON.parse(txtRecord.match(/d=(.+)$/)?.[1]);
return new Response(JSON.stringify({
feature_enabled: config.feature_enabled
}), {
headers: { 'Content-Type': 'application/json' }
});
}
};Vercel Edge Functions
Lightweight configuration for edge middleware.
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export async function middleware(request: NextRequest) {
// Fetch feature flags via DoH (edge has no native DNS)
const doh = await fetch(
'https://dns.google/resolve?name=get.flags.myapp.v1.resolvedb.net&type=TXT'
);
const data = await doh.json();
const record = data.Answer?.[0]?.data?.replace(/"/g, '');
const flags = JSON.parse(record.match(/d=(.+)$/)?.[1]);
// A/B test based on feature flag
if (flags.new_checkout && Math.random() < flags.new_checkout_percent) {
return NextResponse.rewrite(new URL('/checkout-v2', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: '/checkout/:path*'
};Why DNS is faster for serverless
- No TCP/TLS handshake (UDP-based)
- Cached at multiple layers (local, ISP, edge)
- No connection pooling or keep-alive management
- Available immediately in cold start (no client init)
- Sub-millisecond when cached locally
IoT / Embedded
Minimal DNS-only clients for resource-constrained devices. No HTTP stack required, works with any device that can make DNS queries.
Device Configuration
Push configuration to IoT devices via DNS. Devices poll their config periodically using lightweight DNS queries.
DNS Query:
# Device queries its own config by device ID
dig get.config.device-abc123.iot.v1.resolvedb.net TXT +shortExpected Response:
v=rdb1;s=ok;t=data;f=json;ttl=3600;d={"sample_rate":60,"report_interval":300,"firmware":"2.1.0"}Arduino/ESP32 (C++)
#include <WiFi.h>
#include <WiFiUdp.h>
#include <ArduinoJson.h>
WiFiUDP udp;
const char* DNS_SERVER = "8.8.8.8";
const int DNS_PORT = 53;
String dnsQuery(const char* hostname) {
// Simplified DNS query - use a proper DNS library in production
byte packet[512];
int len = buildDnsQuery(packet, hostname, DNS_TYPE_TXT);
udp.beginPacket(DNS_SERVER, DNS_PORT);
udp.write(packet, len);
udp.endPacket();
int responseLen = waitForResponse(packet, 512, 1000);
if (responseLen > 0) {
return parseTxtRecord(packet, responseLen);
}
return "";
}
void updateConfig() {
String deviceId = getDeviceId();
String query = "get.config." + deviceId + ".iot.v1.resolvedb.net";
String response = dnsQuery(query.c_str());
int dataStart = response.indexOf("d=");
if (dataStart > 0) {
String jsonData = response.substring(dataStart + 2);
StaticJsonDocument<256> doc;
deserializeJson(doc, jsonData);
int sampleRate = doc["sample_rate"] | 60;
int reportInterval = doc["report_interval"] | 300;
applySampleRate(sampleRate);
applyReportInterval(reportInterval);
}
}
void loop() {
updateConfig();
delay(3600000); // Check hourly (matches TTL)
}MicroPython (ESP8266/ESP32)
import socket
import ujson
import ure
def dns_query_txt(hostname):
"""Simple TXT record query using system resolver"""
try:
import udns # hypothetical lightweight DNS library
records = udns.query(hostname, 'TXT')
return records[0] if records else None
except Exception as e:
print(f"DNS error: {e}")
return None
def get_config():
device_id = get_device_id()
hostname = f"get.config.{device_id}.iot.v1.resolvedb.net"
response = dns_query_txt(hostname)
if response:
match = ure.search(r'd=(.+)$', response)
if match:
config = ujson.loads(match.group(1))
return config
return {}
# Main loop
while True:
config = get_config()
sample_rate = config.get('sample_rate', 60)
set_sample_rate(sample_rate)
import time
time.sleep(config.get('ttl', 3600))Fleet Configuration Distribution
Push updates to groups of devices simultaneously.
# Global config for all devices
dig get.config.global.iot.v1.resolvedb.net TXT +short
# Config by device type
dig get.config.sensor-v2.iot.v1.resolvedb.net TXT +short
# Config by location
dig get.config.warehouse-nyc.iot.v1.resolvedb.net TXT +short
# Individual device override
dig get.config.device-abc123.iot.v1.resolvedb.net TXT +shortConfiguration Hierarchy (Device Code):
def get_merged_config():
"""Fetch config with fallback hierarchy"""
config = {}
# 1. Start with global defaults
global_config = query_config('global')
config.update(global_config)
# 2. Apply device type overrides
type_config = query_config(f'sensor-{DEVICE_TYPE}')
config.update(type_config)
# 3. Apply location overrides
location_config = query_config(f'location-{DEVICE_LOCATION}')
config.update(location_config)
# 4. Apply device-specific overrides
device_config = query_config(f'device-{DEVICE_ID}')
config.update(device_config)
return configIoT Advantages
- Minimal code footprint - DNS is a standard protocol
- No TLS certificates needed for read-only config
- Works behind NAT without port forwarding
- Firewall-friendly (DNS typically allowed)
- Low power - single UDP packet vs TCP connection